1
0
mirror of https://github.com/rclone/rclone.git synced 2025-12-10 21:33:27 +00:00

config: fix problem reading pasted tokens over 4095 bytes

Before this change we were reading input from stdin using the terminal
in the default line mode which has a limit of 4095 characters.

The typical culprit was onedrive tokens (which are very long) giving the error

    Couldn't decode response: invalid character 'e' looking for beginning of value

This change swaps over to use the github.com/peterh/liner read line
library which does not have that limitation and also enables more
sensible cursor editing.

Fixes #8688 #8323 #5835
This commit is contained in:
Nick Craig-Wood
2025-08-13 15:26:48 +01:00
parent 8d878d0a5f
commit b0b3b04b3b
6 changed files with 32 additions and 23 deletions

View File

@@ -17,7 +17,7 @@ import (
func ReadPassword() string {
stdin := int(os.Stdin.Fd())
if !terminal.IsTerminal(stdin) {
return ReadLine()
return ReadLine("")
}
line, err := terminal.ReadPassword(stdin)
_, _ = fmt.Fprintln(os.Stderr)

View File

@@ -7,5 +7,5 @@ package config
// ReadPassword reads a password with echoing it to the terminal.
func ReadPassword() string {
return ReadLine()
return ReadLine("")
}

View File

@@ -3,7 +3,6 @@
package config
import (
"bufio"
"context"
"errors"
"fmt"
@@ -15,6 +14,7 @@ import (
"strings"
"unicode/utf8"
"github.com/peterh/liner"
"github.com/rclone/rclone/fs"
"github.com/rclone/rclone/fs/config/configmap"
"github.com/rclone/rclone/fs/config/configstruct"
@@ -25,12 +25,22 @@ import (
"golang.org/x/text/unicode/norm"
)
// ReadLine reads some input
var ReadLine = func() string {
buf := bufio.NewReader(os.Stdin)
line, err := buf.ReadString('\n')
if err != nil && (line == "" || err != io.EOF) {
fs.Fatalf(nil, "Failed to read line: %v", err)
// ReadLine reads an unlimited length line from stdin with a prompt.
var ReadLine = func(prompt string) string {
l := liner.NewLiner()
defer func() {
_ = l.Close()
}()
l.SetMultiLineMode(true)
l.SetCtrlCAborts(true)
line, err := l.Prompt(prompt)
if err == io.EOF {
return ""
}
if err != nil {
_ = l.Close()
fs.Fatalf(nil, "Failed to read: %v", err)
}
return strings.TrimSpace(line)
}
@@ -39,8 +49,7 @@ var ReadLine = func() string {
func ReadNonEmptyLine(prompt string) string {
result := ""
for result == "" {
fmt.Print(prompt)
result = strings.TrimSpace(ReadLine())
result = strings.TrimSpace(ReadLine(prompt))
}
return result
}
@@ -63,8 +72,7 @@ func CommandDefault(commands []string, defaultIndex int) byte {
optString := strings.Join(opts, "")
optHelp := strings.Join(opts, "/")
for {
fmt.Printf("%s> ", optHelp)
result := strings.ToLower(ReadLine())
result := strings.ToLower(ReadLine(fmt.Sprintf("%s> ", optHelp)))
if len(result) == 0 {
if defaultIndex >= 0 {
return optString[defaultIndex]
@@ -146,8 +154,7 @@ func Choose(what string, kind string, choices, help []string, defaultValue strin
terminal.WriteString(terminal.Reset)
}
for {
fmt.Printf("%s> ", what)
result := ReadLine()
result := ReadLine(fmt.Sprintf("%s> ", what))
i, err := strconv.Atoi(result)
if err != nil {
if slices.Contains(choices, result) {
@@ -194,8 +201,7 @@ func Enter(what string, kind string, defaultValue string, required bool) string
fmt.Println()
}
for {
fmt.Printf("%s> ", what)
result := ReadLine()
result := ReadLine(fmt.Sprintf("%s> ", what))
if !required || result != "" {
return result
}
@@ -254,8 +260,7 @@ func ChoosePassword(defaultValue string, required bool) string {
// inclusive prompting them with what.
func ChooseNumber(what string, min, max int) int {
for {
fmt.Printf("%s> ", what)
result := ReadLine()
result := ReadLine(fmt.Sprintf("%s> ", what))
i, err := strconv.Atoi(result)
if err != nil {
fmt.Printf("Bad number: %v\n", err)
@@ -526,8 +531,7 @@ func ChooseOption(o *fs.Option, name string) string {
func NewRemoteName() (name string) {
for {
fmt.Println("Enter name for new remote.")
fmt.Printf("name> ")
name = ReadLine()
name = ReadLine("name> ")
if LoadedData().HasSection(name) {
fmt.Printf("Remote %q already exists.\n", name)
continue

View File

@@ -85,9 +85,9 @@ func testConfigFile(t *testing.T, options []fs.Option, configFileName string) fu
// makeReadLine makes a simple readLine which returns a fixed list of
// strings
func makeReadLine(answers []string) func() string {
func makeReadLine(answers []string) func(string) string {
i := 0
return func() string {
return func(string) string {
i++
return answers[i-1]
}

1
go.mod
View File

@@ -56,6 +56,7 @@ require (
github.com/ncw/swift/v2 v2.0.4
github.com/oracle/oci-go-sdk/v65 v65.98.0
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/peterh/liner v1.2.2
github.com/pkg/sftp v1.13.9
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2
github.com/prometheus/client_golang v1.23.0

4
go.sum
View File

@@ -454,6 +454,7 @@ github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHP
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/minio/crc64nvme v1.1.1 h1:8dwx/Pz49suywbO+auHCBpCtlW1OfpcLN7wYgVR6wAI=
@@ -500,6 +501,8 @@ github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/pengsrc/go-shared v0.2.1-0.20190131101655-1999055a4a14 h1:XeOYlK9W1uCmhjJSsY78Mcuh7MVkNjTzmHx1yBzizSU=
github.com/pengsrc/go-shared v0.2.1-0.20190131101655-1999055a4a14/go.mod h1:jVblp62SafmidSkvWrXyxAme3gaTfEtWwRPGz5cpvHg=
github.com/peterh/liner v1.2.2 h1:aJ4AOodmL+JxOZZEL2u9iJf8omNRpqHc/EbrK+3mAXw=
github.com/peterh/liner v1.2.2/go.mod h1:xFwJyiKIXJZUKItq5dGHZSTBRAuG/CpeNpWLyiNRNwI=
github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM=
github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
@@ -845,6 +848,7 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=