Skip to content

Commit bfb6dd6

Browse files
authored
fix quoted, space separated, HASH parameters (#459) by @drakkan as suggested by @syncplify
1 parent 1586bde commit bfb6dd6

File tree

2 files changed

+72
-20
lines changed

2 files changed

+72
-20
lines changed

handle_files.go

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -606,9 +606,14 @@ func (c *clientHandler) handleGenericHash(param string, algo HASHAlgo, isCustomM
606606
return nil
607607
}
608608

609-
args := strings.SplitN(param, " ", 3)
610-
info, err := c.driver.Stat(args[0])
609+
args, err := unquoteSpaceSeparatedParams(param)
610+
if err != nil || len(args) == 0 {
611+
c.writeMessage(StatusSyntaxErrorParameters, fmt.Sprintf("invalid HASH parameters: %v", param))
612+
613+
return nil //nolint:nilerr
614+
}
611615

616+
info, err := c.driver.Stat(args[0])
612617
if err != nil {
613618
c.writeMessage(StatusActionNotTaken, fmt.Sprintf("%v: %v", param, err))
614619

@@ -627,25 +632,11 @@ func (c *clientHandler) handleGenericHash(param string, algo HASHAlgo, isCustomM
627632
// to support partial hash also for the HASH command, we should implement RANG,
628633
// but it applies also to uploads/downloads and so it complicates their handling,
629634
// we'll add this support in future improvements
630-
if isCustomMode { //nolint:nestif // too much effort to change for now
631-
// for custom command the range can be specified in this way:
632-
// XSHA1 <file> <start> <end>
633-
if len(args) > 1 {
634-
start, err = strconv.ParseInt(args[1], 10, 64)
635-
if err != nil {
636-
c.writeMessage(StatusSyntaxErrorParameters, fmt.Sprintf("invalid start offset %v: %v", args[1], err))
637-
638-
return nil
639-
}
640-
}
641-
642-
if len(args) > 2 {
643-
end, err = strconv.ParseInt(args[2], 10, 64)
644-
if err != nil {
645-
c.writeMessage(StatusSyntaxErrorParameters, fmt.Sprintf("invalid end offset %v: %v", args[2], err))
635+
if isCustomMode {
636+
if err = getPartialHASHRange(args, &start, &end); err != nil {
637+
c.writeMessage(StatusSyntaxErrorParameters, err.Error())
646638

647-
return nil
648-
}
639+
return nil
649640
}
650641
}
651642

@@ -747,6 +738,30 @@ func (c *clientHandler) closeUnchecked(file io.Closer) {
747738
}
748739
}
749740

741+
func getPartialHASHRange(args []string, start *int64, end *int64) error {
742+
// for custom HASH commands the range can be specified in this way:
743+
// XSHA1 <file> <start> <end>
744+
if len(args) > 1 {
745+
val, err := strconv.ParseInt(args[1], 10, 64)
746+
if err != nil {
747+
return fmt.Errorf("invalid start offset %v: %w", args[1], err)
748+
}
749+
750+
*start = val
751+
}
752+
753+
if len(args) > 2 {
754+
val, err := strconv.ParseInt(args[2], 10, 64)
755+
if err != nil {
756+
return fmt.Errorf("invalid end offset %v: %w", args[1], err)
757+
}
758+
759+
*end = val
760+
}
761+
762+
return nil
763+
}
764+
750765
// This method split params by spaces, except when the space is inside quotes.
751766
// It was introduced to support COMB command. Supported COMB examples:
752767
//

handle_files_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,7 @@ func TestHASHCommand(t *testing.T) {
546546
sha256Hash := "ceee704dd96e2b8c2ceca59c4c697bc01123fb9e66a1a3ac34dbdd2d6da9659b"
547547

548548
ftpUpload(t, client, tempFile, "file.txt")
549+
ftpUpload(t, client, tempFile, "file with space.txt")
549550

550551
raw, err := client.OpenRawConn()
551552
require.NoError(t, err, "Couldn't open raw connection")
@@ -562,6 +563,11 @@ func TestHASHCommand(t *testing.T) {
562563
require.NoError(t, err)
563564
require.Equal(t, StatusFileStatus, returnCode)
564565
require.True(t, strings.HasSuffix(message, fmt.Sprintf("SHA-256 0-36 %v file.txt", sha256Hash)))
566+
// test the same quoting the file name
567+
returnCode, message, err = raw.SendCommand(`HASH "file with space.txt"`)
568+
require.NoError(t, err)
569+
require.Equal(t, StatusFileStatus, returnCode)
570+
require.True(t, strings.HasSuffix(message, fmt.Sprintf("SHA-256 0-36 %v file with space.txt", sha256Hash)))
565571

566572
// change algo and request the hash again
567573
returnCode, message, err = raw.SendCommand("OPTS HASH CRC32")
@@ -575,6 +581,37 @@ func TestHASHCommand(t *testing.T) {
575581
require.True(t, strings.HasSuffix(message, fmt.Sprintf("CRC32 0-36 %v file.txt", crc32Sum)))
576582
}
577583

584+
func TestHashWithoutParams(t *testing.T) {
585+
server := NewTestServerWithTestDriver(
586+
t,
587+
&TestServerDriver{
588+
Debug: false,
589+
Settings: &Settings{
590+
EnableHASH: true,
591+
},
592+
},
593+
)
594+
conf := goftp.Config{
595+
User: authUser,
596+
Password: authPass,
597+
}
598+
599+
client, err := goftp.DialConfig(conf, server.Addr())
600+
require.NoError(t, err, "Couldn't connect")
601+
602+
defer func() { panicOnError(client.Close()) }()
603+
604+
raw, err := client.OpenRawConn()
605+
require.NoError(t, err, "Couldn't open raw connection")
606+
607+
defer func() { require.NoError(t, raw.Close()) }()
608+
609+
returnCode, message, err := raw.SendCommand("HASH")
610+
require.NoError(t, err)
611+
require.Equal(t, StatusSyntaxErrorParameters, returnCode)
612+
require.Contains(t, message, "invalid HASH parameters")
613+
}
614+
578615
func TestCustomHASHCommands(t *testing.T) {
579616
server := NewTestServer(t, false)
580617
server.settings.EnableHASH = true

0 commit comments

Comments
 (0)