internal_test.go 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227
  1. package sftpd
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io"
  6. "io/ioutil"
  7. "net"
  8. "os"
  9. "runtime"
  10. "strings"
  11. "testing"
  12. "time"
  13. "github.com/drakkan/sftpgo/dataprovider"
  14. "github.com/drakkan/sftpgo/utils"
  15. "github.com/pkg/sftp"
  16. )
  17. type MockChannel struct {
  18. Buffer *bytes.Buffer
  19. StdErrBuffer *bytes.Buffer
  20. ReadError error
  21. WriteError error
  22. ShortWriteErr bool
  23. }
  24. func (c *MockChannel) Read(data []byte) (int, error) {
  25. if c.ReadError != nil {
  26. return 0, c.ReadError
  27. }
  28. return c.Buffer.Read(data)
  29. }
  30. func (c *MockChannel) Write(data []byte) (int, error) {
  31. if c.WriteError != nil {
  32. return 0, c.WriteError
  33. }
  34. if c.ShortWriteErr {
  35. return 0, nil
  36. }
  37. return c.Buffer.Write(data)
  38. }
  39. func (c *MockChannel) Close() error {
  40. return nil
  41. }
  42. func (c *MockChannel) CloseWrite() error {
  43. return nil
  44. }
  45. func (c *MockChannel) SendRequest(name string, wantReply bool, payload []byte) (bool, error) {
  46. return true, nil
  47. }
  48. func (c *MockChannel) Stderr() io.ReadWriter {
  49. return c.StdErrBuffer
  50. }
  51. func TestWrongActions(t *testing.T) {
  52. actionsCopy := actions
  53. badCommand := "/bad/command"
  54. if runtime.GOOS == "windows" {
  55. badCommand = "C:\\bad\\command"
  56. }
  57. actions = Actions{
  58. ExecuteOn: []string{operationDownload},
  59. Command: badCommand,
  60. HTTPNotificationURL: "",
  61. }
  62. err := executeAction(operationDownload, "username", "path", "", "", 0)
  63. if err == nil {
  64. t.Errorf("action with bad command must fail")
  65. }
  66. err = executeAction(operationDelete, "username", "path", "", "", 0)
  67. if err != nil {
  68. t.Errorf("action not configured must silently fail")
  69. }
  70. actions.Command = ""
  71. actions.HTTPNotificationURL = "http://foo\x7f.com/"
  72. err = executeAction(operationDownload, "username", "path", "", "", 0)
  73. if err == nil {
  74. t.Errorf("action with bad url must fail")
  75. }
  76. actions = actionsCopy
  77. }
  78. func TestRemoveNonexistentTransfer(t *testing.T) {
  79. transfer := Transfer{}
  80. err := removeTransfer(&transfer)
  81. if err == nil {
  82. t.Errorf("remove nonexistent transfer must fail")
  83. }
  84. }
  85. func TestRemoveNonexistentQuotaScan(t *testing.T) {
  86. err := RemoveQuotaScan("username")
  87. if err == nil {
  88. t.Errorf("remove nonexistent transfer must fail")
  89. }
  90. }
  91. func TestGetOSOpenFlags(t *testing.T) {
  92. var flags sftp.FileOpenFlags
  93. flags.Write = true
  94. flags.Excl = true
  95. osFlags := getOSOpenFlags(flags)
  96. if osFlags&os.O_WRONLY == 0 || osFlags&os.O_EXCL == 0 {
  97. t.Errorf("error getting os flags from sftp file open flags")
  98. }
  99. flags.Append = true
  100. // append flag should be ignored to allow resume
  101. if osFlags&os.O_WRONLY == 0 || osFlags&os.O_EXCL == 0 {
  102. t.Errorf("error getting os flags from sftp file open flags")
  103. }
  104. }
  105. func TestUploadResumeInvalidOffset(t *testing.T) {
  106. testfile := "testfile"
  107. file, _ := os.Create(testfile)
  108. transfer := Transfer{
  109. file: file,
  110. path: file.Name(),
  111. start: time.Now(),
  112. bytesSent: 0,
  113. bytesReceived: 0,
  114. user: dataprovider.User{
  115. Username: "testuser",
  116. },
  117. connectionID: "",
  118. transferType: transferUpload,
  119. lastActivity: time.Now(),
  120. isNewFile: false,
  121. protocol: protocolSFTP,
  122. transferError: nil,
  123. isFinished: false,
  124. minWriteOffset: 10,
  125. }
  126. _, err := transfer.WriteAt([]byte("test"), 0)
  127. if err == nil {
  128. t.Errorf("upload with invalid offset must fail")
  129. }
  130. os.Remove(testfile)
  131. }
  132. func TestUploadFiles(t *testing.T) {
  133. oldUploadMode := uploadMode
  134. uploadMode = uploadModeAtomic
  135. c := Connection{}
  136. var flags sftp.FileOpenFlags
  137. flags.Write = true
  138. flags.Trunc = true
  139. _, err := c.handleSFTPUploadToExistingFile(flags, "missing_path", "other_missing_path", 0)
  140. if err == nil {
  141. t.Errorf("upload to existing file must fail if one or both paths are invalid")
  142. }
  143. uploadMode = uploadModeStandard
  144. _, err = c.handleSFTPUploadToExistingFile(flags, "missing_path", "other_missing_path", 0)
  145. if err == nil {
  146. t.Errorf("upload to existing file must fail if one or both paths are invalid")
  147. }
  148. missingFile := "missing/relative/file.txt"
  149. if runtime.GOOS == "windows" {
  150. missingFile = "missing\\relative\\file.txt"
  151. }
  152. _, err = c.handleSFTPUploadToNewFile(".", missingFile)
  153. if err == nil {
  154. t.Errorf("upload new file in missing path must fail")
  155. }
  156. uploadMode = oldUploadMode
  157. }
  158. func TestWithInvalidHome(t *testing.T) {
  159. u := dataprovider.User{}
  160. u.HomeDir = "home_rel_path"
  161. _, err := loginUser(u, "password", "")
  162. if err == nil {
  163. t.Errorf("login a user with an invalid home_dir must fail")
  164. }
  165. c := Connection{
  166. User: u,
  167. }
  168. err = c.isSubDir("dir_rel_path")
  169. if err == nil {
  170. t.Errorf("tested path is not a home subdir")
  171. }
  172. }
  173. func TestSFTPCmdTargetPath(t *testing.T) {
  174. u := dataprovider.User{}
  175. u.HomeDir = "home_rel_path"
  176. u.Username = "test"
  177. u.Permissions = make(map[string][]string)
  178. u.Permissions["/"] = []string{dataprovider.PermAny}
  179. connection := Connection{
  180. User: u,
  181. }
  182. _, err := connection.getSFTPCmdTargetPath("invalid_path")
  183. if err != sftp.ErrSSHFxNoSuchFile {
  184. t.Errorf("getSFTPCmdTargetPath must fal with the expected error: %v", err)
  185. }
  186. }
  187. func TestGetSFTPErrorFromOSError(t *testing.T) {
  188. err := os.ErrNotExist
  189. err = getSFTPErrorFromOSError(err)
  190. if err != sftp.ErrSSHFxNoSuchFile {
  191. t.Errorf("unexpected error: %v", err)
  192. }
  193. err = os.ErrPermission
  194. err = getSFTPErrorFromOSError(err)
  195. if err != sftp.ErrSSHFxPermissionDenied {
  196. t.Errorf("unexpected error: %v", err)
  197. }
  198. err = getSFTPErrorFromOSError(nil)
  199. if err != nil {
  200. t.Errorf("unexpected error: %v", err)
  201. }
  202. }
  203. func TestSetstatModeIgnore(t *testing.T) {
  204. originalMode := setstatMode
  205. setstatMode = 1
  206. connection := Connection{}
  207. err := connection.handleSFTPSetstat("invalid", nil)
  208. if err != nil {
  209. t.Errorf("unexpected error: %v setstat should be silently ignore in mode 1", err)
  210. }
  211. setstatMode = 0
  212. req := sftp.NewRequest("Setstat", "invalid")
  213. err = connection.handleSFTPSetstat("invalid", req)
  214. if err != sftp.ErrSSHFxBadMessage {
  215. t.Errorf("unexpected error: %v", err)
  216. }
  217. setstatMode = originalMode
  218. }
  219. func TestSFTPGetUsedQuota(t *testing.T) {
  220. u := dataprovider.User{}
  221. u.HomeDir = "home_rel_path"
  222. u.Username = "test_invalid_user"
  223. u.QuotaSize = 4096
  224. u.QuotaFiles = 1
  225. u.Permissions = make(map[string][]string)
  226. u.Permissions["/"] = []string{dataprovider.PermAny}
  227. connection := Connection{
  228. User: u,
  229. }
  230. res := connection.hasSpace(false)
  231. if res != false {
  232. t.Errorf("has space must return false if the user is invalid")
  233. }
  234. }
  235. func TestSupportedSSHCommands(t *testing.T) {
  236. cmds := GetSupportedSSHCommands()
  237. if len(cmds) != len(supportedSSHCommands) {
  238. t.Errorf("supported ssh commands does not match")
  239. }
  240. for _, c := range cmds {
  241. if !utils.IsStringInSlice(c, supportedSSHCommands) {
  242. t.Errorf("invalid ssh command: %v", c)
  243. }
  244. }
  245. }
  246. func TestSSHCommandPath(t *testing.T) {
  247. buf := make([]byte, 65535)
  248. stdErrBuf := make([]byte, 65535)
  249. mockSSHChannel := MockChannel{
  250. Buffer: bytes.NewBuffer(buf),
  251. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  252. ReadError: nil,
  253. }
  254. connection := Connection{
  255. channel: &mockSSHChannel,
  256. }
  257. sshCommand := sshCommand{
  258. command: "test",
  259. connection: connection,
  260. args: []string{},
  261. }
  262. path := sshCommand.getDestPath()
  263. if path != "" {
  264. t.Errorf("path must be empty")
  265. }
  266. sshCommand.args = []string{"-t", "/tmp/../path"}
  267. path = sshCommand.getDestPath()
  268. if path != "/path" {
  269. t.Errorf("unexpected path: %v", path)
  270. }
  271. sshCommand.args = []string{"-t", "/tmp/"}
  272. path = sshCommand.getDestPath()
  273. if path != "/tmp/" {
  274. t.Errorf("unexpected path: %v", path)
  275. }
  276. sshCommand.args = []string{"-t", "tmp/"}
  277. path = sshCommand.getDestPath()
  278. if path != "/tmp/" {
  279. t.Errorf("unexpected path: %v", path)
  280. }
  281. sshCommand.args = []string{"-t", "/tmp/../../../path"}
  282. path = sshCommand.getDestPath()
  283. if path != "/path" {
  284. t.Errorf("unexpected path: %v", path)
  285. }
  286. sshCommand.args = []string{"-t", ".."}
  287. path = sshCommand.getDestPath()
  288. if path != "/" {
  289. t.Errorf("unexpected path: %v", path)
  290. }
  291. sshCommand.args = []string{"-t", "."}
  292. path = sshCommand.getDestPath()
  293. if path != "/" {
  294. t.Errorf("unexpected path: %v", path)
  295. }
  296. sshCommand.args = []string{"-t", "//"}
  297. path = sshCommand.getDestPath()
  298. if path != "/" {
  299. t.Errorf("unexpected path: %v", path)
  300. }
  301. sshCommand.args = []string{"-t", "../.."}
  302. path = sshCommand.getDestPath()
  303. if path != "/" {
  304. t.Errorf("unexpected path: %v", path)
  305. }
  306. sshCommand.args = []string{"-t", "/.."}
  307. path = sshCommand.getDestPath()
  308. if path != "/" {
  309. t.Errorf("unexpected path: %v", path)
  310. }
  311. }
  312. func TestSSHCommandErrors(t *testing.T) {
  313. buf := make([]byte, 65535)
  314. stdErrBuf := make([]byte, 65535)
  315. readErr := fmt.Errorf("test read error")
  316. mockSSHChannel := MockChannel{
  317. Buffer: bytes.NewBuffer(buf),
  318. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  319. ReadError: readErr,
  320. }
  321. server, client := net.Pipe()
  322. defer server.Close()
  323. defer client.Close()
  324. user := dataprovider.User{}
  325. user.Permissions = make(map[string][]string)
  326. user.Permissions["/"] = []string{dataprovider.PermAny}
  327. connection := Connection{
  328. channel: &mockSSHChannel,
  329. netConn: client,
  330. User: user,
  331. }
  332. cmd := sshCommand{
  333. command: "md5sum",
  334. connection: connection,
  335. args: []string{},
  336. }
  337. err := cmd.handle()
  338. if err == nil {
  339. t.Errorf("ssh command must fail, we are sending a fake error")
  340. }
  341. cmd = sshCommand{
  342. command: "md5sum",
  343. connection: connection,
  344. args: []string{"/../../test_file.dat"},
  345. }
  346. err = cmd.handle()
  347. if err == nil {
  348. t.Errorf("ssh command must fail, we are requesting an invalid path")
  349. }
  350. cmd = sshCommand{
  351. command: "git-receive-pack",
  352. connection: connection,
  353. args: []string{"/../../testrepo"},
  354. }
  355. err = cmd.handle()
  356. if err == nil {
  357. t.Errorf("ssh command must fail, we are requesting an invalid path")
  358. }
  359. cmd.connection.User.HomeDir = os.TempDir()
  360. cmd.connection.User.QuotaFiles = 1
  361. cmd.connection.User.UsedQuotaFiles = 2
  362. err = cmd.handle()
  363. if err != errQuotaExceeded {
  364. t.Errorf("unexpected error: %v", err)
  365. }
  366. cmd.connection.User.QuotaFiles = 0
  367. cmd.connection.User.UsedQuotaFiles = 0
  368. cmd.connection.User.Permissions = make(map[string][]string)
  369. cmd.connection.User.Permissions["/"] = []string{dataprovider.PermListItems}
  370. err = cmd.handle()
  371. if err != errPermissionDenied {
  372. t.Errorf("unexpected error: %v", err)
  373. }
  374. cmd.connection.User.Permissions["/"] = []string{dataprovider.PermAny}
  375. cmd.command = "invalid_command"
  376. command, err := cmd.getSystemCommand()
  377. if err != nil {
  378. t.Errorf("unexpected error: %v", err)
  379. }
  380. err = cmd.executeSystemCommand(command)
  381. if err == nil {
  382. t.Errorf("invalid command must fail")
  383. }
  384. command, err = cmd.getSystemCommand()
  385. if err != nil {
  386. t.Errorf("unexpected error: %v", err)
  387. }
  388. command.cmd.StderrPipe()
  389. err = cmd.executeSystemCommand(command)
  390. if err == nil {
  391. t.Errorf("command must fail, pipe was already assigned")
  392. }
  393. err = cmd.executeSystemCommand(command)
  394. if err == nil {
  395. t.Errorf("command must fail, pipe was already assigned")
  396. }
  397. command, err = cmd.getSystemCommand()
  398. if err != nil {
  399. t.Errorf("unexpected error: %v", err)
  400. }
  401. command.cmd.StdoutPipe()
  402. err = cmd.executeSystemCommand(command)
  403. if err == nil {
  404. t.Errorf("command must fail, pipe was already assigned")
  405. }
  406. }
  407. func TestSSHCommandQuotaScan(t *testing.T) {
  408. buf := make([]byte, 65535)
  409. stdErrBuf := make([]byte, 65535)
  410. readErr := fmt.Errorf("test read error")
  411. mockSSHChannel := MockChannel{
  412. Buffer: bytes.NewBuffer(buf),
  413. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  414. ReadError: readErr,
  415. }
  416. server, client := net.Pipe()
  417. defer server.Close()
  418. defer client.Close()
  419. permissions := make(map[string][]string)
  420. permissions["/"] = []string{dataprovider.PermAny}
  421. connection := Connection{
  422. channel: &mockSSHChannel,
  423. netConn: client,
  424. User: dataprovider.User{
  425. Permissions: permissions,
  426. QuotaFiles: 1,
  427. HomeDir: "invalid_path",
  428. },
  429. }
  430. cmd := sshCommand{
  431. command: "git-receive-pack",
  432. connection: connection,
  433. args: []string{"/testrepo"},
  434. }
  435. err := cmd.rescanHomeDir()
  436. if err == nil {
  437. t.Errorf("scanning an invalid home dir must fail")
  438. }
  439. }
  440. func TestRsyncOptions(t *testing.T) {
  441. permissions := make(map[string][]string)
  442. permissions["/"] = []string{dataprovider.PermAny}
  443. conn := Connection{
  444. User: dataprovider.User{
  445. Permissions: permissions,
  446. HomeDir: os.TempDir(),
  447. },
  448. }
  449. sshCmd := sshCommand{
  450. command: "rsync",
  451. connection: conn,
  452. args: []string{"--server", "-vlogDtprze.iLsfxC", ".", "/"},
  453. }
  454. cmd, err := sshCmd.getSystemCommand()
  455. if err != nil {
  456. t.Errorf("unexpected error: %v", err)
  457. }
  458. if !utils.IsStringInSlice("--safe-links", cmd.cmd.Args) {
  459. t.Errorf("--safe-links must be added if the user has the create symlinks permission")
  460. }
  461. permissions["/"] = []string{dataprovider.PermDownload, dataprovider.PermUpload, dataprovider.PermCreateDirs,
  462. dataprovider.PermListItems, dataprovider.PermOverwrite, dataprovider.PermDelete, dataprovider.PermRename}
  463. conn = Connection{
  464. User: dataprovider.User{
  465. Permissions: permissions,
  466. HomeDir: os.TempDir(),
  467. },
  468. }
  469. sshCmd = sshCommand{
  470. command: "rsync",
  471. connection: conn,
  472. args: []string{"--server", "-vlogDtprze.iLsfxC", ".", "/"},
  473. }
  474. cmd, err = sshCmd.getSystemCommand()
  475. if err != nil {
  476. t.Errorf("unexpected error: %v", err)
  477. }
  478. if !utils.IsStringInSlice("--munge-links", cmd.cmd.Args) {
  479. t.Errorf("--munge-links must be added if the user has the create symlinks permission")
  480. }
  481. }
  482. func TestSystemCommandErrors(t *testing.T) {
  483. buf := make([]byte, 65535)
  484. stdErrBuf := make([]byte, 65535)
  485. readErr := fmt.Errorf("test read error")
  486. writeErr := fmt.Errorf("test write error")
  487. mockSSHChannel := MockChannel{
  488. Buffer: bytes.NewBuffer(buf),
  489. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  490. ReadError: nil,
  491. WriteError: writeErr,
  492. }
  493. server, client := net.Pipe()
  494. defer server.Close()
  495. defer client.Close()
  496. permissions := make(map[string][]string)
  497. permissions["/"] = []string{dataprovider.PermAny}
  498. connection := Connection{
  499. channel: &mockSSHChannel,
  500. netConn: client,
  501. User: dataprovider.User{
  502. Permissions: permissions,
  503. HomeDir: os.TempDir(),
  504. },
  505. }
  506. sshCmd := sshCommand{
  507. command: "ls",
  508. connection: connection,
  509. args: []string{"/"},
  510. }
  511. systemCmd, err := sshCmd.getSystemCommand()
  512. if err != nil {
  513. t.Errorf("unexpected error: %v", err)
  514. }
  515. systemCmd.cmd.Dir = os.TempDir()
  516. // FIXME: the command completes but the fake client was unable to read the response
  517. // no error is reported in this case
  518. sshCmd.executeSystemCommand(systemCmd)
  519. mockSSHChannel = MockChannel{
  520. Buffer: bytes.NewBuffer(buf),
  521. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  522. ReadError: readErr,
  523. WriteError: nil,
  524. }
  525. sshCmd.connection.channel = &mockSSHChannel
  526. transfer := Transfer{transferType: transferDownload}
  527. destBuff := make([]byte, 65535)
  528. dst := bytes.NewBuffer(destBuff)
  529. _, err = transfer.copyFromReaderToWriter(dst, sshCmd.connection.channel, 0)
  530. if err != readErr {
  531. t.Errorf("unexpected error: %v", err)
  532. }
  533. mockSSHChannel = MockChannel{
  534. Buffer: bytes.NewBuffer(buf),
  535. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  536. ReadError: nil,
  537. WriteError: nil,
  538. }
  539. sshCmd.connection.channel = &mockSSHChannel
  540. _, err = transfer.copyFromReaderToWriter(dst, sshCmd.connection.channel, 1)
  541. if err != errQuotaExceeded {
  542. t.Errorf("unexpected error: %v", err)
  543. }
  544. mockSSHChannel = MockChannel{
  545. Buffer: bytes.NewBuffer(buf),
  546. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  547. ReadError: nil,
  548. WriteError: nil,
  549. ShortWriteErr: true,
  550. }
  551. sshCmd.connection.channel = &mockSSHChannel
  552. _, err = transfer.copyFromReaderToWriter(sshCmd.connection.channel, dst, 0)
  553. if err != io.ErrShortWrite {
  554. t.Errorf("unexpected error: %v", err)
  555. }
  556. }
  557. func TestGetConnectionInfo(t *testing.T) {
  558. c := ConnectionStatus{
  559. Username: "test_user",
  560. ConnectionID: "123",
  561. ClientVersion: "client",
  562. RemoteAddress: "127.0.0.1:1234",
  563. Protocol: protocolSSH,
  564. SSHCommand: "sha1sum /test_file.dat",
  565. }
  566. info := c.GetConnectionInfo()
  567. if !strings.Contains(info, "sha1sum /test_file.dat") {
  568. t.Errorf("ssh command not found in connection info")
  569. }
  570. }
  571. func TestSCPFileMode(t *testing.T) {
  572. mode := getFileModeAsString(0, true)
  573. if mode != "0755" {
  574. t.Errorf("invalid file mode: %v expected: 0755", mode)
  575. }
  576. mode = getFileModeAsString(0700, true)
  577. if mode != "0700" {
  578. t.Errorf("invalid file mode: %v expected: 0700", mode)
  579. }
  580. mode = getFileModeAsString(0750, true)
  581. if mode != "0750" {
  582. t.Errorf("invalid file mode: %v expected: 0750", mode)
  583. }
  584. mode = getFileModeAsString(0777, true)
  585. if mode != "0777" {
  586. t.Errorf("invalid file mode: %v expected: 0777", mode)
  587. }
  588. mode = getFileModeAsString(0640, false)
  589. if mode != "0640" {
  590. t.Errorf("invalid file mode: %v expected: 0640", mode)
  591. }
  592. mode = getFileModeAsString(0600, false)
  593. if mode != "0600" {
  594. t.Errorf("invalid file mode: %v expected: 0600", mode)
  595. }
  596. mode = getFileModeAsString(0, false)
  597. if mode != "0644" {
  598. t.Errorf("invalid file mode: %v expected: 0644", mode)
  599. }
  600. fileMode := uint32(0777)
  601. fileMode = fileMode | uint32(os.ModeSetgid)
  602. fileMode = fileMode | uint32(os.ModeSetuid)
  603. fileMode = fileMode | uint32(os.ModeSticky)
  604. mode = getFileModeAsString(os.FileMode(fileMode), false)
  605. if mode != "7777" {
  606. t.Errorf("invalid file mode: %v expected: 7777", mode)
  607. }
  608. fileMode = uint32(0644)
  609. fileMode = fileMode | uint32(os.ModeSetgid)
  610. mode = getFileModeAsString(os.FileMode(fileMode), false)
  611. if mode != "4644" {
  612. t.Errorf("invalid file mode: %v expected: 4644", mode)
  613. }
  614. fileMode = uint32(0600)
  615. fileMode = fileMode | uint32(os.ModeSetuid)
  616. mode = getFileModeAsString(os.FileMode(fileMode), false)
  617. if mode != "2600" {
  618. t.Errorf("invalid file mode: %v expected: 2600", mode)
  619. }
  620. fileMode = uint32(0044)
  621. fileMode = fileMode | uint32(os.ModeSticky)
  622. mode = getFileModeAsString(os.FileMode(fileMode), false)
  623. if mode != "1044" {
  624. t.Errorf("invalid file mode: %v expected: 1044", mode)
  625. }
  626. }
  627. func TestSCPParseUploadMessage(t *testing.T) {
  628. buf := make([]byte, 65535)
  629. stdErrBuf := make([]byte, 65535)
  630. mockSSHChannel := MockChannel{
  631. Buffer: bytes.NewBuffer(buf),
  632. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  633. ReadError: nil,
  634. }
  635. connection := Connection{
  636. channel: &mockSSHChannel,
  637. }
  638. scpCommand := scpCommand{
  639. sshCommand: sshCommand{
  640. command: "scp",
  641. connection: connection,
  642. args: []string{"-t", "/tmp"},
  643. },
  644. }
  645. _, _, err := scpCommand.parseUploadMessage("invalid")
  646. if err == nil {
  647. t.Errorf("parsing invalid upload message must fail")
  648. }
  649. _, _, err = scpCommand.parseUploadMessage("D0755 0")
  650. if err == nil {
  651. t.Errorf("parsing incomplete upload message must fail")
  652. }
  653. _, _, err = scpCommand.parseUploadMessage("D0755 invalidsize testdir")
  654. if err == nil {
  655. t.Errorf("parsing upload message with invalid size must fail")
  656. }
  657. _, _, err = scpCommand.parseUploadMessage("D0755 0 ")
  658. if err == nil {
  659. t.Errorf("parsing upload message with invalid name must fail")
  660. }
  661. }
  662. func TestSCPProtocolMessages(t *testing.T) {
  663. buf := make([]byte, 65535)
  664. stdErrBuf := make([]byte, 65535)
  665. readErr := fmt.Errorf("test read error")
  666. writeErr := fmt.Errorf("test write error")
  667. mockSSHChannel := MockChannel{
  668. Buffer: bytes.NewBuffer(buf),
  669. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  670. ReadError: readErr,
  671. WriteError: writeErr,
  672. }
  673. connection := Connection{
  674. channel: &mockSSHChannel,
  675. }
  676. scpCommand := scpCommand{
  677. sshCommand: sshCommand{
  678. command: "scp",
  679. connection: connection,
  680. args: []string{"-t", "/tmp"},
  681. },
  682. }
  683. _, err := scpCommand.readProtocolMessage()
  684. if err == nil || err != readErr {
  685. t.Errorf("read protocol message must fail, we are sending a fake error")
  686. }
  687. err = scpCommand.sendConfirmationMessage()
  688. if err != writeErr {
  689. t.Errorf("write confirmation message must fail, we are sending a fake error")
  690. }
  691. err = scpCommand.sendProtocolMessage("E\n")
  692. if err != writeErr {
  693. t.Errorf("write confirmation message must fail, we are sending a fake error")
  694. }
  695. _, err = scpCommand.getNextUploadProtocolMessage()
  696. if err == nil || err != readErr {
  697. t.Errorf("read next upload protocol message must fail, we are sending a fake read error")
  698. }
  699. mockSSHChannel = MockChannel{
  700. Buffer: bytes.NewBuffer([]byte("T1183832947 0 1183833773 0\n")),
  701. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  702. ReadError: nil,
  703. WriteError: writeErr,
  704. }
  705. scpCommand.connection.channel = &mockSSHChannel
  706. _, err = scpCommand.getNextUploadProtocolMessage()
  707. if err == nil || err != writeErr {
  708. t.Errorf("read next upload protocol message must fail, we are sending a fake write error")
  709. }
  710. respBuffer := []byte{0x02}
  711. protocolErrorMsg := "protocol error msg"
  712. respBuffer = append(respBuffer, protocolErrorMsg...)
  713. respBuffer = append(respBuffer, 0x0A)
  714. mockSSHChannel = MockChannel{
  715. Buffer: bytes.NewBuffer(respBuffer),
  716. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  717. ReadError: nil,
  718. WriteError: nil,
  719. }
  720. scpCommand.connection.channel = &mockSSHChannel
  721. err = scpCommand.readConfirmationMessage()
  722. if err == nil || err.Error() != protocolErrorMsg {
  723. t.Errorf("read confirmation message must return the expected protocol error, actual err: %v", err)
  724. }
  725. }
  726. func TestSCPTestDownloadProtocolMessages(t *testing.T) {
  727. buf := make([]byte, 65535)
  728. stdErrBuf := make([]byte, 65535)
  729. readErr := fmt.Errorf("test read error")
  730. writeErr := fmt.Errorf("test write error")
  731. mockSSHChannel := MockChannel{
  732. Buffer: bytes.NewBuffer(buf),
  733. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  734. ReadError: readErr,
  735. WriteError: writeErr,
  736. }
  737. connection := Connection{
  738. channel: &mockSSHChannel,
  739. }
  740. scpCommand := scpCommand{
  741. sshCommand: sshCommand{
  742. command: "scp",
  743. connection: connection,
  744. args: []string{"-f", "-p", "/tmp"},
  745. },
  746. }
  747. path := "testDir"
  748. os.Mkdir(path, 0777)
  749. stat, _ := os.Stat(path)
  750. err := scpCommand.sendDownloadProtocolMessages(path, stat)
  751. if err != writeErr {
  752. t.Errorf("sendDownloadProtocolMessages must return the expected error: %v", err)
  753. }
  754. mockSSHChannel = MockChannel{
  755. Buffer: bytes.NewBuffer(buf),
  756. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  757. ReadError: readErr,
  758. WriteError: nil,
  759. }
  760. err = scpCommand.sendDownloadProtocolMessages(path, stat)
  761. if err != readErr {
  762. t.Errorf("sendDownloadProtocolMessages must return the expected error: %v", err)
  763. }
  764. mockSSHChannel = MockChannel{
  765. Buffer: bytes.NewBuffer(buf),
  766. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  767. ReadError: readErr,
  768. WriteError: writeErr,
  769. }
  770. scpCommand.args = []string{"-f", "/tmp"}
  771. scpCommand.connection.channel = &mockSSHChannel
  772. err = scpCommand.sendDownloadProtocolMessages(path, stat)
  773. if err != writeErr {
  774. t.Errorf("sendDownloadProtocolMessages must return the expected error: %v", err)
  775. }
  776. mockSSHChannel = MockChannel{
  777. Buffer: bytes.NewBuffer(buf),
  778. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  779. ReadError: readErr,
  780. WriteError: nil,
  781. }
  782. scpCommand.connection.channel = &mockSSHChannel
  783. err = scpCommand.sendDownloadProtocolMessages(path, stat)
  784. if err != readErr {
  785. t.Errorf("sendDownloadProtocolMessages must return the expected error: %v", err)
  786. }
  787. os.Remove(path)
  788. }
  789. func TestSCPCommandHandleErrors(t *testing.T) {
  790. buf := make([]byte, 65535)
  791. stdErrBuf := make([]byte, 65535)
  792. readErr := fmt.Errorf("test read error")
  793. writeErr := fmt.Errorf("test write error")
  794. mockSSHChannel := MockChannel{
  795. Buffer: bytes.NewBuffer(buf),
  796. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  797. ReadError: readErr,
  798. WriteError: writeErr,
  799. }
  800. server, client := net.Pipe()
  801. defer server.Close()
  802. defer client.Close()
  803. connection := Connection{
  804. channel: &mockSSHChannel,
  805. netConn: client,
  806. }
  807. scpCommand := scpCommand{
  808. sshCommand: sshCommand{
  809. command: "scp",
  810. connection: connection,
  811. args: []string{"-f", "/tmp"},
  812. },
  813. }
  814. err := scpCommand.handle()
  815. if err == nil || err != readErr {
  816. t.Errorf("scp download must fail, we are sending a fake error")
  817. }
  818. scpCommand.args = []string{"-i", "/tmp"}
  819. err = scpCommand.handle()
  820. if err == nil {
  821. t.Errorf("invalid scp command must fail")
  822. }
  823. }
  824. func TestSCPRecursiveDownloadErrors(t *testing.T) {
  825. buf := make([]byte, 65535)
  826. stdErrBuf := make([]byte, 65535)
  827. readErr := fmt.Errorf("test read error")
  828. writeErr := fmt.Errorf("test write error")
  829. mockSSHChannel := MockChannel{
  830. Buffer: bytes.NewBuffer(buf),
  831. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  832. ReadError: readErr,
  833. WriteError: writeErr,
  834. }
  835. server, client := net.Pipe()
  836. defer server.Close()
  837. defer client.Close()
  838. connection := Connection{
  839. channel: &mockSSHChannel,
  840. netConn: client,
  841. }
  842. scpCommand := scpCommand{
  843. sshCommand: sshCommand{
  844. command: "scp",
  845. connection: connection,
  846. args: []string{"-r", "-f", "/tmp"},
  847. },
  848. }
  849. path := "testDir"
  850. os.Mkdir(path, 0777)
  851. stat, _ := os.Stat(path)
  852. err := scpCommand.handleRecursiveDownload("invalid_dir", stat)
  853. if err != writeErr {
  854. t.Errorf("recursive upload download must fail with the expected error: %v", err)
  855. }
  856. mockSSHChannel = MockChannel{
  857. Buffer: bytes.NewBuffer(buf),
  858. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  859. ReadError: nil,
  860. WriteError: nil,
  861. }
  862. scpCommand.connection.channel = &mockSSHChannel
  863. err = scpCommand.handleRecursiveDownload("invalid_dir", stat)
  864. if err == nil {
  865. t.Errorf("recursive upload download must fail for a non existing dir")
  866. }
  867. os.Remove(path)
  868. }
  869. func TestSCPRecursiveUploadErrors(t *testing.T) {
  870. buf := make([]byte, 65535)
  871. stdErrBuf := make([]byte, 65535)
  872. readErr := fmt.Errorf("test read error")
  873. writeErr := fmt.Errorf("test write error")
  874. mockSSHChannel := MockChannel{
  875. Buffer: bytes.NewBuffer(buf),
  876. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  877. ReadError: readErr,
  878. WriteError: writeErr,
  879. }
  880. connection := Connection{
  881. channel: &mockSSHChannel,
  882. }
  883. scpCommand := scpCommand{
  884. sshCommand: sshCommand{
  885. command: "scp",
  886. connection: connection,
  887. args: []string{"-r", "-t", "/tmp"},
  888. },
  889. }
  890. err := scpCommand.handleRecursiveUpload()
  891. if err == nil {
  892. t.Errorf("recursive upload must fail, we send a fake error message")
  893. }
  894. mockSSHChannel = MockChannel{
  895. Buffer: bytes.NewBuffer(buf),
  896. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  897. ReadError: readErr,
  898. WriteError: nil,
  899. }
  900. scpCommand.connection.channel = &mockSSHChannel
  901. err = scpCommand.handleRecursiveUpload()
  902. if err == nil {
  903. t.Errorf("recursive upload must fail, we send a fake error message")
  904. }
  905. }
  906. func TestSCPCreateDirs(t *testing.T) {
  907. buf := make([]byte, 65535)
  908. stdErrBuf := make([]byte, 65535)
  909. u := dataprovider.User{}
  910. u.HomeDir = "home_rel_path"
  911. u.Username = "test"
  912. u.Permissions = make(map[string][]string)
  913. u.Permissions["/"] = []string{dataprovider.PermAny}
  914. mockSSHChannel := MockChannel{
  915. Buffer: bytes.NewBuffer(buf),
  916. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  917. ReadError: nil,
  918. WriteError: nil,
  919. }
  920. connection := Connection{
  921. User: u,
  922. channel: &mockSSHChannel,
  923. }
  924. scpCommand := scpCommand{
  925. sshCommand: sshCommand{
  926. command: "scp",
  927. connection: connection,
  928. args: []string{"-r", "-t", "/tmp"},
  929. },
  930. }
  931. err := scpCommand.handleCreateDir("invalid_dir")
  932. if err == nil {
  933. t.Errorf("create invalid dir must fail")
  934. }
  935. }
  936. func TestSCPDownloadFileData(t *testing.T) {
  937. testfile := "testfile"
  938. buf := make([]byte, 65535)
  939. readErr := fmt.Errorf("test read error")
  940. writeErr := fmt.Errorf("test write error")
  941. stdErrBuf := make([]byte, 65535)
  942. mockSSHChannelReadErr := MockChannel{
  943. Buffer: bytes.NewBuffer(buf),
  944. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  945. ReadError: readErr,
  946. WriteError: nil,
  947. }
  948. mockSSHChannelWriteErr := MockChannel{
  949. Buffer: bytes.NewBuffer(buf),
  950. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  951. ReadError: nil,
  952. WriteError: writeErr,
  953. }
  954. connection := Connection{
  955. channel: &mockSSHChannelReadErr,
  956. }
  957. scpCommand := scpCommand{
  958. sshCommand: sshCommand{
  959. command: "scp",
  960. connection: connection,
  961. args: []string{"-r", "-f", "/tmp"},
  962. },
  963. }
  964. ioutil.WriteFile(testfile, []byte("test"), 0666)
  965. stat, _ := os.Stat(testfile)
  966. err := scpCommand.sendDownloadFileData(testfile, stat, nil)
  967. if err != readErr {
  968. t.Errorf("send download file data must fail with the expected error: %v", err)
  969. }
  970. scpCommand.connection.channel = &mockSSHChannelWriteErr
  971. err = scpCommand.sendDownloadFileData(testfile, stat, nil)
  972. if err != writeErr {
  973. t.Errorf("send download file data must fail with the expected error: %v", err)
  974. }
  975. scpCommand.args = []string{"-r", "-p", "-f", "/tmp"}
  976. err = scpCommand.sendDownloadFileData(testfile, stat, nil)
  977. if err != writeErr {
  978. t.Errorf("send download file data must fail with the expected error: %v", err)
  979. }
  980. scpCommand.connection.channel = &mockSSHChannelReadErr
  981. err = scpCommand.sendDownloadFileData(testfile, stat, nil)
  982. if err != readErr {
  983. t.Errorf("send download file data must fail with the expected error: %v", err)
  984. }
  985. os.Remove(testfile)
  986. }
  987. func TestSCPUploadFiledata(t *testing.T) {
  988. testfile := "testfile"
  989. buf := make([]byte, 65535)
  990. stdErrBuf := make([]byte, 65535)
  991. readErr := fmt.Errorf("test read error")
  992. writeErr := fmt.Errorf("test write error")
  993. mockSSHChannel := MockChannel{
  994. Buffer: bytes.NewBuffer(buf),
  995. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  996. ReadError: readErr,
  997. WriteError: writeErr,
  998. }
  999. connection := Connection{
  1000. User: dataprovider.User{
  1001. Username: "testuser",
  1002. },
  1003. protocol: protocolSCP,
  1004. channel: &mockSSHChannel,
  1005. }
  1006. scpCommand := scpCommand{
  1007. sshCommand: sshCommand{
  1008. command: "scp",
  1009. connection: connection,
  1010. args: []string{"-r", "-t", "/tmp"},
  1011. },
  1012. }
  1013. file, _ := os.Create(testfile)
  1014. transfer := Transfer{
  1015. file: file,
  1016. path: file.Name(),
  1017. start: time.Now(),
  1018. bytesSent: 0,
  1019. bytesReceived: 0,
  1020. user: scpCommand.connection.User,
  1021. connectionID: "",
  1022. transferType: transferDownload,
  1023. lastActivity: time.Now(),
  1024. isNewFile: true,
  1025. protocol: connection.protocol,
  1026. transferError: nil,
  1027. isFinished: false,
  1028. minWriteOffset: 0,
  1029. }
  1030. addTransfer(&transfer)
  1031. err := scpCommand.getUploadFileData(2, &transfer)
  1032. if err == nil {
  1033. t.Errorf("upload must fail, we send a fake write error message")
  1034. }
  1035. mockSSHChannel = MockChannel{
  1036. Buffer: bytes.NewBuffer(buf),
  1037. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  1038. ReadError: readErr,
  1039. WriteError: nil,
  1040. }
  1041. scpCommand.connection.channel = &mockSSHChannel
  1042. file, _ = os.Create(testfile)
  1043. transfer.file = file
  1044. addTransfer(&transfer)
  1045. err = scpCommand.getUploadFileData(2, &transfer)
  1046. if err == nil {
  1047. t.Errorf("upload must fail, we send a fake read error message")
  1048. }
  1049. respBuffer := []byte("12")
  1050. respBuffer = append(respBuffer, 0x02)
  1051. mockSSHChannel = MockChannel{
  1052. Buffer: bytes.NewBuffer(respBuffer),
  1053. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  1054. ReadError: nil,
  1055. WriteError: nil,
  1056. }
  1057. scpCommand.connection.channel = &mockSSHChannel
  1058. file, _ = os.Create(testfile)
  1059. transfer.file = file
  1060. addTransfer(&transfer)
  1061. err = scpCommand.getUploadFileData(2, &transfer)
  1062. if err == nil {
  1063. t.Errorf("upload must fail, we have not enough data to read")
  1064. }
  1065. // the file is already closed so we have an error on trasfer closing
  1066. mockSSHChannel = MockChannel{
  1067. Buffer: bytes.NewBuffer(buf),
  1068. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  1069. ReadError: nil,
  1070. WriteError: nil,
  1071. }
  1072. addTransfer(&transfer)
  1073. err = scpCommand.getUploadFileData(0, &transfer)
  1074. if err == nil {
  1075. t.Errorf("upload must fail, the file is closed")
  1076. }
  1077. os.Remove(testfile)
  1078. }
  1079. func TestUploadError(t *testing.T) {
  1080. oldUploadMode := uploadMode
  1081. uploadMode = uploadModeAtomic
  1082. connection := Connection{
  1083. User: dataprovider.User{
  1084. Username: "testuser",
  1085. },
  1086. protocol: protocolSCP,
  1087. }
  1088. testfile := "testfile"
  1089. fileTempName := "temptestfile"
  1090. file, _ := os.Create(fileTempName)
  1091. transfer := Transfer{
  1092. file: file,
  1093. path: testfile,
  1094. start: time.Now(),
  1095. bytesSent: 0,
  1096. bytesReceived: 100,
  1097. user: connection.User,
  1098. connectionID: "",
  1099. transferType: transferUpload,
  1100. lastActivity: time.Now(),
  1101. isNewFile: true,
  1102. protocol: connection.protocol,
  1103. transferError: nil,
  1104. isFinished: false,
  1105. minWriteOffset: 0,
  1106. }
  1107. addTransfer(&transfer)
  1108. transfer.TransferError(fmt.Errorf("fake error"))
  1109. transfer.Close()
  1110. if transfer.bytesReceived > 0 {
  1111. t.Errorf("byte sent should be 0 for a failed transfer: %v", transfer.bytesSent)
  1112. }
  1113. _, err := os.Stat(testfile)
  1114. if !os.IsNotExist(err) {
  1115. t.Errorf("file uploaded must be deleted after an error: %v", err)
  1116. }
  1117. _, err = os.Stat(fileTempName)
  1118. if !os.IsNotExist(err) {
  1119. t.Errorf("file uploaded must be deleted after an error: %v", err)
  1120. }
  1121. uploadMode = oldUploadMode
  1122. }
  1123. func TestConnectionStatusStruct(t *testing.T) {
  1124. var transfers []connectionTransfer
  1125. transferUL := connectionTransfer{
  1126. OperationType: operationUpload,
  1127. StartTime: utils.GetTimeAsMsSinceEpoch(time.Now()),
  1128. Size: 123,
  1129. LastActivity: utils.GetTimeAsMsSinceEpoch(time.Now()),
  1130. Path: "/test.upload",
  1131. }
  1132. transferDL := connectionTransfer{
  1133. OperationType: operationDownload,
  1134. StartTime: utils.GetTimeAsMsSinceEpoch(time.Now()),
  1135. Size: 123,
  1136. LastActivity: utils.GetTimeAsMsSinceEpoch(time.Now()),
  1137. Path: "/test.download",
  1138. }
  1139. transfers = append(transfers, transferUL)
  1140. transfers = append(transfers, transferDL)
  1141. c := ConnectionStatus{
  1142. Username: "test",
  1143. ConnectionID: "123",
  1144. ClientVersion: "fakeClient-1.0.0",
  1145. RemoteAddress: "127.0.0.1:1234",
  1146. ConnectionTime: utils.GetTimeAsMsSinceEpoch(time.Now()),
  1147. LastActivity: utils.GetTimeAsMsSinceEpoch(time.Now()),
  1148. Protocol: "SFTP",
  1149. Transfers: transfers,
  1150. }
  1151. durationString := c.GetConnectionDuration()
  1152. if len(durationString) == 0 {
  1153. t.Errorf("error getting connection duration")
  1154. }
  1155. transfersString := c.GetTransfersAsString()
  1156. if len(transfersString) == 0 {
  1157. t.Errorf("error getting transfers as string")
  1158. }
  1159. connInfo := c.GetConnectionInfo()
  1160. if len(connInfo) == 0 {
  1161. t.Errorf("error getting connection info")
  1162. }
  1163. }
  1164. func TestSFTPExtensions(t *testing.T) {
  1165. initialSFTPExtensions := sftpExtensions
  1166. c := Configuration{}
  1167. err := c.configureSFTPExtensions()
  1168. if err != nil {
  1169. t.Errorf("error configuring SFTP extensions")
  1170. }
  1171. sftpExtensions = append(sftpExtensions, "[email protected]")
  1172. err = c.configureSFTPExtensions()
  1173. if err == nil {
  1174. t.Errorf("configuring invalid SFTP extensions must fail")
  1175. }
  1176. sftpExtensions = initialSFTPExtensions
  1177. }