From 36efb994580dff48cf6cd3e8fe2955117357213c Mon Sep 17 00:00:00 2001 From: mkitsdts Date: Wed, 25 Mar 2026 17:04:32 +0800 Subject: [PATCH 01/10] feat(internal): add plugin interface --- internal/plugin/all/all.go | 8 +++ internal/plugin/config.go | 79 +++++++++++++++++++++++ internal/plugin/plugin.go | 8 +++ internal/plugin/register.go | 121 ++++++++++++++++++++++++++++++++++++ 4 files changed, 216 insertions(+) create mode 100644 internal/plugin/all/all.go create mode 100644 internal/plugin/config.go create mode 100644 internal/plugin/plugin.go create mode 100644 internal/plugin/register.go diff --git a/internal/plugin/all/all.go b/internal/plugin/all/all.go new file mode 100644 index 000000000..4fc245c13 --- /dev/null +++ b/internal/plugin/all/all.go @@ -0,0 +1,8 @@ +package all + +import ( + _ "github.com/OpenListTeam/OpenList/v4/plugins/ftp" + _ "github.com/OpenListTeam/OpenList/v4/plugins/s3" + _ "github.com/OpenListTeam/OpenList/v4/plugins/sftp" + _ "github.com/OpenListTeam/OpenList/v4/plugins/webdav" +) diff --git a/internal/plugin/config.go b/internal/plugin/config.go new file mode 100644 index 000000000..22a5b221d --- /dev/null +++ b/internal/plugin/config.go @@ -0,0 +1,79 @@ +package plugin + +import ( + "fmt" + "strconv" +) + +func IntValue(config map[string]any, key string, fallback int) (int, error) { + value, ok := config[key] + if !ok || value == nil { + return fallback, nil + } + switch v := value.(type) { + case int: + return v, nil + case int8: + return int(v), nil + case int16: + return int(v), nil + case int32: + return int(v), nil + case int64: + return int(v), nil + case uint: + return int(v), nil + case uint8: + return int(v), nil + case uint16: + return int(v), nil + case uint32: + return int(v), nil + case uint64: + return int(v), nil + case float32: + return int(v), nil + case float64: + return int(v), nil + case string: + parsed, err := strconv.Atoi(v) + if err != nil { + return 0, fmt.Errorf("parse %s as int: %w", key, err) + } + return parsed, nil + default: + return 0, fmt.Errorf("parse %s as int: unsupported type %T", key, value) + } +} + +func BoolValue(config map[string]any, key string, fallback bool) (bool, error) { + value, ok := config[key] + if !ok || value == nil { + return fallback, nil + } + switch v := value.(type) { + case bool: + return v, nil + case string: + parsed, err := strconv.ParseBool(v) + if err != nil { + return false, fmt.Errorf("parse %s as bool: %w", key, err) + } + return parsed, nil + default: + return false, fmt.Errorf("parse %s as bool: unsupported type %T", key, value) + } +} + +func StringValue(config map[string]any, key, fallback string) (string, error) { + value, ok := config[key] + if !ok || value == nil { + return fallback, nil + } + switch v := value.(type) { + case string: + return v, nil + default: + return "", fmt.Errorf("parse %s as string: unsupported type %T", key, value) + } +} diff --git a/internal/plugin/plugin.go b/internal/plugin/plugin.go new file mode 100644 index 000000000..b46c04efa --- /dev/null +++ b/internal/plugin/plugin.go @@ -0,0 +1,8 @@ +package plugin + +type Plugin interface { + Name() string + Init(config map[string]any) error + Start() error + Stop() error +} diff --git a/internal/plugin/register.go b/internal/plugin/register.go new file mode 100644 index 000000000..f2f2c8f7a --- /dev/null +++ b/internal/plugin/register.go @@ -0,0 +1,121 @@ +package plugin + +import ( + "sync" + + "github.com/OpenListTeam/OpenList/v4/internal/conf" + log "github.com/sirupsen/logrus" +) + +var ( + plugins map[string]Plugin + initialized map[string]bool + running map[string]bool + mu sync.RWMutex +) + +func RegisterPlugin(name string, construct func() Plugin) { + if plugins == nil { + plugins = make(map[string]Plugin) + } + if initialized == nil { + initialized = make(map[string]bool) + } + if running == nil { + running = make(map[string]bool) + } + mu.Lock() + plugins[name] = construct() + mu.Unlock() +} + +func Init(name string, data map[string]any) error { + mu.Lock() + p, ok := plugins[name] + if !ok { + mu.Unlock() + return nil + } + if initialized[name] { + mu.Unlock() + return nil + } + mu.Unlock() + if err := p.Init(data); err != nil { + return err + } + mu.Lock() + initialized[name] = true + mu.Unlock() + return nil +} + +func Start(name string) { + mu.RLock() + p := plugins[name] + mu.RUnlock() + if p == nil { + log.Warnf("plugin %s is not registered", name) + return + } + go func(name string, p Plugin) { + setRunning(name, true) + err := p.Start() + setRunning(name, false) + if err != nil { + log.Errorf("start plugin %s failed: %+v", name, err) + } + }(name, p) + +} + +func Stop(name string) { + mu.RLock() + state, ok := running[name] + p := plugins[name] + mu.RUnlock() + if !ok || !state || p == nil { + return + } + if err := p.Stop(); err != nil { + log.Errorf("stop plugin %s failed: %+v", name, err) + } + setRunning(name, false) +} + +func StartAll() { + for _, p := range conf.Conf.Plugins { + if err := Init(p.Name, p.Data); err != nil { + log.Errorf("init plugin %s failed: %+v", p.Name, err) + continue + } + if p.Enable { + Start(p.Name) + } + } +} + +func StopAll() { + mu.Lock() + defer mu.Unlock() + for name := range running { + if state := running[name]; state { + if err := plugins[name].Stop(); err != nil { + log.Errorf("stop plugin %s failed: %+v", name, err) + } + } + running[name] = false + } +} + +func IsRunning(name string) bool { + mu.RLock() + defer mu.RUnlock() + return running[name] +} + +func setRunning(name string, value bool) { + mu.Lock() + defer mu.Unlock() + running[name] = value +} From b62b191d38af1cf8134b64337370d13bd98f0a6c Mon Sep 17 00:00:00 2001 From: mkitsdts Date: Wed, 25 Mar 2026 17:06:26 +0800 Subject: [PATCH 02/10] feat(plugin/ftp): adapt ftp into plugin --- {server => plugins}/ftp/afero.go | 0 plugins/ftp/config.go | 13 ++++ {server => plugins}/ftp/fsmanage.go | 0 {server => plugins}/ftp/fsread.go | 0 {server => plugins}/ftp/fsup.go | 0 plugins/ftp/plugin.go | 93 +++++++++++++++++++++++++ server/ftp.go => plugins/ftp/runtime.go | 86 +++++++++++------------ plugins/ftp/server.go | 1 + {server => plugins}/ftp/site.go | 0 {server => plugins}/ftp/upload_stage.go | 0 plugins/ftp/utils.go | 14 ++++ 11 files changed, 162 insertions(+), 45 deletions(-) rename {server => plugins}/ftp/afero.go (100%) create mode 100644 plugins/ftp/config.go rename {server => plugins}/ftp/fsmanage.go (100%) rename {server => plugins}/ftp/fsread.go (100%) rename {server => plugins}/ftp/fsup.go (100%) create mode 100644 plugins/ftp/plugin.go rename server/ftp.go => plugins/ftp/runtime.go (79%) create mode 100644 plugins/ftp/server.go rename {server => plugins}/ftp/site.go (100%) rename {server => plugins}/ftp/upload_stage.go (100%) create mode 100644 plugins/ftp/utils.go diff --git a/server/ftp/afero.go b/plugins/ftp/afero.go similarity index 100% rename from server/ftp/afero.go rename to plugins/ftp/afero.go diff --git a/plugins/ftp/config.go b/plugins/ftp/config.go new file mode 100644 index 000000000..470c924a7 --- /dev/null +++ b/plugins/ftp/config.go @@ -0,0 +1,13 @@ +package ftp + +type FTP struct { + Listen string `json:"listen" env:"LISTEN"` + FindPasvPortAttempts int `json:"find_pasv_port_attempts" env:"FIND_PASV_PORT_ATTEMPTS"` + ActiveTransferPortNon20 bool `json:"active_transfer_port_non_20" env:"ACTIVE_TRANSFER_PORT_NON_20"` + IdleTimeout int `json:"idle_timeout" env:"IDLE_TIMEOUT"` + ConnectionTimeout int `json:"connection_timeout" env:"CONNECTION_TIMEOUT"` + DisableActiveMode bool `json:"disable_active_mode" env:"DISABLE_ACTIVE_MODE"` + DefaultTransferBinary bool `json:"default_transfer_binary" env:"DEFAULT_TRANSFER_BINARY"` + EnableActiveConnIPCheck bool `json:"enable_active_conn_ip_check" env:"ENABLE_ACTIVE_CONN_IP_CHECK"` + EnablePasvConnIPCheck bool `json:"enable_pasv_conn_ip_check" env:"ENABLE_PASV_CONN_IP_CHECK"` +} diff --git a/server/ftp/fsmanage.go b/plugins/ftp/fsmanage.go similarity index 100% rename from server/ftp/fsmanage.go rename to plugins/ftp/fsmanage.go diff --git a/server/ftp/fsread.go b/plugins/ftp/fsread.go similarity index 100% rename from server/ftp/fsread.go rename to plugins/ftp/fsread.go diff --git a/server/ftp/fsup.go b/plugins/ftp/fsup.go similarity index 100% rename from server/ftp/fsup.go rename to plugins/ftp/fsup.go diff --git a/plugins/ftp/plugin.go b/plugins/ftp/plugin.go new file mode 100644 index 000000000..0722fdc0f --- /dev/null +++ b/plugins/ftp/plugin.go @@ -0,0 +1,93 @@ +package ftp + +import ( + "fmt" + + iplugin "github.com/OpenListTeam/OpenList/v4/internal/plugin" + "github.com/OpenListTeam/OpenList/v4/pkg/utils" + ftpserver "github.com/fclairamb/ftpserverlib" +) + +type FTPPlugin struct { + driver *MainDriver + server *ftpserver.FtpServer + conf FTP +} + +func (p *FTPPlugin) Name() string { + return "ftp" +} + +func (p *FTPPlugin) Init(config map[string]any) error { + var err error + p.conf = FTP{ + Listen: ":5221", + FindPasvPortAttempts: 50, + ActiveTransferPortNon20: false, + IdleTimeout: 900, + ConnectionTimeout: 30, + DisableActiveMode: false, + DefaultTransferBinary: false, + EnableActiveConnIPCheck: true, + EnablePasvConnIPCheck: true, + } + if p.conf.Listen, err = iplugin.StringValue(config, "listen", p.conf.Listen); err != nil { + return err + } + if p.conf.FindPasvPortAttempts, err = iplugin.IntValue(config, "find_pasv_port_attempts", p.conf.FindPasvPortAttempts); err != nil { + return err + } + if p.conf.ActiveTransferPortNon20, err = iplugin.BoolValue(config, "active_transfer_port_non_20", p.conf.ActiveTransferPortNon20); err != nil { + return err + } + if p.conf.IdleTimeout, err = iplugin.IntValue(config, "idle_timeout", p.conf.IdleTimeout); err != nil { + return err + } + if p.conf.ConnectionTimeout, err = iplugin.IntValue(config, "connection_timeout", p.conf.ConnectionTimeout); err != nil { + return err + } + if p.conf.DisableActiveMode, err = iplugin.BoolValue(config, "disable_active_mode", p.conf.DisableActiveMode); err != nil { + return err + } + if p.conf.DefaultTransferBinary, err = iplugin.BoolValue(config, "default_transfer_binary", p.conf.DefaultTransferBinary); err != nil { + return err + } + if p.conf.EnableActiveConnIPCheck, err = iplugin.BoolValue(config, "enable_active_conn_ip_check", p.conf.EnableActiveConnIPCheck); err != nil { + return err + } + if p.conf.EnablePasvConnIPCheck, err = iplugin.BoolValue(config, "enable_pasv_conn_ip_check", p.conf.EnablePasvConnIPCheck); err != nil { + return err + } + return nil +} + +func (p *FTPPlugin) Start() error { + driver, err := NewMainDriver(p.conf) + if err != nil { + return err + } + p.driver = driver + utils.Log.Infof("start ftp server on %s", p.conf.Listen) + fmt.Printf("start ftp server on %s\n", p.conf.Listen) + p.server = ftpserver.NewFtpServer(driver) + return p.server.ListenAndServe() +} + +func (p *FTPPlugin) Stop() error { + if p.driver != nil { + p.driver.Stop() + p.driver = nil + } + if p.server == nil { + return nil + } + err := p.server.Stop() + p.server = nil + return err +} + +var _ iplugin.Plugin = (*FTPPlugin)(nil) + +func init() { + iplugin.RegisterPlugin("ftp", func() iplugin.Plugin { return &FTPPlugin{} }) +} diff --git a/server/ftp.go b/plugins/ftp/runtime.go similarity index 79% rename from server/ftp.go rename to plugins/ftp/runtime.go index d07a62dd9..d00d2adb8 100644 --- a/server/ftp.go +++ b/plugins/ftp/runtime.go @@ -1,4 +1,4 @@ -package server +package ftp import ( "context" @@ -20,31 +20,31 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/setting" "github.com/OpenListTeam/OpenList/v4/pkg/utils" "github.com/OpenListTeam/OpenList/v4/server/common" - "github.com/OpenListTeam/OpenList/v4/server/ftp" ftpserver "github.com/fclairamb/ftpserverlib" ) -type FtpMainDriver struct { +type MainDriver struct { settings *ftpserver.Settings proxyHeader http.Header clients map[uint32]ftpserver.ClientContext shutdownLock sync.RWMutex isShutdown bool tlsConfig *tls.Config + conf FTP } -func NewMainDriver() (*FtpMainDriver, error) { - ftp.InitStage() +func NewMainDriver(cfg FTP) (*MainDriver, error) { + InitStage() transferType := ftpserver.TransferTypeASCII - if conf.Conf.FTP.DefaultTransferBinary { + if cfg.DefaultTransferBinary { transferType = ftpserver.TransferTypeBinary } activeConnCheck := ftpserver.IPMatchDisabled - if conf.Conf.FTP.EnableActiveConnIPCheck { + if cfg.EnableActiveConnIPCheck { activeConnCheck = ftpserver.IPMatchRequired } pasvConnCheck := ftpserver.IPMatchDisabled - if conf.Conf.FTP.EnablePasvConnIPCheck { + if cfg.EnablePasvConnIPCheck { pasvConnCheck = ftpserver.IPMatchRequired } tlsRequired := ftpserver.ClearOrEncrypted @@ -53,18 +53,18 @@ func NewMainDriver() (*FtpMainDriver, error) { } else if setting.GetBool(conf.FTPMandatoryTLS) { tlsRequired = ftpserver.MandatoryEncryption } - tlsConf, err := getTlsConf(setting.GetStr(conf.FTPTLSPrivateKeyPath), setting.GetStr(conf.FTPTLSPublicCertPath)) + tlsConf, err := getTLSConfig(setting.GetStr(conf.FTPTLSPrivateKeyPath), setting.GetStr(conf.FTPTLSPublicCertPath)) if err != nil && tlsRequired != ftpserver.ClearOrEncrypted { return nil, fmt.Errorf("FTP mandatory TLS has been enabled, but the certificate failed to load: %w", err) } - return &FtpMainDriver{ + return &MainDriver{ settings: &ftpserver.Settings{ - ListenAddr: conf.Conf.FTP.Listen, + ListenAddr: cfg.Listen, PublicHost: lookupIP(setting.GetStr(conf.FTPPublicHost)), - PassiveTransferPortRange: newPortMapper(setting.GetStr(conf.FTPPasvPortMap)), - ActiveTransferPortNon20: conf.Conf.FTP.ActiveTransferPortNon20, - IdleTimeout: conf.Conf.FTP.IdleTimeout, - ConnectionTimeout: conf.Conf.FTP.ConnectionTimeout, + PassiveTransferPortRange: newPortMapper(setting.GetStr(conf.FTPPasvPortMap), cfg.FindPasvPortAttempts), + ActiveTransferPortNon20: cfg.ActiveTransferPortNon20, + IdleTimeout: cfg.IdleTimeout, + ConnectionTimeout: cfg.ConnectionTimeout, DisableMLSD: false, DisableMLST: false, DisableMFMT: true, @@ -72,7 +72,7 @@ func NewMainDriver() (*FtpMainDriver, error) { TLSRequired: tlsRequired, DisableLISTArgs: false, DisableSite: false, - DisableActiveMode: conf.Conf.FTP.DisableActiveMode, + DisableActiveMode: cfg.DisableActiveMode, EnableHASH: false, DisableSTAT: false, DisableSYST: false, @@ -84,18 +84,17 @@ func NewMainDriver() (*FtpMainDriver, error) { proxyHeader: http.Header{ "User-Agent": {base.UserAgent}, }, - clients: make(map[uint32]ftpserver.ClientContext), - shutdownLock: sync.RWMutex{}, - isShutdown: false, - tlsConfig: tlsConf, + clients: make(map[uint32]ftpserver.ClientContext), + tlsConfig: tlsConf, + conf: cfg, }, nil } -func (d *FtpMainDriver) GetSettings() (*ftpserver.Settings, error) { +func (d *MainDriver) GetSettings() (*ftpserver.Settings, error) { return d.settings, nil } -func (d *FtpMainDriver) ClientConnected(cc ftpserver.ClientContext) (string, error) { +func (d *MainDriver) ClientConnected(cc ftpserver.ClientContext) (string, error) { if d.isShutdown || !d.shutdownLock.TryRLock() { return "", errors.New("server has shutdown") } @@ -104,15 +103,14 @@ func (d *FtpMainDriver) ClientConnected(cc ftpserver.ClientContext) (string, err return "OpenList FTP Endpoint", nil } -func (d *FtpMainDriver) ClientDisconnected(cc ftpserver.ClientContext) { - err := cc.Close() - if err != nil { +func (d *MainDriver) ClientDisconnected(cc ftpserver.ClientContext) { + if err := cc.Close(); err != nil { utils.Log.Errorf("failed to close client: %v", err) } delete(d.clients, cc.ID()) } -func (d *FtpMainDriver) AuthUser(cc ftpserver.ClientContext, user, pass string) (ftpserver.ClientDriver, error) { +func (d *MainDriver) AuthUser(cc ftpserver.ClientContext, user, pass string) (ftpserver.ClientDriver, error) { ip := cc.RemoteAddr().String() count, ok := model.LoginCache.Get(ip) if ok && count >= model.DefaultMaxAuthRetries { @@ -156,22 +154,22 @@ func (d *FtpMainDriver) AuthUser(cc ftpserver.ClientContext, user, pass string) } ctx = context.WithValue(ctx, conf.ClientIPKey, ip) ctx = context.WithValue(ctx, conf.ProxyHeaderKey, d.proxyHeader) - return ftp.NewAferoAdapter(ctx), nil + return NewAferoAdapter(ctx), nil } -func (d *FtpMainDriver) GetTLSConfig() (*tls.Config, error) { +func (d *MainDriver) GetTLSConfig() (*tls.Config, error) { if d.tlsConfig == nil { return nil, errors.New("TLS config not provided") } return d.tlsConfig, nil } -func (d *FtpMainDriver) Stop() { +func (d *MainDriver) Stop() { d.isShutdown = true d.shutdownLock.Lock() defer d.shutdownLock.Unlock() - for _, value := range d.clients { - _ = value.Close() + for _, client := range d.clients { + _ = client.Close() } } @@ -201,6 +199,7 @@ type group struct { } type pasvPortGetter struct { + attempts int groups []group totalLength int } @@ -210,19 +209,18 @@ func (m *pasvPortGetter) FetchNext() (int, int, bool) { for _, g := range m.groups { if idxPort >= g.Length { idxPort -= g.Length - } else { - return g.ExposedStart + idxPort, g.ListenedStart + idxPort, true + continue } + return g.ExposedStart + idxPort, g.ListenedStart + idxPort, true } - // unreachable return 0, 0, false } func (m *pasvPortGetter) NumberAttempts() int { - return conf.Conf.FTP.FindPasvPortAttempts + return m.attempts } -func newPortMapper(str string) ftpserver.PasvPortGetter { +func newPortMapper(str string, attempts int) ftpserver.PasvPortGetter { if str == "" { return nil } @@ -244,14 +242,12 @@ func newPortMapper(str string) ftpserver.PasvPortGetter { return 0, 0, errors.New("invalid port") } return si, ei - si + 1, nil - } else { - ret, err := strconv.Atoi(str) - if err != nil { - return 0, 0, err - } else { - return ret, 1, nil - } } + ret, err := strconv.Atoi(str) + if err != nil { + return 0, 0, err + } + return ret, 1, nil } for i, mapper := range pasvPortMappers { var err error @@ -290,10 +286,10 @@ func newPortMapper(str string) ftpserver.PasvPortGetter { return nil } } - return &pasvPortGetter{groups: groups, totalLength: totalLength} + return &pasvPortGetter{attempts: attempts, groups: groups, totalLength: totalLength} } -func getTlsConf(keyPath, certPath string) (*tls.Config, error) { +func getTLSConfig(keyPath, certPath string) (*tls.Config, error) { if keyPath == "" || certPath == "" { return nil, errors.New("private key or certificate is not provided") } diff --git a/plugins/ftp/server.go b/plugins/ftp/server.go new file mode 100644 index 000000000..4c9820334 --- /dev/null +++ b/plugins/ftp/server.go @@ -0,0 +1 @@ +package ftp diff --git a/server/ftp/site.go b/plugins/ftp/site.go similarity index 100% rename from server/ftp/site.go rename to plugins/ftp/site.go diff --git a/server/ftp/upload_stage.go b/plugins/ftp/upload_stage.go similarity index 100% rename from server/ftp/upload_stage.go rename to plugins/ftp/upload_stage.go diff --git a/plugins/ftp/utils.go b/plugins/ftp/utils.go new file mode 100644 index 000000000..421fd520f --- /dev/null +++ b/plugins/ftp/utils.go @@ -0,0 +1,14 @@ +package ftp + +import ( + "github.com/OpenListTeam/OpenList/v4/internal/model" + "github.com/OpenListTeam/OpenList/v4/server/common" +) + +func tryLdapLoginAndRegister(user, pass string) (*model.User, error) { + err := common.HandleLdapLogin(user, pass) + if err != nil { + return nil, err + } + return common.LdapRegister(user) +} From 0b6e3c0dff04306ba259a52bd2332753628d950a Mon Sep 17 00:00:00 2001 From: mkitsdts Date: Wed, 25 Mar 2026 17:07:08 +0800 Subject: [PATCH 03/10] feat(plugin/s3): adapt s3 into plugin --- {server => plugins}/s3/backend.go | 0 plugins/s3/config.go | 6 +++ {server => plugins}/s3/ioutils.go | 0 {server => plugins}/s3/list.go | 0 {server => plugins}/s3/logger.go | 0 {server => plugins}/s3/pager.go | 0 plugins/s3/plugin.go | 76 +++++++++++++++++++++++++++++++ {server => plugins}/s3/server.go | 2 +- {server => plugins}/s3/utils.go | 0 server/s3.go | 39 ---------------- 10 files changed, 83 insertions(+), 40 deletions(-) rename {server => plugins}/s3/backend.go (100%) create mode 100644 plugins/s3/config.go rename {server => plugins}/s3/ioutils.go (100%) rename {server => plugins}/s3/list.go (100%) rename {server => plugins}/s3/logger.go (100%) rename {server => plugins}/s3/pager.go (100%) create mode 100644 plugins/s3/plugin.go rename {server => plugins}/s3/server.go (90%) rename {server => plugins}/s3/utils.go (100%) delete mode 100644 server/s3.go diff --git a/server/s3/backend.go b/plugins/s3/backend.go similarity index 100% rename from server/s3/backend.go rename to plugins/s3/backend.go diff --git a/plugins/s3/config.go b/plugins/s3/config.go new file mode 100644 index 000000000..e644fb33e --- /dev/null +++ b/plugins/s3/config.go @@ -0,0 +1,6 @@ +package s3 + +type S3 struct { + Port int `json:"port" env:"PORT"` + SSL bool `json:"ssl" env:"SSL"` +} diff --git a/server/s3/ioutils.go b/plugins/s3/ioutils.go similarity index 100% rename from server/s3/ioutils.go rename to plugins/s3/ioutils.go diff --git a/server/s3/list.go b/plugins/s3/list.go similarity index 100% rename from server/s3/list.go rename to plugins/s3/list.go diff --git a/server/s3/logger.go b/plugins/s3/logger.go similarity index 100% rename from server/s3/logger.go rename to plugins/s3/logger.go diff --git a/server/s3/pager.go b/plugins/s3/pager.go similarity index 100% rename from server/s3/pager.go rename to plugins/s3/pager.go diff --git a/plugins/s3/plugin.go b/plugins/s3/plugin.go new file mode 100644 index 000000000..4985554b0 --- /dev/null +++ b/plugins/s3/plugin.go @@ -0,0 +1,76 @@ +package s3 + +import ( + "context" + "fmt" + "net/http" + + "github.com/OpenListTeam/OpenList/v4/internal/conf" + iplugin "github.com/OpenListTeam/OpenList/v4/internal/plugin" + "github.com/OpenListTeam/OpenList/v4/pkg/utils" + "github.com/gin-gonic/gin" + log "github.com/sirupsen/logrus" +) + +type S3Plugin struct { + server *http.Server + conf *S3 +} + +func (p *S3Plugin) Name() string { + return "s3" +} + +func (p *S3Plugin) Init(config map[string]any) error { + p.conf = &S3{ + Port: 5246, + SSL: false, + } + var err error + if p.conf.Port, err = iplugin.IntValue(config, "port", p.conf.Port); err != nil { + return err + } + if p.conf.SSL, err = iplugin.BoolValue(config, "ssl", p.conf.SSL); err != nil { + return err + } + return nil +} + +func (p *S3Plugin) Start() error { + if p.conf.Port == -1 { + return nil + } + h, err := NewServer(context.Background()) + if err != nil { + return err + } + r := gin.New() + r.Use(gin.LoggerWithWriter(log.StandardLogger().Out), gin.RecoveryWithWriter(log.StandardLogger().Out)) + r.Any("/*path", gin.WrapH(h)) + r.Any("/", gin.WrapH(h)) + addr := fmt.Sprintf("%s:%d", conf.Conf.Scheme.Address, p.conf.Port) + utils.Log.Infof("start S3 server @ %s", addr) + fmt.Printf("start S3 server @ %s\n", addr) + p.server = &http.Server{Addr: addr, Handler: r} + if p.conf.SSL { + return p.server.ListenAndServeTLS(conf.Conf.Scheme.CertFile, conf.Conf.Scheme.KeyFile) + } + return p.server.ListenAndServe() +} + +func (p *S3Plugin) Stop() error { + if p.server == nil { + return nil + } + err := p.server.Close() + p.server = nil + return err +} + +var _ iplugin.Plugin = (*S3Plugin)(nil) + +func init() { + iplugin.RegisterPlugin("s3", func() iplugin.Plugin { + return &S3Plugin{} + }) +} diff --git a/server/s3/server.go b/plugins/s3/server.go similarity index 90% rename from server/s3/server.go rename to plugins/s3/server.go index 360eb8752..560ccea1e 100644 --- a/server/s3/server.go +++ b/plugins/s3/server.go @@ -11,7 +11,7 @@ import ( ) // Make a new S3 Server to serve the remote -func NewServer(ctx context.Context) (h http.Handler, err error) { +func NewServer(ctx context.Context) (r http.Handler, err error) { var newLogger logger faker := gofakes3.New( newBackend(), diff --git a/server/s3/utils.go b/plugins/s3/utils.go similarity index 100% rename from server/s3/utils.go rename to plugins/s3/utils.go diff --git a/server/s3.go b/server/s3.go deleted file mode 100644 index 1c0b5925a..000000000 --- a/server/s3.go +++ /dev/null @@ -1,39 +0,0 @@ -package server - -import ( - "context" - "path" - "strings" - - "github.com/OpenListTeam/OpenList/v4/internal/conf" - "github.com/OpenListTeam/OpenList/v4/server/common" - "github.com/OpenListTeam/OpenList/v4/server/s3" - "github.com/gin-gonic/gin" -) - -func S3(g *gin.RouterGroup) { - if !conf.Conf.S3.Enable { - g.Any("/*path", func(c *gin.Context) { - common.ErrorStrResp(c, "S3 server is not enabled", 403) - }) - return - } - if conf.Conf.S3.Port != -1 { - g.Any("/*path", func(c *gin.Context) { - common.ErrorStrResp(c, "S3 server bound to single port", 403) - }) - return - } - h, _ := s3.NewServer(context.Background()) - - g.Any("/*path", func(c *gin.Context) { - adjustedPath := strings.TrimPrefix(c.Request.URL.Path, path.Join(conf.URL.Path, "/s3")) - c.Request.URL.Path = adjustedPath - gin.WrapH(h)(c) - }) -} - -func S3Server(g *gin.RouterGroup) { - h, _ := s3.NewServer(context.Background()) - g.Any("/*path", gin.WrapH(h)) -} From 35d531fc2b0fcdc6a611a35eed7663b43d7ed8e4 Mon Sep 17 00:00:00 2001 From: mkitsdts Date: Wed, 25 Mar 2026 17:08:21 +0800 Subject: [PATCH 04/10] feat(plugin/sftp): adapt sftp into plugin --- plugins/sftp/config.go | 5 +++ {server => plugins}/sftp/const.go | 0 {server => plugins}/sftp/hostkey.go | 0 plugins/sftp/plugin.go | 54 +++++++++++++++++++++++ server/sftp.go => plugins/sftp/runtime.go | 43 +++++++++--------- {server => plugins}/sftp/sftp.go | 4 +- plugins/sftp/utils.go | 14 ++++++ 7 files changed, 96 insertions(+), 24 deletions(-) create mode 100644 plugins/sftp/config.go rename {server => plugins}/sftp/const.go (100%) rename {server => plugins}/sftp/hostkey.go (100%) create mode 100644 plugins/sftp/plugin.go rename server/sftp.go => plugins/sftp/runtime.go (78%) rename {server => plugins}/sftp/sftp.go (96%) create mode 100644 plugins/sftp/utils.go diff --git a/plugins/sftp/config.go b/plugins/sftp/config.go new file mode 100644 index 000000000..66a078228 --- /dev/null +++ b/plugins/sftp/config.go @@ -0,0 +1,5 @@ +package sftp + +type SFTP struct { + Listen string `json:"listen" env:"LISTEN"` +} diff --git a/server/sftp/const.go b/plugins/sftp/const.go similarity index 100% rename from server/sftp/const.go rename to plugins/sftp/const.go diff --git a/server/sftp/hostkey.go b/plugins/sftp/hostkey.go similarity index 100% rename from server/sftp/hostkey.go rename to plugins/sftp/hostkey.go diff --git a/plugins/sftp/plugin.go b/plugins/sftp/plugin.go new file mode 100644 index 000000000..ad9bd3561 --- /dev/null +++ b/plugins/sftp/plugin.go @@ -0,0 +1,54 @@ +package sftp + +import ( + "fmt" + + iplugin "github.com/OpenListTeam/OpenList/v4/internal/plugin" + "github.com/OpenListTeam/OpenList/v4/pkg/utils" + "github.com/OpenListTeam/sftpd-openlist" +) + +type SFTPPlugin struct { + driver *Driver + server *sftpd.SftpServer + conf SFTP +} + +func (p *SFTPPlugin) Name() string { + return "sftp" +} + +func (p *SFTPPlugin) Init(config map[string]any) error { + var err error + p.conf = SFTP{Listen: ":5222"} + p.conf.Listen, err = iplugin.StringValue(config, "listen", p.conf.Listen) + return err +} + +func (p *SFTPPlugin) Start() error { + driver, err := NewDriver(p.conf) + if err != nil { + return err + } + p.driver = driver + utils.Log.Infof("start sftp server on %s", p.conf.Listen) + fmt.Printf("start sftp server on %s\n", p.conf.Listen) + p.server = sftpd.NewSftpServer(driver) + return p.server.RunServer() +} + +func (p *SFTPPlugin) Stop() error { + if p.server == nil { + return nil + } + err := p.server.Close() + p.server = nil + p.driver = nil + return err +} + +func init() { + iplugin.RegisterPlugin("sftp", func() iplugin.Plugin { + return &SFTPPlugin{} + }) +} diff --git a/server/sftp.go b/plugins/sftp/runtime.go similarity index 78% rename from server/sftp.go rename to plugins/sftp/runtime.go index 37dc9870d..26255d3ac 100644 --- a/server/sftp.go +++ b/plugins/sftp/runtime.go @@ -1,4 +1,4 @@ -package server +package sftp import ( "context" @@ -11,34 +11,35 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/op" "github.com/OpenListTeam/OpenList/v4/internal/setting" "github.com/OpenListTeam/OpenList/v4/pkg/utils" + pluginftp "github.com/OpenListTeam/OpenList/v4/plugins/ftp" "github.com/OpenListTeam/OpenList/v4/server/common" - "github.com/OpenListTeam/OpenList/v4/server/ftp" - "github.com/OpenListTeam/OpenList/v4/server/sftp" "github.com/OpenListTeam/sftpd-openlist" "github.com/pkg/errors" "golang.org/x/crypto/ssh" ) -type SftpDriver struct { +type Driver struct { proxyHeader http.Header config *sftpd.Config + listen string } -func NewSftpDriver() (*SftpDriver, error) { - ftp.InitStage() - sftp.InitHostKey() - return &SftpDriver{ +func NewDriver(cfg SFTP) (*Driver, error) { + pluginftp.InitStage() + InitHostKey() + return &Driver{ proxyHeader: http.Header{ "User-Agent": {base.UserAgent}, }, + listen: cfg.Listen, }, nil } -func (d *SftpDriver) GetConfig() *sftpd.Config { +func (d *Driver) GetConfig() *sftpd.Config { if d.config != nil { return d.config } - var pwdAuth func(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) = nil + var pwdAuth func(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) if !setting.GetBool(conf.SFTPDisablePasswordLogin) { pwdAuth = d.PasswordAuth } @@ -50,19 +51,18 @@ func (d *SftpDriver) GetConfig() *sftpd.Config { AuthLogCallback: d.AuthLogCallback, BannerCallback: d.GetBanner, } - for _, k := range sftp.SSHSigners { + for _, k := range SSHSigners { serverConfig.AddHostKey(k) } d.config = &sftpd.Config{ ServerConfig: serverConfig, - HostPort: conf.Conf.SFTP.Listen, + HostPort: d.listen, ErrorLogFunc: utils.Log.Error, - // DebugLogFunc: utils.Log.Debugf, } return d.config } -func (d *SftpDriver) GetFileSystem(sc *ssh.ServerConn) (sftpd.FileSystem, error) { +func (d *Driver) GetFileSystem(sc *ssh.ServerConn) (sftpd.FileSystem, error) { userObj, err := op.GetUserByName(sc.User()) if err != nil { return nil, err @@ -72,13 +72,12 @@ func (d *SftpDriver) GetFileSystem(sc *ssh.ServerConn) (sftpd.FileSystem, error) ctx = context.WithValue(ctx, conf.MetaPassKey, "") ctx = context.WithValue(ctx, conf.ClientIPKey, sc.RemoteAddr().String()) ctx = context.WithValue(ctx, conf.ProxyHeaderKey, d.proxyHeader) - return &sftp.DriverAdapter{FtpDriver: ftp.NewAferoAdapter(ctx)}, nil + return &DriverAdapter{FtpDriver: pluginftp.NewAferoAdapter(ctx)}, nil } -func (d *SftpDriver) Close() { -} +func (d *Driver) Close() {} -func (d *SftpDriver) NoClientAuth(conn ssh.ConnMetadata) (*ssh.Permissions, error) { +func (d *Driver) NoClientAuth(conn ssh.ConnMetadata) (*ssh.Permissions, error) { if conn.User() != "guest" { return nil, errors.New("only guest is allowed to login without authorization") } @@ -92,7 +91,7 @@ func (d *SftpDriver) NoClientAuth(conn ssh.ConnMetadata) (*ssh.Permissions, erro return nil, nil } -func (d *SftpDriver) PasswordAuth(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) { +func (d *Driver) PasswordAuth(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) { ip := conn.RemoteAddr().String() count, ok := model.LoginCache.Get(ip) if ok && count >= model.DefaultMaxAuthRetries { @@ -121,7 +120,7 @@ func (d *SftpDriver) PasswordAuth(conn ssh.ConnMetadata, password []byte) (*ssh. return nil, nil } -func (d *SftpDriver) PublicKeyAuth(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { +func (d *Driver) PublicKeyAuth(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { userObj, err := op.GetUserByName(conn.User()) if err != nil { return nil, err @@ -148,7 +147,7 @@ func (d *SftpDriver) PublicKeyAuth(conn ssh.ConnMetadata, key ssh.PublicKey) (*s return nil, errors.New("public key refused") } -func (d *SftpDriver) AuthLogCallback(conn ssh.ConnMetadata, method string, err error) { +func (d *Driver) AuthLogCallback(conn ssh.ConnMetadata, method string, err error) { ip := conn.RemoteAddr().String() if err == nil { utils.Log.Infof("[SFTP] %s(%s) logged in via %s", conn.User(), ip, method) @@ -157,6 +156,6 @@ func (d *SftpDriver) AuthLogCallback(conn ssh.ConnMetadata, method string, err e } } -func (d *SftpDriver) GetBanner(_ ssh.ConnMetadata) string { +func (d *Driver) GetBanner(_ ssh.ConnMetadata) string { return setting.GetStr(conf.Announcement) } diff --git a/server/sftp/sftp.go b/plugins/sftp/sftp.go similarity index 96% rename from server/sftp/sftp.go rename to plugins/sftp/sftp.go index efd56132c..46ba4e833 100644 --- a/server/sftp/sftp.go +++ b/plugins/sftp/sftp.go @@ -6,12 +6,12 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/errs" "github.com/OpenListTeam/OpenList/v4/internal/model" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server/ftp" + pluginftp "github.com/OpenListTeam/OpenList/v4/plugins/ftp" "github.com/OpenListTeam/sftpd-openlist" ) type DriverAdapter struct { - FtpDriver *ftp.AferoAdapter + FtpDriver *pluginftp.AferoAdapter } func (s *DriverAdapter) OpenFile(_ string, _ uint32, _ *sftpd.Attr) (sftpd.File, error) { diff --git a/plugins/sftp/utils.go b/plugins/sftp/utils.go new file mode 100644 index 000000000..74498a6b4 --- /dev/null +++ b/plugins/sftp/utils.go @@ -0,0 +1,14 @@ +package sftp + +import ( + "github.com/OpenListTeam/OpenList/v4/internal/model" + "github.com/OpenListTeam/OpenList/v4/server/common" +) + +func tryLdapLoginAndRegister(user, pass string) (*model.User, error) { + err := common.HandleLdapLogin(user, pass) + if err != nil { + return nil, err + } + return common.LdapRegister(user) +} From 59670ff4331df4d61e62d776e5230974b0ab4749 Mon Sep 17 00:00:00 2001 From: mkitsdts Date: Wed, 25 Mar 2026 17:10:18 +0800 Subject: [PATCH 05/10] feat(plugin/webdav): adapt webdav into plugin --- .../webdav/buffered_response_writer.go | 0 plugins/webdav/config.go | 8 ++ {server => plugins}/webdav/file.go | 0 {server => plugins}/webdav/if.go | 0 .../webdav/internal/xml/README | 0 .../webdav/internal/xml/atom_test.go | 0 .../webdav/internal/xml/example_test.go | 0 .../webdav/internal/xml/marshal.go | 0 .../webdav/internal/xml/marshal_test.go | 0 .../webdav/internal/xml/read.go | 0 .../webdav/internal/xml/read_test.go | 0 .../webdav/internal/xml/typeinfo.go | 0 .../webdav/internal/xml/xml.go | 0 .../webdav/internal/xml/xml_test.go | 0 .../webdav/litmus_test_server.go | 0 {server => plugins}/webdav/lock.go | 0 {server => plugins}/webdav/lock_test.go | 0 plugins/webdav/plugin.go | 78 +++++++++++++++++++ {server => plugins}/webdav/prop.go | 0 server/webdav.go => plugins/webdav/server.go | 10 +-- {server => plugins}/webdav/util.go | 0 plugins/webdav/utils.go | 14 ++++ {server => plugins}/webdav/webdav.go | 0 {server => plugins}/webdav/xml.go | 2 +- {server => plugins}/webdav/xml_test.go | 2 +- 25 files changed, 105 insertions(+), 9 deletions(-) rename {server => plugins}/webdav/buffered_response_writer.go (100%) create mode 100644 plugins/webdav/config.go rename {server => plugins}/webdav/file.go (100%) rename {server => plugins}/webdav/if.go (100%) rename {server => plugins}/webdav/internal/xml/README (100%) rename {server => plugins}/webdav/internal/xml/atom_test.go (100%) rename {server => plugins}/webdav/internal/xml/example_test.go (100%) rename {server => plugins}/webdav/internal/xml/marshal.go (100%) rename {server => plugins}/webdav/internal/xml/marshal_test.go (100%) rename {server => plugins}/webdav/internal/xml/read.go (100%) rename {server => plugins}/webdav/internal/xml/read_test.go (100%) rename {server => plugins}/webdav/internal/xml/typeinfo.go (100%) rename {server => plugins}/webdav/internal/xml/xml.go (100%) rename {server => plugins}/webdav/internal/xml/xml_test.go (100%) rename {server => plugins}/webdav/litmus_test_server.go (100%) rename {server => plugins}/webdav/lock.go (100%) rename {server => plugins}/webdav/lock_test.go (100%) create mode 100644 plugins/webdav/plugin.go rename {server => plugins}/webdav/prop.go (100%) rename server/webdav.go => plugins/webdav/server.go (94%) rename {server => plugins}/webdav/util.go (100%) create mode 100644 plugins/webdav/utils.go rename {server => plugins}/webdav/webdav.go (100%) rename {server => plugins}/webdav/xml.go (99%) rename {server => plugins}/webdav/xml_test.go (99%) diff --git a/server/webdav/buffered_response_writer.go b/plugins/webdav/buffered_response_writer.go similarity index 100% rename from server/webdav/buffered_response_writer.go rename to plugins/webdav/buffered_response_writer.go diff --git a/plugins/webdav/config.go b/plugins/webdav/config.go new file mode 100644 index 000000000..3e43c2bed --- /dev/null +++ b/plugins/webdav/config.go @@ -0,0 +1,8 @@ +package webdav + +type WebDAVConfig struct { + Listen string `json:"listen"` + SSL bool `json:"ssl"` + CertFile string `json:"cert_file"` + KeyFile string `json:"key_file"` +} diff --git a/server/webdav/file.go b/plugins/webdav/file.go similarity index 100% rename from server/webdav/file.go rename to plugins/webdav/file.go diff --git a/server/webdav/if.go b/plugins/webdav/if.go similarity index 100% rename from server/webdav/if.go rename to plugins/webdav/if.go diff --git a/server/webdav/internal/xml/README b/plugins/webdav/internal/xml/README similarity index 100% rename from server/webdav/internal/xml/README rename to plugins/webdav/internal/xml/README diff --git a/server/webdav/internal/xml/atom_test.go b/plugins/webdav/internal/xml/atom_test.go similarity index 100% rename from server/webdav/internal/xml/atom_test.go rename to plugins/webdav/internal/xml/atom_test.go diff --git a/server/webdav/internal/xml/example_test.go b/plugins/webdav/internal/xml/example_test.go similarity index 100% rename from server/webdav/internal/xml/example_test.go rename to plugins/webdav/internal/xml/example_test.go diff --git a/server/webdav/internal/xml/marshal.go b/plugins/webdav/internal/xml/marshal.go similarity index 100% rename from server/webdav/internal/xml/marshal.go rename to plugins/webdav/internal/xml/marshal.go diff --git a/server/webdav/internal/xml/marshal_test.go b/plugins/webdav/internal/xml/marshal_test.go similarity index 100% rename from server/webdav/internal/xml/marshal_test.go rename to plugins/webdav/internal/xml/marshal_test.go diff --git a/server/webdav/internal/xml/read.go b/plugins/webdav/internal/xml/read.go similarity index 100% rename from server/webdav/internal/xml/read.go rename to plugins/webdav/internal/xml/read.go diff --git a/server/webdav/internal/xml/read_test.go b/plugins/webdav/internal/xml/read_test.go similarity index 100% rename from server/webdav/internal/xml/read_test.go rename to plugins/webdav/internal/xml/read_test.go diff --git a/server/webdav/internal/xml/typeinfo.go b/plugins/webdav/internal/xml/typeinfo.go similarity index 100% rename from server/webdav/internal/xml/typeinfo.go rename to plugins/webdav/internal/xml/typeinfo.go diff --git a/server/webdav/internal/xml/xml.go b/plugins/webdav/internal/xml/xml.go similarity index 100% rename from server/webdav/internal/xml/xml.go rename to plugins/webdav/internal/xml/xml.go diff --git a/server/webdav/internal/xml/xml_test.go b/plugins/webdav/internal/xml/xml_test.go similarity index 100% rename from server/webdav/internal/xml/xml_test.go rename to plugins/webdav/internal/xml/xml_test.go diff --git a/server/webdav/litmus_test_server.go b/plugins/webdav/litmus_test_server.go similarity index 100% rename from server/webdav/litmus_test_server.go rename to plugins/webdav/litmus_test_server.go diff --git a/server/webdav/lock.go b/plugins/webdav/lock.go similarity index 100% rename from server/webdav/lock.go rename to plugins/webdav/lock.go diff --git a/server/webdav/lock_test.go b/plugins/webdav/lock_test.go similarity index 100% rename from server/webdav/lock_test.go rename to plugins/webdav/lock_test.go diff --git a/plugins/webdav/plugin.go b/plugins/webdav/plugin.go new file mode 100644 index 000000000..33c2a87a4 --- /dev/null +++ b/plugins/webdav/plugin.go @@ -0,0 +1,78 @@ +package webdav + +import ( + "fmt" + "net/http" + + "github.com/OpenListTeam/OpenList/v4/internal/conf" + iplugin "github.com/OpenListTeam/OpenList/v4/internal/plugin" + "github.com/OpenListTeam/OpenList/v4/pkg/utils" + "github.com/gin-gonic/gin" + log "github.com/sirupsen/logrus" +) + +type WebDAVPlugin struct { + conf WebDAVConfig + server *http.Server +} + +func (p *WebDAVPlugin) Name() string { + return "webdav" +} + +func (p *WebDAVPlugin) Init(config map[string]any) error { + var err error + p.conf = WebDAVConfig{ + Listen: ":5288", + SSL: false, + } + if p.conf.Listen, err = iplugin.StringValue(config, "listen", p.conf.Listen); err != nil { + return err + } + if p.conf.SSL, err = iplugin.BoolValue(config, "ssl", p.conf.SSL); err != nil { + return err + } + if p.conf.CertFile, err = iplugin.StringValue(config, "cert_file", p.conf.CertFile); err != nil { + return err + } + if p.conf.KeyFile, err = iplugin.StringValue(config, "key_file", p.conf.KeyFile); err != nil { + return err + } + return nil +} + +func (p *WebDAVPlugin) Start() error { + r := gin.New() + r.Use(gin.LoggerWithWriter(log.StandardLogger().Out), gin.RecoveryWithWriter(log.StandardLogger().Out)) + WebDav(r) + utils.Log.Infof("start WebDAV server @ %s", p.conf.Listen) + fmt.Printf("start WebDAV server @ %s\n", p.conf.Listen) + p.server = &http.Server{Addr: p.conf.Listen, Handler: r} + if p.conf.SSL { + certFile := p.conf.CertFile + if certFile == "" { + certFile = conf.Conf.Scheme.CertFile + } + keyFile := p.conf.KeyFile + if keyFile == "" { + keyFile = conf.Conf.Scheme.KeyFile + } + return p.server.ListenAndServeTLS(certFile, keyFile) + } + return p.server.ListenAndServe() +} + +func (p *WebDAVPlugin) Stop() error { + if p.server == nil { + return nil + } + err := p.server.Close() + p.server = nil + return err +} + +func init() { + iplugin.RegisterPlugin("webdav", func() iplugin.Plugin { + return &WebDAVPlugin{} + }) +} diff --git a/server/webdav/prop.go b/plugins/webdav/prop.go similarity index 100% rename from server/webdav/prop.go rename to plugins/webdav/prop.go diff --git a/server/webdav.go b/plugins/webdav/server.go similarity index 94% rename from server/webdav.go rename to plugins/webdav/server.go index 789236b8b..8b82d1223 100644 --- a/server/webdav.go +++ b/plugins/webdav/server.go @@ -1,9 +1,8 @@ -package server +package webdav import ( "crypto/subtle" "net/http" - "path" "strings" "github.com/OpenListTeam/OpenList/v4/internal/conf" @@ -13,16 +12,15 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/stream" "github.com/OpenListTeam/OpenList/v4/server/common" "github.com/OpenListTeam/OpenList/v4/server/middlewares" - "github.com/OpenListTeam/OpenList/v4/server/webdav" "github.com/gin-gonic/gin" log "github.com/sirupsen/logrus" + "golang.org/x/net/webdav" ) var handler *webdav.Handler -func WebDav(dav *gin.RouterGroup) { +func WebDav(dav *gin.Engine) { handler = &webdav.Handler{ - Prefix: path.Join(conf.URL.Path, "/dav"), LockSystem: webdav.NewMemLS(), Logger: func(request *http.Request, err error) { log.Errorf("%s %s %+v", request.Method, request.URL.Path, err) @@ -32,9 +30,7 @@ func WebDav(dav *gin.RouterGroup) { uploadLimiter := middlewares.UploadRateLimiter(stream.ClientUploadLimit) downloadLimiter := middlewares.DownloadRateLimiter(stream.ClientDownloadLimit) dav.Any("/*path", uploadLimiter, downloadLimiter, ServeWebDAV) - dav.Any("", uploadLimiter, downloadLimiter, ServeWebDAV) dav.Handle("PROPFIND", "/*path", ServeWebDAV) - dav.Handle("PROPFIND", "", ServeWebDAV) dav.Handle("MKCOL", "/*path", ServeWebDAV) dav.Handle("LOCK", "/*path", ServeWebDAV) dav.Handle("UNLOCK", "/*path", ServeWebDAV) diff --git a/server/webdav/util.go b/plugins/webdav/util.go similarity index 100% rename from server/webdav/util.go rename to plugins/webdav/util.go diff --git a/plugins/webdav/utils.go b/plugins/webdav/utils.go new file mode 100644 index 000000000..b67de89ed --- /dev/null +++ b/plugins/webdav/utils.go @@ -0,0 +1,14 @@ +package webdav + +import ( + "github.com/OpenListTeam/OpenList/v4/internal/model" + "github.com/OpenListTeam/OpenList/v4/server/common" +) + +func tryLdapLoginAndRegister(user, pass string) (*model.User, error) { + err := common.HandleLdapLogin(user, pass) + if err != nil { + return nil, err + } + return common.LdapRegister(user) +} diff --git a/server/webdav/webdav.go b/plugins/webdav/webdav.go similarity index 100% rename from server/webdav/webdav.go rename to plugins/webdav/webdav.go diff --git a/server/webdav/xml.go b/plugins/webdav/xml.go similarity index 99% rename from server/webdav/xml.go rename to plugins/webdav/xml.go index c9ec61dff..04ea723bd 100644 --- a/server/webdav/xml.go +++ b/plugins/webdav/xml.go @@ -32,7 +32,7 @@ import ( // In the long term, this package should use the standard library's version // only, and the internal fork deleted, once // https://github.com/golang/go/issues/13400 is resolved. - ixml "github.com/OpenListTeam/OpenList/v4/server/webdav/internal/xml" + ixml "github.com/OpenListTeam/OpenList/v4/plugins/webdav/internal/xml" ) // http://www.webdav.org/specs/rfc4918.html#ELEMENT_lockinfo diff --git a/server/webdav/xml_test.go b/plugins/webdav/xml_test.go similarity index 99% rename from server/webdav/xml_test.go rename to plugins/webdav/xml_test.go index 4af13c87b..3a6c819a1 100644 --- a/server/webdav/xml_test.go +++ b/plugins/webdav/xml_test.go @@ -16,7 +16,7 @@ import ( "strings" "testing" - ixml "github.com/OpenListTeam/OpenList/v4/server/webdav/internal/xml" + ixml "github.com/OpenListTeam/OpenList/v4/plugins/webdav/internal/xml" ) func TestReadLockInfo(t *testing.T) { From ab1f36cfb8a890e659021fcb0f4d6605dfad918d Mon Sep 17 00:00:00 2001 From: mkitsdts Date: Wed, 25 Mar 2026 17:11:49 +0800 Subject: [PATCH 06/10] feat(plugin): support plugin start --- internal/bootstrap/run.go | 132 +++--------------------------- internal/conf/config.go | 163 ++++++++++++++++++++++---------------- server/router.go | 7 -- server/utils.go | 14 ---- 4 files changed, 106 insertions(+), 210 deletions(-) delete mode 100644 server/utils.go diff --git a/internal/bootstrap/run.go b/internal/bootstrap/run.go index 6740dba65..1be5056fa 100644 --- a/internal/bootstrap/run.go +++ b/internal/bootstrap/run.go @@ -15,11 +15,11 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/conf" "github.com/OpenListTeam/OpenList/v4/internal/db" "github.com/OpenListTeam/OpenList/v4/internal/fs" + "github.com/OpenListTeam/OpenList/v4/internal/plugin" + _ "github.com/OpenListTeam/OpenList/v4/internal/plugin/all" "github.com/OpenListTeam/OpenList/v4/pkg/utils" "github.com/OpenListTeam/OpenList/v4/server" "github.com/OpenListTeam/OpenList/v4/server/middlewares" - "github.com/OpenListTeam/sftpd-openlist" - ftpserver "github.com/fclairamb/ftpserverlib" "github.com/gin-gonic/gin" "github.com/google/uuid" "github.com/pkg/errors" @@ -53,14 +53,6 @@ var ( unixRunning bool quicSrv *http3.Server quicRunning bool - s3Srv *http.Server - s3Running bool - ftpDriver *server.FtpMainDriver - ftpServer *ftpserver.FtpServer - ftpRunning bool - sftpDriver *server.SftpDriver - sftpServer *sftpd.SftpServer - sftpRunning bool ) // Called by OpenList-Mobile @@ -74,14 +66,9 @@ func IsRunning(t string) bool { return unixRunning case "quic": return quicRunning - case "s3": - return s3Running - case "sftp": - return sftpRunning - case "ftp": - return ftpRunning + default: + return plugin.IsRunning(t) } - return running } func Start() { @@ -198,76 +185,7 @@ func Start() { } }() } - if conf.Conf.S3.Port != -1 && conf.Conf.S3.Enable { - s3r := gin.New() - s3r.Use(gin.LoggerWithWriter(log.StandardLogger().Out), gin.RecoveryWithWriter(log.StandardLogger().Out)) - server.InitS3(s3r) - s3Base := fmt.Sprintf("%s:%d", conf.Conf.Scheme.Address, conf.Conf.S3.Port) - fmt.Printf("start S3 server @ %s\n", s3Base) - utils.Log.Infof("start S3 server @ %s", s3Base) - go func() { - s3Running = true - var err error - if conf.Conf.S3.SSL { - s3Srv = &http.Server{Addr: s3Base, Handler: s3r} - err = s3Srv.ListenAndServeTLS(conf.Conf.Scheme.CertFile, conf.Conf.Scheme.KeyFile) - } else { - s3Srv = &http.Server{Addr: s3Base, Handler: s3r} - err = s3Srv.ListenAndServe() - } - s3Running = false - if err != nil && !errors.Is(err, http.ErrServerClosed) { - handleEndpointStartFailedHooks("s3", err) - utils.Log.Errorf("failed to start s3 server: %s", err.Error()) - } else { - handleEndpointShutdownHooks("s3") - } - }() - } - if conf.Conf.FTP.Listen != "" && conf.Conf.FTP.Enable { - var err error - ftpDriver, err = server.NewMainDriver() - if err != nil { - utils.Log.Errorf("failed to start ftp driver: %s", err.Error()) - } else { - fmt.Printf("start ftp server on %s\n", conf.Conf.FTP.Listen) - utils.Log.Infof("start ftp server on %s", conf.Conf.FTP.Listen) - go func() { - ftpServer = ftpserver.NewFtpServer(ftpDriver) - ftpRunning = true - err = ftpServer.ListenAndServe() - ftpRunning = false - if err != nil { - handleEndpointStartFailedHooks("ftp", err) - utils.Log.Errorf("problem ftp server listening: %s", err.Error()) - } else { - handleEndpointShutdownHooks("ftp") - } - }() - } - } - if conf.Conf.SFTP.Listen != "" && conf.Conf.SFTP.Enable { - var err error - sftpDriver, err = server.NewSftpDriver() - if err != nil { - utils.Log.Errorf("failed to start sftp driver: %s", err.Error()) - } else { - fmt.Printf("start sftp server on %s", conf.Conf.SFTP.Listen) - utils.Log.Infof("start sftp server on %s", conf.Conf.SFTP.Listen) - go func() { - sftpServer = sftpd.NewSftpServer(sftpDriver) - sftpRunning = true - err = sftpServer.RunServer() - sftpRunning = false - if err != nil { - handleEndpointStartFailedHooks("sftp", err) - utils.Log.Errorf("problem sftp server listening: %s", err.Error()) - } else { - handleEndpointShutdownHooks("sftp") - } - }() - } - } + plugin.StartAll() running = true } @@ -317,41 +235,11 @@ func Shutdown(timeout time.Duration) { unixSrv = nil }() } - if s3Srv != nil && conf.Conf.S3.Port != -1 && conf.Conf.S3.Enable { - wg.Add(1) - go func() { - defer wg.Done() - if err := s3Srv.Shutdown(ctx); err != nil { - utils.Log.Error("S3 server shutdown err: ", err) - } - s3Srv = nil - }() - } - if conf.Conf.FTP.Listen != "" && conf.Conf.FTP.Enable && ftpServer != nil { - wg.Add(1) - go func() { - defer wg.Done() - if ftpDriver != nil { - ftpDriver.Stop() - ftpDriver = nil - } - if err := ftpServer.Stop(); err != nil { - utils.Log.Error("FTP server shutdown err: ", err) - } - ftpServer = nil - }() - } - if conf.Conf.SFTP.Listen != "" && conf.Conf.SFTP.Enable && sftpServer != nil { - wg.Add(1) - go func() { - defer wg.Done() - if err := sftpServer.Close(); err != nil { - utils.Log.Error("SFTP server shutdown err: ", err) - } - sftpServer = nil - sftpDriver = nil - }() - } + wg.Add(1) + go func() { + defer wg.Done() + plugin.StopAll() + }() wg.Wait() utils.Log.Println("Server exit") running = false diff --git a/internal/conf/config.go b/internal/conf/config.go index f347380d8..dd40384f3 100644 --- a/internal/conf/config.go +++ b/internal/conf/config.go @@ -1,6 +1,7 @@ package conf import ( + "encoding/json" "path/filepath" "github.com/OpenListTeam/OpenList/v4/pkg/utils/random" @@ -82,56 +83,37 @@ type Cors struct { AllowHeaders []string `json:"allow_headers" env:"ALLOW_HEADERS"` } -type S3 struct { - Enable bool `json:"enable" env:"ENABLE"` - Port int `json:"port" env:"PORT"` - SSL bool `json:"ssl" env:"SSL"` -} - -type FTP struct { - Enable bool `json:"enable" env:"ENABLE"` - Listen string `json:"listen" env:"LISTEN"` - FindPasvPortAttempts int `json:"find_pasv_port_attempts" env:"FIND_PASV_PORT_ATTEMPTS"` - ActiveTransferPortNon20 bool `json:"active_transfer_port_non_20" env:"ACTIVE_TRANSFER_PORT_NON_20"` - IdleTimeout int `json:"idle_timeout" env:"IDLE_TIMEOUT"` - ConnectionTimeout int `json:"connection_timeout" env:"CONNECTION_TIMEOUT"` - DisableActiveMode bool `json:"disable_active_mode" env:"DISABLE_ACTIVE_MODE"` - DefaultTransferBinary bool `json:"default_transfer_binary" env:"DEFAULT_TRANSFER_BINARY"` - EnableActiveConnIPCheck bool `json:"enable_active_conn_ip_check" env:"ENABLE_ACTIVE_CONN_IP_CHECK"` - EnablePasvConnIPCheck bool `json:"enable_pasv_conn_ip_check" env:"ENABLE_PASV_CONN_IP_CHECK"` -} - -type SFTP struct { - Enable bool `json:"enable" env:"ENABLE"` - Listen string `json:"listen" env:"LISTEN"` +type PluginConfig struct { + Name string `json:"name"` + Enable bool `json:"enable"` + Enabled *bool `json:"enabled,omitempty"` + Data map[string]any `json:"data"` } type Config struct { - Force bool `json:"force" env:"FORCE"` - SiteURL string `json:"site_url" env:"SITE_URL"` - Cdn string `json:"cdn" env:"CDN"` - JwtSecret string `json:"jwt_secret" env:"JWT_SECRET"` - TokenExpiresIn int `json:"token_expires_in" env:"TOKEN_EXPIRES_IN"` - Database Database `json:"database" envPrefix:"DB_"` - Meilisearch Meilisearch `json:"meilisearch" envPrefix:"MEILISEARCH_"` - Scheme Scheme `json:"scheme"` - TempDir string `json:"temp_dir" env:"TEMP_DIR"` - BleveDir string `json:"bleve_dir" env:"BLEVE_DIR"` - DistDir string `json:"dist_dir"` - Log LogConfig `json:"log" envPrefix:"LOG_"` - DelayedStart int `json:"delayed_start" env:"DELAYED_START"` - MaxBufferLimit int `json:"max_buffer_limitMB" env:"MAX_BUFFER_LIMIT_MB"` - MmapThreshold int `json:"mmap_thresholdMB" env:"MMAP_THRESHOLD_MB"` - MaxConnections int `json:"max_connections" env:"MAX_CONNECTIONS"` - MaxConcurrency int `json:"max_concurrency" env:"MAX_CONCURRENCY"` - TlsInsecureSkipVerify bool `json:"tls_insecure_skip_verify" env:"TLS_INSECURE_SKIP_VERIFY"` - Tasks TasksConfig `json:"tasks" envPrefix:"TASKS_"` - Cors Cors `json:"cors" envPrefix:"CORS_"` - S3 S3 `json:"s3" envPrefix:"S3_"` - FTP FTP `json:"ftp" envPrefix:"FTP_"` - SFTP SFTP `json:"sftp" envPrefix:"SFTP_"` - LastLaunchedVersion string `json:"last_launched_version"` - ProxyAddress string `json:"proxy_address" env:"PROXY_ADDRESS"` + Force bool `json:"force" env:"FORCE"` + SiteURL string `json:"site_url" env:"SITE_URL"` + Cdn string `json:"cdn" env:"CDN"` + JwtSecret string `json:"jwt_secret" env:"JWT_SECRET"` + TokenExpiresIn int `json:"token_expires_in" env:"TOKEN_EXPIRES_IN"` + Database Database `json:"database" envPrefix:"DB_"` + Meilisearch Meilisearch `json:"meilisearch" envPrefix:"MEILISEARCH_"` + Scheme Scheme `json:"scheme"` + TempDir string `json:"temp_dir" env:"TEMP_DIR"` + BleveDir string `json:"bleve_dir" env:"BLEVE_DIR"` + DistDir string `json:"dist_dir"` + Log LogConfig `json:"log" envPrefix:"LOG_"` + DelayedStart int `json:"delayed_start" env:"DELAYED_START"` + MaxBufferLimit int `json:"max_buffer_limitMB" env:"MAX_BUFFER_LIMIT_MB"` + MmapThreshold int `json:"mmap_thresholdMB" env:"MMAP_THRESHOLD_MB"` + MaxConnections int `json:"max_connections" env:"MAX_CONNECTIONS"` + MaxConcurrency int `json:"max_concurrency" env:"MAX_CONCURRENCY"` + TlsInsecureSkipVerify bool `json:"tls_insecure_skip_verify" env:"TLS_INSECURE_SKIP_VERIFY"` + Tasks TasksConfig `json:"tasks" envPrefix:"TASKS_"` + Cors Cors `json:"cors" envPrefix:"CORS_"` + Plugins []PluginConfig `json:"plugins"` + LastLaunchedVersion string `json:"last_launched_version"` + ProxyAddress string `json:"proxy_address" env:"PROXY_ADDRESS"` } func DefaultConfig(dataDir string) *Config { @@ -223,28 +205,75 @@ func DefaultConfig(dataDir string) *Config { AllowMethods: []string{"*"}, AllowHeaders: []string{"*"}, }, - S3: S3{ - Enable: false, - Port: 5246, - SSL: false, - }, - FTP: FTP{ - Enable: false, - Listen: ":5221", - FindPasvPortAttempts: 50, - ActiveTransferPortNon20: false, - IdleTimeout: 900, - ConnectionTimeout: 30, - DisableActiveMode: false, - DefaultTransferBinary: false, - EnableActiveConnIPCheck: true, - EnablePasvConnIPCheck: true, - }, - SFTP: SFTP{ - Enable: false, - Listen: ":5222", + Plugins: []PluginConfig{ + { + Name: "webdav", + Enable: false, + Data: map[string]any{ + "enabled": true, + }, + }, + { + Name: "s3", + Enable: false, + Data: map[string]any{ + "enabled": false, + "port": 5246, + "ssl": false, + }, + }, + { + Name: "ftp", + Enable: false, + Data: map[string]any{ + "enabled": false, + "listen": ":5221", + "find_pasv_port_attempts": 50, + "active_transfer_port_non_20": false, + "idle_timeout": 900, + "connection_timeout": 30, + "disable_active_mode": false, + "default_transfer_binary": false, + "enable_active_conn_ip_check": true, + "enable_pasv_conn_ip_check": true, + }, + }, + { + Name: "sftp", + Enable: false, + Data: map[string]any{ + "enabled": false, + "listen": ":5222", + }, + }, }, LastLaunchedVersion: "", ProxyAddress: "", } } + +func (c *Config) UnmarshalJSON(data []byte) error { + type configAlias Config + aux := struct { + *configAlias + Plugins *[]PluginConfig `json:"plugins"` + }{ + configAlias: (*configAlias)(c), + } + if err := json.Unmarshal(data, &aux); err != nil { + return err + } + if aux.Plugins != nil { + c.Plugins = *aux.Plugins + for i := range c.Plugins { + if c.Plugins[i].Enabled != nil { + c.Plugins[i].Enable = *c.Plugins[i].Enabled + c.Plugins[i].Enabled = nil + } + if c.Plugins[i].Data == nil { + c.Plugins[i].Data = map[string]any{} + } + } + } + return nil +} diff --git a/server/router.go b/server/router.go index 57d1166ae..ac0f1e5cc 100644 --- a/server/router.go +++ b/server/router.go @@ -39,8 +39,6 @@ func Init(e *gin.Engine) { if conf.Conf.MaxConnections > 0 { g.Use(middlewares.MaxAllowed(conf.Conf.MaxConnections)) } - WebDav(g.Group("/dav")) - S3(g.Group("/s3")) downloadLimiter := middlewares.DownloadRateLimiter(stream.ClientDownloadLimit) signCheck := middlewares.Down(sign.Verify) @@ -243,8 +241,3 @@ func Cors(r *gin.Engine) { config.AllowMethods = conf.Conf.Cors.AllowMethods r.Use(cors.New(config)) } - -func InitS3(e *gin.Engine) { - Cors(e) - S3Server(e.Group("/")) -} diff --git a/server/utils.go b/server/utils.go deleted file mode 100644 index 0e9d68809..000000000 --- a/server/utils.go +++ /dev/null @@ -1,14 +0,0 @@ -package server - -import ( - "github.com/OpenListTeam/OpenList/v4/internal/model" - "github.com/OpenListTeam/OpenList/v4/server/common" -) - -func tryLdapLoginAndRegister(user, pass string) (*model.User, error) { - err := common.HandleLdapLogin(user, pass) - if err != nil { - return nil, err - } - return common.LdapRegister(user) -} From 243651db2cac9f53a064211de6661d489d9250bc Mon Sep 17 00:00:00 2001 From: mkitsdts Date: Wed, 25 Mar 2026 17:30:41 +0800 Subject: [PATCH 07/10] chore(plugin): add interface check --- plugins/sftp/plugin.go | 2 ++ plugins/webdav/plugin.go | 2 ++ 2 files changed, 4 insertions(+) diff --git a/plugins/sftp/plugin.go b/plugins/sftp/plugin.go index ad9bd3561..ec61aeaa3 100644 --- a/plugins/sftp/plugin.go +++ b/plugins/sftp/plugin.go @@ -47,6 +47,8 @@ func (p *SFTPPlugin) Stop() error { return err } +var _ iplugin.Plugin = (*SFTPPlugin)(nil) + func init() { iplugin.RegisterPlugin("sftp", func() iplugin.Plugin { return &SFTPPlugin{} diff --git a/plugins/webdav/plugin.go b/plugins/webdav/plugin.go index 33c2a87a4..663339f02 100644 --- a/plugins/webdav/plugin.go +++ b/plugins/webdav/plugin.go @@ -71,6 +71,8 @@ func (p *WebDAVPlugin) Stop() error { return err } +var _ iplugin.Plugin = (*WebDAVPlugin)(nil) + func init() { iplugin.RegisterPlugin("webdav", func() iplugin.Plugin { return &WebDAVPlugin{} From 4e983bacc379bc3092db9cfe57263943eb870350 Mon Sep 17 00:00:00 2001 From: mkitsdts Date: Thu, 26 Mar 2026 10:01:23 +0800 Subject: [PATCH 08/10] feat(plugin): remove dependency ftp from sftp --- go.mod | 4 +- go.sum | 278 +++------------------- plugins/sftp/plugin.go | 12 +- plugins/sftp/runtime.go | 182 +++++++++++---- plugins/sftp/sftp.go | 499 ++++++++++++++++++++++++++++++++++------ 5 files changed, 600 insertions(+), 375 deletions(-) diff --git a/go.mod b/go.mod index c36ac1ca0..6edc91ff9 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,6 @@ require ( github.com/KarpelesLab/reflink v1.0.2 github.com/KirCute/zip v1.0.1 github.com/OpenListTeam/go-cache v0.1.0 - github.com/OpenListTeam/sftpd-openlist v1.0.1 github.com/OpenListTeam/tache v0.2.2 github.com/OpenListTeam/times v0.1.0 github.com/OpenListTeam/wopan-sdk-go v0.1.5 @@ -89,8 +88,8 @@ require ( ) require ( - cloud.google.com/go/compute/metadata v0.9.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect + github.com/BurntSushi/toml v1.6.0 // indirect github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf // indirect github.com/ProtonMail/gluon v0.17.1-0.20230724134000-308be39be96e // indirect github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f // indirect @@ -158,7 +157,6 @@ require ( github.com/microcosm-cc/bluemonday v1.0.27 github.com/nwaples/rardecode/v2 v2.1.1 github.com/sorairolake/lzip-go v0.3.5 // indirect - github.com/taruti/bytepool v0.0.0-20160310082835-5e3a9ea56543 // indirect github.com/ulikunitz/xz v0.5.12 // indirect github.com/yuin/goldmark v1.7.13 go4.org v0.0.0-20260112195520-a5071408f32f diff --git a/go.sum b/go.sum index b9a4570bd..53c7d8cca 100644 --- a/go.sum +++ b/go.sum @@ -1,28 +1,10 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.53.0 h1:MZQCQQaRwOrAcuKjiHWHrgKykt4fZyuwF2dtiG3fGW8= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go/auth v0.16.2 h1:QvBAGFPLrDeoiNjyfVunhQ10HKNYuOwZ5noee0M5df4= -cloud.google.com/go/auth v0.16.2/go.mod h1:sRBas2Y1fB1vZTdurouM0AzuYQBMZinrUYL8EufhtEA= +cloud.google.com/go v0.121.6 h1:waZiuajrI28iAf40cWgycWNgaXPO06dupuS+sgibK6c= +cloud.google.com/go/auth v0.18.0 h1:wnqy5hrv7p3k7cShwAU/Br3nzod7fxoqG+k0VZ+/Pk0= +cloud.google.com/go/auth v0.18.0/go.mod h1:wwkPM1AgE1f2u6dG443MiWoD8C3BtOywNsUMcUTVDRo= cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU= -cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo= +cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1 h1:Wc1ml6QlJs2BHQ/9Bqu1jiyggbsSjramq2oUmp5WeIo= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1 h1:B+blDbyVIG3WaikNxPnhPiJ1MThR03b3vKGtER95TP4= @@ -35,9 +17,8 @@ github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.2 h1:FwladfywkNirM+FZY github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.2/go.mod h1:vv5Ad0RrIoT1lJFdWBZwt4mB1+j+V8DUroixmKDTCdk= github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 h1:oygO0locgZJe7PpYPXT5A29ZkwJaPqcva7BVeemZOZs= github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk= +github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/Da3zKi7/saferith v0.33.0-fixed h1:fnIWTk7EP9mZAICf7aQjeoAwpfrlCrkOvqmi6CbWdTk= github.com/Da3zKi7/saferith v0.33.0-fixed/go.mod h1:QKJhjoqUtBsXCAVEjw38mFqoi7DebT7kthcD7UzbnoA= github.com/KarpelesLab/reflink v1.0.2 h1:hQ1aM3TmjU2kTNUx5p/HaobDoADYk+a6AuEinG4Cv88= @@ -54,8 +35,6 @@ github.com/OpenListTeam/go-cache v0.1.0 h1:eV2+FCP+rt+E4OCJqLUW7wGccWZNJMV0NNkh+ github.com/OpenListTeam/go-cache v0.1.0/go.mod h1:AHWjKhNK3LE4rorVdKyEALDHoeMnP8SjiNyfVlB+Pz4= github.com/OpenListTeam/gsync v0.1.0 h1:ywzGybOvA3lW8K1BUjKZ2IUlT2FSlzPO4DOazfYXjcs= github.com/OpenListTeam/gsync v0.1.0/go.mod h1:h/Rvv9aX/6CdW/7B8di3xK3xNV8dUg45Fehrd/ksZ9s= -github.com/OpenListTeam/sftpd-openlist v1.0.1 h1:j4S3iPFOpnXCUKRPS7uCT4mF2VCl34GyqvH6lqwnkUU= -github.com/OpenListTeam/sftpd-openlist v1.0.1/go.mod h1:uO/wKnbvbdq3rBLmClMTZXuCnw7XW4wlAq4dZe91a40= github.com/OpenListTeam/tache v0.2.2 h1:CWFn6sr1AIYaEjC8ONdKs+LrxHyuErheenAjEqRhh4k= github.com/OpenListTeam/tache v0.2.2/go.mod h1:qmnZ/VpY2DUlmjg3UoDeNFy/LRqrw0biN3hYEEGc/+A= github.com/OpenListTeam/times v0.1.0 h1:qknxw+qj5CYKgXAwydA102UEpPcpU8TYNGRmwRyPYpg= @@ -205,7 +184,6 @@ github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCN github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= github.com/caarlos0/env/v9 v9.0.0 h1:SI6JNsOA+y5gj9njpgybykATIylrRMklbs5ch6wO6pc= github.com/caarlos0/env/v9 v9.0.0/go.mod h1:ye5mlCVMYh6tZ+vCgrs/B95sj88cg5Tlnc0XIzgZ020= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs= @@ -226,12 +204,8 @@ github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQ github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927 h1:SKI1/fuSdodxmNNyVBR8d7X/HuLnRpvvFO0AgyQk764= github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/city404/v6-public-rpc-proto/go v0.0.0-20240817070657-90f8e24b653e h1:GLC8iDDcbt1H8+RkNao2nRGjyNTIo81e1rAJT9/uWYA= github.com/city404/v6-public-rpc-proto/go v0.0.0-20240817070657-90f8e24b653e/go.mod h1:ln9Whp+wVY/FTbn2SK0ag+SKD2fC0yQCF/Lqowc1LmU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I= github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0= github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= @@ -278,8 +252,6 @@ github.com/emersion/go-message v0.18.2 h1:rl55SQdjd9oJcIoQNhubD2Acs1E6IzlZISRTK7 github.com/emersion/go-message v0.18.2/go.mod h1:XpJyL70LwRvq2a8rVbHXikPgKj8+aI0kGdHlg16ibYA= github.com/emersion/go-vcard v0.0.0-20241024213814-c9703dde27ff h1:4N8wnS3f1hNHSmFD5zgFkWCyA4L1kCDkImPAtK7D6tg= github.com/emersion/go-vcard v0.0.0-20241024213814-c9703dde27ff/go.mod h1:HMJKR5wlh/ziNp+sHEDV2ltblO4JD2+IdDOWtGcQBTM= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= github.com/fclairamb/ftpserverlib v0.26.1-0.20250709223522-4a925d79caf6 h1:q1b+gv6AG2TDPN+f0QAkbRrAvJ3ZosnwRLTKNxSXlaA= @@ -309,8 +281,6 @@ github.com/go-chi/chi/v5 v5.2.2 h1:CMwsvRVTbXVytCk1Wd72Zy1LAsAh9GxMmSNWLHCG618= github.com/go-chi/chi/v5 v5.2.2/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= github.com/go-darwin/apfs v0.0.0-20211011131704-f84b94dbf348 h1:JnrjqG5iR07/8k7NqrLNilRsl3s1EPRQEGvbPyOce68= github.com/go-darwin/apfs v0.0.0-20211011131704-f84b94dbf348/go.mod h1:Czxo/d1g948LtrALAZdL04TL/HnkopquAjxYUuI02bo= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= @@ -348,32 +318,14 @@ github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXe github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v5 v5.2.3 h1:kkGXqQOBSDDWRhWNXTFpqGSCMyh/PLnqUvMGJPDJDs0= github.com/golang-jwt/jwt/v5 v5.2.3/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= @@ -381,22 +333,15 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX github.com/google/go-tpm v0.9.5 h1:ocUmnDebX54dnW+MQWGQRbdaAcJELsa6PqZhJ48KwVU= github.com/google/go-tpm v0.9.5/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4= -github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.14.2 h1:eBLnkZ9635krYIPD+ag1USrOAI0Nr0QYF3+/3GqO0k0= -github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w= +github.com/googleapis/enterprise-certificate-proxy v0.3.7 h1:zrn2Ee/nWmHulBx5sAVrGgAa0f2/R35S4DJwfFaUPFQ= +github.com/googleapis/enterprise-certificate-proxy v0.3.7/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA= +github.com/googleapis/gax-go/v2 v2.16.0 h1:iHbQmKLLZrexmb0OSsNGTeSTS0HO4YvFOG8g5E4Zd0Y= +github.com/googleapis/gax-go/v2 v2.16.0/go.mod h1:o1vfQjjNZn4+dPnRdl/4ZD7S9414Y4xA+a/6Icj6l14= github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8= github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0= github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= @@ -419,8 +364,6 @@ github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/C github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= @@ -432,7 +375,6 @@ github.com/henrybear327/Proton-API-Bridge v1.0.0 h1:gjKAaWfKu++77WsZTHg6FUyPC5W0 github.com/henrybear327/Proton-API-Bridge v1.0.0/go.mod h1:gunH16hf6U74W2b9CGDaWRadiLICsoJ6KRkSt53zLts= github.com/henrybear327/go-proton-api v1.0.0 h1:zYi/IbjLwFAW7ltCeqXneUGJey0TN//Xo851a/BgLXw= github.com/henrybear327/go-proton-api v1.0.0/go.mod h1:w63MZuzufKcIZ93pwRgiOtxMXYafI8H74D77AxytOBc= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/ipfs/boxo v0.12.0 h1:AXHg/1ONZdRQHQLgG5JHsSC3XoE4DjCAMgK+asZvUcQ= @@ -478,8 +420,6 @@ github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFF github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jzelinskie/whirlpool v0.0.0-20201016144138-0675e54bb004 h1:G+9t9cEtnC9jFiTxyptEKuNIAbiN5ZCQzX2a74lj3xg= github.com/jzelinskie/whirlpool v0.0.0-20201016144138-0675e54bb004/go.mod h1:KmHnJWQrgEvbuy0vcvj00gtMqbvNn1L+3YUZLK/B92c= github.com/kdomanski/iso9660 v0.4.0 h1:BPKKdcINz3m0MdjIMwS0wx1nofsOjxOq8TOr45WGHFg= @@ -498,11 +438,8 @@ github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQ github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= @@ -621,7 +558,6 @@ github.com/pquerna/otp v1.5.0 h1:NMMR+WrmaqXU4EzdGJEE1aUUI0AMRzsp96fFFWNPwxs= github.com/pquerna/otp v1.5.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.64.0 h1:pdZeA+g617P7oGv1CzdTzyeShxAGrTBsolKNOLQPGO4= @@ -641,11 +577,9 @@ github.com/rfjakob/eme v1.1.2/go.mod h1:cVvpasglm/G3ngEfcfT/Wt0GwhkuO32pf/poW6Ny github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk= github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 h1:GHRpF1pTW19a8tTFrMLUcfWwyC0pnifVo2ClaLq+hP8= github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8= github.com/secsy/goftp v0.0.0-20200609142545-aa2de14babf4 h1:PT+ElG/UUFMfqy5HrxJxNzj3QBOf7dZwupeVC+mG1Lo= @@ -689,8 +623,6 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/t3rm1n4l/go-mega v0.0.0-20241213151442-a19cff0ec7b5 h1:Sa+sR8aaAMFwxhXWENEnE6ZpqhZ9d7u1RT2722Rw6hc= github.com/t3rm1n4l/go-mega v0.0.0-20241213151442-a19cff0ec7b5/go.mod h1:UdZiFUFu6e2WjjtjxivwXWcwc1N/8zgbkBR9QNucUOY= -github.com/taruti/bytepool v0.0.0-20160310082835-5e3a9ea56543 h1:6Y51mutOvRGRx6KqyMNo//xk8B8o6zW9/RVmy1VamOs= -github.com/taruti/bytepool v0.0.0-20160310082835-5e3a9ea56543/go.mod h1:jpwqYA8KUVEvSUJHkCXsnBRJCSKP1BMa81QZ6kvRpow= github.com/tchap/go-patricia/v2 v2.3.3 h1:xfNEsODumaEcCcY3gI0hYPZ/PcpVv5ju6RMAhgwZDDc= github.com/tchap/go-patricia/v2 v2.3.3/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k= github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4= @@ -729,30 +661,24 @@ github.com/zzzhr1990/go-common-entity v0.0.0-20250202070650-1a200048f0d3 h1:PSRw github.com/zzzhr1990/go-common-entity v0.0.0-20250202070650-1a200048f0d3/go.mod h1:CKriYB8bkNgSbYUQF1khSpejKb5IsV6cR7MdaAR7Fc0= go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk= go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= -go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q= -go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg= -go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E= -go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE= -go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs= -go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY= -go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= -go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o= -go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w= -go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w= -go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA= +go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= +go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= +go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= +go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= +go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= +go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= +go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= +go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= +go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= +go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= -go4.org v0.0.0-20230225012048-214862532bf5 h1:nifaUDeh+rPaBCMPMQHZmvJf+QdpLFnuQPwx+LxVmtc= -go4.org v0.0.0-20230225012048-214862532bf5/go.mod h1:F57wTi5Lrj6WLyswp5EYV1ncrEbFGHD4hhz6S1ZYeaU= go4.org v0.0.0-20260112195520-a5071408f32f h1:ziUVAjmTPwQMBmYR1tbdRFJPtTcQUI12fH9QQjfb0Sw= go4.org v0.0.0-20260112195520-a5071408f32f/go.mod h1:ZRJnO5ZI4zAwMFp+dS1+V6J6MSyAowhRqAE+DPa1Xp0= gocv.io/x/gocv v0.25.0/go.mod h1:Rar2PS6DV+T4FL+PM535EImD/h13hGVaHhnCu1xarBs= @@ -760,9 +686,6 @@ golang.org/x/arch v0.18.0 h1:WN9poc33zL4AzGxqf8VtpKUnGvMi8O9lhNyBMF/85qc= golang.org/x/arch v0.18.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= @@ -771,63 +694,23 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= -golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 h1:bsqhLWFR6G6xiQcb+JoGqdKdRU6WzPWmK8E0jxTjzo4= golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.29.0 h1:HcdsyR4Gsuys/Axh0rDEmlBmB68rW1U9BUdB3UVHsas= golang.org/x/image v0.29.0/go.mod h1:RVJROnf3SLK8d26OW91j4FrIHGbsJ8QnbEocVTOWQDA= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ= -golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc= golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= @@ -839,48 +722,22 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= -golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= -golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= -golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= -golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -900,8 +757,6 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= -golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= @@ -914,13 +769,9 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= -golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= -golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -932,111 +783,42 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= -golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= -golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190829051458-42f498d34c4d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= -golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.236.0 h1:CAiEiDVtO4D/Qja2IA9VzlFrgPnK3XVMmRoJZlSWbc0= -google.golang.org/api v0.236.0/go.mod h1:X1WF9CU2oTc+Jml1tiIxGmWFK/UZezdqEu09gcxZAj4= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= +google.golang.org/api v0.259.0 h1:90TaGVIxScrh1Vn/XI2426kRpBqHwWIzVBzJsVZ5XrQ= +google.golang.org/api v0.259.0/go.mod h1:LC2ISWGWbRoyQVpxGntWwLWN/vLNxxKBK9KuJRI8Te4= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b h1:Mv8VFug0MP9e5vUxfBcE3vUkV6CImK3cMNMIDFjmzxU= google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= -google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc= google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= -google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d h1:TxyelI5cVkbREznMhfzycHdkp5cLA7DpE+GKjSslYhM= gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/go-jose/go-jose.v2 v2.6.3 h1:nt80fvSDlhKWQgSWyHyy5CfmlQr+asih51R8PTWNKKs= gopkg.in/go-jose/go-jose.v2 v2.6.3/go.mod h1:zzZDPkNNw/c9IE7Z9jr11mBZQhKQTMzoEEIoEdZlFBI= gopkg.in/ldap.v3 v3.1.0 h1:DIDWEjI7vQWREh0S8X5/NFPCZ3MCVd55LmXKPW4XLGE= @@ -1061,17 +843,9 @@ gorm.io/driver/sqlite v1.5.6/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDa gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= gorm.io/gorm v1.25.11 h1:/Wfyg1B/je1hnDx3sMkX+gAlxrlZpn6X0BXRlwXlvHg= gorm.io/gorm v1.25.11/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0= lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= resty.dev/v3 v3.0.0-beta.2 h1:xu4mGAdbCLuc3kbk7eddWfWm4JfhwDtdapwss5nCjnQ= resty.dev/v3 v3.0.0-beta.2/go.mod h1:OgkqiPvTDtOuV4MGZuUDhwOpkY8enjOsjjMzeOHefy4= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/plugins/sftp/plugin.go b/plugins/sftp/plugin.go index ec61aeaa3..ba6262070 100644 --- a/plugins/sftp/plugin.go +++ b/plugins/sftp/plugin.go @@ -5,12 +5,10 @@ import ( iplugin "github.com/OpenListTeam/OpenList/v4/internal/plugin" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/sftpd-openlist" ) type SFTPPlugin struct { - driver *Driver - server *sftpd.SftpServer + server *Server conf SFTP } @@ -26,15 +24,14 @@ func (p *SFTPPlugin) Init(config map[string]any) error { } func (p *SFTPPlugin) Start() error { - driver, err := NewDriver(p.conf) + server, err := NewServer(p.conf) if err != nil { return err } - p.driver = driver + p.server = server utils.Log.Infof("start sftp server on %s", p.conf.Listen) fmt.Printf("start sftp server on %s\n", p.conf.Listen) - p.server = sftpd.NewSftpServer(driver) - return p.server.RunServer() + return p.server.Serve() } func (p *SFTPPlugin) Stop() error { @@ -43,7 +40,6 @@ func (p *SFTPPlugin) Stop() error { } err := p.server.Close() p.server = nil - p.driver = nil return err } diff --git a/plugins/sftp/runtime.go b/plugins/sftp/runtime.go index 26255d3ac..de21da3a6 100644 --- a/plugins/sftp/runtime.go +++ b/plugins/sftp/runtime.go @@ -1,8 +1,10 @@ package sftp import ( - "context" + "io" + "net" "net/http" + "sync" "time" "github.com/OpenListTeam/OpenList/v4/drivers/base" @@ -11,73 +13,149 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/op" "github.com/OpenListTeam/OpenList/v4/internal/setting" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - pluginftp "github.com/OpenListTeam/OpenList/v4/plugins/ftp" - "github.com/OpenListTeam/OpenList/v4/server/common" - "github.com/OpenListTeam/sftpd-openlist" + pkgsftp "github.com/pkg/sftp" "github.com/pkg/errors" + "github.com/OpenListTeam/OpenList/v4/server/common" "golang.org/x/crypto/ssh" ) -type Driver struct { - proxyHeader http.Header - config *sftpd.Config +type Server struct { listen string + listener net.Listener + proxyHeader http.Header + conns map[net.Conn]struct{} + mu sync.Mutex } -func NewDriver(cfg SFTP) (*Driver, error) { - pluginftp.InitStage() +func NewServer(cfg SFTP) (*Server, error) { InitHostKey() - return &Driver{ + return &Server{ + listen: cfg.Listen, proxyHeader: http.Header{ "User-Agent": {base.UserAgent}, }, - listen: cfg.Listen, + conns: make(map[net.Conn]struct{}), }, nil } -func (d *Driver) GetConfig() *sftpd.Config { - if d.config != nil { - return d.config +func (s *Server) Serve() error { + listener, err := net.Listen("tcp", s.listen) + if err != nil { + return err + } + s.listener = listener + for { + conn, err := listener.Accept() + if err != nil { + if errors.Is(err, net.ErrClosed) { + return nil + } + return err + } + s.trackConn(conn) + go s.handleConn(conn) + } +} + +func (s *Server) Close() error { + if s.listener != nil { + _ = s.listener.Close() + s.listener = nil + } + s.mu.Lock() + for conn := range s.conns { + _ = conn.Close() + } + s.conns = make(map[net.Conn]struct{}) + s.mu.Unlock() + return nil +} + +func (s *Server) handleConn(conn net.Conn) { + defer s.untrackConn(conn) + sshConn, chans, reqs, err := ssh.NewServerConn(conn, s.serverConfig()) + if err != nil { + utils.Log.Errorf("[SFTP] handshake failed from %s: %+v", conn.RemoteAddr(), err) + return + } + defer sshConn.Close() + go ssh.DiscardRequests(reqs) + for newChannel := range chans { + if newChannel.ChannelType() != "session" { + _ = newChannel.Reject(ssh.UnknownChannelType, "unknown channel type") + continue + } + channel, requests, err := newChannel.Accept() + if err != nil { + utils.Log.Errorf("[SFTP] accept session failed: %+v", err) + continue + } + go s.handleSession(sshConn, channel, requests) + } +} + +func (s *Server) handleSession(conn *ssh.ServerConn, channel ssh.Channel, requests <-chan *ssh.Request) { + defer channel.Close() + for req := range requests { + ok := req.Type == "subsystem" && string(req.Payload[4:]) == "sftp" + if req.WantReply { + _ = req.Reply(ok, nil) + } + if !ok { + continue + } + handler, err := s.newHandler(conn) + if err != nil { + utils.Log.Errorf("[SFTP] init handler failed: %+v", err) + return + } + server := pkgsftp.NewRequestServer(channel, pkgsftp.Handlers{ + FileGet: handler, + FilePut: handler, + FileCmd: handler, + FileList: handler, + }) + if err := server.Serve(); err != nil && !errors.Is(err, io.EOF) { + utils.Log.Errorf("[SFTP] request server failed: %+v", err) + } + _ = server.Close() + return + } +} + +func (s *Server) newHandler(conn *ssh.ServerConn) (*Handler, error) { + userObj, err := op.GetUserByName(conn.User()) + if err != nil { + return nil, err } + return &Handler{ + user: userObj, + metaPass: "", + clientIP: conn.RemoteAddr().String(), + proxyHeader: s.proxyHeader, + }, nil +} + +func (s *Server) serverConfig() *ssh.ServerConfig { var pwdAuth func(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) if !setting.GetBool(conf.SFTPDisablePasswordLogin) { - pwdAuth = d.PasswordAuth + pwdAuth = s.PasswordAuth } - serverConfig := ssh.ServerConfig{ + serverConfig := &ssh.ServerConfig{ NoClientAuth: true, - NoClientAuthCallback: d.NoClientAuth, + NoClientAuthCallback: s.NoClientAuth, PasswordCallback: pwdAuth, - PublicKeyCallback: d.PublicKeyAuth, - AuthLogCallback: d.AuthLogCallback, - BannerCallback: d.GetBanner, + PublicKeyCallback: s.PublicKeyAuth, + AuthLogCallback: s.AuthLogCallback, + BannerCallback: s.GetBanner, } for _, k := range SSHSigners { serverConfig.AddHostKey(k) } - d.config = &sftpd.Config{ - ServerConfig: serverConfig, - HostPort: d.listen, - ErrorLogFunc: utils.Log.Error, - } - return d.config -} - -func (d *Driver) GetFileSystem(sc *ssh.ServerConn) (sftpd.FileSystem, error) { - userObj, err := op.GetUserByName(sc.User()) - if err != nil { - return nil, err - } - ctx := context.Background() - ctx = context.WithValue(ctx, conf.UserKey, userObj) - ctx = context.WithValue(ctx, conf.MetaPassKey, "") - ctx = context.WithValue(ctx, conf.ClientIPKey, sc.RemoteAddr().String()) - ctx = context.WithValue(ctx, conf.ProxyHeaderKey, d.proxyHeader) - return &DriverAdapter{FtpDriver: pluginftp.NewAferoAdapter(ctx)}, nil + return serverConfig } -func (d *Driver) Close() {} - -func (d *Driver) NoClientAuth(conn ssh.ConnMetadata) (*ssh.Permissions, error) { +func (s *Server) NoClientAuth(conn ssh.ConnMetadata) (*ssh.Permissions, error) { if conn.User() != "guest" { return nil, errors.New("only guest is allowed to login without authorization") } @@ -91,7 +169,7 @@ func (d *Driver) NoClientAuth(conn ssh.ConnMetadata) (*ssh.Permissions, error) { return nil, nil } -func (d *Driver) PasswordAuth(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) { +func (s *Server) PasswordAuth(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) { ip := conn.RemoteAddr().String() count, ok := model.LoginCache.Get(ip) if ok && count >= model.DefaultMaxAuthRetries { @@ -120,7 +198,7 @@ func (d *Driver) PasswordAuth(conn ssh.ConnMetadata, password []byte) (*ssh.Perm return nil, nil } -func (d *Driver) PublicKeyAuth(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { +func (s *Server) PublicKeyAuth(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { userObj, err := op.GetUserByName(conn.User()) if err != nil { return nil, err @@ -147,7 +225,7 @@ func (d *Driver) PublicKeyAuth(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.P return nil, errors.New("public key refused") } -func (d *Driver) AuthLogCallback(conn ssh.ConnMetadata, method string, err error) { +func (s *Server) AuthLogCallback(conn ssh.ConnMetadata, method string, err error) { ip := conn.RemoteAddr().String() if err == nil { utils.Log.Infof("[SFTP] %s(%s) logged in via %s", conn.User(), ip, method) @@ -156,6 +234,18 @@ func (d *Driver) AuthLogCallback(conn ssh.ConnMetadata, method string, err error } } -func (d *Driver) GetBanner(_ ssh.ConnMetadata) string { +func (s *Server) GetBanner(_ ssh.ConnMetadata) string { return setting.GetStr(conf.Announcement) } + +func (s *Server) trackConn(conn net.Conn) { + s.mu.Lock() + defer s.mu.Unlock() + s.conns[conn] = struct{}{} +} + +func (s *Server) untrackConn(conn net.Conn) { + s.mu.Lock() + defer s.mu.Unlock() + delete(s.conns, conn) +} diff --git a/plugins/sftp/sftp.go b/plugins/sftp/sftp.go index 46ba4e833..e2672364a 100644 --- a/plugins/sftp/sftp.go +++ b/plugins/sftp/sftp.go @@ -1,124 +1,491 @@ package sftp import ( + "context" + "io" + fs2 "io/fs" + "net/http" "os" + stdpath "path" + "sync" + "syscall" + "time" + "github.com/OpenListTeam/OpenList/v4/internal/conf" "github.com/OpenListTeam/OpenList/v4/internal/errs" + "github.com/OpenListTeam/OpenList/v4/internal/fs" "github.com/OpenListTeam/OpenList/v4/internal/model" + "github.com/OpenListTeam/OpenList/v4/internal/op" + "github.com/OpenListTeam/OpenList/v4/internal/setting" + "github.com/OpenListTeam/OpenList/v4/internal/stream" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - pluginftp "github.com/OpenListTeam/OpenList/v4/plugins/ftp" - "github.com/OpenListTeam/sftpd-openlist" + pkgsftp "github.com/pkg/sftp" + "github.com/pkg/errors" + "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/shirou/gopsutil/v4/disk" ) -type DriverAdapter struct { - FtpDriver *pluginftp.AferoAdapter +type Handler struct { + user *model.User + metaPass string + clientIP string + proxyHeader http.Header } -func (s *DriverAdapter) OpenFile(_ string, _ uint32, _ *sftpd.Attr) (sftpd.File, error) { - // See also GetHandle - return nil, errs.NotImplement +func (h *Handler) Fileread(r *pkgsftp.Request) (io.ReaderAt, error) { + flags := r.Pflags() + if !flags.Read { + return nil, os.ErrInvalid + } + return openDownload(h.requestContext(r), r.Filepath) } -func (s *DriverAdapter) OpenDir(_ string) (sftpd.Dir, error) { - // See also GetHandle - return nil, errs.NotImplement +func (h *Handler) Filewrite(r *pkgsftp.Request) (io.WriterAt, error) { + flags := r.Pflags() + if !flags.Write { + return nil, os.ErrInvalid + } + return openUpload(h.requestContext(r), r.Filepath, flags) } -func (s *DriverAdapter) Remove(name string) error { - return s.FtpDriver.Remove(name) +func (h *Handler) OpenFile(r *pkgsftp.Request) (pkgsftp.WriterAtReaderAt, error) { + flags := r.Pflags() + if flags.Read && !flags.Write { + return newReadWriteHandle(openDownload(h.requestContext(r), r.Filepath)) + } + if !flags.Write { + return nil, os.ErrInvalid + } + return openUpload(h.requestContext(r), r.Filepath, flags) } -func (s *DriverAdapter) Rename(old, new string, _ uint32) error { - return s.FtpDriver.Rename(old, new) +func (h *Handler) Filecmd(r *pkgsftp.Request) error { + ctx := h.requestContext(r) + switch r.Method { + case "Setstat": + return setstat(ctx, r) + case "Mkdir": + return mkdir(ctx, r.Filepath) + case "Remove", "Rmdir": + return remove(ctx, r.Filepath) + case "Rename": + return rename(ctx, r.Filepath, r.Target) + case "Link", "Symlink": + return nil + default: + return nil + } } -func (s *DriverAdapter) Mkdir(name string, attr *sftpd.Attr) error { - return s.FtpDriver.Mkdir(name, attr.Mode) +func (h *Handler) Filelist(r *pkgsftp.Request) (pkgsftp.ListerAt, error) { + ctx := h.requestContext(r) + switch r.Method { + case "List": + items, err := list(ctx, r.Filepath) + if err != nil { + return nil, err + } + return &fileLister{items: items}, nil + case "Stat": + item, err := stat(ctx, r.Filepath) + if err != nil { + return nil, err + } + return &fileLister{items: []os.FileInfo{item}}, nil + default: + item, err := stat(ctx, r.Filepath) + if err != nil { + return nil, err + } + return &fileLister{items: []os.FileInfo{item}}, nil + } } -func (s *DriverAdapter) Rmdir(name string) error { - return s.Remove(name) +func (h *Handler) Lstat(r *pkgsftp.Request) (pkgsftp.ListerAt, error) { + return h.Filelist(r) } -func (s *DriverAdapter) Stat(name string, _ bool) (*sftpd.Attr, error) { - stat, err := s.FtpDriver.Stat(name) +func (h *Handler) RealPath(path string) (string, error) { + return utils.FixAndCleanPath(path), nil +} + +func (h *Handler) Readlink(path string) (string, error) { + return utils.FixAndCleanPath(path), nil +} + +func (h *Handler) PosixRename(r *pkgsftp.Request) error { + return rename(h.requestContext(r), r.Filepath, r.Target) +} + +func (h *Handler) StatVFS(_ *pkgsftp.Request) (*pkgsftp.StatVFS, error) { + usage, err := disk.Usage(conf.Conf.TempDir) if err != nil { return nil, err } - return fileInfoToSftpAttr(stat), nil + return &pkgsftp.StatVFS{ + Bsize: 4096, + Frsize: 4096, + Blocks: usage.Total / 4096, + Bfree: usage.Free / 4096, + Bavail: usage.Free / 4096, + Files: usage.InodesTotal, + Ffree: usage.InodesFree, + Favail: usage.InodesFree, + Namemax: 255, + }, nil } -func (s *DriverAdapter) SetStat(_ string, _ *sftpd.Attr) error { - return errs.NotSupport +func (h *Handler) requestContext(r *pkgsftp.Request) context.Context { + ctx := r.Context() + ctx = context.WithValue(ctx, conf.UserKey, h.user) + ctx = context.WithValue(ctx, conf.MetaPassKey, h.metaPass) + ctx = context.WithValue(ctx, conf.ClientIPKey, h.clientIP) + ctx = context.WithValue(ctx, conf.ProxyHeaderKey, h.proxyHeader) + return ctx } -func (s *DriverAdapter) ReadLink(_ string) (string, error) { - return "", errs.NotSupport +type fileDownloadProxy struct { + model.File + io.Closer + ctx context.Context } -func (s *DriverAdapter) CreateLink(_, _ string, _ uint32) error { - return errs.NotSupport +func openDownload(ctx context.Context, filePath string) (*fileDownloadProxy, error) { + reqPath, meta, err := resolveAccessiblePath(ctx, filePath) + if err != nil { + return nil, err + } + ctx = context.WithValue(ctx, conf.MetaKey, meta) + header, _ := ctx.Value(conf.ProxyHeaderKey).(http.Header) + ip, _ := ctx.Value(conf.ClientIPKey).(string) + link, obj, err := fs.Link(ctx, reqPath, model.LinkArgs{IP: ip, Header: header}) + if err != nil { + return nil, err + } + ss, err := stream.NewSeekableStream(&stream.FileStream{ + Obj: obj, + Ctx: ctx, + }, link) + if err != nil { + _ = link.Close() + return nil, err + } + reader, err := stream.NewReadAtSeeker(ss, 0) + if err != nil { + _ = ss.Close() + return nil, err + } + return &fileDownloadProxy{File: reader, Closer: ss, ctx: ctx}, nil } -func (s *DriverAdapter) RealPath(path string) (string, error) { - return utils.FixAndCleanPath(path), nil +func (f *fileDownloadProxy) ReadAt(p []byte, off int64) (n int, err error) { + n, err = f.File.ReadAt(p, off) + if err != nil && !errors.Is(err, io.EOF) { + return n, err + } + waitErr := stream.ClientDownloadLimit.WaitN(f.ctx, n) + if errors.Is(err, io.EOF) { + return n, err + } + return n, waitErr } -func (s *DriverAdapter) GetHandle(name string, flags uint32, _ *sftpd.Attr, offset uint64) (sftpd.FileTransfer, error) { - return s.FtpDriver.GetHandle(name, sftpFlagToOpenMode(flags), int64(offset)) +type uploadHandle struct { + ctx context.Context + path string + file *os.File + flags pkgsftp.FileOpenFlags + closed sync.Once } -func (s *DriverAdapter) ReadDir(name string) ([]sftpd.NamedAttr, error) { - dir, err := s.FtpDriver.ReadDir(name) +func openUpload(ctx context.Context, filePath string, flags pkgsftp.FileOpenFlags) (*uploadHandle, error) { + reqPath, err := resolveWritablePath(ctx, filePath) if err != nil { return nil, err } - ret := make([]sftpd.NamedAttr, len(dir)) - for i, d := range dir { - ret[i] = *fileInfoToSftpNamedAttr(d) + _, name := stdpath.Split(reqPath) + if setting.GetBool(conf.IgnoreSystemFiles) && utils.IsSystemFile(name) { + return nil, errs.IgnoredSystemFile } - return ret, nil + tmpFile, err := os.CreateTemp(conf.Conf.TempDir, "sftp-*") + if err != nil { + return nil, err + } + handle := &uploadHandle{ctx: ctx, path: reqPath, file: tmpFile, flags: flags} + if !flags.Trunc || flags.Read || flags.Append { + if err := handle.seed(); err != nil { + _ = os.Remove(tmpFile.Name()) + _ = tmpFile.Close() + return nil, err + } + } + return handle, nil +} + +func (u *uploadHandle) ReadAt(p []byte, off int64) (int, error) { + return u.file.ReadAt(p, off) } -// From leffss/sftpd -func sftpFlagToOpenMode(flags uint32) int { - mode := 0 - if (flags & SSH_FXF_READ) != 0 { - mode |= os.O_RDONLY +func (u *uploadHandle) WriteAt(p []byte, off int64) (int, error) { + n, err := u.file.WriteAt(p, off) + if err != nil { + return n, err } - if (flags & SSH_FXF_WRITE) != 0 { - mode |= os.O_WRONLY + return n, stream.ClientUploadLimit.WaitN(u.ctx, n) +} + +func (u *uploadHandle) Close() error { + var retErr error + u.closed.Do(func() { + defer func() { + _ = os.Remove(u.file.Name()) + _ = u.file.Close() + }() + size, err := u.file.Seek(0, io.SeekEnd) + if err != nil { + retErr = err + return + } + if _, err := u.file.Seek(0, io.SeekStart); err != nil { + retErr = err + return + } + header := make([]byte, 512) + n, err := u.file.Read(header) + if err != nil && !errors.Is(err, io.EOF) { + retErr = err + return + } + if _, err := u.file.Seek(0, io.SeekStart); err != nil { + retErr = err + return + } + if u.flags.Trunc { + _ = fs.Remove(u.ctx, u.path) + } + dir, name := stdpath.Split(u.path) + file := &stream.FileStream{ + Obj: &model.Object{ + Name: name, + Size: size, + Modified: time.Now(), + Ctime: time.Now(), + }, + Mimetype: http.DetectContentType(header[:n]), + Reader: u.file, + } + retErr = fs.PutDirectly(u.ctx, dir, file, true) + }) + return retErr +} + +func (u *uploadHandle) seed() error { + reader, err := openDownload(u.ctx, u.path) + if err != nil { + if errors.Is(err, errs.ObjectNotFound) { + return nil + } + return err } - if (flags & SSH_FXF_APPEND) != 0 { - mode |= os.O_APPEND + defer reader.Close() + _, err = io.Copy(u.file, reader) + if err != nil { + return err } - if (flags & SSH_FXF_CREAT) != 0 { - mode |= os.O_CREATE + _, err = u.file.Seek(0, io.SeekStart) + return err +} + +type readWriteHandle struct { + rd io.ReaderAt +} + +func newReadWriteHandle(rd io.ReaderAt, err error) (*readWriteHandle, error) { + if err != nil { + return nil, err } - if (flags & SSH_FXF_TRUNC) != 0 { - mode |= os.O_TRUNC + return &readWriteHandle{rd: rd}, nil +} + +func (h *readWriteHandle) ReadAt(p []byte, off int64) (int, error) { + return h.rd.ReadAt(p, off) +} + +func (h *readWriteHandle) WriteAt(_ []byte, _ int64) (int, error) { + return 0, syscall.EBADF +} + +func (h *readWriteHandle) Close() error { + if closer, ok := h.rd.(io.Closer); ok { + return closer.Close() } - if (flags & SSH_FXF_EXCL) != 0 { - mode |= os.O_EXCL + return nil +} + +type osFileInfoAdapter struct { + obj model.Obj +} + +func (o *osFileInfoAdapter) Name() string { return o.obj.GetName() } +func (o *osFileInfoAdapter) Size() int64 { return o.obj.GetSize() } +func (o *osFileInfoAdapter) ModTime() time.Time { return o.obj.ModTime() } +func (o *osFileInfoAdapter) IsDir() bool { return o.obj.IsDir() } +func (o *osFileInfoAdapter) Sys() any { return o.obj } + +func (o *osFileInfoAdapter) Mode() fs2.FileMode { + var mode fs2.FileMode = 0o755 + if o.obj.IsDir() { + mode |= fs2.ModeDir } return mode } -func fileInfoToSftpAttr(stat os.FileInfo) *sftpd.Attr { - ret := &sftpd.Attr{} - ret.Flags |= sftpd.ATTR_SIZE - ret.Size = uint64(stat.Size()) - ret.Flags |= sftpd.ATTR_MODE - ret.Mode = stat.Mode() - ret.Flags |= sftpd.ATTR_TIME - ret.ATime = stat.Sys().(model.Obj).CreateTime() - ret.MTime = stat.ModTime() - return ret +type fileLister struct { + items []os.FileInfo +} + +func (l *fileLister) ListAt(dst []os.FileInfo, offset int64) (int, error) { + if offset >= int64(len(l.items)) { + return 0, io.EOF + } + n := copy(dst, l.items[offset:]) + if int(offset)+n >= len(l.items) { + return n, io.EOF + } + return n, nil +} + +func stat(ctx context.Context, filePath string) (os.FileInfo, error) { + reqPath, meta, err := resolveAccessiblePath(ctx, filePath) + if err != nil { + return nil, err + } + ctx = context.WithValue(ctx, conf.MetaKey, meta) + obj, err := fs.Get(ctx, reqPath, &fs.GetArgs{}) + if err != nil { + return nil, err + } + return &osFileInfoAdapter{obj: obj}, nil } -func fileInfoToSftpNamedAttr(stat os.FileInfo) *sftpd.NamedAttr { - return &sftpd.NamedAttr{ - Name: stat.Name(), - Attr: *fileInfoToSftpAttr(stat), +func list(ctx context.Context, filePath string) ([]os.FileInfo, error) { + reqPath, meta, err := resolveAccessiblePath(ctx, filePath) + if err != nil { + return nil, err + } + ctx = context.WithValue(ctx, conf.MetaKey, meta) + objs, err := fs.List(ctx, reqPath, &fs.ListArgs{}) + if err != nil { + return nil, err + } + ret := make([]os.FileInfo, len(objs)) + for i, obj := range objs { + ret[i] = &osFileInfoAdapter{obj: obj} + } + return ret, nil +} + +func mkdir(ctx context.Context, filePath string) error { + user := ctx.Value(conf.UserKey).(*model.User) + reqPath, err := user.JoinPath(filePath) + if err != nil { + return err + } + if !user.CanWrite() || !user.CanFTPManage() { + meta, err := op.GetNearestMeta(stdpath.Dir(reqPath)) + if err != nil && !errors.Is(errors.Cause(err), errs.MetaNotFound) { + return err + } + if !common.CanWrite(meta, reqPath) { + return errs.PermissionDenied + } + } + return fs.MakeDir(ctx, reqPath) +} + +func remove(ctx context.Context, filePath string) error { + user := ctx.Value(conf.UserKey).(*model.User) + if !user.CanRemove() || !user.CanFTPManage() { + return errs.PermissionDenied + } + reqPath, err := user.JoinPath(filePath) + if err != nil { + return err + } + return fs.Remove(ctx, reqPath) +} + +func rename(ctx context.Context, oldPath, newPath string) error { + user := ctx.Value(conf.UserKey).(*model.User) + srcPath, err := user.JoinPath(oldPath) + if err != nil { + return err + } + dstPath, err := user.JoinPath(newPath) + if err != nil { + return err + } + srcDir, srcBase := stdpath.Split(srcPath) + dstDir, dstBase := stdpath.Split(dstPath) + if srcDir == dstDir { + if !user.CanRename() || !user.CanFTPManage() { + return errs.PermissionDenied + } + return fs.Rename(ctx, srcPath, dstBase) + } + if !user.CanFTPManage() || !user.CanMove() || (srcBase != dstBase && !user.CanRename()) { + return errs.PermissionDenied + } + if srcBase != dstBase { + if err := fs.Rename(ctx, srcPath, dstBase, true); err != nil { + return err + } + } + _, err = fs.Move(ctx, stdpath.Join(srcDir, dstBase), dstDir) + return err +} + +func setstat(ctx context.Context, r *pkgsftp.Request) error { + if r.AttrFlags().Size { + // Truncation semantics are storage-driver dependent. + // Ignore the request for compatibility instead of failing the session. + return nil + } + if r.AttrFlags().Permissions || r.AttrFlags().Acmodtime || r.AttrFlags().UidGid { + return nil + } + return nil +} + +func resolveAccessiblePath(ctx context.Context, filePath string) (string, *model.Meta, error) { + user := ctx.Value(conf.UserKey).(*model.User) + reqPath, err := user.JoinPath(filePath) + if err != nil { + return "", nil, err + } + meta, err := op.GetNearestMeta(reqPath) + if err != nil && !errors.Is(errors.Cause(err), errs.MetaNotFound) { + return "", nil, err + } + if !common.CanAccess(user, meta, reqPath, ctx.Value(conf.MetaPassKey).(string)) { + return "", nil, errs.PermissionDenied + } + return reqPath, meta, nil +} + +func resolveWritablePath(ctx context.Context, filePath string) (string, error) { + user := ctx.Value(conf.UserKey).(*model.User) + reqPath, err := user.JoinPath(filePath) + if err != nil { + return "", err + } + meta, err := op.GetNearestMeta(stdpath.Dir(reqPath)) + if err != nil && !errors.Is(errors.Cause(err), errs.MetaNotFound) { + return "", err + } + if !(common.CanAccess(user, meta, reqPath, ctx.Value(conf.MetaPassKey).(string)) && + ((user.CanFTPManage() && user.CanWrite()) || common.CanWrite(meta, stdpath.Dir(reqPath)))) { + return "", errs.PermissionDenied } + return reqPath, nil } From 81f0c2d9df3f4175f09845abd5689a61b1e9da8e Mon Sep 17 00:00:00 2001 From: mkitsdts Date: Thu, 26 Mar 2026 11:15:57 +0800 Subject: [PATCH 09/10] chore(middlewares): move middlewares from server to pkg --- internal/bootstrap/run.go | 2 +- {server => pkg}/middlewares/auth.go | 0 {server => pkg}/middlewares/check.go | 0 {server => pkg}/middlewares/down.go | 0 {server => pkg}/middlewares/filtered_logger.go | 0 {server => pkg}/middlewares/fsup.go | 0 {server => pkg}/middlewares/https.go | 0 {server => pkg}/middlewares/limit.go | 0 {server => pkg}/middlewares/search.go | 0 {server => pkg}/middlewares/sharing.go | 0 plugins/webdav/server.go | 2 +- server/debug.go | 2 +- server/router.go | 2 +- 13 files changed, 4 insertions(+), 4 deletions(-) rename {server => pkg}/middlewares/auth.go (100%) rename {server => pkg}/middlewares/check.go (100%) rename {server => pkg}/middlewares/down.go (100%) rename {server => pkg}/middlewares/filtered_logger.go (100%) rename {server => pkg}/middlewares/fsup.go (100%) rename {server => pkg}/middlewares/https.go (100%) rename {server => pkg}/middlewares/limit.go (100%) rename {server => pkg}/middlewares/search.go (100%) rename {server => pkg}/middlewares/sharing.go (100%) diff --git a/internal/bootstrap/run.go b/internal/bootstrap/run.go index 1be5056fa..4ab3a3b11 100644 --- a/internal/bootstrap/run.go +++ b/internal/bootstrap/run.go @@ -17,9 +17,9 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/fs" "github.com/OpenListTeam/OpenList/v4/internal/plugin" _ "github.com/OpenListTeam/OpenList/v4/internal/plugin/all" + "github.com/OpenListTeam/OpenList/v4/pkg/middlewares" "github.com/OpenListTeam/OpenList/v4/pkg/utils" "github.com/OpenListTeam/OpenList/v4/server" - "github.com/OpenListTeam/OpenList/v4/server/middlewares" "github.com/gin-gonic/gin" "github.com/google/uuid" "github.com/pkg/errors" diff --git a/server/middlewares/auth.go b/pkg/middlewares/auth.go similarity index 100% rename from server/middlewares/auth.go rename to pkg/middlewares/auth.go diff --git a/server/middlewares/check.go b/pkg/middlewares/check.go similarity index 100% rename from server/middlewares/check.go rename to pkg/middlewares/check.go diff --git a/server/middlewares/down.go b/pkg/middlewares/down.go similarity index 100% rename from server/middlewares/down.go rename to pkg/middlewares/down.go diff --git a/server/middlewares/filtered_logger.go b/pkg/middlewares/filtered_logger.go similarity index 100% rename from server/middlewares/filtered_logger.go rename to pkg/middlewares/filtered_logger.go diff --git a/server/middlewares/fsup.go b/pkg/middlewares/fsup.go similarity index 100% rename from server/middlewares/fsup.go rename to pkg/middlewares/fsup.go diff --git a/server/middlewares/https.go b/pkg/middlewares/https.go similarity index 100% rename from server/middlewares/https.go rename to pkg/middlewares/https.go diff --git a/server/middlewares/limit.go b/pkg/middlewares/limit.go similarity index 100% rename from server/middlewares/limit.go rename to pkg/middlewares/limit.go diff --git a/server/middlewares/search.go b/pkg/middlewares/search.go similarity index 100% rename from server/middlewares/search.go rename to pkg/middlewares/search.go diff --git a/server/middlewares/sharing.go b/pkg/middlewares/sharing.go similarity index 100% rename from server/middlewares/sharing.go rename to pkg/middlewares/sharing.go diff --git a/plugins/webdav/server.go b/plugins/webdav/server.go index 8b82d1223..c105512da 100644 --- a/plugins/webdav/server.go +++ b/plugins/webdav/server.go @@ -10,8 +10,8 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/op" "github.com/OpenListTeam/OpenList/v4/internal/setting" "github.com/OpenListTeam/OpenList/v4/internal/stream" + "github.com/OpenListTeam/OpenList/v4/pkg/middlewares" "github.com/OpenListTeam/OpenList/v4/server/common" - "github.com/OpenListTeam/OpenList/v4/server/middlewares" "github.com/gin-gonic/gin" log "github.com/sirupsen/logrus" "golang.org/x/net/webdav" diff --git a/server/debug.go b/server/debug.go index 86096b0e3..5b40e3d17 100644 --- a/server/debug.go +++ b/server/debug.go @@ -7,8 +7,8 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/conf" "github.com/OpenListTeam/OpenList/v4/internal/sign" + "github.com/OpenListTeam/OpenList/v4/pkg/middlewares" "github.com/OpenListTeam/OpenList/v4/server/common" - "github.com/OpenListTeam/OpenList/v4/server/middlewares" "github.com/gin-gonic/gin" ) diff --git a/server/router.go b/server/router.go index ac0f1e5cc..e73911ac9 100644 --- a/server/router.go +++ b/server/router.go @@ -6,10 +6,10 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/message" "github.com/OpenListTeam/OpenList/v4/internal/sign" "github.com/OpenListTeam/OpenList/v4/internal/stream" + "github.com/OpenListTeam/OpenList/v4/pkg/middlewares" "github.com/OpenListTeam/OpenList/v4/pkg/utils" "github.com/OpenListTeam/OpenList/v4/server/common" "github.com/OpenListTeam/OpenList/v4/server/handles" - "github.com/OpenListTeam/OpenList/v4/server/middlewares" "github.com/OpenListTeam/OpenList/v4/server/static" "github.com/gin-contrib/cors" "github.com/gin-gonic/gin" From 206576548929bc701e7ce07c3b52d6a932ada92d Mon Sep 17 00:00:00 2001 From: mkitsdts Date: Thu, 26 Mar 2026 12:32:37 +0800 Subject: [PATCH 10/10] feat(plugin/server): change server to plugin --- cmd/user.go | 21 +- drivers/alias/driver.go | 2 +- drivers/alias/util.go | 2 +- drivers/alist_v3/driver.go | 2 +- drivers/alist_v3/util.go | 2 +- drivers/chunk/driver.go | 2 +- drivers/crypt/driver.go | 2 +- drivers/local/driver.go | 2 +- drivers/netease_music/types.go | 2 +- drivers/openlist/driver.go | 2 +- drivers/openlist/util.go | 2 +- drivers/openlist_share/driver.go | 2 +- drivers/s3/driver.go | 2 +- drivers/strm/driver.go | 2 +- drivers/strm/util.go | 2 +- internal/authn/authn.go | 2 +- internal/bootstrap/config.go | 3 - internal/bootstrap/run.go | 187 +-------- internal/conf/config.go | 91 ++--- internal/fs/archive.go | 2 +- internal/fs/copy_move.go | 2 +- internal/fs/link.go | 2 +- internal/fs/put.go | 2 +- internal/message/http.go | 2 +- internal/offline_download/tool/add.go | 2 +- internal/offline_download/tool/transfer.go | 2 +- internal/plugin/all/all.go | 1 + internal/sharing/link.go | 2 +- {server => pkg}/common/auth.go | 0 {server => pkg}/common/base.go | 0 {server => pkg}/common/check.go | 0 {server => pkg}/common/check_test.go | 0 {server => pkg}/common/common.go | 0 {server => pkg}/common/hide_privacy_test.go | 0 {server => pkg}/common/ldap.go | 0 {server => pkg}/common/proxy.go | 0 {server => pkg}/common/resp.go | 0 {server => pkg}/common/sign.go | 0 pkg/middlewares/auth.go | 2 +- pkg/middlewares/check.go | 2 +- pkg/middlewares/down.go | 2 +- pkg/middlewares/fsup.go | 2 +- pkg/middlewares/https.go | 20 +- pkg/middlewares/search.go | 2 +- pkg/middlewares/sharing.go | 2 +- plugins/ftp/fsmanage.go | 2 +- plugins/ftp/fsread.go | 2 +- plugins/ftp/fsup.go | 2 +- plugins/ftp/runtime.go | 2 +- plugins/ftp/server.go | 1 - plugins/ftp/utils.go | 2 +- plugins/s3/config.go | 7 +- plugins/s3/plugin.go | 41 +- {server => plugins/server}/debug.go | 2 +- {server => plugins/server}/handles/archive.go | 2 +- {server => plugins/server}/handles/auth.go | 2 +- {server => plugins/server}/handles/const.go | 0 .../server}/handles/direct_upload.go | 2 +- {server => plugins/server}/handles/down.go | 2 +- {server => plugins/server}/handles/driver.go | 2 +- {server => plugins/server}/handles/fsbatch.go | 2 +- .../server}/handles/fsmanage.go | 2 +- {server => plugins/server}/handles/fsread.go | 2 +- {server => plugins/server}/handles/fsup.go | 2 +- {server => plugins/server}/handles/helper.go | 2 +- {server => plugins/server}/handles/index.go | 2 +- .../server}/handles/ldap_login.go | 2 +- {server => plugins/server}/handles/meta.go | 2 +- .../server}/handles/offline_download.go | 2 +- {server => plugins/server}/handles/scan.go | 2 +- {server => plugins/server}/handles/search.go | 2 +- {server => plugins/server}/handles/setting.go | 4 +- {server => plugins/server}/handles/sharing.go | 2 +- {server => plugins/server}/handles/sshkey.go | 2 +- .../server}/handles/ssologin.go | 2 +- {server => plugins/server}/handles/storage.go | 2 +- {server => plugins/server}/handles/task.go | 2 +- {server => plugins/server}/handles/user.go | 2 +- .../server}/handles/webauthn.go | 2 +- plugins/server/plugin.go | 369 ++++++++++++++++++ {server => plugins/server}/router.go | 104 +---- {server => plugins/server}/static/config.go | 0 {server => plugins/server}/static/static.go | 0 plugins/sftp/runtime.go | 4 +- plugins/sftp/sftp.go | 4 +- plugins/sftp/utils.go | 2 +- plugins/webdav/plugin.go | 33 +- plugins/webdav/prop.go | 2 +- plugins/webdav/server.go | 2 +- plugins/webdav/utils.go | 2 +- plugins/webdav/webdav.go | 2 +- 91 files changed, 575 insertions(+), 441 deletions(-) rename {server => pkg}/common/auth.go (100%) rename {server => pkg}/common/base.go (100%) rename {server => pkg}/common/check.go (100%) rename {server => pkg}/common/check_test.go (100%) rename {server => pkg}/common/common.go (100%) rename {server => pkg}/common/hide_privacy_test.go (100%) rename {server => pkg}/common/ldap.go (100%) rename {server => pkg}/common/proxy.go (100%) rename {server => pkg}/common/resp.go (100%) rename {server => pkg}/common/sign.go (100%) delete mode 100644 plugins/ftp/server.go rename {server => plugins/server}/debug.go (93%) rename {server => plugins/server}/handles/archive.go (99%) rename {server => plugins/server}/handles/auth.go (98%) rename {server => plugins/server}/handles/const.go (100%) rename {server => plugins/server}/handles/direct_upload.go (96%) rename {server => plugins/server}/handles/down.go (98%) rename {server => plugins/server}/handles/driver.go (91%) rename {server => plugins/server}/handles/fsbatch.go (99%) rename {server => plugins/server}/handles/fsmanage.go (99%) rename {server => plugins/server}/handles/fsread.go (99%) rename {server => plugins/server}/handles/fsup.go (99%) rename {server => plugins/server}/handles/helper.go (98%) rename {server => plugins/server}/handles/index.go (97%) rename {server => plugins/server}/handles/ldap_login.go (96%) rename {server => plugins/server}/handles/meta.go (97%) rename {server => plugins/server}/handles/offline_download.go (99%) rename {server => plugins/server}/handles/scan.go (94%) rename {server => plugins/server}/handles/search.go (97%) rename {server => plugins/server}/handles/setting.go (96%) rename {server => plugins/server}/handles/sharing.go (99%) rename {server => plugins/server}/handles/sshkey.go (98%) rename {server => plugins/server}/handles/ssologin.go (99%) rename {server => plugins/server}/handles/storage.go (98%) rename {server => plugins/server}/handles/task.go (99%) rename {server => plugins/server}/handles/user.go (98%) rename {server => plugins/server}/handles/webauthn.go (99%) create mode 100644 plugins/server/plugin.go rename {server => plugins/server}/router.go (51%) rename {server => plugins/server}/static/config.go (100%) rename {server => plugins/server}/static/static.go (100%) diff --git a/cmd/user.go b/cmd/user.go index 948dd902f..8aa91b53f 100644 --- a/cmd/user.go +++ b/cmd/user.go @@ -7,6 +7,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/conf" "github.com/OpenListTeam/OpenList/v4/internal/op" + iplugin "github.com/OpenListTeam/OpenList/v4/internal/plugin" "github.com/OpenListTeam/OpenList/v4/internal/setting" "github.com/OpenListTeam/OpenList/v4/pkg/utils" "github.com/go-resty/resty/v2" @@ -24,14 +25,28 @@ func DelAdminCacheOnline() { func DelUserCacheOnline(username string) { client := resty.New().SetTimeout(1 * time.Second).SetTLSClientConfig(&tls.Config{InsecureSkipVerify: conf.Conf.TlsInsecureSkipVerify}) token := setting.GetStr(conf.Token) - port := conf.Conf.Scheme.HttpPort + serverPlugin := conf.Conf.Plugin("server") + if serverPlugin == nil { + utils.Log.Warnf("[del_user_cache] server plugin config missing") + return + } + port, err := iplugin.IntValue(serverPlugin.Data, "http_port", -1) + if err != nil { + utils.Log.Warnf("[del_user_cache] parse server http_port failed: %+v", err) + return + } u := fmt.Sprintf("http://localhost:%d/api/admin/user/del_cache", port) if port == -1 { - if conf.Conf.Scheme.HttpsPort == -1 { + httpsPort, err := iplugin.IntValue(serverPlugin.Data, "https_port", -1) + if err != nil { + utils.Log.Warnf("[del_user_cache] parse server https_port failed: %+v", err) + return + } + if httpsPort == -1 { utils.Log.Warnf("[del_user_cache] no open port") return } - u = fmt.Sprintf("https://localhost:%d/api/admin/user/del_cache", conf.Conf.Scheme.HttpsPort) + u = fmt.Sprintf("https://localhost:%d/api/admin/user/del_cache", httpsPort) } res, err := client.R().SetHeader("Authorization", token).SetQueryParam("username", username).Post(u) if err != nil { diff --git a/drivers/alias/driver.go b/drivers/alias/driver.go index e1ba41eb6..655677d3b 100644 --- a/drivers/alias/driver.go +++ b/drivers/alias/driver.go @@ -19,7 +19,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/stream" "github.com/OpenListTeam/OpenList/v4/pkg/http_range" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" ) type Alias struct { diff --git a/drivers/alias/util.go b/drivers/alias/util.go index 8e5eb8a84..4923bba34 100644 --- a/drivers/alias/util.go +++ b/drivers/alias/util.go @@ -12,7 +12,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/fs" "github.com/OpenListTeam/OpenList/v4/internal/model" "github.com/OpenListTeam/OpenList/v4/internal/op" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/pkg/errors" log "github.com/sirupsen/logrus" ) diff --git a/drivers/alist_v3/driver.go b/drivers/alist_v3/driver.go index a9fc44fcb..796ede5f5 100644 --- a/drivers/alist_v3/driver.go +++ b/drivers/alist_v3/driver.go @@ -15,7 +15,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/errs" "github.com/OpenListTeam/OpenList/v4/internal/model" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/go-resty/resty/v2" log "github.com/sirupsen/logrus" ) diff --git a/drivers/alist_v3/util.go b/drivers/alist_v3/util.go index 821fe5465..c122d5134 100644 --- a/drivers/alist_v3/util.go +++ b/drivers/alist_v3/util.go @@ -6,8 +6,8 @@ import ( "github.com/OpenListTeam/OpenList/v4/drivers/base" "github.com/OpenListTeam/OpenList/v4/internal/op" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server/common" "github.com/go-resty/resty/v2" log "github.com/sirupsen/logrus" ) diff --git a/drivers/chunk/driver.go b/drivers/chunk/driver.go index b544391dd..063fdbbea 100644 --- a/drivers/chunk/driver.go +++ b/drivers/chunk/driver.go @@ -21,7 +21,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/pkg/errgroup" "github.com/OpenListTeam/OpenList/v4/pkg/http_range" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/avast/retry-go" ) diff --git a/drivers/crypt/driver.go b/drivers/crypt/driver.go index 9e8b5c5c7..22489c8c2 100644 --- a/drivers/crypt/driver.go +++ b/drivers/crypt/driver.go @@ -18,9 +18,9 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/op" "github.com/OpenListTeam/OpenList/v4/internal/sign" "github.com/OpenListTeam/OpenList/v4/internal/stream" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/OpenListTeam/OpenList/v4/pkg/http_range" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server/common" rcCrypt "github.com/rclone/rclone/backend/crypt" "github.com/rclone/rclone/fs/config/configmap" "github.com/rclone/rclone/fs/config/obscure" diff --git a/drivers/local/driver.go b/drivers/local/driver.go index 7189648a7..bf993ebb9 100644 --- a/drivers/local/driver.go +++ b/drivers/local/driver.go @@ -21,7 +21,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/sign" "github.com/OpenListTeam/OpenList/v4/internal/stream" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/OpenListTeam/times" log "github.com/sirupsen/logrus" _ "golang.org/x/image/webp" diff --git a/drivers/netease_music/types.go b/drivers/netease_music/types.go index c3898c2f9..a235c722e 100644 --- a/drivers/netease_music/types.go +++ b/drivers/netease_music/types.go @@ -13,7 +13,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/stream" "github.com/OpenListTeam/OpenList/v4/pkg/utils" "github.com/OpenListTeam/OpenList/v4/pkg/utils/random" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" ) type HostsResp struct { diff --git a/drivers/openlist/driver.go b/drivers/openlist/driver.go index 2ca60ff61..f54d15b93 100644 --- a/drivers/openlist/driver.go +++ b/drivers/openlist/driver.go @@ -15,7 +15,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/errs" "github.com/OpenListTeam/OpenList/v4/internal/model" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/go-resty/resty/v2" log "github.com/sirupsen/logrus" ) diff --git a/drivers/openlist/util.go b/drivers/openlist/util.go index 743ba266b..80bab0941 100644 --- a/drivers/openlist/util.go +++ b/drivers/openlist/util.go @@ -6,8 +6,8 @@ import ( "github.com/OpenListTeam/OpenList/v4/drivers/base" "github.com/OpenListTeam/OpenList/v4/internal/op" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server/common" "github.com/go-resty/resty/v2" log "github.com/sirupsen/logrus" ) diff --git a/drivers/openlist_share/driver.go b/drivers/openlist_share/driver.go index 0b99edd07..2067a2be5 100644 --- a/drivers/openlist_share/driver.go +++ b/drivers/openlist_share/driver.go @@ -12,7 +12,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/errs" "github.com/OpenListTeam/OpenList/v4/internal/model" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/go-resty/resty/v2" ) diff --git a/drivers/s3/driver.go b/drivers/s3/driver.go index a9edef10b..6aea2b52c 100644 --- a/drivers/s3/driver.go +++ b/drivers/s3/driver.go @@ -15,7 +15,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/stream" "github.com/OpenListTeam/OpenList/v4/pkg/cron" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/s3" "github.com/aws/aws-sdk-go/service/s3/s3manager" diff --git a/drivers/strm/driver.go b/drivers/strm/driver.go index 422f0e1b1..af246fb77 100644 --- a/drivers/strm/driver.go +++ b/drivers/strm/driver.go @@ -14,7 +14,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/sign" "github.com/OpenListTeam/OpenList/v4/internal/stream" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" log "github.com/sirupsen/logrus" ) diff --git a/drivers/strm/util.go b/drivers/strm/util.go index b9a40da5e..631675501 100644 --- a/drivers/strm/util.go +++ b/drivers/strm/util.go @@ -10,8 +10,8 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/model" "github.com/OpenListTeam/OpenList/v4/internal/op" "github.com/OpenListTeam/OpenList/v4/internal/sign" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server/common" ) func (d *Strm) listRoot() []model.Obj { diff --git a/internal/authn/authn.go b/internal/authn/authn.go index a57823d15..8aa1cf014 100644 --- a/internal/authn/authn.go +++ b/internal/authn/authn.go @@ -6,7 +6,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/conf" "github.com/OpenListTeam/OpenList/v4/internal/setting" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/gin-gonic/gin" "github.com/go-webauthn/webauthn/webauthn" ) diff --git a/internal/bootstrap/config.go b/internal/bootstrap/config.go index 74e218f8f..0a7a5ae47 100644 --- a/internal/bootstrap/config.go +++ b/internal/bootstrap/config.go @@ -128,9 +128,6 @@ func InitConfig() { } } convertAbsPath(&conf.Conf.Database.DBFile) - convertAbsPath(&conf.Conf.Scheme.CertFile) - convertAbsPath(&conf.Conf.Scheme.KeyFile) - convertAbsPath(&conf.Conf.Scheme.UnixFile) convertAbsPath(&conf.Conf.Log.Name) convertAbsPath(&conf.Conf.TempDir) convertAbsPath(&conf.Conf.BleveDir) diff --git a/internal/bootstrap/run.go b/internal/bootstrap/run.go index 4ab3a3b11..9fb712ba2 100644 --- a/internal/bootstrap/run.go +++ b/internal/bootstrap/run.go @@ -1,32 +1,17 @@ package bootstrap import ( - "context" - "fmt" - "net" - "net/http" - "os" - "strconv" "sync" "time" - "github.com/OpenListTeam/OpenList/v4/cmd/flags" "github.com/OpenListTeam/OpenList/v4/internal/bootstrap/data" "github.com/OpenListTeam/OpenList/v4/internal/conf" "github.com/OpenListTeam/OpenList/v4/internal/db" "github.com/OpenListTeam/OpenList/v4/internal/fs" "github.com/OpenListTeam/OpenList/v4/internal/plugin" _ "github.com/OpenListTeam/OpenList/v4/internal/plugin/all" - "github.com/OpenListTeam/OpenList/v4/pkg/middlewares" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server" - "github.com/gin-gonic/gin" "github.com/google/uuid" - "github.com/pkg/errors" - "github.com/quic-go/quic-go/http3" - log "github.com/sirupsen/logrus" - "golang.org/x/net/http2" - "golang.org/x/net/http2/h2c" ) func Init() { @@ -44,31 +29,12 @@ func Release() { } var ( - running bool - httpSrv *http.Server - httpRunning bool - httpsSrv *http.Server - httpsRunning bool - unixSrv *http.Server - unixRunning bool - quicSrv *http3.Server - quicRunning bool + running bool ) // Called by OpenList-Mobile func IsRunning(t string) bool { - switch t { - case "http": - return httpRunning - case "https": - return httpsRunning - case "unix": - return unixRunning - case "quic": - return quicRunning - default: - return plugin.IsRunning(t) - } + return plugin.IsRunning(t) } func Start() { @@ -79,112 +45,6 @@ func Start() { InitOfflineDownloadTools() LoadStorages() InitTaskManager() - if !flags.Debug && !flags.Dev { - gin.SetMode(gin.ReleaseMode) - } - r := gin.New() - - // gin log - if conf.Conf.Log.Filter.Enable { - r.Use(middlewares.FilteredLogger()) - } else { - r.Use(gin.LoggerWithWriter(log.StandardLogger().Out)) - } - r.Use(gin.RecoveryWithWriter(log.StandardLogger().Out)) - - server.Init(r) - var httpHandler http.Handler = r - if conf.Conf.Scheme.EnableH2c { - httpHandler = h2c.NewHandler(r, &http2.Server{}) - } - if conf.Conf.Scheme.HttpPort != -1 { - httpBase := fmt.Sprintf("%s:%d", conf.Conf.Scheme.Address, conf.Conf.Scheme.HttpPort) - fmt.Printf("start HTTP server @ %s\n", httpBase) - utils.Log.Infof("start HTTP server @ %s", httpBase) - httpSrv = &http.Server{Addr: httpBase, Handler: httpHandler} - go func() { - httpRunning = true - err := httpSrv.ListenAndServe() - httpRunning = false - if err != nil && !errors.Is(err, http.ErrServerClosed) { - handleEndpointStartFailedHooks("http", err) - utils.Log.Errorf("failed to start http: %s", err.Error()) - } else { - handleEndpointShutdownHooks("http") - } - }() - } - if conf.Conf.Scheme.HttpsPort != -1 { - httpsBase := fmt.Sprintf("%s:%d", conf.Conf.Scheme.Address, conf.Conf.Scheme.HttpsPort) - fmt.Printf("start HTTPS server @ %s\n", httpsBase) - utils.Log.Infof("start HTTPS server @ %s", httpsBase) - httpsSrv = &http.Server{Addr: httpsBase, Handler: r} - go func() { - httpsRunning = true - err := httpsSrv.ListenAndServeTLS(conf.Conf.Scheme.CertFile, conf.Conf.Scheme.KeyFile) - httpsRunning = false - if err != nil && !errors.Is(err, http.ErrServerClosed) { - handleEndpointStartFailedHooks("https", err) - utils.Log.Errorf("failed to start https: %s", err.Error()) - } else { - handleEndpointShutdownHooks("https") - } - }() - if conf.Conf.Scheme.EnableH3 { - fmt.Printf("start HTTP3 (quic) server @ %s\n", httpsBase) - utils.Log.Infof("start HTTP3 (quic) server @ %s", httpsBase) - r.Use(func(c *gin.Context) { - if c.Request.TLS != nil { - port := conf.Conf.Scheme.HttpsPort - c.Header("Alt-Svc", fmt.Sprintf("h3=\":%d\"; ma=86400", port)) - } - c.Next() - }) - quicSrv = &http3.Server{Addr: httpsBase, Handler: r} - go func() { - quicRunning = true - err := quicSrv.ListenAndServeTLS(conf.Conf.Scheme.CertFile, conf.Conf.Scheme.KeyFile) - quicRunning = false - if err != nil && !errors.Is(err, http.ErrServerClosed) { - handleEndpointStartFailedHooks("quic", err) - utils.Log.Errorf("failed to start http3 (quic): %s", err.Error()) - } else { - handleEndpointShutdownHooks("quic") - } - }() - } - } - if conf.Conf.Scheme.UnixFile != "" { - fmt.Printf("start unix server @ %s\n", conf.Conf.Scheme.UnixFile) - utils.Log.Infof("start unix server @ %s", conf.Conf.Scheme.UnixFile) - unixSrv = &http.Server{Handler: httpHandler} - go func() { - listener, err := net.Listen("unix", conf.Conf.Scheme.UnixFile) - if err != nil { - utils.Log.Errorf("failed to listen unix: %+v", err) - return - } - unixRunning = true - // set socket file permission - mode, err := strconv.ParseUint(conf.Conf.Scheme.UnixFilePerm, 8, 32) - if err != nil { - utils.Log.Errorf("failed to parse socket file permission: %+v", err) - } else { - err = os.Chmod(conf.Conf.Scheme.UnixFile, os.FileMode(mode)) - if err != nil { - utils.Log.Errorf("failed to chmod socket file: %+v", err) - } - } - err = unixSrv.Serve(listener) - unixRunning = false - if err != nil && !errors.Is(err, http.ErrServerClosed) { - handleEndpointStartFailedHooks("unix", err) - utils.Log.Errorf("failed to start unix: %s", err.Error()) - } else { - handleEndpointShutdownHooks("unix") - } - }() - } plugin.StartAll() running = true } @@ -192,49 +52,8 @@ func Start() { func Shutdown(timeout time.Duration) { utils.Log.Println("Shutdown server...") fs.ArchiveContentUploadTaskManager.RemoveAll() - ctx, cancel := context.WithTimeout(context.Background(), timeout) - defer cancel() + _ = timeout var wg sync.WaitGroup - if httpSrv != nil && conf.Conf.Scheme.HttpPort != -1 { - wg.Add(1) - go func() { - defer wg.Done() - if err := httpSrv.Shutdown(ctx); err != nil { - utils.Log.Error("HTTP server shutdown err: ", err) - } - httpSrv = nil - }() - } - if httpsSrv != nil && conf.Conf.Scheme.HttpsPort != -1 { - wg.Add(1) - go func() { - defer wg.Done() - if err := httpsSrv.Shutdown(ctx); err != nil { - utils.Log.Error("HTTPS server shutdown err: ", err) - } - httpsSrv = nil - }() - if quicSrv != nil && conf.Conf.Scheme.EnableH3 { - wg.Add(1) - go func() { - defer wg.Done() - if err := quicSrv.Shutdown(ctx); err != nil { - utils.Log.Error("HTTP3 (quic) server shutdown err: ", err) - } - quicSrv = nil - }() - } - } - if unixSrv != nil && conf.Conf.Scheme.UnixFile != "" { - wg.Add(1) - go func() { - defer wg.Done() - if err := unixSrv.Shutdown(ctx); err != nil { - utils.Log.Error("Unix server shutdown err: ", err) - } - unixSrv = nil - }() - } wg.Add(1) go func() { defer wg.Done() diff --git a/internal/conf/config.go b/internal/conf/config.go index dd40384f3..61f4ca0df 100644 --- a/internal/conf/config.go +++ b/internal/conf/config.go @@ -26,19 +26,6 @@ type Meilisearch struct { Index string `json:"index" env:"INDEX"` } -type Scheme struct { - Address string `json:"address" env:"ADDR"` - HttpPort int `json:"http_port" env:"HTTP_PORT"` - HttpsPort int `json:"https_port" env:"HTTPS_PORT"` - ForceHttps bool `json:"force_https" env:"FORCE_HTTPS"` - CertFile string `json:"cert_file" env:"CERT_FILE"` - KeyFile string `json:"key_file" env:"KEY_FILE"` - UnixFile string `json:"unix_file" env:"UNIX_FILE"` - UnixFilePerm string `json:"unix_file_perm" env:"UNIX_FILE_PERM"` - EnableH2c bool `json:"enable_h2c" env:"ENABLE_H2C"` - EnableH3 bool `json:"enable_h3" env:"ENABLE_H3"` -} - type LogConfig struct { Enable bool `json:"enable" env:"ENABLE"` Name string `json:"name" env:"NAME"` @@ -84,10 +71,9 @@ type Cors struct { } type PluginConfig struct { - Name string `json:"name"` - Enable bool `json:"enable"` - Enabled *bool `json:"enabled,omitempty"` - Data map[string]any `json:"data"` + Name string `json:"name"` + Enable bool `json:"enable"` + Data map[string]any `json:"data"` } type Config struct { @@ -98,7 +84,6 @@ type Config struct { TokenExpiresIn int `json:"token_expires_in" env:"TOKEN_EXPIRES_IN"` Database Database `json:"database" envPrefix:"DB_"` Meilisearch Meilisearch `json:"meilisearch" envPrefix:"MEILISEARCH_"` - Scheme Scheme `json:"scheme"` TempDir string `json:"temp_dir" env:"TEMP_DIR"` BleveDir string `json:"bleve_dir" env:"BLEVE_DIR"` DistDir string `json:"dist_dir"` @@ -122,15 +107,6 @@ func DefaultConfig(dataDir string) *Config { logPath := filepath.Join(dataDir, "log/log.log") dbPath := filepath.Join(dataDir, "data.db") return &Config{ - Scheme: Scheme{ - Address: "0.0.0.0", - UnixFile: "", - HttpPort: 5244, - HttpsPort: -1, - ForceHttps: false, - CertFile: "", - KeyFile: "", - }, JwtSecret: random.String(16), TokenExpiresIn: 48, TempDir: tempDir, @@ -206,27 +182,45 @@ func DefaultConfig(dataDir string) *Config { AllowHeaders: []string{"*"}, }, Plugins: []PluginConfig{ + { + Name: "server", + Enable: true, + Data: map[string]any{ + "address": "0.0.0.0", + "http_port": 5244, + "https_port": -1, + "force_https": false, + "cert_file": "", + "key_file": "", + "unix_file": "", + "unix_file_perm": "", + "enable_h2c": false, + "enable_h3": false, + }, + }, { Name: "webdav", Enable: false, Data: map[string]any{ - "enabled": true, + "listen": ":5288", + "ssl": false, }, }, { Name: "s3", Enable: false, Data: map[string]any{ - "enabled": false, - "port": 5246, - "ssl": false, + "address": "0.0.0.0", + "port": 5246, + "ssl": false, + "cert_file": "", + "key_file": "", }, }, { Name: "ftp", Enable: false, Data: map[string]any{ - "enabled": false, "listen": ":5221", "find_pasv_port_attempts": 50, "active_transfer_port_non_20": false, @@ -242,8 +236,7 @@ func DefaultConfig(dataDir string) *Config { Name: "sftp", Enable: false, Data: map[string]any{ - "enabled": false, - "listen": ":5222", + "listen": ":5222", }, }, }, @@ -254,25 +247,21 @@ func DefaultConfig(dataDir string) *Config { func (c *Config) UnmarshalJSON(data []byte) error { type configAlias Config - aux := struct { - *configAlias - Plugins *[]PluginConfig `json:"plugins"` - }{ - configAlias: (*configAlias)(c), - } - if err := json.Unmarshal(data, &aux); err != nil { + if err := json.Unmarshal(data, (*configAlias)(c)); err != nil { return err } - if aux.Plugins != nil { - c.Plugins = *aux.Plugins - for i := range c.Plugins { - if c.Plugins[i].Enabled != nil { - c.Plugins[i].Enable = *c.Plugins[i].Enabled - c.Plugins[i].Enabled = nil - } - if c.Plugins[i].Data == nil { - c.Plugins[i].Data = map[string]any{} - } + for i := range c.Plugins { + if c.Plugins[i].Data == nil { + c.Plugins[i].Data = map[string]any{} + } + } + return nil +} + +func (c *Config) Plugin(name string) *PluginConfig { + for i := range c.Plugins { + if c.Plugins[i].Name == name { + return &c.Plugins[i] } } return nil diff --git a/internal/fs/archive.go b/internal/fs/archive.go index 784ba587a..7e9e022f7 100644 --- a/internal/fs/archive.go +++ b/internal/fs/archive.go @@ -21,7 +21,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/task" "github.com/OpenListTeam/OpenList/v4/internal/task_group" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/OpenListTeam/tache" "github.com/pkg/errors" log "github.com/sirupsen/logrus" diff --git a/internal/fs/copy_move.go b/internal/fs/copy_move.go index e78fc9be8..5d2923195 100644 --- a/internal/fs/copy_move.go +++ b/internal/fs/copy_move.go @@ -13,8 +13,8 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/stream" "github.com/OpenListTeam/OpenList/v4/internal/task" "github.com/OpenListTeam/OpenList/v4/internal/task_group" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server/common" "github.com/OpenListTeam/tache" "github.com/pkg/errors" ) diff --git a/internal/fs/link.go b/internal/fs/link.go index d84090cfc..d75e7641f 100644 --- a/internal/fs/link.go +++ b/internal/fs/link.go @@ -6,7 +6,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/model" "github.com/OpenListTeam/OpenList/v4/internal/op" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/pkg/errors" ) diff --git a/internal/fs/put.go b/internal/fs/put.go index be829ae47..aa1bd2699 100644 --- a/internal/fs/put.go +++ b/internal/fs/put.go @@ -6,8 +6,8 @@ import ( stdpath "path" "time" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server/common" "github.com/OpenListTeam/OpenList/v4/internal/conf" "github.com/OpenListTeam/OpenList/v4/internal/driver" diff --git a/internal/message/http.go b/internal/message/http.go index 3e3f8e9a3..b13c86d47 100644 --- a/internal/message/http.go +++ b/internal/message/http.go @@ -3,7 +3,7 @@ package message import ( "time" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/gin-gonic/gin" "github.com/pkg/errors" ) diff --git a/internal/offline_download/tool/add.go b/internal/offline_download/tool/add.go index 0f574571e..5f359fe42 100644 --- a/internal/offline_download/tool/add.go +++ b/internal/offline_download/tool/add.go @@ -21,7 +21,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/op" "github.com/OpenListTeam/OpenList/v4/internal/setting" "github.com/OpenListTeam/OpenList/v4/internal/task" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/google/uuid" "github.com/pkg/errors" ) diff --git a/internal/offline_download/tool/transfer.go b/internal/offline_download/tool/transfer.go index fd6b8f464..8c10972e1 100644 --- a/internal/offline_download/tool/transfer.go +++ b/internal/offline_download/tool/transfer.go @@ -16,9 +16,9 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/stream" "github.com/OpenListTeam/OpenList/v4/internal/task" "github.com/OpenListTeam/OpenList/v4/internal/task_group" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/OpenListTeam/OpenList/v4/pkg/http_range" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server/common" "github.com/OpenListTeam/tache" "github.com/pkg/errors" log "github.com/sirupsen/logrus" diff --git a/internal/plugin/all/all.go b/internal/plugin/all/all.go index 4fc245c13..78417a379 100644 --- a/internal/plugin/all/all.go +++ b/internal/plugin/all/all.go @@ -3,6 +3,7 @@ package all import ( _ "github.com/OpenListTeam/OpenList/v4/plugins/ftp" _ "github.com/OpenListTeam/OpenList/v4/plugins/s3" + _ "github.com/OpenListTeam/OpenList/v4/plugins/server" _ "github.com/OpenListTeam/OpenList/v4/plugins/sftp" _ "github.com/OpenListTeam/OpenList/v4/plugins/webdav" ) diff --git a/internal/sharing/link.go b/internal/sharing/link.go index 32ae6b836..f0c84c3f9 100644 --- a/internal/sharing/link.go +++ b/internal/sharing/link.go @@ -8,7 +8,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/model" "github.com/OpenListTeam/OpenList/v4/internal/op" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/pkg/errors" ) diff --git a/server/common/auth.go b/pkg/common/auth.go similarity index 100% rename from server/common/auth.go rename to pkg/common/auth.go diff --git a/server/common/base.go b/pkg/common/base.go similarity index 100% rename from server/common/base.go rename to pkg/common/base.go diff --git a/server/common/check.go b/pkg/common/check.go similarity index 100% rename from server/common/check.go rename to pkg/common/check.go diff --git a/server/common/check_test.go b/pkg/common/check_test.go similarity index 100% rename from server/common/check_test.go rename to pkg/common/check_test.go diff --git a/server/common/common.go b/pkg/common/common.go similarity index 100% rename from server/common/common.go rename to pkg/common/common.go diff --git a/server/common/hide_privacy_test.go b/pkg/common/hide_privacy_test.go similarity index 100% rename from server/common/hide_privacy_test.go rename to pkg/common/hide_privacy_test.go diff --git a/server/common/ldap.go b/pkg/common/ldap.go similarity index 100% rename from server/common/ldap.go rename to pkg/common/ldap.go diff --git a/server/common/proxy.go b/pkg/common/proxy.go similarity index 100% rename from server/common/proxy.go rename to pkg/common/proxy.go diff --git a/server/common/resp.go b/pkg/common/resp.go similarity index 100% rename from server/common/resp.go rename to pkg/common/resp.go diff --git a/server/common/sign.go b/pkg/common/sign.go similarity index 100% rename from server/common/sign.go rename to pkg/common/sign.go diff --git a/pkg/middlewares/auth.go b/pkg/middlewares/auth.go index 0fc243617..c097a9479 100644 --- a/pkg/middlewares/auth.go +++ b/pkg/middlewares/auth.go @@ -7,7 +7,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/model" "github.com/OpenListTeam/OpenList/v4/internal/op" "github.com/OpenListTeam/OpenList/v4/internal/setting" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/gin-gonic/gin" log "github.com/sirupsen/logrus" ) diff --git a/pkg/middlewares/check.go b/pkg/middlewares/check.go index c7203a490..b6add993e 100644 --- a/pkg/middlewares/check.go +++ b/pkg/middlewares/check.go @@ -4,8 +4,8 @@ import ( "strings" "github.com/OpenListTeam/OpenList/v4/internal/conf" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server/common" "github.com/gin-gonic/gin" ) diff --git a/pkg/middlewares/down.go b/pkg/middlewares/down.go index cb87eb3c3..8def87361 100644 --- a/pkg/middlewares/down.go +++ b/pkg/middlewares/down.go @@ -9,8 +9,8 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/errs" "github.com/OpenListTeam/OpenList/v4/internal/model" "github.com/OpenListTeam/OpenList/v4/internal/op" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server/common" "github.com/gin-gonic/gin" "github.com/pkg/errors" ) diff --git a/pkg/middlewares/fsup.go b/pkg/middlewares/fsup.go index 08b160ee5..8a4937157 100644 --- a/pkg/middlewares/fsup.go +++ b/pkg/middlewares/fsup.go @@ -8,7 +8,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/errs" "github.com/OpenListTeam/OpenList/v4/internal/model" "github.com/OpenListTeam/OpenList/v4/internal/op" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/gin-gonic/gin" "github.com/pkg/errors" ) diff --git a/pkg/middlewares/https.go b/pkg/middlewares/https.go index a78bb322f..8057eecf4 100644 --- a/pkg/middlewares/https.go +++ b/pkg/middlewares/https.go @@ -4,18 +4,18 @@ import ( "fmt" "strings" - "github.com/OpenListTeam/OpenList/v4/internal/conf" "github.com/gin-gonic/gin" ) -func ForceHttps(c *gin.Context) { - if c.Request.TLS == nil { - host := c.Request.Host - // change port to https port - host = strings.Replace(host, fmt.Sprintf(":%d", conf.Conf.Scheme.HttpPort), fmt.Sprintf(":%d", conf.Conf.Scheme.HttpsPort), 1) - c.Redirect(302, "https://"+host+c.Request.RequestURI) - c.Abort() - return +func ForceHttps(httpPort, httpsPort int) gin.HandlerFunc { + return func(c *gin.Context) { + if c.Request.TLS == nil { + host := c.Request.Host + host = strings.Replace(host, fmt.Sprintf(":%d", httpPort), fmt.Sprintf(":%d", httpsPort), 1) + c.Redirect(302, "https://"+host+c.Request.RequestURI) + c.Abort() + return + } + c.Next() } - c.Next() } diff --git a/pkg/middlewares/search.go b/pkg/middlewares/search.go index dc89a08ad..85167aae5 100644 --- a/pkg/middlewares/search.go +++ b/pkg/middlewares/search.go @@ -4,7 +4,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/conf" "github.com/OpenListTeam/OpenList/v4/internal/errs" "github.com/OpenListTeam/OpenList/v4/internal/setting" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/gin-gonic/gin" ) diff --git a/pkg/middlewares/sharing.go b/pkg/middlewares/sharing.go index d7549202f..b7c299574 100644 --- a/pkg/middlewares/sharing.go +++ b/pkg/middlewares/sharing.go @@ -2,7 +2,7 @@ package middlewares import ( "github.com/OpenListTeam/OpenList/v4/internal/conf" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/gin-gonic/gin" ) diff --git a/plugins/ftp/fsmanage.go b/plugins/ftp/fsmanage.go index 48f72794e..1b0da01b7 100644 --- a/plugins/ftp/fsmanage.go +++ b/plugins/ftp/fsmanage.go @@ -9,7 +9,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/fs" "github.com/OpenListTeam/OpenList/v4/internal/model" "github.com/OpenListTeam/OpenList/v4/internal/op" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/pkg/errors" ) diff --git a/plugins/ftp/fsread.go b/plugins/ftp/fsread.go index 9080bae17..0bc985c1e 100644 --- a/plugins/ftp/fsread.go +++ b/plugins/ftp/fsread.go @@ -14,7 +14,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/model" "github.com/OpenListTeam/OpenList/v4/internal/op" "github.com/OpenListTeam/OpenList/v4/internal/stream" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/pkg/errors" ) diff --git a/plugins/ftp/fsup.go b/plugins/ftp/fsup.go index c549a1943..db9aa861f 100644 --- a/plugins/ftp/fsup.go +++ b/plugins/ftp/fsup.go @@ -17,8 +17,8 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/op" "github.com/OpenListTeam/OpenList/v4/internal/setting" "github.com/OpenListTeam/OpenList/v4/internal/stream" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server/common" ftpserver "github.com/fclairamb/ftpserverlib" "github.com/pkg/errors" ) diff --git a/plugins/ftp/runtime.go b/plugins/ftp/runtime.go index d00d2adb8..c5c578f7c 100644 --- a/plugins/ftp/runtime.go +++ b/plugins/ftp/runtime.go @@ -18,8 +18,8 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/model" "github.com/OpenListTeam/OpenList/v4/internal/op" "github.com/OpenListTeam/OpenList/v4/internal/setting" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server/common" ftpserver "github.com/fclairamb/ftpserverlib" ) diff --git a/plugins/ftp/server.go b/plugins/ftp/server.go deleted file mode 100644 index 4c9820334..000000000 --- a/plugins/ftp/server.go +++ /dev/null @@ -1 +0,0 @@ -package ftp diff --git a/plugins/ftp/utils.go b/plugins/ftp/utils.go index 421fd520f..7bb0af66f 100644 --- a/plugins/ftp/utils.go +++ b/plugins/ftp/utils.go @@ -2,7 +2,7 @@ package ftp import ( "github.com/OpenListTeam/OpenList/v4/internal/model" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" ) func tryLdapLoginAndRegister(user, pass string) (*model.User, error) { diff --git a/plugins/s3/config.go b/plugins/s3/config.go index e644fb33e..1bb061e2a 100644 --- a/plugins/s3/config.go +++ b/plugins/s3/config.go @@ -1,6 +1,9 @@ package s3 type S3 struct { - Port int `json:"port" env:"PORT"` - SSL bool `json:"ssl" env:"SSL"` + Address string `json:"address" env:"ADDR"` + Port int `json:"port" env:"PORT"` + SSL bool `json:"ssl" env:"SSL"` + CertFile string `json:"cert_file" env:"CERT_FILE"` + KeyFile string `json:"key_file" env:"KEY_FILE"` } diff --git a/plugins/s3/plugin.go b/plugins/s3/plugin.go index 4985554b0..a60ddc049 100644 --- a/plugins/s3/plugin.go +++ b/plugins/s3/plugin.go @@ -4,8 +4,10 @@ import ( "context" "fmt" "net/http" + "os" + "path/filepath" - "github.com/OpenListTeam/OpenList/v4/internal/conf" + "github.com/OpenListTeam/OpenList/v4/cmd/flags" iplugin "github.com/OpenListTeam/OpenList/v4/internal/plugin" "github.com/OpenListTeam/OpenList/v4/pkg/utils" "github.com/gin-gonic/gin" @@ -23,16 +25,28 @@ func (p *S3Plugin) Name() string { func (p *S3Plugin) Init(config map[string]any) error { p.conf = &S3{ - Port: 5246, - SSL: false, + Address: "0.0.0.0", + Port: 5246, + SSL: false, } var err error + if p.conf.Address, err = iplugin.StringValue(config, "address", p.conf.Address); err != nil { + return err + } if p.conf.Port, err = iplugin.IntValue(config, "port", p.conf.Port); err != nil { return err } if p.conf.SSL, err = iplugin.BoolValue(config, "ssl", p.conf.SSL); err != nil { return err } + if p.conf.CertFile, err = iplugin.StringValue(config, "cert_file", p.conf.CertFile); err != nil { + return err + } + p.conf.CertFile = resolvePluginPath(p.conf.CertFile) + if p.conf.KeyFile, err = iplugin.StringValue(config, "key_file", p.conf.KeyFile); err != nil { + return err + } + p.conf.KeyFile = resolvePluginPath(p.conf.KeyFile) return nil } @@ -48,12 +62,12 @@ func (p *S3Plugin) Start() error { r.Use(gin.LoggerWithWriter(log.StandardLogger().Out), gin.RecoveryWithWriter(log.StandardLogger().Out)) r.Any("/*path", gin.WrapH(h)) r.Any("/", gin.WrapH(h)) - addr := fmt.Sprintf("%s:%d", conf.Conf.Scheme.Address, p.conf.Port) + addr := fmt.Sprintf("%s:%d", p.conf.Address, p.conf.Port) utils.Log.Infof("start S3 server @ %s", addr) fmt.Printf("start S3 server @ %s\n", addr) p.server = &http.Server{Addr: addr, Handler: r} if p.conf.SSL { - return p.server.ListenAndServeTLS(conf.Conf.Scheme.CertFile, conf.Conf.Scheme.KeyFile) + return p.server.ListenAndServeTLS(p.conf.CertFile, p.conf.KeyFile) } return p.server.ListenAndServe() } @@ -74,3 +88,20 @@ func init() { return &S3Plugin{} }) } + +func resolvePluginPath(path string) string { + if path == "" || filepath.IsAbs(path) { + return path + } + if flags.ForceBinDir { + executable, err := os.Executable() + if err == nil { + return filepath.Join(filepath.Dir(executable), path) + } + } + wd, err := os.Getwd() + if err != nil { + return path + } + return filepath.Join(wd, path) +} diff --git a/server/debug.go b/plugins/server/debug.go similarity index 93% rename from server/debug.go rename to plugins/server/debug.go index 5b40e3d17..7f1ea2e26 100644 --- a/server/debug.go +++ b/plugins/server/debug.go @@ -8,7 +8,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/conf" "github.com/OpenListTeam/OpenList/v4/internal/sign" "github.com/OpenListTeam/OpenList/v4/pkg/middlewares" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/gin-gonic/gin" ) diff --git a/server/handles/archive.go b/plugins/server/handles/archive.go similarity index 99% rename from server/handles/archive.go rename to plugins/server/handles/archive.go index 4fd405688..e2ef5f269 100644 --- a/server/handles/archive.go +++ b/plugins/server/handles/archive.go @@ -15,8 +15,8 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/setting" "github.com/OpenListTeam/OpenList/v4/internal/sign" "github.com/OpenListTeam/OpenList/v4/internal/task" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server/common" "github.com/gin-gonic/gin" "github.com/pkg/errors" log "github.com/sirupsen/logrus" diff --git a/server/handles/auth.go b/plugins/server/handles/auth.go similarity index 98% rename from server/handles/auth.go rename to plugins/server/handles/auth.go index 780069091..e5b93bb16 100644 --- a/server/handles/auth.go +++ b/plugins/server/handles/auth.go @@ -8,7 +8,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/conf" "github.com/OpenListTeam/OpenList/v4/internal/model" "github.com/OpenListTeam/OpenList/v4/internal/op" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/gin-gonic/gin" "github.com/pquerna/otp/totp" ) diff --git a/server/handles/const.go b/plugins/server/handles/const.go similarity index 100% rename from server/handles/const.go rename to plugins/server/handles/const.go diff --git a/server/handles/direct_upload.go b/plugins/server/handles/direct_upload.go similarity index 96% rename from server/handles/direct_upload.go rename to plugins/server/handles/direct_upload.go index 69cfd2fa8..98f7dd631 100644 --- a/server/handles/direct_upload.go +++ b/plugins/server/handles/direct_upload.go @@ -6,7 +6,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/conf" "github.com/OpenListTeam/OpenList/v4/internal/fs" "github.com/OpenListTeam/OpenList/v4/internal/model" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/gin-gonic/gin" ) diff --git a/server/handles/down.go b/plugins/server/handles/down.go similarity index 98% rename from server/handles/down.go rename to plugins/server/handles/down.go index d4d634cbe..fba6bc5d3 100644 --- a/server/handles/down.go +++ b/plugins/server/handles/down.go @@ -14,8 +14,8 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/model" "github.com/OpenListTeam/OpenList/v4/internal/net" "github.com/OpenListTeam/OpenList/v4/internal/setting" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server/common" "github.com/gin-gonic/gin" "github.com/microcosm-cc/bluemonday" log "github.com/sirupsen/logrus" diff --git a/server/handles/driver.go b/plugins/server/handles/driver.go similarity index 91% rename from server/handles/driver.go rename to plugins/server/handles/driver.go index 28ed7f111..acc73e3f0 100644 --- a/server/handles/driver.go +++ b/plugins/server/handles/driver.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/OpenListTeam/OpenList/v4/internal/op" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/gin-gonic/gin" ) diff --git a/server/handles/fsbatch.go b/plugins/server/handles/fsbatch.go similarity index 99% rename from server/handles/fsbatch.go rename to plugins/server/handles/fsbatch.go index 162419f7b..4d16cdce0 100644 --- a/server/handles/fsbatch.go +++ b/plugins/server/handles/fsbatch.go @@ -10,8 +10,8 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/fs" "github.com/OpenListTeam/OpenList/v4/internal/model" "github.com/OpenListTeam/OpenList/v4/internal/op" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/OpenListTeam/OpenList/v4/pkg/generic" - "github.com/OpenListTeam/OpenList/v4/server/common" "github.com/gin-gonic/gin" "github.com/pkg/errors" ) diff --git a/server/handles/fsmanage.go b/plugins/server/handles/fsmanage.go similarity index 99% rename from server/handles/fsmanage.go rename to plugins/server/handles/fsmanage.go index 62382a27c..551a5c8f3 100644 --- a/server/handles/fsmanage.go +++ b/plugins/server/handles/fsmanage.go @@ -12,9 +12,9 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/op" "github.com/OpenListTeam/OpenList/v4/internal/sign" "github.com/OpenListTeam/OpenList/v4/internal/task" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/OpenListTeam/OpenList/v4/pkg/generic" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server/common" "github.com/gin-gonic/gin" "github.com/pkg/errors" log "github.com/sirupsen/logrus" diff --git a/server/handles/fsread.go b/plugins/server/handles/fsread.go similarity index 99% rename from server/handles/fsread.go rename to plugins/server/handles/fsread.go index 886da9dc9..98e7aba17 100644 --- a/server/handles/fsread.go +++ b/plugins/server/handles/fsread.go @@ -13,8 +13,8 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/op" "github.com/OpenListTeam/OpenList/v4/internal/setting" "github.com/OpenListTeam/OpenList/v4/internal/sign" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server/common" "github.com/gin-gonic/gin" "github.com/pkg/errors" ) diff --git a/server/handles/fsup.go b/plugins/server/handles/fsup.go similarity index 99% rename from server/handles/fsup.go rename to plugins/server/handles/fsup.go index 0f46398cd..01b6a3f4b 100644 --- a/server/handles/fsup.go +++ b/plugins/server/handles/fsup.go @@ -14,8 +14,8 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/setting" "github.com/OpenListTeam/OpenList/v4/internal/stream" "github.com/OpenListTeam/OpenList/v4/internal/task" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server/common" "github.com/gin-gonic/gin" ) diff --git a/server/handles/helper.go b/plugins/server/handles/helper.go similarity index 98% rename from server/handles/helper.go rename to plugins/server/handles/helper.go index bae9bb0de..c5d9acc1b 100644 --- a/server/handles/helper.go +++ b/plugins/server/handles/helper.go @@ -8,8 +8,8 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/conf" "github.com/OpenListTeam/OpenList/v4/internal/setting" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server/common" "github.com/gin-gonic/gin" ) diff --git a/server/handles/index.go b/plugins/server/handles/index.go similarity index 97% rename from server/handles/index.go rename to plugins/server/handles/index.go index cd270f6f9..6197824c1 100644 --- a/server/handles/index.go +++ b/plugins/server/handles/index.go @@ -7,7 +7,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/model" "github.com/OpenListTeam/OpenList/v4/internal/search" "github.com/OpenListTeam/OpenList/v4/internal/setting" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/gin-gonic/gin" log "github.com/sirupsen/logrus" ) diff --git a/server/handles/ldap_login.go b/plugins/server/handles/ldap_login.go similarity index 96% rename from server/handles/ldap_login.go rename to plugins/server/handles/ldap_login.go index ba44615f7..9d9220c6d 100644 --- a/server/handles/ldap_login.go +++ b/plugins/server/handles/ldap_login.go @@ -5,7 +5,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/model" "github.com/OpenListTeam/OpenList/v4/internal/op" "github.com/OpenListTeam/OpenList/v4/internal/setting" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/gin-gonic/gin" "github.com/pkg/errors" ) diff --git a/server/handles/meta.go b/plugins/server/handles/meta.go similarity index 97% rename from server/handles/meta.go rename to plugins/server/handles/meta.go index af4b65271..e9937aaa4 100644 --- a/server/handles/meta.go +++ b/plugins/server/handles/meta.go @@ -7,7 +7,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/model" "github.com/OpenListTeam/OpenList/v4/internal/op" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/dlclark/regexp2" "github.com/gin-gonic/gin" log "github.com/sirupsen/logrus" diff --git a/server/handles/offline_download.go b/plugins/server/handles/offline_download.go similarity index 99% rename from server/handles/offline_download.go rename to plugins/server/handles/offline_download.go index b726d7152..b7ddf8e8b 100644 --- a/server/handles/offline_download.go +++ b/plugins/server/handles/offline_download.go @@ -16,7 +16,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/offline_download/tool" "github.com/OpenListTeam/OpenList/v4/internal/op" "github.com/OpenListTeam/OpenList/v4/internal/task" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/gin-gonic/gin" ) diff --git a/server/handles/scan.go b/plugins/server/handles/scan.go similarity index 94% rename from server/handles/scan.go rename to plugins/server/handles/scan.go index fc5e80f66..2431f33a3 100644 --- a/server/handles/scan.go +++ b/plugins/server/handles/scan.go @@ -2,7 +2,7 @@ package handles import ( "github.com/OpenListTeam/OpenList/v4/internal/op" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/gin-gonic/gin" ) diff --git a/server/handles/search.go b/plugins/server/handles/search.go similarity index 97% rename from server/handles/search.go rename to plugins/server/handles/search.go index 32e4e9558..b7f3bd8b4 100644 --- a/server/handles/search.go +++ b/plugins/server/handles/search.go @@ -9,8 +9,8 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/model" "github.com/OpenListTeam/OpenList/v4/internal/op" "github.com/OpenListTeam/OpenList/v4/internal/search" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server/common" "github.com/gin-gonic/gin" "github.com/pkg/errors" ) diff --git a/server/handles/setting.go b/plugins/server/handles/setting.go similarity index 96% rename from server/handles/setting.go rename to plugins/server/handles/setting.go index 198219e1f..3c2669939 100644 --- a/server/handles/setting.go +++ b/plugins/server/handles/setting.go @@ -10,9 +10,9 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/model" "github.com/OpenListTeam/OpenList/v4/internal/op" "github.com/OpenListTeam/OpenList/v4/internal/sign" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/OpenListTeam/OpenList/v4/pkg/utils/random" - "github.com/OpenListTeam/OpenList/v4/server/common" - "github.com/OpenListTeam/OpenList/v4/server/static" + "github.com/OpenListTeam/OpenList/v4/plugins/server/static" "github.com/gin-gonic/gin" ) diff --git a/server/handles/sharing.go b/plugins/server/handles/sharing.go similarity index 99% rename from server/handles/sharing.go rename to plugins/server/handles/sharing.go index 43f855afb..23b296bf1 100644 --- a/server/handles/sharing.go +++ b/plugins/server/handles/sharing.go @@ -13,8 +13,8 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/op" "github.com/OpenListTeam/OpenList/v4/internal/setting" "github.com/OpenListTeam/OpenList/v4/internal/sharing" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server/common" "github.com/OpenListTeam/go-cache" "github.com/gin-gonic/gin" "github.com/pkg/errors" diff --git a/server/handles/sshkey.go b/plugins/server/handles/sshkey.go similarity index 98% rename from server/handles/sshkey.go rename to plugins/server/handles/sshkey.go index d4521b9d6..bfed9808f 100644 --- a/server/handles/sshkey.go +++ b/plugins/server/handles/sshkey.go @@ -7,7 +7,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/conf" "github.com/OpenListTeam/OpenList/v4/internal/model" "github.com/OpenListTeam/OpenList/v4/internal/op" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/gin-gonic/gin" ) diff --git a/server/handles/ssologin.go b/plugins/server/handles/ssologin.go similarity index 99% rename from server/handles/ssologin.go rename to plugins/server/handles/ssologin.go index 4baabf6c1..f371567c8 100644 --- a/server/handles/ssologin.go +++ b/plugins/server/handles/ssologin.go @@ -16,9 +16,9 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/db" "github.com/OpenListTeam/OpenList/v4/internal/model" "github.com/OpenListTeam/OpenList/v4/internal/setting" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/OpenListTeam/OpenList/v4/pkg/utils" "github.com/OpenListTeam/OpenList/v4/pkg/utils/random" - "github.com/OpenListTeam/OpenList/v4/server/common" "github.com/coreos/go-oidc" "github.com/gin-gonic/gin" "github.com/go-resty/resty/v2" diff --git a/server/handles/storage.go b/plugins/server/handles/storage.go similarity index 98% rename from server/handles/storage.go rename to plugins/server/handles/storage.go index 687c93551..603ea0774 100644 --- a/server/handles/storage.go +++ b/plugins/server/handles/storage.go @@ -13,7 +13,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/model" "github.com/OpenListTeam/OpenList/v4/internal/op" "github.com/OpenListTeam/OpenList/v4/internal/setting" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/gin-gonic/gin" log "github.com/sirupsen/logrus" ) diff --git a/server/handles/task.go b/plugins/server/handles/task.go similarity index 99% rename from server/handles/task.go rename to plugins/server/handles/task.go index 032f363ad..f2e230683 100644 --- a/server/handles/task.go +++ b/plugins/server/handles/task.go @@ -10,8 +10,8 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/fs" "github.com/OpenListTeam/OpenList/v4/internal/offline_download/tool" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server/common" "github.com/OpenListTeam/tache" "github.com/gin-gonic/gin" ) diff --git a/server/handles/user.go b/plugins/server/handles/user.go similarity index 98% rename from server/handles/user.go rename to plugins/server/handles/user.go index 095089d70..44a7c5fa3 100644 --- a/server/handles/user.go +++ b/plugins/server/handles/user.go @@ -5,7 +5,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/model" "github.com/OpenListTeam/OpenList/v4/internal/op" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/gin-gonic/gin" log "github.com/sirupsen/logrus" ) diff --git a/server/handles/webauthn.go b/plugins/server/handles/webauthn.go similarity index 99% rename from server/handles/webauthn.go rename to plugins/server/handles/webauthn.go index b2a0fbfb4..169a87e80 100644 --- a/server/handles/webauthn.go +++ b/plugins/server/handles/webauthn.go @@ -12,7 +12,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/model" "github.com/OpenListTeam/OpenList/v4/internal/op" "github.com/OpenListTeam/OpenList/v4/internal/setting" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/gin-gonic/gin" "github.com/go-webauthn/webauthn/protocol" "github.com/go-webauthn/webauthn/webauthn" diff --git a/plugins/server/plugin.go b/plugins/server/plugin.go new file mode 100644 index 000000000..b8f15516d --- /dev/null +++ b/plugins/server/plugin.go @@ -0,0 +1,369 @@ +package server + +import ( + "context" + "fmt" + "net" + "net/http" + "os" + "path/filepath" + "strconv" + "sync" + "time" + + iplugin "github.com/OpenListTeam/OpenList/v4/internal/plugin" + "github.com/pkg/errors" + "github.com/quic-go/quic-go/http3" + "golang.org/x/net/http2" + "golang.org/x/net/http2/h2c" + + "github.com/OpenListTeam/OpenList/v4/cmd/flags" + "github.com/OpenListTeam/OpenList/v4/internal/conf" + "github.com/OpenListTeam/OpenList/v4/internal/sign" + "github.com/OpenListTeam/OpenList/v4/internal/stream" + "github.com/OpenListTeam/OpenList/v4/pkg/common" + "github.com/OpenListTeam/OpenList/v4/pkg/middlewares" + "github.com/OpenListTeam/OpenList/v4/pkg/utils" + "github.com/OpenListTeam/OpenList/v4/plugins/server/handles" + "github.com/OpenListTeam/OpenList/v4/plugins/server/static" + "github.com/gin-gonic/gin" + log "github.com/sirupsen/logrus" +) + +type ServerPlugin struct { + r *gin.Engine + conf ServerConfig + httpServer *http.Server + httpsServer *http.Server + unixServer *http.Server + quicServer *http3.Server + unixLn net.Listener + stopCh chan struct{} + stopOnce sync.Once +} + +type ServerConfig struct { + Address string + HttpPort int + HttpsPort int + ForceHttps bool + CertFile string + KeyFile string + UnixFile string + UnixFilePerm string + EnableH2c bool + EnableH3 bool +} + +func (s *ServerPlugin) Name() string { + return "server" +} + +func (s *ServerPlugin) Init(data map[string]any) error { + s.conf = ServerConfig{ + Address: "0.0.0.0", + HttpPort: 5244, + HttpsPort: -1, + ForceHttps: false, + CertFile: "", + KeyFile: "", + UnixFile: "", + UnixFilePerm: "", + EnableH2c: false, + EnableH3: false, + } + var err error + if s.conf.Address, err = iplugin.StringValue(data, "address", s.conf.Address); err != nil { + return err + } + if s.conf.HttpPort, err = iplugin.IntValue(data, "http_port", s.conf.HttpPort); err != nil { + return err + } + if s.conf.HttpsPort, err = iplugin.IntValue(data, "https_port", s.conf.HttpsPort); err != nil { + return err + } + if s.conf.ForceHttps, err = iplugin.BoolValue(data, "force_https", s.conf.ForceHttps); err != nil { + return err + } + if s.conf.CertFile, err = iplugin.StringValue(data, "cert_file", s.conf.CertFile); err != nil { + return err + } + s.conf.CertFile = resolvePluginPath(s.conf.CertFile) + if s.conf.KeyFile, err = iplugin.StringValue(data, "key_file", s.conf.KeyFile); err != nil { + return err + } + s.conf.KeyFile = resolvePluginPath(s.conf.KeyFile) + if s.conf.UnixFile, err = iplugin.StringValue(data, "unix_file", s.conf.UnixFile); err != nil { + return err + } + s.conf.UnixFile = resolvePluginPath(s.conf.UnixFile) + if s.conf.UnixFilePerm, err = iplugin.StringValue(data, "unix_file_perm", s.conf.UnixFilePerm); err != nil { + return err + } + if s.conf.EnableH2c, err = iplugin.BoolValue(data, "enable_h2c", s.conf.EnableH2c); err != nil { + return err + } + if s.conf.EnableH3, err = iplugin.BoolValue(data, "enable_h3", s.conf.EnableH3); err != nil { + return err + } + if !flags.Debug && !flags.Dev { + gin.SetMode(gin.ReleaseMode) + } + + s.r = gin.New() + if conf.Conf.Log.Filter.Enable { + s.r.Use(middlewares.FilteredLogger()) + } else { + s.r.Use(gin.LoggerWithWriter(log.StandardLogger().Out)) + } + s.r.Use(gin.RecoveryWithWriter(log.StandardLogger().Out)) + s.r.ContextWithFallback = true + if !utils.SliceContains([]string{"", "/"}, conf.URL.Path) { + s.r.GET("/", func(c *gin.Context) { + c.Redirect(302, conf.URL.Path) + }) + } + Cors(s.r) + g := s.r.Group(conf.URL.Path) + if s.conf.HttpPort != -1 && s.conf.HttpsPort != -1 && s.conf.ForceHttps { + s.r.Use(middlewares.ForceHttps(s.conf.HttpPort, s.conf.HttpsPort)) + } + g.Any("/ping", func(c *gin.Context) { + c.String(200, "pong") + }) + g.GET("/favicon.ico", handles.Favicon) + g.GET("/robots.txt", handles.Robots) + g.GET("/manifest.json", static.ManifestJSON) + g.GET("/i/:link_name", handles.Plist) + common.SecretKey = []byte(conf.Conf.JwtSecret) + g.Use(middlewares.StoragesLoaded) + if conf.Conf.MaxConnections > 0 { + g.Use(middlewares.MaxAllowed(conf.Conf.MaxConnections)) + } + + downloadLimiter := middlewares.DownloadRateLimiter(stream.ClientDownloadLimit) + signCheck := middlewares.Down(sign.Verify) + g.GET("/d/*path", middlewares.PathParse, signCheck, downloadLimiter, handles.Down) + g.GET("/p/*path", middlewares.PathParse, signCheck, downloadLimiter, handles.Proxy) + g.HEAD("/d/*path", middlewares.PathParse, signCheck, handles.Down) + g.HEAD("/p/*path", middlewares.PathParse, signCheck, handles.Proxy) + archiveSignCheck := middlewares.Down(sign.VerifyArchive) + g.GET("/ad/*path", middlewares.PathParse, archiveSignCheck, downloadLimiter, handles.ArchiveDown) + g.GET("/ap/*path", middlewares.PathParse, archiveSignCheck, downloadLimiter, handles.ArchiveProxy) + g.GET("/ae/*path", middlewares.PathParse, archiveSignCheck, downloadLimiter, handles.ArchiveInternalExtract) + g.HEAD("/ad/*path", middlewares.PathParse, archiveSignCheck, handles.ArchiveDown) + g.HEAD("/ap/*path", middlewares.PathParse, archiveSignCheck, handles.ArchiveProxy) + g.HEAD("/ae/*path", middlewares.PathParse, archiveSignCheck, handles.ArchiveInternalExtract) + + g.GET("/sd/:sid", middlewares.EmptyPathParse, middlewares.SharingIdParse, downloadLimiter, handles.SharingDown) + g.GET("/sd/:sid/*path", middlewares.PathParse, middlewares.SharingIdParse, downloadLimiter, handles.SharingDown) + g.HEAD("/sd/:sid", middlewares.EmptyPathParse, middlewares.SharingIdParse, handles.SharingDown) + g.HEAD("/sd/:sid/*path", middlewares.PathParse, middlewares.SharingIdParse, handles.SharingDown) + g.GET("/sad/:sid", middlewares.EmptyPathParse, middlewares.SharingIdParse, downloadLimiter, handles.SharingArchiveExtract) + g.GET("/sad/:sid/*path", middlewares.PathParse, middlewares.SharingIdParse, downloadLimiter, handles.SharingArchiveExtract) + g.HEAD("/sad/:sid", middlewares.EmptyPathParse, middlewares.SharingIdParse, handles.SharingArchiveExtract) + g.HEAD("/sad/:sid/*path", middlewares.PathParse, middlewares.SharingIdParse, handles.SharingArchiveExtract) + + api := g.Group("/api") + auth := api.Group("", middlewares.Auth(false)) + webauthn := api.Group("/authn", middlewares.Authn) + + api.POST("/auth/login", handles.Login) + api.POST("/auth/login/hash", handles.LoginHash) + api.POST("/auth/login/ldap", handles.LoginLdap) + auth.GET("/me", handles.CurrentUser) + auth.POST("/me/update", handles.UpdateCurrent) + auth.GET("/me/sshkey/list", handles.ListMyPublicKey) + auth.POST("/me/sshkey/add", handles.AddMyPublicKey) + auth.POST("/me/sshkey/delete", handles.DeleteMyPublicKey) + auth.POST("/auth/2fa/generate", handles.Generate2FA) + auth.POST("/auth/2fa/verify", handles.Verify2FA) + auth.GET("/auth/logout", handles.LogOut) + + // auth + api.GET("/auth/sso", handles.SSOLoginRedirect) + api.GET("/auth/sso_callback", handles.SSOLoginCallback) + api.GET("/auth/get_sso_id", handles.SSOLoginCallback) + api.GET("/auth/sso_get_token", handles.SSOLoginCallback) + + // webauthn + api.GET("/authn/webauthn_begin_login", handles.BeginAuthnLogin) + api.POST("/authn/webauthn_finish_login", handles.FinishAuthnLogin) + webauthn.GET("/webauthn_begin_registration", handles.BeginAuthnRegistration) + webauthn.POST("/webauthn_finish_registration", handles.FinishAuthnRegistration) + webauthn.POST("/delete_authn", handles.DeleteAuthnLogin) + webauthn.GET("/getcredentials", handles.GetAuthnCredentials) + + // no need auth + public := api.Group("/public") + public.Any("/settings", handles.PublicSettings) + public.Any("/offline_download_tools", handles.OfflineDownloadTools) + public.Any("/archive_extensions", handles.ArchiveExtensions) + + _fs(auth.Group("/fs")) + fsAndShare(api.Group("/fs", middlewares.Auth(true))) + _task(auth.Group("/task", middlewares.AuthNotGuest)) + _sharing(auth.Group("/share", middlewares.AuthNotGuest)) + admin(auth.Group("/admin", middlewares.AuthAdmin)) + if flags.Debug || flags.Dev { + debug(g.Group("/debug")) + } + static.Static(g, func(handlers ...gin.HandlerFunc) { + s.r.NoRoute(handlers...) + }) + return nil +} + +func (s *ServerPlugin) Start() error { + s.stopCh = make(chan struct{}) + s.stopOnce = sync.Once{} + errCh := make(chan error, 4) + listenerCount := 0 + + var httpHandler http.Handler = s.r + if s.conf.EnableH2c { + httpHandler = h2c.NewHandler(s.r, &http2.Server{}) + } + if s.conf.HttpPort != -1 { + listenerCount++ + httpBase := fmt.Sprintf("%s:%d", s.conf.Address, s.conf.HttpPort) + fmt.Printf("start HTTP server @ %s\n", httpBase) + utils.Log.Infof("start HTTP server @ %s", httpBase) + s.httpServer = &http.Server{Addr: httpBase, Handler: httpHandler} + go func() { + if err := s.httpServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { + errCh <- fmt.Errorf("start http: %w", err) + } + }() + } + if s.conf.HttpsPort != -1 { + listenerCount++ + httpsBase := fmt.Sprintf("%s:%d", s.conf.Address, s.conf.HttpsPort) + fmt.Printf("start HTTPS server @ %s\n", httpsBase) + utils.Log.Infof("start HTTPS server @ %s", httpsBase) + s.httpsServer = &http.Server{Addr: httpsBase, Handler: httpHandler} + go func() { + if err := s.httpsServer.ListenAndServeTLS(s.conf.CertFile, s.conf.KeyFile); err != nil && !errors.Is(err, http.ErrServerClosed) { + errCh <- fmt.Errorf("start https: %w", err) + } + }() + if s.conf.EnableH3 { + fmt.Printf("start HTTP3 (quic) server @ %s\n", httpsBase) + utils.Log.Infof("start HTTP3 (quic) server @ %s", httpsBase) + s.r.Use(func(c *gin.Context) { + if c.Request.TLS != nil { + port := s.conf.HttpsPort + c.Header("Alt-Svc", fmt.Sprintf("h3=\":%d\"; ma=86400", port)) + } + c.Next() + }) + s.quicServer = &http3.Server{Addr: httpsBase, Handler: s.r} + go func() { + if err := s.quicServer.ListenAndServeTLS(s.conf.CertFile, s.conf.KeyFile); err != nil && !errors.Is(err, http.ErrServerClosed) { + errCh <- fmt.Errorf("start http3 (quic): %w", err) + } + }() + } + } + if s.conf.UnixFile != "" { + listenerCount++ + fmt.Printf("start unix server @ %s\n", s.conf.UnixFile) + utils.Log.Infof("start unix server @ %s", s.conf.UnixFile) + listener, err := net.Listen("unix", s.conf.UnixFile) + if err != nil { + _ = s.Stop() + return err + } + s.unixLn = listener + s.unixServer = &http.Server{Handler: httpHandler} + if s.conf.UnixFilePerm != "" { + mode, err := strconv.ParseUint(s.conf.UnixFilePerm, 8, 32) + if err != nil { + utils.Log.Errorf("failed to parse socket file permission: %+v", err) + } else if err = os.Chmod(s.conf.UnixFile, os.FileMode(mode)); err != nil { + utils.Log.Errorf("failed to chmod socket file: %+v", err) + } + } + go func() { + if err := s.unixServer.Serve(listener); err != nil && !errors.Is(err, http.ErrServerClosed) { + errCh <- fmt.Errorf("start unix: %w", err) + } + }() + } + if listenerCount == 0 { + return fmt.Errorf("server plugin has no enabled listeners") + } + + select { + case err := <-errCh: + _ = s.Stop() + return err + case <-s.stopCh: + return nil + } +} + +func (s *ServerPlugin) Stop() error { + s.stopOnce.Do(func() { + if s.stopCh != nil { + close(s.stopCh) + } + }) + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + if s.quicServer != nil { + if err := s.quicServer.Shutdown(ctx); err != nil { + utils.Log.Errorf("failed to shutdown http3 (quic): %s", err.Error()) + } + s.quicServer = nil + } + if s.unixServer != nil { + if err := s.unixServer.Shutdown(ctx); err != nil { + utils.Log.Errorf("failed to shutdown unix: %s", err.Error()) + } + s.unixServer = nil + } + if s.unixLn != nil { + _ = s.unixLn.Close() + s.unixLn = nil + } + if s.httpsServer != nil { + if err := s.httpsServer.Shutdown(ctx); err != nil { + utils.Log.Errorf("failed to shutdown https: %s", err.Error()) + } + s.httpsServer = nil + } + if s.httpServer != nil { + if err := s.httpServer.Shutdown(ctx); err != nil { + utils.Log.Errorf("failed to shutdown http: %s", err.Error()) + } + s.httpServer = nil + } + return nil +} + +var _ iplugin.Plugin = (*ServerPlugin)(nil) + +func init() { + iplugin.RegisterPlugin("server", func() iplugin.Plugin { + return &ServerPlugin{} + }) +} + +func resolvePluginPath(path string) string { + if path == "" || filepath.IsAbs(path) { + return path + } + if flags.ForceBinDir { + executable, err := os.Executable() + if err == nil { + return filepath.Join(filepath.Dir(executable), path) + } + } + wd, err := os.Getwd() + if err != nil { + return path + } + return filepath.Join(wd, path) +} diff --git a/server/router.go b/plugins/server/router.go similarity index 51% rename from server/router.go rename to plugins/server/router.go index e73911ac9..c31a1f9a0 100644 --- a/server/router.go +++ b/plugins/server/router.go @@ -1,117 +1,15 @@ package server import ( - "github.com/OpenListTeam/OpenList/v4/cmd/flags" "github.com/OpenListTeam/OpenList/v4/internal/conf" "github.com/OpenListTeam/OpenList/v4/internal/message" - "github.com/OpenListTeam/OpenList/v4/internal/sign" "github.com/OpenListTeam/OpenList/v4/internal/stream" "github.com/OpenListTeam/OpenList/v4/pkg/middlewares" - "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server/common" - "github.com/OpenListTeam/OpenList/v4/server/handles" - "github.com/OpenListTeam/OpenList/v4/server/static" + "github.com/OpenListTeam/OpenList/v4/plugins/server/handles" "github.com/gin-contrib/cors" "github.com/gin-gonic/gin" ) -func Init(e *gin.Engine) { - e.ContextWithFallback = true - if !utils.SliceContains([]string{"", "/"}, conf.URL.Path) { - e.GET("/", func(c *gin.Context) { - c.Redirect(302, conf.URL.Path) - }) - } - Cors(e) - g := e.Group(conf.URL.Path) - if conf.Conf.Scheme.HttpPort != -1 && conf.Conf.Scheme.HttpsPort != -1 && conf.Conf.Scheme.ForceHttps { - e.Use(middlewares.ForceHttps) - } - g.Any("/ping", func(c *gin.Context) { - c.String(200, "pong") - }) - g.GET("/favicon.ico", handles.Favicon) - g.GET("/robots.txt", handles.Robots) - g.GET("/manifest.json", static.ManifestJSON) - g.GET("/i/:link_name", handles.Plist) - common.SecretKey = []byte(conf.Conf.JwtSecret) - g.Use(middlewares.StoragesLoaded) - if conf.Conf.MaxConnections > 0 { - g.Use(middlewares.MaxAllowed(conf.Conf.MaxConnections)) - } - - downloadLimiter := middlewares.DownloadRateLimiter(stream.ClientDownloadLimit) - signCheck := middlewares.Down(sign.Verify) - g.GET("/d/*path", middlewares.PathParse, signCheck, downloadLimiter, handles.Down) - g.GET("/p/*path", middlewares.PathParse, signCheck, downloadLimiter, handles.Proxy) - g.HEAD("/d/*path", middlewares.PathParse, signCheck, handles.Down) - g.HEAD("/p/*path", middlewares.PathParse, signCheck, handles.Proxy) - archiveSignCheck := middlewares.Down(sign.VerifyArchive) - g.GET("/ad/*path", middlewares.PathParse, archiveSignCheck, downloadLimiter, handles.ArchiveDown) - g.GET("/ap/*path", middlewares.PathParse, archiveSignCheck, downloadLimiter, handles.ArchiveProxy) - g.GET("/ae/*path", middlewares.PathParse, archiveSignCheck, downloadLimiter, handles.ArchiveInternalExtract) - g.HEAD("/ad/*path", middlewares.PathParse, archiveSignCheck, handles.ArchiveDown) - g.HEAD("/ap/*path", middlewares.PathParse, archiveSignCheck, handles.ArchiveProxy) - g.HEAD("/ae/*path", middlewares.PathParse, archiveSignCheck, handles.ArchiveInternalExtract) - - g.GET("/sd/:sid", middlewares.EmptyPathParse, middlewares.SharingIdParse, downloadLimiter, handles.SharingDown) - g.GET("/sd/:sid/*path", middlewares.PathParse, middlewares.SharingIdParse, downloadLimiter, handles.SharingDown) - g.HEAD("/sd/:sid", middlewares.EmptyPathParse, middlewares.SharingIdParse, handles.SharingDown) - g.HEAD("/sd/:sid/*path", middlewares.PathParse, middlewares.SharingIdParse, handles.SharingDown) - g.GET("/sad/:sid", middlewares.EmptyPathParse, middlewares.SharingIdParse, downloadLimiter, handles.SharingArchiveExtract) - g.GET("/sad/:sid/*path", middlewares.PathParse, middlewares.SharingIdParse, downloadLimiter, handles.SharingArchiveExtract) - g.HEAD("/sad/:sid", middlewares.EmptyPathParse, middlewares.SharingIdParse, handles.SharingArchiveExtract) - g.HEAD("/sad/:sid/*path", middlewares.PathParse, middlewares.SharingIdParse, handles.SharingArchiveExtract) - - api := g.Group("/api") - auth := api.Group("", middlewares.Auth(false)) - webauthn := api.Group("/authn", middlewares.Authn) - - api.POST("/auth/login", handles.Login) - api.POST("/auth/login/hash", handles.LoginHash) - api.POST("/auth/login/ldap", handles.LoginLdap) - auth.GET("/me", handles.CurrentUser) - auth.POST("/me/update", handles.UpdateCurrent) - auth.GET("/me/sshkey/list", handles.ListMyPublicKey) - auth.POST("/me/sshkey/add", handles.AddMyPublicKey) - auth.POST("/me/sshkey/delete", handles.DeleteMyPublicKey) - auth.POST("/auth/2fa/generate", handles.Generate2FA) - auth.POST("/auth/2fa/verify", handles.Verify2FA) - auth.GET("/auth/logout", handles.LogOut) - - // auth - api.GET("/auth/sso", handles.SSOLoginRedirect) - api.GET("/auth/sso_callback", handles.SSOLoginCallback) - api.GET("/auth/get_sso_id", handles.SSOLoginCallback) - api.GET("/auth/sso_get_token", handles.SSOLoginCallback) - - // webauthn - api.GET("/authn/webauthn_begin_login", handles.BeginAuthnLogin) - api.POST("/authn/webauthn_finish_login", handles.FinishAuthnLogin) - webauthn.GET("/webauthn_begin_registration", handles.BeginAuthnRegistration) - webauthn.POST("/webauthn_finish_registration", handles.FinishAuthnRegistration) - webauthn.POST("/delete_authn", handles.DeleteAuthnLogin) - webauthn.GET("/getcredentials", handles.GetAuthnCredentials) - - // no need auth - public := api.Group("/public") - public.Any("/settings", handles.PublicSettings) - public.Any("/offline_download_tools", handles.OfflineDownloadTools) - public.Any("/archive_extensions", handles.ArchiveExtensions) - - _fs(auth.Group("/fs")) - fsAndShare(api.Group("/fs", middlewares.Auth(true))) - _task(auth.Group("/task", middlewares.AuthNotGuest)) - _sharing(auth.Group("/share", middlewares.AuthNotGuest)) - admin(auth.Group("/admin", middlewares.AuthAdmin)) - if flags.Debug || flags.Dev { - debug(g.Group("/debug")) - } - static.Static(g, func(handlers ...gin.HandlerFunc) { - e.NoRoute(handlers...) - }) -} - func admin(g *gin.RouterGroup) { meta := g.Group("/meta") meta.GET("/list", handles.ListMetas) diff --git a/server/static/config.go b/plugins/server/static/config.go similarity index 100% rename from server/static/config.go rename to plugins/server/static/config.go diff --git a/server/static/static.go b/plugins/server/static/static.go similarity index 100% rename from server/static/static.go rename to plugins/server/static/static.go diff --git a/plugins/sftp/runtime.go b/plugins/sftp/runtime.go index de21da3a6..93005a4d1 100644 --- a/plugins/sftp/runtime.go +++ b/plugins/sftp/runtime.go @@ -12,10 +12,10 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/model" "github.com/OpenListTeam/OpenList/v4/internal/op" "github.com/OpenListTeam/OpenList/v4/internal/setting" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - pkgsftp "github.com/pkg/sftp" "github.com/pkg/errors" - "github.com/OpenListTeam/OpenList/v4/server/common" + pkgsftp "github.com/pkg/sftp" "golang.org/x/crypto/ssh" ) diff --git a/plugins/sftp/sftp.go b/plugins/sftp/sftp.go index e2672364a..a2289c8af 100644 --- a/plugins/sftp/sftp.go +++ b/plugins/sftp/sftp.go @@ -18,10 +18,10 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/op" "github.com/OpenListTeam/OpenList/v4/internal/setting" "github.com/OpenListTeam/OpenList/v4/internal/stream" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - pkgsftp "github.com/pkg/sftp" "github.com/pkg/errors" - "github.com/OpenListTeam/OpenList/v4/server/common" + pkgsftp "github.com/pkg/sftp" "github.com/shirou/gopsutil/v4/disk" ) diff --git a/plugins/sftp/utils.go b/plugins/sftp/utils.go index 74498a6b4..6e20a5ed9 100644 --- a/plugins/sftp/utils.go +++ b/plugins/sftp/utils.go @@ -2,7 +2,7 @@ package sftp import ( "github.com/OpenListTeam/OpenList/v4/internal/model" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" ) func tryLdapLoginAndRegister(user, pass string) (*model.User, error) { diff --git a/plugins/webdav/plugin.go b/plugins/webdav/plugin.go index 663339f02..cbee321ce 100644 --- a/plugins/webdav/plugin.go +++ b/plugins/webdav/plugin.go @@ -3,8 +3,10 @@ package webdav import ( "fmt" "net/http" + "os" + "path/filepath" - "github.com/OpenListTeam/OpenList/v4/internal/conf" + "github.com/OpenListTeam/OpenList/v4/cmd/flags" iplugin "github.com/OpenListTeam/OpenList/v4/internal/plugin" "github.com/OpenListTeam/OpenList/v4/pkg/utils" "github.com/gin-gonic/gin" @@ -35,9 +37,11 @@ func (p *WebDAVPlugin) Init(config map[string]any) error { if p.conf.CertFile, err = iplugin.StringValue(config, "cert_file", p.conf.CertFile); err != nil { return err } + p.conf.CertFile = resolvePluginPath(p.conf.CertFile) if p.conf.KeyFile, err = iplugin.StringValue(config, "key_file", p.conf.KeyFile); err != nil { return err } + p.conf.KeyFile = resolvePluginPath(p.conf.KeyFile) return nil } @@ -49,15 +53,7 @@ func (p *WebDAVPlugin) Start() error { fmt.Printf("start WebDAV server @ %s\n", p.conf.Listen) p.server = &http.Server{Addr: p.conf.Listen, Handler: r} if p.conf.SSL { - certFile := p.conf.CertFile - if certFile == "" { - certFile = conf.Conf.Scheme.CertFile - } - keyFile := p.conf.KeyFile - if keyFile == "" { - keyFile = conf.Conf.Scheme.KeyFile - } - return p.server.ListenAndServeTLS(certFile, keyFile) + return p.server.ListenAndServeTLS(p.conf.CertFile, p.conf.KeyFile) } return p.server.ListenAndServe() } @@ -78,3 +74,20 @@ func init() { return &WebDAVPlugin{} }) } + +func resolvePluginPath(path string) string { + if path == "" || filepath.IsAbs(path) { + return path + } + if flags.ForceBinDir { + executable, err := os.Executable() + if err == nil { + return filepath.Join(filepath.Dir(executable), path) + } + } + wd, err := os.Getwd() + if err != nil { + return path + } + return filepath.Join(wd, path) +} diff --git a/plugins/webdav/prop.go b/plugins/webdav/prop.go index 5c8889341..ed8806fd2 100644 --- a/plugins/webdav/prop.go +++ b/plugins/webdav/prop.go @@ -18,7 +18,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/conf" "github.com/OpenListTeam/OpenList/v4/internal/model" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" ) // Proppatch describes a property update instruction as defined in RFC 4918. diff --git a/plugins/webdav/server.go b/plugins/webdav/server.go index c105512da..aeb83df91 100644 --- a/plugins/webdav/server.go +++ b/plugins/webdav/server.go @@ -10,8 +10,8 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/op" "github.com/OpenListTeam/OpenList/v4/internal/setting" "github.com/OpenListTeam/OpenList/v4/internal/stream" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/OpenListTeam/OpenList/v4/pkg/middlewares" - "github.com/OpenListTeam/OpenList/v4/server/common" "github.com/gin-gonic/gin" log "github.com/sirupsen/logrus" "golang.org/x/net/webdav" diff --git a/plugins/webdav/utils.go b/plugins/webdav/utils.go index b67de89ed..5ad69bde5 100644 --- a/plugins/webdav/utils.go +++ b/plugins/webdav/utils.go @@ -2,7 +2,7 @@ package webdav import ( "github.com/OpenListTeam/OpenList/v4/internal/model" - "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/OpenListTeam/OpenList/v4/pkg/common" ) func tryLdapLoginAndRegister(user, pass string) (*model.User, error) { diff --git a/plugins/webdav/webdav.go b/plugins/webdav/webdav.go index 504c5fc1d..9cadcf4c2 100644 --- a/plugins/webdav/webdav.go +++ b/plugins/webdav/webdav.go @@ -26,8 +26,8 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/errs" "github.com/OpenListTeam/OpenList/v4/internal/fs" "github.com/OpenListTeam/OpenList/v4/internal/model" + "github.com/OpenListTeam/OpenList/v4/pkg/common" "github.com/OpenListTeam/OpenList/v4/pkg/utils" - "github.com/OpenListTeam/OpenList/v4/server/common" ) type Handler struct {