diff --git a/go.mod b/go.mod index 1d84440e..7c81fa6e 100644 --- a/go.mod +++ b/go.mod @@ -79,7 +79,7 @@ require ( require ( cloud.google.com/go v0.112.2 // indirect - cloud.google.com/go/auth v0.3.0 // indirect + cloud.google.com/go/auth v0.4.0 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect cloud.google.com/go/compute/metadata v0.3.0 // indirect cloud.google.com/go/iam v1.1.8 // indirect diff --git a/go.sum b/go.sum index dddfd581..f18645d8 100644 --- a/go.sum +++ b/go.sum @@ -3,8 +3,11 @@ cloud.google.com/go v0.112.2 h1:ZaGT6LiG7dBzi6zNOvVZwacaXlmf3lRqnC4DQzqyRQw= cloud.google.com/go v0.112.2/go.mod h1:iEqjp//KquGIJV/m+Pk3xecgKNhV+ry+vVTsy4TbDms= cloud.google.com/go/auth v0.3.0 h1:PRyzEpGfx/Z9e8+lHsbkoUVXD0gnu4MNmm7Gp8TQNIs= cloud.google.com/go/auth v0.3.0/go.mod h1:lBv6NKTWp8E3LPzmO1TbiiRKc4drLOfHsgmlH9ogv5w= +cloud.google.com/go/auth v0.4.0 h1:vcJWEguhY8KuiHoSs/udg1JtIRYm3YAWPBE1moF1m3U= +cloud.google.com/go/auth v0.4.0/go.mod h1:tO/chJN3obc5AbRYFQDsuFbL4wW5y8LfbPtDCfgwOVE= cloud.google.com/go/auth/oauth2adapt v0.2.2 h1:+TTV8aXpjeChS9M+aTtN/TjdQnzJvmzKFt//oWu7HX4= cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q= +cloud.google.com/go/compute v1.26.0 h1:uHf0NN2nvxl1Gh4QO83yRCOdMK4zivtMS5gv0dEX0hg= cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/iam v1.1.8 h1:r7umDwhj+BQyz0ScZMp4QrGXjSTI3ZINnpgU2nlB/K0= @@ -236,6 +239,7 @@ github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw= github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A= +github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0= github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= diff --git a/internal/acme/acme.go b/internal/acme/acme.go index 261c7140..409ef260 100644 --- a/internal/acme/acme.go +++ b/internal/acme/acme.go @@ -329,7 +329,7 @@ func (c *Configuration) getLockTime() (time.Time, error) { acmeLog(logger.LevelError, "unable to read lock file %q: %v", c.lockPath, err) return time.Time{}, err } - msec, err := strconv.ParseInt(strings.TrimSpace(string(content)), 10, 64) + msec, err := strconv.ParseInt(strings.TrimSpace(util.BytesToString(content)), 10, 64) if err != nil { acmeLog(logger.LevelError, "unable to parse lock time: %v", err) return time.Time{}, fmt.Errorf("unable to parse lock time: %w", err) diff --git a/internal/cmd/portable.go b/internal/cmd/portable.go index c9c32487..0a39fb20 100644 --- a/internal/cmd/portable.go +++ b/internal/cmd/portable.go @@ -196,7 +196,7 @@ Please take a look at the usage below to customize the serving parameters`, fmt.Printf("Unable to read password file %q: %v", portablePasswordFile, err) os.Exit(1) } - pwd = strings.TrimSpace(string(content)) + pwd = strings.TrimSpace(util.BytesToString(content)) } service.SetGraceTime(graceTime) service := service.Service{ @@ -523,7 +523,7 @@ func getFileContents(name string) (string, error) { if err != nil { return "", err } - return string(contents), nil + return util.BytesToString(contents), nil } func convertFsProvider() string { diff --git a/internal/common/actions.go b/internal/common/actions.go index cd9a9b49..446068c1 100644 --- a/internal/common/actions.go +++ b/internal/common/actions.go @@ -345,7 +345,7 @@ func notificationAsEnvVars(event *notifier.FsEvent) []string { if len(event.Metadata) > 0 { data, err := json.Marshal(event.Metadata) if err == nil { - result = append(result, fmt.Sprintf("SFTPGO_ACTION_METADATA=%s", string(data))) + result = append(result, fmt.Sprintf("SFTPGO_ACTION_METADATA=%s", util.BytesToString(data))) } } return result diff --git a/internal/common/dataretention.go b/internal/common/dataretention.go index 4ecc8c90..4f0f9aca 100644 --- a/internal/common/dataretention.go +++ b/internal/common/dataretention.go @@ -479,7 +479,7 @@ func (c *RetentionCheck) sendHookNotification(elapsed time.Duration, errCheck er cmd := exec.CommandContext(ctx, Config.DataRetentionHook, args...) cmd.Env = append(env, - fmt.Sprintf("SFTPGO_DATA_RETENTION_RESULT=%s", string(jsonData))) + fmt.Sprintf("SFTPGO_DATA_RETENTION_RESULT=%s", util.BytesToString(jsonData))) err := cmd.Run() c.conn.Log(logger.LevelDebug, "notified result using command: %q, elapsed: %s err: %v", diff --git a/internal/common/eventmanager.go b/internal/common/eventmanager.go index d8fbe7f8..2c4d45fa 100644 --- a/internal/common/eventmanager.go +++ b/internal/common/eventmanager.go @@ -811,7 +811,7 @@ func (p *EventParams) getStringReplacements(addObjectData, jsonEscaped bool) []s if addObjectData { data, err := p.Object.RenderAsJSON(p.Event != operationDelete) if err == nil { - dataString := string(data) + dataString := util.BytesToString(data) replacements[len(replacements)-3] = p.getStringReplacement(dataString, false) replacements[len(replacements)-1] = p.getStringReplacement(dataString, true) } @@ -826,7 +826,7 @@ func (p *EventParams) getStringReplacements(addObjectData, jsonEscaped bool) []s if len(p.Metadata) > 0 { data, err := json.Marshal(p.Metadata) if err == nil { - dataString := string(data) + dataString := util.BytesToString(data) replacements[len(replacements)-3] = p.getStringReplacement(dataString, false) replacements[len(replacements)-1] = p.getStringReplacement(dataString, true) } @@ -1466,7 +1466,8 @@ func executeHTTPRuleAction(c dataprovider.EventActionHTTPConfig, params *EventPa endpoint, time.Since(startTime), resp.StatusCode) if resp.StatusCode < http.StatusOK || resp.StatusCode > http.StatusNoContent { if rb, err := io.ReadAll(io.LimitReader(resp.Body, 2048)); err == nil { - eventManagerLog(logger.LevelDebug, "error notification response from endpoint %q: %s", endpoint, string(rb)) + eventManagerLog(logger.LevelDebug, "error notification response from endpoint %q: %s", + endpoint, util.BytesToString(rb)) } return fmt.Errorf("unexpected status code: %d", resp.StatusCode) } diff --git a/internal/dataprovider/actions.go b/internal/dataprovider/actions.go index 2b89459f..066b7bf7 100644 --- a/internal/dataprovider/actions.go +++ b/internal/dataprovider/actions.go @@ -148,7 +148,7 @@ func executeNotificationCommand(operation, executor, ip, objectType, objectName, fmt.Sprintf("SFTPGO_PROVIDER_IP=%s", ip), fmt.Sprintf("SFTPGO_PROVIDER_ROLE=%s", role), fmt.Sprintf("SFTPGO_PROVIDER_TIMESTAMP=%d", util.GetTimeAsMsSinceEpoch(time.Now())), - fmt.Sprintf("SFTPGO_PROVIDER_OBJECT=%s", string(objectAsJSON))) + fmt.Sprintf("SFTPGO_PROVIDER_OBJECT=%s", util.BytesToString(objectAsJSON))) startTime := time.Now() err := cmd.Run() diff --git a/internal/dataprovider/admin.go b/internal/dataprovider/admin.go index 8b11cb13..b88cbe00 100644 --- a/internal/dataprovider/admin.go +++ b/internal/dataprovider/admin.go @@ -297,7 +297,7 @@ func (a *Admin) hashPassword() error { if err != nil { return err } - a.Password = string(pwd) + a.Password = util.BytesToString(pwd) } else { pwd, err := argon2id.CreateHash(a.Password, argon2Params) if err != nil { diff --git a/internal/dataprovider/apikey.go b/internal/dataprovider/apikey.go index a493bd57..b6c8499d 100644 --- a/internal/dataprovider/apikey.go +++ b/internal/dataprovider/apikey.go @@ -118,7 +118,7 @@ func (k *APIKey) hashKey() error { if err != nil { return err } - k.Key = string(hashed) + k.Key = util.BytesToString(hashed) } else { hashed, err := argon2id.CreateHash(k.Key, argon2Params) if err != nil { diff --git a/internal/dataprovider/dataprovider.go b/internal/dataprovider/dataprovider.go index 11bf52a6..36512a47 100644 --- a/internal/dataprovider/dataprovider.go +++ b/internal/dataprovider/dataprovider.go @@ -3255,7 +3255,7 @@ func hashPlainPassword(plainPwd string) (string, error) { if err != nil { return "", fmt.Errorf("bcrypt hashing error: %w", err) } - return string(pwd), nil + return util.BytesToString(pwd), nil } pwd, err := argon2id.CreateHash(plainPwd, argon2Params) if err != nil { @@ -4115,7 +4115,7 @@ func getPreLoginHookResponse(loginMethod, ip, protocol string, userAsJSON []byte cmd := exec.CommandContext(ctx, config.PreLoginHook, args...) cmd.Env = append(env, - fmt.Sprintf("SFTPGO_LOGIND_USER=%s", string(userAsJSON)), + fmt.Sprintf("SFTPGO_LOGIND_USER=%s", util.BytesToString(userAsJSON)), fmt.Sprintf("SFTPGO_LOGIND_METHOD=%s", loginMethod), fmt.Sprintf("SFTPGO_LOGIND_IP=%s", ip), fmt.Sprintf("SFTPGO_LOGIND_PROTOCOL=%s", protocol), @@ -4162,7 +4162,7 @@ func executePreLoginHook(username, loginMethod, ip, protocol string, oidcTokenFi recoveryCodes := u.Filters.RecoveryCodes err = json.Unmarshal(out, &u) if err != nil { - return u, fmt.Errorf("invalid pre-login hook response %q, error: %v", string(out), err) + return u, fmt.Errorf("invalid pre-login hook response %q, error: %v", util.BytesToString(out), err) } u.ID = userID u.UsedQuotaSize = userUsedQuotaSize @@ -4257,7 +4257,7 @@ func ExecutePostLoginHook(user *User, loginMethod, ip, protocol string, err erro cmd := exec.CommandContext(ctx, config.PostLoginHook, args...) cmd.Env = append(env, - fmt.Sprintf("SFTPGO_LOGIND_USER=%s", string(userAsJSON)), + fmt.Sprintf("SFTPGO_LOGIND_USER=%s", util.BytesToString(userAsJSON)), fmt.Sprintf("SFTPGO_LOGIND_IP=%s", ip), fmt.Sprintf("SFTPGO_LOGIND_METHOD=%s", loginMethod), fmt.Sprintf("SFTPGO_LOGIND_STATUS=%s", status), @@ -4326,7 +4326,7 @@ func getExternalAuthResponse(username, password, pkey, keyboardInteractive, ip, cmd := exec.CommandContext(ctx, config.ExternalAuthHook, args...) cmd.Env = append(env, fmt.Sprintf("SFTPGO_AUTHD_USERNAME=%s", username), - fmt.Sprintf("SFTPGO_AUTHD_USER=%s", string(userAsJSON)), + fmt.Sprintf("SFTPGO_AUTHD_USER=%s", util.BytesToString(userAsJSON)), fmt.Sprintf("SFTPGO_AUTHD_IP=%s", ip), fmt.Sprintf("SFTPGO_AUTHD_PASSWORD=%s", password), fmt.Sprintf("SFTPGO_AUTHD_PUBLIC_KEY=%s", pkey), diff --git a/internal/dataprovider/node.go b/internal/dataprovider/node.go index 0354a37a..a1c8b2c4 100644 --- a/internal/dataprovider/node.go +++ b/internal/dataprovider/node.go @@ -99,7 +99,7 @@ func (n *NodeData) validate() error { if n.Proto != NodeProtoHTTP && n.Proto != NodeProtoHTTPS { return util.NewValidationError(fmt.Sprintf("invalid node proto: %s", n.Proto)) } - n.Key = kms.NewPlainSecret(string(util.GenerateRandomBytes(32))) + n.Key = kms.NewPlainSecret(util.BytesToString(util.GenerateRandomBytes(32))) n.Key.SetAdditionalData(n.Host) if err := n.Key.Encrypt(); err != nil { return fmt.Errorf("unable to encrypt node key: %w", err) @@ -191,7 +191,7 @@ func (n *Node) generateAuthToken(username, role string) (string, error) { if err != nil { return "", fmt.Errorf("unable to sign authentication token: %w", err) } - return string(payload), nil + return util.BytesToString(payload), nil } func (n *Node) prepareRequest(ctx context.Context, username, role, relativeURL, method string, diff --git a/internal/dataprovider/share.go b/internal/dataprovider/share.go index 83c08655..7e8a4798 100644 --- a/internal/dataprovider/share.go +++ b/internal/dataprovider/share.go @@ -155,7 +155,7 @@ func (s *Share) hashPassword() error { if err != nil { return err } - s.Password = string(hashed) + s.Password = util.BytesToString(hashed) } else { hashed, err := argon2id.CreateHash(s.Password, argon2Params) if err != nil { diff --git a/internal/ftpd/server.go b/internal/ftpd/server.go index dd234362..ecd1edb3 100644 --- a/internal/ftpd/server.go +++ b/internal/ftpd/server.go @@ -63,7 +63,7 @@ func NewServer(config *Configuration, configDir string, binding Binding, id int) } bannerContent, err := os.ReadFile(bannerFilePath) if err == nil { - server.initialMsg = string(bannerContent) + server.initialMsg = util.BytesToString(bannerContent) } else { logger.WarnToConsole("unable to read FTPD banner file: %v", err) logger.Warn(logSender, "", "unable to read banner file: %v", err) diff --git a/internal/httpd/api_defender.go b/internal/httpd/api_defender.go index e67d4560..8da5c3df 100644 --- a/internal/httpd/api_defender.go +++ b/internal/httpd/api_defender.go @@ -25,6 +25,7 @@ import ( "github.com/drakkan/sftpgo/v2/internal/common" "github.com/drakkan/sftpgo/v2/internal/dataprovider" + "github.com/drakkan/sftpgo/v2/internal/util" ) func getDefenderHosts(w http.ResponseWriter, r *http.Request) { @@ -76,7 +77,7 @@ func getIPFromID(r *http.Request) (string, error) { if err != nil { return "", errors.New("invalid host id") } - ip := string(decoded) + ip := util.BytesToString(decoded) err = validateIPAddress(ip) if err != nil { return "", err diff --git a/internal/httpd/webadmin.go b/internal/httpd/webadmin.go index 98f6851d..f8ffa63f 100644 --- a/internal/httpd/webadmin.go +++ b/internal/httpd/webadmin.go @@ -1594,7 +1594,7 @@ func getGCSConfig(r *http.Request) (vfs.GCSFsConfig, error) { } return config, err } - config.Credentials = kms.NewPlainSecret(string(fileBytes)) + config.Credentials = kms.NewPlainSecret(util.BytesToString(fileBytes)) config.AutomaticCredentials = 0 return config, err } diff --git a/internal/kms/builtin.go b/internal/kms/builtin.go index bac192d0..08a0f090 100644 --- a/internal/kms/builtin.go +++ b/internal/kms/builtin.go @@ -23,6 +23,7 @@ import ( "errors" "io" + "github.com/drakkan/sftpgo/v2/internal/util" sdkkms "github.com/sftpgo/sdk/kms" ) @@ -132,7 +133,7 @@ func (s *builtinSecret) Decrypt() error { return err } s.Status = sdkkms.SecretStatusPlain - s.Payload = string(plaintext) + s.Payload = util.BytesToString(plaintext) s.Key = "" s.AdditionalData = "" return nil diff --git a/internal/kms/local.go b/internal/kms/local.go index 4b1ac9cc..e6bb52c7 100644 --- a/internal/kms/local.go +++ b/internal/kms/local.go @@ -21,6 +21,7 @@ import ( "encoding/hex" "io" + "github.com/drakkan/sftpgo/v2/internal/util" sdkkms "github.com/sftpgo/sdk/kms" "gocloud.dev/secrets/localsecrets" "golang.org/x/crypto/hkdf" @@ -104,7 +105,7 @@ func (s *localSecret) Decrypt() error { return err } s.Status = sdkkms.SecretStatusPlain - s.Payload = string(plaintext) + s.Payload = util.BytesToString(plaintext) s.Key = "" s.AdditionalData = "" s.Mode = 0 diff --git a/internal/logger/logger.go b/internal/logger/logger.go index 2c58cfcc..a5191ee1 100644 --- a/internal/logger/logger.go +++ b/internal/logger/logger.go @@ -29,6 +29,7 @@ import ( "os" "path/filepath" "time" + "unsafe" ftpserverlog "github.com/fclairamb/go-log" "github.com/rs/zerolog" @@ -283,7 +284,7 @@ func (l *StdLoggerWrapper) Write(p []byte) (n int, err error) { p = p[0 : n-1] } - Log(LevelError, l.Sender, "", string(p)) + Log(LevelError, l.Sender, "", bytesToString(p)) return } @@ -363,3 +364,12 @@ func (l *LeveledLogger) With(keysAndValues ...any) ftpserverlog.Logger { additionalKeyVals: append(l.additionalKeyVals, keysAndValues...), } } + +func bytesToString(b []byte) string { + // unsafe.SliceData relies on cap whereas we want to rely on len + if len(b) == 0 { + return "" + } + // https://github.com/golang/go/blob/4ed358b57efdad9ed710be7f4fc51495a7620ce2/src/strings/builder.go#L41 + return unsafe.String(unsafe.SliceData(b), len(b)) +} diff --git a/internal/sftpd/server.go b/internal/sftpd/server.go index 8be4fede..94e18881 100644 --- a/internal/sftpd/server.go +++ b/internal/sftpd/server.go @@ -513,7 +513,7 @@ func (c *Configuration) configureLoginBanner(serverConfig *ssh.ServerConfig, con } bannerContent, err := os.ReadFile(bannerFilePath) if err == nil { - banner := string(bannerContent) + banner := util.BytesToString(bannerContent) serverConfig.BannerCallback = func(_ ssh.ConnMetadata) string { return banner } @@ -603,7 +603,8 @@ func (c *Configuration) AcceptInboundConnection(conn net.Conn, config *ssh.Serve logger.Log(logger.LevelInfo, common.ProtocolSSH, connectionID, "User %q logged in with %q, from ip %q, client version %q, negotiated algorithms: %+v", - user.Username, loginType, ipAddr, string(sconn.ClientVersion()), sconn.Conn.(ssh.AlgorithmsConnMetadata).Algorithms()) + user.Username, loginType, ipAddr, util.BytesToString(sconn.ClientVersion()), + sconn.Conn.(ssh.AlgorithmsConnMetadata).Algorithms()) dataprovider.UpdateLastLogin(&user) sshConnection := common.NewSSHConnection(connectionID, conn) @@ -639,12 +640,12 @@ func (c *Configuration) AcceptInboundConnection(conn net.Conn, config *ssh.Serve switch req.Type { case "subsystem": - if string(req.Payload[4:]) == "sftp" { + if util.BytesToString(req.Payload[4:]) == "sftp" { ok = true connection := &Connection{ BaseConnection: common.NewBaseConnection(connID, common.ProtocolSFTP, conn.LocalAddr().String(), conn.RemoteAddr().String(), user), - ClientVersion: string(sconn.ClientVersion()), + ClientVersion: util.BytesToString(sconn.ClientVersion()), RemoteAddr: conn.RemoteAddr(), LocalAddr: conn.LocalAddr(), channel: channel, @@ -656,7 +657,7 @@ func (c *Configuration) AcceptInboundConnection(conn net.Conn, config *ssh.Serve connection := Connection{ BaseConnection: common.NewBaseConnection(connID, "sshd_exec", conn.LocalAddr().String(), conn.RemoteAddr().String(), user), - ClientVersion: string(sconn.ClientVersion()), + ClientVersion: util.BytesToString(sconn.ClientVersion()), RemoteAddr: conn.RemoteAddr(), LocalAddr: conn.LocalAddr(), channel: channel, @@ -816,7 +817,7 @@ func loginUser(user *dataprovider.User, loginMethod, publicKey string, conn ssh. } p := &ssh.Permissions{} p.Extensions = make(map[string]string) - p.Extensions["sftpgo_user"] = string(json) + p.Extensions["sftpgo_user"] = util.BytesToString(json) p.Extensions["sftpgo_login_method"] = loginMethod return p, nil } @@ -1180,7 +1181,7 @@ func (c *Configuration) validatePasswordCredentials(conn ssh.ConnMetadata, pass var sshPerm *ssh.Permissions ipAddr := util.GetIPFromRemoteAddress(conn.RemoteAddr().String()) - if user, err = dataprovider.CheckUserAndPass(conn.User(), string(pass), ipAddr, common.ProtocolSSH); err == nil { + if user, err = dataprovider.CheckUserAndPass(conn.User(), util.BytesToString(pass), ipAddr, common.ProtocolSSH); err == nil { sshPerm, err = loginUser(&user, method, "", conn) } user.Username = conn.User() diff --git a/internal/util/i18n.go b/internal/util/i18n.go index 0c578794..fd8dba70 100644 --- a/internal/util/i18n.go +++ b/internal/util/i18n.go @@ -367,7 +367,7 @@ func (e *I18nError) Args() string { if len(e.args) > 0 { data, err := json.Marshal(e.args) if err == nil { - return string(data) + return BytesToString(data) } } return "{}" diff --git a/internal/util/util.go b/internal/util/util.go index 353b6464..8c9041c1 100644 --- a/internal/util/util.go +++ b/internal/util/util.go @@ -44,6 +44,7 @@ import ( "strings" "time" "unicode" + "unsafe" "github.com/google/uuid" "github.com/lithammer/shortuuid/v3" @@ -288,6 +289,16 @@ func ParseBytes(s string) (int64, error) { return 0, fmt.Errorf("unhandled size name: %v", extra) } +// BytesToString converts []byte to string without allocations. +func BytesToString(b []byte) string { + // unsafe.SliceData relies on cap whereas we want to rely on len + if len(b) == 0 { + return "" + } + // https://github.com/golang/go/blob/4ed358b57efdad9ed710be7f4fc51495a7620ce2/src/strings/builder.go#L41 + return unsafe.String(unsafe.SliceData(b), len(b)) +} + // GetIPFromRemoteAddress returns the IP from the remote address. // If the given remote address cannot be parsed it will be returned unchanged func GetIPFromRemoteAddress(remoteAddress string) string { @@ -660,7 +671,7 @@ func EncodeTLSCertToPem(tlsCert *x509.Certificate) (string, error) { Type: "CERTIFICATE", Bytes: tlsCert.Raw, } - return string(pem.EncodeToMemory(&publicKeyBlock)), nil + return BytesToString(pem.EncodeToMemory(&publicKeyBlock)), nil } // CheckTCP4Port quits the app if bind on the given IPv4 port fails. @@ -704,7 +715,7 @@ func GetSSHPublicKeyAsString(pubKey []byte) (string, error) { if err != nil { return "", err } - return string(ssh.MarshalAuthorizedKey(k)), nil + return BytesToString(ssh.MarshalAuthorizedKey(k)), nil } // GetRealIP returns the ip address as result of parsing the specified @@ -880,7 +891,7 @@ func JSONEscape(val string) string { if err != nil { return "" } - return string(b[1 : len(b)-1]) + return BytesToString(b[1 : len(b)-1]) } // ReadConfigFromFile reads a configuration parameter from the specified file @@ -901,5 +912,5 @@ func ReadConfigFromFile(name, configDir string) (string, error) { if err != nil { return "", err } - return strings.TrimSpace(string(val)), nil + return strings.TrimSpace(BytesToString(val)), nil } diff --git a/internal/webdavd/file.go b/internal/webdavd/file.go index a8529299..345c2714 100644 --- a/internal/webdavd/file.go +++ b/internal/webdavd/file.go @@ -448,10 +448,10 @@ func (f *webDavFile) Patch(patches []webdav.Proppatch) ([]webdav.Propstat, error for _, p := range patch.Props { if status == http.StatusForbidden && !hasError { if !patch.Remove && util.Contains(lastModifiedProps, p.XMLName.Local) { - parsed, err := parseTime(string(p.InnerXML)) + parsed, err := parseTime(util.BytesToString(p.InnerXML)) if err != nil { f.Connection.Log(logger.LevelWarn, "unsupported last modification time: %q, err: %v", - string(p.InnerXML), err) + util.BytesToString(p.InnerXML), err) hasError = true continue }