ftpd_test.go 133 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958
  1. // Copyright (C) 2019-2022 Nicola Murino
  2. //
  3. // This program is free software: you can redistribute it and/or modify
  4. // it under the terms of the GNU Affero General Public License as published
  5. // by the Free Software Foundation, version 3.
  6. //
  7. // This program is distributed in the hope that it will be useful,
  8. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. // GNU Affero General Public License for more details.
  11. //
  12. // You should have received a copy of the GNU Affero General Public License
  13. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. package ftpd_test
  15. import (
  16. "crypto/rand"
  17. "crypto/sha256"
  18. "crypto/tls"
  19. "encoding/hex"
  20. "encoding/json"
  21. "errors"
  22. "fmt"
  23. "io"
  24. "io/fs"
  25. "net"
  26. "net/http"
  27. "os"
  28. "os/exec"
  29. "path"
  30. "path/filepath"
  31. "runtime"
  32. "strconv"
  33. "testing"
  34. "time"
  35. ftpserver "github.com/fclairamb/ftpserverlib"
  36. "github.com/jlaffaye/ftp"
  37. "github.com/pquerna/otp"
  38. "github.com/pquerna/otp/totp"
  39. "github.com/rs/zerolog"
  40. "github.com/sftpgo/sdk"
  41. sdkkms "github.com/sftpgo/sdk/kms"
  42. "github.com/stretchr/testify/assert"
  43. "github.com/stretchr/testify/require"
  44. "github.com/drakkan/sftpgo/v2/internal/common"
  45. "github.com/drakkan/sftpgo/v2/internal/config"
  46. "github.com/drakkan/sftpgo/v2/internal/dataprovider"
  47. "github.com/drakkan/sftpgo/v2/internal/ftpd"
  48. "github.com/drakkan/sftpgo/v2/internal/httpdtest"
  49. "github.com/drakkan/sftpgo/v2/internal/kms"
  50. "github.com/drakkan/sftpgo/v2/internal/logger"
  51. "github.com/drakkan/sftpgo/v2/internal/mfa"
  52. "github.com/drakkan/sftpgo/v2/internal/sftpd"
  53. "github.com/drakkan/sftpgo/v2/internal/vfs"
  54. )
  55. const (
  56. logSender = "ftpdTesting"
  57. ftpServerAddr = "127.0.0.1:2121"
  58. sftpServerAddr = "127.0.0.1:2122"
  59. ftpSrvAddrTLS = "127.0.0.1:2124" // ftp server with implicit tls
  60. defaultUsername = "test_user_ftp"
  61. defaultPassword = "test_password"
  62. osWindows = "windows"
  63. ftpsCert = `-----BEGIN CERTIFICATE-----
  64. MIICHTCCAaKgAwIBAgIUHnqw7QnB1Bj9oUsNpdb+ZkFPOxMwCgYIKoZIzj0EAwIw
  65. RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
  66. dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDAyMDQwOTUzMDRaFw0zMDAyMDEw
  67. OTUzMDRaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYD
  68. VQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwdjAQBgcqhkjOPQIBBgUrgQQA
  69. IgNiAARCjRMqJ85rzMC998X5z761nJ+xL3bkmGVqWvrJ51t5OxV0v25NsOgR82CA
  70. NXUgvhVYs7vNFN+jxtb2aj6Xg+/2G/BNxkaFspIVCzgWkxiz7XE4lgUwX44FCXZM
  71. 3+JeUbKjUzBRMB0GA1UdDgQWBBRhLw+/o3+Z02MI/d4tmaMui9W16jAfBgNVHSME
  72. GDAWgBRhLw+/o3+Z02MI/d4tmaMui9W16jAPBgNVHRMBAf8EBTADAQH/MAoGCCqG
  73. SM49BAMCA2kAMGYCMQDqLt2lm8mE+tGgtjDmtFgdOcI72HSbRQ74D5rYTzgST1rY
  74. /8wTi5xl8TiFUyLMUsICMQC5ViVxdXbhuG7gX6yEqSkMKZICHpO8hqFwOD/uaFVI
  75. dV4vKmHUzwK/eIx+8Ay3neE=
  76. -----END CERTIFICATE-----`
  77. ftpsKey = `-----BEGIN EC PARAMETERS-----
  78. BgUrgQQAIg==
  79. -----END EC PARAMETERS-----
  80. -----BEGIN EC PRIVATE KEY-----
  81. MIGkAgEBBDCfMNsN6miEE3rVyUPwElfiJSWaR5huPCzUenZOfJT04GAcQdWvEju3
  82. UM2lmBLIXpGgBwYFK4EEACKhZANiAARCjRMqJ85rzMC998X5z761nJ+xL3bkmGVq
  83. WvrJ51t5OxV0v25NsOgR82CANXUgvhVYs7vNFN+jxtb2aj6Xg+/2G/BNxkaFspIV
  84. CzgWkxiz7XE4lgUwX44FCXZM3+JeUbI=
  85. -----END EC PRIVATE KEY-----`
  86. caCRT = `-----BEGIN CERTIFICATE-----
  87. MIIE5jCCAs6gAwIBAgIBATANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDEwhDZXJ0
  88. QXV0aDAeFw0yMjA3MDQxNTQzMTFaFw0yNDAxMDQxNTUzMDhaMBMxETAPBgNVBAMT
  89. CENlcnRBdXRoMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4eyDJkmW
  90. D4OVYo7ddgiZkd6QQdPyLcsa31Wc9jdR2/peEabyNT8jSWteS6ouY84GRlnhfFeZ
  91. mpXgbaUJu/Z8Y/8riPxwL8XF4vCScQDMywpQnVUd6E9x2/+/uaD4p/BBswgKqKPe
  92. uDcHZn7MkD4QlquUhMElDrBUi1Dv/AVHnQ6iP4vd5Jlv0F+40jdq/8Wa7yhW7Pu5
  93. iNvPwCk8HjENBKVur/re+Acif8A2TlbCsuOnVduSQNmnWH+iZmB9upyBZtUszGS0
  94. JhUwtSnwUX/JapF70Pwte/PV3RK8cJ5FjuAPNeTyJvSuMTELFSAyCeiNynFGgyhW
  95. cqbEiPu6BURLculyVkmh4dOrhTrYZv/n3UJAhyxkdYrbh3INHmTa4izvclcuwoEo
  96. lFlJp3l77D0lIi+pbtcBV6ys7reyuxUAkBNwnpt2pWfCQoi4QYKcNbHm47c2phOb
  97. QSojQ8SsNU5bnlY2MDzkKo5DPav/i4d0HpndphUpx4f8hA0KylLevDRkMz9TAH7H
  98. uDssn0CxFOGHiveEAGGbn+doHjNWM339x/cdLbK0vuieDKby8YYcBY1JML57Dl9f
  99. rs52ySnDZbMqOb9zF66mQpC2FZoAj713xSkDSnSCUekrqgck1EA1ifxAviHt+p26
  100. JwaEDL7Lk01EEdYN4csSd1fezbCqTrG8ffUCAwEAAaNFMEMwDgYDVR0PAQH/BAQD
  101. AgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFPirPBPO01zUuf7xC+ds
  102. bOOY5QvAMA0GCSqGSIb3DQEBCwUAA4ICAQBUYa+ydfTPKjTN4lXyEZgchZQ+juny
  103. aMy1xosLz6Evj0us2Bwczmy6X2Zvaw/KteFlgKaU1Ex2UkU7FfAlaH0HtwTLFMVM
  104. p9nB7ZzStvg0n8zFM29SEkOFwZ9FRonxx4sY3FdvI4QvAWyDyqgOl8+Eedg0kC4+
  105. M7hxarTFmZZ7POZl8Hio592yx3asMmSCcmb7oUCKVI98qsf9fuL+LIZSpn4fE7av
  106. AiNBcOqCZ10CRnl4VSgAW2LH4oqROYdUv+me1u1YRwh7fCF/R7VjOLuaDzv0mp/g
  107. hzG9U+Yso3WV4b28MsctwUmGTK8Zc5QaANKgmI3ulkta37wN5KjrUuescHC7MqZg
  108. vN9n60801be1EoUL83KUx57Bix95YZR02Zge0gYdYTb+E2bwaZ4GMlf7cs6qmC6A
  109. ZPLR7Tffw2J4dPTcfEx3rPZ91s3MkAdPzYYGdGlbKp8RCFnezZ7rw2z57rnT0zDr
  110. LuL3Q6ADBfothoos/EBIC5ekXb9czp8gig+nJXLC6jlqcQpCLrV88oS3+8zACmx1
  111. d6tje9uuAqPgiQGddKZj4b4BlHmAMXq0PufQsZVoyzboTewZiLVCtTR9/iF7Cepg
  112. 6EVv57p61pFhPu8lNRAi0aH/po9yt+7435FGpn2kan6k9aDIVdaqeuxxITwsqJ4R
  113. WwSa13hh6yjoDQ==
  114. -----END CERTIFICATE-----`
  115. caCRL = `-----BEGIN X509 CRL-----
  116. MIICpzCBkAIBATANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDEwhDZXJ0QXV0aBcN
  117. MjIwNzA0MTU1MzU4WhcNMjQwNzAzMTU1MzU4WjAkMCICEQDZo5Q3lhxFuDUsxGNm
  118. 794YFw0yMjA3MDQxNTUzNThaoCMwITAfBgNVHSMEGDAWgBT4qzwTztNc1Ln+8Qvn
  119. bGzjmOULwDANBgkqhkiG9w0BAQsFAAOCAgEA1lK6g8qmhyY6myx8342dDuaauY03
  120. 0iojkxpasuYcytK6XRm96YqjZK9EETxsHHViVU0vCXES60D6wJ9gw4fTWn3WxEdx
  121. nIwbGyjUGHh2y+R3uQsfvwxsdYvDsTLAnOLwOo68dAHWmMDZRmgTuGNoYFxVQRGR
  122. Cn90ZR7LPLpCScclWM8FE/W1B90x3ZE8EhJiCI/WyyTh3EgshmB7A5GoDrFZfmvR
  123. dzoTKO+F9p2XjtmgfiBE3czWQysfATmbutZUbG/ZRb89u+ZEUyPoC94mg8fhNWoX
  124. 1d5G9QAkZFHp957/5QHLq9OHNfnWXoohhebjF4VWqZH7w+RtLc8t0PIog2lX4t1o
  125. 5N/xFk9akvuoyNGg/fYuJBmN162Q0MdeYfYKDGWdXxf6fpHxVr5v2JrIx6gOwubb
  126. cIKP22ZBv/PYOeFsAZ755lTl4OTFUjU5ZJEPD6pUc1daaIqfxsxu8gDZP92FZjsB
  127. zaalMbh30n2OhagSMBzSLg5rE6WmBzlQX0ZN8YrW4l2Vq6twnnFHY+UyblRZS+d4
  128. oHBaoOaxPEkLxNZ8ulzJS4B6c4D1CXOaBEf++snVzRRUOEdX3x7TvkkrLvIsm06R
  129. ux0L1zJb9LbZ/1rhuv70z/kIlD55sqYuRqu3RpgTgZuTERU//rYIqWd03Y5Qon8i
  130. VoC6Yp9DPldQJrk=
  131. -----END X509 CRL-----`
  132. client1Crt = `-----BEGIN CERTIFICATE-----
  133. MIIEITCCAgmgAwIBAgIRAJla/m/UkZMifNwG+DxFr2MwDQYJKoZIhvcNAQELBQAw
  134. EzERMA8GA1UEAxMIQ2VydEF1dGgwHhcNMjIwNzA0MTU0MzM3WhcNMjQwMTA0MTU1
  135. MzA3WjASMRAwDgYDVQQDEwdjbGllbnQxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
  136. MIIBCgKCAQEA8xM5v+2QfdzfwnNT5cl+6oEy2fZoI2YG6L6c25rG0pr+yl1IHKdM
  137. Zcvn93uat7hlbzxeOLfJRM7+QK1lLaxuppq9p+gT+1x9eG3E4X7e0pdbjrpJGbvN
  138. ji0hwDBLDWD8mHNq/SCk9FKtGnfZqrNB5BLw2uIKjJzVGXVlsjN6geBDm2hVjTSm
  139. zMr39CfLUdtvMaZhpIPJzbH+sNfp1zKavFIpmwCd77p/z0QAiQ9NaIvzv4PZDDEE
  140. MUHzmVAU6bUjD8GToXaMbRiz694SU8aAwvvcdjGexdbHnfSAfLOl2wTPPxvePncR
  141. aa656ZeZWxY9pRCItP+v43nm7d4sAyRD4QIDAQABo3EwbzAOBgNVHQ8BAf8EBAMC
  142. A7gwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQWBBQbwDqF
  143. aja3ifZHm6mtSeTK9IHc+zAfBgNVHSMEGDAWgBT4qzwTztNc1Ln+8QvnbGzjmOUL
  144. wDANBgkqhkiG9w0BAQsFAAOCAgEAprE/zV6u8UIH8g4Jb73wtUD/eIL3iBJ7mNYa
  145. lqwCyJrWH7/F9fcovJnF9WO1QPTeHxhoD9rlQK70GitUAeboYw611yNWDS4tDlaL
  146. sjpJKykUxBgBR7QSLZCrPtQ3fP2WvlZzLGqB28rASTLphShqTuGp4gJaxGHfbCU7
  147. mlV9QYi+InQxOICJJPebXUOwx5wYkFQWJ9qE1AK3QrWPi8QYFznJvHgkNAaMBEmI
  148. jAlggOzpveVvy8f4z3QG9o29LIwp7JvtJQs7QXL80FZK98/8US/3gONwTrBz2Imx
  149. 28ywvwCq7fpMyPgxX4sXtxphCNim+vuHcqDn2CvLS9p/6L6zzqbFNxpmMkJDLrOc
  150. YqtHE4TLWIaXpb5JNrYJgNCZyJuYDICVTbivtMacHpSwYtXQ4iuzY2nIr0+4y9i9
  151. MNpqv3W47xnvgUQa5vbTbIqo2NSY24A84mF5EyjhaNgNtDlN56+qTQ6HLZNVr6pv
  152. eUCCWnY4GkaZUEU1M8/uNtKaZKv1WA7gJxZDQHj8+R110mPtzm1C5jqg7jSjGy9C
  153. 8PhAwBqIXkVLNayFEtyZZobTxMH5qY1yFkI3sic7S9ZyXt3quY1Q1UT3liRteIm/
  154. sZHC5zEoidsHObkTeU44hqZVPkbvrfmgW01xTJjddnMPBH+yqjCCc94yCbW79j/2
  155. 7LEmxYg=
  156. -----END CERTIFICATE-----`
  157. client1Key = `-----BEGIN RSA PRIVATE KEY-----
  158. MIIEpAIBAAKCAQEA8xM5v+2QfdzfwnNT5cl+6oEy2fZoI2YG6L6c25rG0pr+yl1I
  159. HKdMZcvn93uat7hlbzxeOLfJRM7+QK1lLaxuppq9p+gT+1x9eG3E4X7e0pdbjrpJ
  160. GbvNji0hwDBLDWD8mHNq/SCk9FKtGnfZqrNB5BLw2uIKjJzVGXVlsjN6geBDm2hV
  161. jTSmzMr39CfLUdtvMaZhpIPJzbH+sNfp1zKavFIpmwCd77p/z0QAiQ9NaIvzv4PZ
  162. DDEEMUHzmVAU6bUjD8GToXaMbRiz694SU8aAwvvcdjGexdbHnfSAfLOl2wTPPxve
  163. PncRaa656ZeZWxY9pRCItP+v43nm7d4sAyRD4QIDAQABAoIBADE17zcgDWSt1s8z
  164. MgUPahZn2beu3x5rhXKRRIhhKWdx4atufy7t39WsFmZQK96OAlsmyZyJ+MFpdqf5
  165. csZwZmZsZYEcxw7Yhr5e2sEcQlg4NF0M8ce38cGa+X5DSK6IuBrVIw/kEAE2y7zU
  166. Dsk0SV63RvPJV4FoLuxcjB4rtd2c+JBduNUXQYVppz/KhsXN+9CbPbZ7wo1cB5fo
  167. Iu/VswvvW6EAxVx39zZcwSGdkss9XUktU8akx7T/pepIH6fwkm7uXSNez6GH9d1I
  168. 8qOiORk/gAtqPL1TJgConyYheWMM9RbXP/IwL0BV8U4ZVG53S8jx2XpP4OJQ+k35
  169. WYvz8JECgYEA+9OywKOG2lMiiUB1qZfmXB80PngNsz+L6xUWkrw58gSqYZIg0xyH
  170. Sfr7HBo0yn/PB0oMMWPpNfYvG8/kSMIWiVlsYz9fdsUuqIvN+Kh9VF6o2wn+gnJk
  171. sBE3KVMofcgwgLE6eMVv2MSQlBoXhGPNlCBHS1gorQdYE82dxDPBBzsCgYEA9xpm
  172. c3C9LxiVbw9ZZ5D2C+vzwIG2+ZeDwKSizM1436MAnzNQgQTMzQ20uFGNBD562VjI
  173. rHFlZYr3KCtSIw5gvCSuox0YB64Yq/WAtGZtH9JyKRz4h4juq6iM4FT7nUwM4DF9
  174. 3CUiDS8DGoqvCNpY50GvzSR5QVT1DKTZsMunh5MCgYEAyIWMq7pK0iQqtvG9/3o1
  175. 8xrhxfBgsF+kcV+MZvE8jstKRIFQY+oujCkutPTlHm3hE2PSC64L8G0Em/fRRmJO
  176. AbZUCT9YK8HdYlZYf2zix0DM4gW2RHcEV/KNYvmVn3q9rGvzLGHCqu/yVAvmuAOk
  177. mhON0Z/0W7siVjp/KtEvHisCgYA/cfTaMRkyDXLY6C0BbXPvTa7xP5z2atO2U89F
  178. HICrkxOmzKsf5VacU6eSJ8Y4T76FLcmglSD+uHaLRsw5Ggj2Zci9MswntKi7Bjb8
  179. msvr/sG3EqwxSJRXWNiLBObx1UP9EFgLfTFIB0kZuIAGmuF2xyPXXUUQ5Dpi+7S1
  180. MyUZpwKBgQDg+AIPvk41vQ4Cz2CKrQX5/uJSW4bOhgP1yk7ruIH4Djkag3ZzTnHM
  181. zA9/pLzRfz1ENc5I/WaYSh92eKw3j6tUtMJlE2AbfCpgOQtRUNs3IBmzCWrY8J01
  182. W/8bwB+KhfFxNYwvszYsvvOq51NgahYQkgThVm38UixB3PFpEf+NiQ==
  183. -----END RSA PRIVATE KEY-----`
  184. // client 2 crt is revoked
  185. client2Crt = `-----BEGIN CERTIFICATE-----
  186. MIIEITCCAgmgAwIBAgIRANmjlDeWHEW4NSzEY2bv3hgwDQYJKoZIhvcNAQELBQAw
  187. EzERMA8GA1UEAxMIQ2VydEF1dGgwHhcNMjIwNzA0MTU0MzUxWhcNMjQwMTA0MTU1
  188. MzA3WjASMRAwDgYDVQQDEwdjbGllbnQyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
  189. MIIBCgKCAQEAzNl7q7yS8MSaQs6zRbuqrsUuwEJ5ZH85vf7zHZKgOW3zNniXLOmH
  190. JdtQ3jKZQ1BCIsJFvez2GxGIMWbXaSPw4bL0J3vl5oItChsjGg34IvqcDxWuIk2a
  191. muRdMh7r1ryVs2ir2cQ5YHzI59BEpUWKQg3bD4yragdkb6BRc7lVgzCbrM1Eq758
  192. HHbaLwlsfpqOvheaum4IG113CeD/HHrw42W6g/qQWL+FHlYqV3plHZ8Bj+bhcZI5
  193. jdU4paGEzeY0a0NlnyH4gXGPjLKvPKFZHy4D6RiRlLHvHeiRyDtTu4wFkAiXxzGs
  194. E4UBbykmYUB85zgwpjaktOaoe36IM1T8CQIDAQABo3EwbzAOBgNVHQ8BAf8EBAMC
  195. A7gwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQWBBRdYIEk
  196. gxh+vTaMpAbqaPGRKGGBpTAfBgNVHSMEGDAWgBT4qzwTztNc1Ln+8QvnbGzjmOUL
  197. wDANBgkqhkiG9w0BAQsFAAOCAgEABSR/PbPfiNZ6FOrt91/I0g6LviwICDcuXhfr
  198. re4UsWp1kxXeS3CB2G71qXv3hswN8phG2hdsij0/FBEGUTLS3FTCmLmqmcVqPj3/
  199. 677PMFDoACBKgT5iIwpnNvdD+4ROM8JFjUwy7aTWx85a5yoPFGnB+ORMfLCYjr2S
  200. D02KFvKuSXWCjXphqJ41cFGne4oeh/JMkN0RNArm7wTT8yWCGgO1k4OON8dphuTV
  201. 48Wm6I9UBSWuLk1vcIlgb/8YWVwy9rBNmjOBDGuroL6PSmfZD+e9Etii0X2znZ+t
  202. qDpXJB7V5U0DbsBCtGM/dHaFz/LCoBYX9z6th1iPUHksUTM3RzN9L24r9/28dY/a
  203. shBpn5rK3ui/2mPBpO26wX14Kl/DUkdKUV9dJllSlmwo8Z0RluY9S4xnCrna/ODH
  204. FbhWmlTSs+odCZl6Lc0nuw+WQ2HnlTVJYBSFAGfsGQQ3pzk4DC5VynnxY0UniUgD
  205. WYPR8JEYa+BpH3rIQ9jmnOKWLtyc7lFPB9ab63pQBBiwRvWo+tZ2vybqjeHPuu5N
  206. BuKvvtu3RKKdSCnIo5Rs5zw4JYCjvlx/NVk9jtpa1lIHYHilvBmCcRX5DkE/yH/x
  207. IjEKhCOQpGR6D5Kkca9xNL7zNcat3bzLn+d7Wo4m09uWi9ifPdchxed0w5d9ihx1
  208. enqNrFI=
  209. -----END CERTIFICATE-----`
  210. client2Key = `-----BEGIN RSA PRIVATE KEY-----
  211. MIIEowIBAAKCAQEAzNl7q7yS8MSaQs6zRbuqrsUuwEJ5ZH85vf7zHZKgOW3zNniX
  212. LOmHJdtQ3jKZQ1BCIsJFvez2GxGIMWbXaSPw4bL0J3vl5oItChsjGg34IvqcDxWu
  213. Ik2amuRdMh7r1ryVs2ir2cQ5YHzI59BEpUWKQg3bD4yragdkb6BRc7lVgzCbrM1E
  214. q758HHbaLwlsfpqOvheaum4IG113CeD/HHrw42W6g/qQWL+FHlYqV3plHZ8Bj+bh
  215. cZI5jdU4paGEzeY0a0NlnyH4gXGPjLKvPKFZHy4D6RiRlLHvHeiRyDtTu4wFkAiX
  216. xzGsE4UBbykmYUB85zgwpjaktOaoe36IM1T8CQIDAQABAoIBAETHMJK0udFE8VZE
  217. +EQNgn0zj0LWDtQDM2vrUc04Ebu2gtZjHr7hmZLIVBqGepbzN4FcIPZnvSnRdRzB
  218. HsoaWyIsZ3VqUAJY6q5d9iclUY7M/eDCsripvaML0Y6meyCaKNkX57sx+uG+g+Xx
  219. M1saQhVzeX17CYKMANjJxw9HxsJI0aBPyiBbILHMwfRfsJU8Ou72HH1sIQuPdH2H
  220. /c9ru8YZAno6oVq1zuC/pCis+h50U9HzTnt3/4NNS6cWG/y2YLztCvm9uGo4MTd/
  221. mA9s4cxVhvQW6gCDHgGn6zj661OL/d2rpak1eWizhZvZ8jsIN/sM87b0AJeVT4zH
  222. 6xA3egECgYEA1nI5EsCetQbFBp7tDovSp3fbitwoQtdtHtLn2u4DfvmbLrgSoq0Z
  223. L+9N13xML/l8lzWai2gI69uA3c2+y1O64LkaiSeDqbeBp9b6fKMlmwIVbklEke1w
  224. XVTIWOYTTF5/8+tUOlsgme5BhLAWnQ7+SoitzHtl5e1vEYaAGamE2DECgYEA9Is2
  225. BbTk2YCqkcsB7D9q95JbY0SZpecvTv0rLR+acz3T8JrAASdmvqdBOlPWc+0ZaEdS
  226. PcJaOEw3yxYJ33cR/nLBaR2/Uu5qQebyPALs3B2pjjTFdGvcpeFxO55fowwsfR/e
  227. 0H+HeiFj5Y4S+kFWT+3FRmJ6GUB828LJYaVhQ1kCgYEA1bdsTdYN1Vfzz89fbZnH
  228. zQLUl6UlssfDhm6mhzeh4E+eaocke1+LtIwHxfOocj9v/bp8VObPzU8rNOIxfa3q
  229. lr+jRIFO5DtwSfckGEb32W3QMeNvJQe/biRqrr5NCVU8q7kibi4XZZFfVn+vacNh
  230. hqKEoz9vpCBnCs5CqFCbhmECgYAG8qWYR+lwnI08Ey58zdh2LDxYd6x94DGh5uOB
  231. JrK2r30ECwGFht8Ob6YUyCkBpizgn5YglxMFInU7Webx6GokdpI0MFotOwTd1nfv
  232. aI3eOyGEHs+1XRMpy1vyO6+v7DqfW3ZzKgxpVeWGsiCr54tSPgkq1MVvTju96qza
  233. D17SEQKBgCKC0GjDjnt/JvujdzHuBt1sWdOtb+B6kQvA09qVmuDF/Dq36jiaHDjg
  234. XMf5HU3ThYqYn3bYypZZ8nQ7BXVh4LqGNqG29wR4v6l+dLO6odXnLzfApGD9e+d4
  235. 2tmlLP54LaN35hQxRjhT8lCN0BkrNF44+bh8frwm/kuxSd8wT2S+
  236. -----END RSA PRIVATE KEY-----`
  237. testFileName = "test_file_ftp.dat"
  238. testDLFileName = "test_download_ftp.dat"
  239. tlsClient1Username = "client1"
  240. tlsClient2Username = "client2"
  241. httpFsPort = 23456
  242. defaultHTTPFsUsername = "httpfs_ftp_user"
  243. emptyPwdPlaceholder = "empty"
  244. )
  245. var (
  246. configDir = filepath.Join(".", "..", "..")
  247. allPerms = []string{dataprovider.PermAny}
  248. homeBasePath string
  249. hookCmdPath string
  250. extAuthPath string
  251. preLoginPath string
  252. postConnectPath string
  253. preDownloadPath string
  254. preUploadPath string
  255. logFilePath string
  256. caCrtPath string
  257. caCRLPath string
  258. )
  259. func TestMain(m *testing.M) {
  260. logFilePath = filepath.Join(configDir, "sftpgo_ftpd_test.log")
  261. bannerFileName := "banner_file"
  262. bannerFile := filepath.Join(configDir, bannerFileName)
  263. logger.InitLogger(logFilePath, 5, 1, 28, false, false, zerolog.DebugLevel)
  264. err := os.WriteFile(bannerFile, []byte("SFTPGo test ready\nsimple banner line\n"), os.ModePerm)
  265. if err != nil {
  266. logger.ErrorToConsole("error creating banner file: %v", err)
  267. }
  268. // we run the test cases with UploadMode atomic and resume support. The non atomic code path
  269. // simply does not execute some code so if it works in atomic mode will
  270. // work in non atomic mode too
  271. os.Setenv("SFTPGO_COMMON__UPLOAD_MODE", "2")
  272. os.Setenv("SFTPGO_DATA_PROVIDER__CREATE_DEFAULT_ADMIN", "1")
  273. os.Setenv("SFTPGO_DEFAULT_ADMIN_USERNAME", "admin")
  274. os.Setenv("SFTPGO_DEFAULT_ADMIN_PASSWORD", "password")
  275. err = config.LoadConfig(configDir, "")
  276. if err != nil {
  277. logger.ErrorToConsole("error loading configuration: %v", err)
  278. os.Exit(1)
  279. }
  280. providerConf := config.GetProviderConf()
  281. logger.InfoToConsole("Starting FTPD tests, provider: %v", providerConf.Driver)
  282. commonConf := config.GetCommonConfig()
  283. homeBasePath = os.TempDir()
  284. if runtime.GOOS != osWindows {
  285. commonConf.Actions.ExecuteOn = []string{"download", "upload", "rename", "delete"}
  286. commonConf.Actions.Hook = hookCmdPath
  287. hookCmdPath, err = exec.LookPath("true")
  288. if err != nil {
  289. logger.Warn(logSender, "", "unable to get hook command: %v", err)
  290. logger.WarnToConsole("unable to get hook command: %v", err)
  291. }
  292. }
  293. certPath := filepath.Join(os.TempDir(), "test_ftpd.crt")
  294. keyPath := filepath.Join(os.TempDir(), "test_ftpd.key")
  295. caCrtPath = filepath.Join(os.TempDir(), "test_ftpd_ca.crt")
  296. caCRLPath = filepath.Join(os.TempDir(), "test_ftpd_crl.crt")
  297. err = writeCerts(certPath, keyPath, caCrtPath, caCRLPath)
  298. if err != nil {
  299. os.Exit(1)
  300. }
  301. err = common.Initialize(commonConf, 0)
  302. if err != nil {
  303. logger.WarnToConsole("error initializing common: %v", err)
  304. os.Exit(1)
  305. }
  306. err = dataprovider.Initialize(providerConf, configDir, true)
  307. if err != nil {
  308. logger.ErrorToConsole("error initializing data provider: %v", err)
  309. os.Exit(1)
  310. }
  311. httpConfig := config.GetHTTPConfig()
  312. httpConfig.Initialize(configDir) //nolint:errcheck
  313. kmsConfig := config.GetKMSConfig()
  314. err = kmsConfig.Initialize()
  315. if err != nil {
  316. logger.ErrorToConsole("error initializing kms: %v", err)
  317. os.Exit(1)
  318. }
  319. mfaConfig := config.GetMFAConfig()
  320. err = mfaConfig.Initialize()
  321. if err != nil {
  322. logger.ErrorToConsole("error initializing MFA: %v", err)
  323. os.Exit(1)
  324. }
  325. httpdConf := config.GetHTTPDConfig()
  326. httpdConf.Bindings[0].Port = 8079
  327. httpdtest.SetBaseURL("http://127.0.0.1:8079")
  328. ftpdConf := config.GetFTPDConfig()
  329. ftpdConf.Bindings = []ftpd.Binding{
  330. {
  331. Port: 2121,
  332. ClientAuthType: 2,
  333. CertificateFile: certPath,
  334. CertificateKeyFile: keyPath,
  335. },
  336. }
  337. ftpdConf.PassivePortRange.Start = 0
  338. ftpdConf.PassivePortRange.End = 0
  339. ftpdConf.BannerFile = bannerFileName
  340. ftpdConf.CACertificates = []string{caCrtPath}
  341. ftpdConf.CARevocationLists = []string{caCRLPath}
  342. ftpdConf.EnableSite = true
  343. // required to test sftpfs
  344. sftpdConf := config.GetSFTPDConfig()
  345. sftpdConf.Bindings = []sftpd.Binding{
  346. {
  347. Port: 2122,
  348. },
  349. }
  350. hostKeyPath := filepath.Join(os.TempDir(), "id_ed25519")
  351. sftpdConf.HostKeys = []string{hostKeyPath}
  352. extAuthPath = filepath.Join(homeBasePath, "extauth.sh")
  353. preLoginPath = filepath.Join(homeBasePath, "prelogin.sh")
  354. postConnectPath = filepath.Join(homeBasePath, "postconnect.sh")
  355. preDownloadPath = filepath.Join(homeBasePath, "predownload.sh")
  356. preUploadPath = filepath.Join(homeBasePath, "preupload.sh")
  357. status := ftpd.GetStatus()
  358. if status.IsActive {
  359. logger.ErrorToConsole("ftpd is already active")
  360. os.Exit(1)
  361. }
  362. go func() {
  363. logger.Debug(logSender, "", "initializing FTP server with config %+v", ftpdConf)
  364. if err := ftpdConf.Initialize(configDir); err != nil {
  365. logger.ErrorToConsole("could not start FTP server: %v", err)
  366. os.Exit(1)
  367. }
  368. }()
  369. go func() {
  370. logger.Debug(logSender, "", "initializing SFTP server with config %+v", sftpdConf)
  371. if err := sftpdConf.Initialize(configDir); err != nil {
  372. logger.ErrorToConsole("could not start SFTP server: %v", err)
  373. os.Exit(1)
  374. }
  375. }()
  376. go func() {
  377. if err := httpdConf.Initialize(configDir, 0); err != nil {
  378. logger.ErrorToConsole("could not start HTTP server: %v", err)
  379. os.Exit(1)
  380. }
  381. }()
  382. waitTCPListening(ftpdConf.Bindings[0].GetAddress())
  383. waitTCPListening(httpdConf.Bindings[0].GetAddress())
  384. waitTCPListening(sftpdConf.Bindings[0].GetAddress())
  385. ftpd.ReloadCertificateMgr() //nolint:errcheck
  386. ftpdConf = config.GetFTPDConfig()
  387. ftpdConf.Bindings = []ftpd.Binding{
  388. {
  389. Port: 2124,
  390. TLSMode: 2,
  391. },
  392. }
  393. ftpdConf.CertificateFile = certPath
  394. ftpdConf.CertificateKeyFile = keyPath
  395. ftpdConf.CACertificates = []string{caCrtPath}
  396. ftpdConf.CARevocationLists = []string{caCRLPath}
  397. ftpdConf.EnableSite = false
  398. ftpdConf.DisableActiveMode = true
  399. ftpdConf.CombineSupport = 1
  400. ftpdConf.HASHSupport = 1
  401. go func() {
  402. logger.Debug(logSender, "", "initializing FTP server with config %+v", ftpdConf)
  403. if err := ftpdConf.Initialize(configDir); err != nil {
  404. logger.ErrorToConsole("could not start FTP server: %v", err)
  405. os.Exit(1)
  406. }
  407. }()
  408. waitTCPListening(ftpdConf.Bindings[0].GetAddress())
  409. waitNoConnections()
  410. startHTTPFs()
  411. exitCode := m.Run()
  412. os.Remove(logFilePath)
  413. os.Remove(bannerFile)
  414. os.Remove(extAuthPath)
  415. os.Remove(preLoginPath)
  416. os.Remove(postConnectPath)
  417. os.Remove(preDownloadPath)
  418. os.Remove(preUploadPath)
  419. os.Remove(certPath)
  420. os.Remove(keyPath)
  421. os.Remove(caCrtPath)
  422. os.Remove(caCRLPath)
  423. os.Remove(hostKeyPath)
  424. os.Remove(hostKeyPath + ".pub")
  425. os.Exit(exitCode)
  426. }
  427. func TestInitializationFailure(t *testing.T) {
  428. ftpdConf := config.GetFTPDConfig()
  429. ftpdConf.Bindings = []ftpd.Binding{}
  430. ftpdConf.CertificateFile = filepath.Join(os.TempDir(), "test_ftpd.crt")
  431. ftpdConf.CertificateKeyFile = filepath.Join(os.TempDir(), "test_ftpd.key")
  432. err := ftpdConf.Initialize(configDir)
  433. require.EqualError(t, err, common.ErrNoBinding.Error())
  434. ftpdConf.Bindings = []ftpd.Binding{
  435. {
  436. Port: 0,
  437. },
  438. {
  439. Port: 2121,
  440. },
  441. }
  442. ftpdConf.BannerFile = "a-missing-file"
  443. err = ftpdConf.Initialize(configDir)
  444. require.Error(t, err)
  445. ftpdConf.BannerFile = ""
  446. ftpdConf.Bindings[1].TLSMode = 10
  447. err = ftpdConf.Initialize(configDir)
  448. require.Error(t, err)
  449. ftpdConf.CertificateFile = ""
  450. ftpdConf.CertificateKeyFile = ""
  451. ftpdConf.Bindings[1].TLSMode = 1
  452. err = ftpdConf.Initialize(configDir)
  453. require.Error(t, err)
  454. certPath := filepath.Join(os.TempDir(), "test_ftpd.crt")
  455. keyPath := filepath.Join(os.TempDir(), "test_ftpd.key")
  456. ftpdConf.CertificateFile = certPath
  457. ftpdConf.CertificateKeyFile = keyPath
  458. ftpdConf.CACertificates = []string{"invalid ca cert"}
  459. err = ftpdConf.Initialize(configDir)
  460. require.Error(t, err)
  461. ftpdConf.CACertificates = nil
  462. ftpdConf.CARevocationLists = []string{""}
  463. err = ftpdConf.Initialize(configDir)
  464. require.Error(t, err)
  465. ftpdConf.CACertificates = []string{caCrtPath}
  466. ftpdConf.CARevocationLists = []string{caCRLPath}
  467. ftpdConf.Bindings[1].ForcePassiveIP = "127001"
  468. err = ftpdConf.Initialize(configDir)
  469. require.Error(t, err)
  470. require.Contains(t, err.Error(), "the provided passive IP \"127001\" is not valid")
  471. ftpdConf.Bindings[1].ForcePassiveIP = ""
  472. err = ftpdConf.Initialize(configDir)
  473. require.Error(t, err)
  474. }
  475. func TestBasicFTPHandling(t *testing.T) {
  476. u := getTestUser()
  477. u.QuotaSize = 6553600
  478. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  479. assert.NoError(t, err)
  480. u = getTestSFTPUser()
  481. u.QuotaSize = 6553600
  482. sftpUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  483. assert.NoError(t, err)
  484. for _, user := range []dataprovider.User{localUser, sftpUser} {
  485. client, err := getFTPClient(user, true, nil)
  486. if assert.NoError(t, err) {
  487. if user.Username == defaultUsername {
  488. assert.Len(t, common.Connections.GetStats(), 1)
  489. } else {
  490. assert.Len(t, common.Connections.GetStats(), 2)
  491. }
  492. testFilePath := filepath.Join(homeBasePath, testFileName)
  493. testFileSize := int64(65535)
  494. expectedQuotaSize := testFileSize
  495. expectedQuotaFiles := 1
  496. err = createTestFile(testFilePath, testFileSize)
  497. assert.NoError(t, err)
  498. err = checkBasicFTP(client)
  499. assert.NoError(t, err)
  500. err = ftpUploadFile(testFilePath, path.Join("/missing_dir", testFileName), testFileSize, client, 0)
  501. assert.Error(t, err)
  502. user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
  503. assert.NoError(t, err)
  504. assert.Equal(t, int64(0), user.FirstUpload)
  505. assert.Equal(t, int64(0), user.FirstDownload)
  506. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  507. assert.NoError(t, err)
  508. user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
  509. assert.NoError(t, err)
  510. assert.Greater(t, user.FirstUpload, int64(0))
  511. assert.Equal(t, int64(0), user.FirstDownload)
  512. // overwrite an existing file
  513. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  514. assert.NoError(t, err)
  515. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  516. err = ftpDownloadFile(testFileName, localDownloadPath, testFileSize, client, 0)
  517. assert.NoError(t, err)
  518. user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
  519. assert.NoError(t, err)
  520. assert.Equal(t, expectedQuotaFiles, user.UsedQuotaFiles)
  521. assert.Equal(t, expectedQuotaSize, user.UsedQuotaSize)
  522. assert.Greater(t, user.FirstUpload, int64(0))
  523. assert.Greater(t, user.FirstDownload, int64(0))
  524. err = client.Rename(testFileName, testFileName+"1")
  525. assert.NoError(t, err)
  526. err = client.Delete(testFileName)
  527. assert.Error(t, err)
  528. err = client.Delete(testFileName + "1")
  529. assert.NoError(t, err)
  530. user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
  531. assert.NoError(t, err)
  532. assert.Equal(t, expectedQuotaFiles-1, user.UsedQuotaFiles)
  533. assert.Equal(t, expectedQuotaSize-testFileSize, user.UsedQuotaSize)
  534. curDir, err := client.CurrentDir()
  535. if assert.NoError(t, err) {
  536. assert.Equal(t, "/", curDir)
  537. }
  538. testDir := "testDir"
  539. err = client.MakeDir(testDir)
  540. assert.NoError(t, err)
  541. err = client.ChangeDir(testDir)
  542. assert.NoError(t, err)
  543. curDir, err = client.CurrentDir()
  544. if assert.NoError(t, err) {
  545. assert.Equal(t, path.Join("/", testDir), curDir)
  546. }
  547. res, err := client.List(path.Join("/", testDir))
  548. assert.NoError(t, err)
  549. assert.Len(t, res, 0)
  550. res, err = client.List(path.Join("/"))
  551. assert.NoError(t, err)
  552. if assert.Len(t, res, 1) {
  553. assert.Equal(t, testDir, res[0].Name)
  554. }
  555. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  556. assert.NoError(t, err)
  557. size, err := client.FileSize(path.Join("/", testDir, testFileName))
  558. assert.NoError(t, err)
  559. assert.Equal(t, testFileSize, size)
  560. err = client.ChangeDirToParent()
  561. assert.NoError(t, err)
  562. curDir, err = client.CurrentDir()
  563. if assert.NoError(t, err) {
  564. assert.Equal(t, "/", curDir)
  565. }
  566. err = client.Delete(path.Join("/", testDir, testFileName))
  567. assert.NoError(t, err)
  568. err = client.Delete(testDir)
  569. assert.Error(t, err)
  570. err = client.RemoveDir(testDir)
  571. assert.NoError(t, err)
  572. err = os.Remove(testFilePath)
  573. assert.NoError(t, err)
  574. err = os.Remove(localDownloadPath)
  575. assert.NoError(t, err)
  576. err = client.Quit()
  577. assert.NoError(t, err)
  578. }
  579. }
  580. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  581. assert.NoError(t, err)
  582. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  583. assert.NoError(t, err)
  584. err = os.RemoveAll(localUser.GetHomeDir())
  585. assert.NoError(t, err)
  586. assert.Eventually(t, func() bool { return len(common.Connections.GetStats()) == 0 }, 1*time.Second, 50*time.Millisecond)
  587. assert.Eventually(t, func() bool { return common.Connections.GetClientConnections() == 0 }, 1000*time.Millisecond,
  588. 50*time.Millisecond)
  589. }
  590. func TestHTTPFs(t *testing.T) {
  591. u := getTestUserWithHTTPFs()
  592. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  593. assert.NoError(t, err)
  594. client, err := getFTPClient(user, true, nil)
  595. if assert.NoError(t, err) {
  596. err = checkBasicFTP(client)
  597. assert.NoError(t, err)
  598. testFilePath := filepath.Join(homeBasePath, testFileName)
  599. testFileSize := int64(65535)
  600. err = createTestFile(testFilePath, testFileSize)
  601. assert.NoError(t, err)
  602. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  603. assert.NoError(t, err)
  604. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  605. err = ftpDownloadFile(testFileName, localDownloadPath, testFileSize, client, 0)
  606. assert.NoError(t, err)
  607. // test a download resume
  608. data := []byte("test data")
  609. err = os.WriteFile(testFilePath, data, os.ModePerm)
  610. assert.NoError(t, err)
  611. err = ftpUploadFile(testFilePath, testFileName, int64(len(data)), client, 0)
  612. assert.NoError(t, err)
  613. err = ftpDownloadFile(testFileName, localDownloadPath, int64(len(data)-5), client, 5)
  614. assert.NoError(t, err)
  615. readed, err := os.ReadFile(localDownloadPath)
  616. assert.NoError(t, err)
  617. assert.Equal(t, []byte("data"), readed, "readed data mismatch: %q", string(readed))
  618. err = os.Remove(testFilePath)
  619. assert.NoError(t, err)
  620. err = os.Remove(localDownloadPath)
  621. assert.NoError(t, err)
  622. err = client.Quit()
  623. assert.NoError(t, err)
  624. }
  625. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  626. assert.NoError(t, err)
  627. err = os.RemoveAll(user.GetHomeDir())
  628. assert.NoError(t, err)
  629. assert.Eventually(t, func() bool { return len(common.Connections.GetStats()) == 0 }, 1*time.Second, 50*time.Millisecond)
  630. assert.Eventually(t, func() bool { return common.Connections.GetClientConnections() == 0 }, 1000*time.Millisecond,
  631. 50*time.Millisecond)
  632. }
  633. func TestListDirWithWildcards(t *testing.T) {
  634. localUser, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
  635. assert.NoError(t, err)
  636. sftpUser, _, err := httpdtest.AddUser(getTestSFTPUser(), http.StatusCreated)
  637. assert.NoError(t, err)
  638. defer func() {
  639. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  640. assert.NoError(t, err)
  641. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  642. assert.NoError(t, err)
  643. err = os.RemoveAll(localUser.GetHomeDir())
  644. assert.NoError(t, err)
  645. }()
  646. for _, user := range []dataprovider.User{localUser, sftpUser} {
  647. client, err := getFTPClient(user, true, nil, ftp.DialWithDisabledMLSD(true))
  648. if assert.NoError(t, err) {
  649. dir1 := "test.dir"
  650. dir2 := "test.dir1"
  651. err = client.MakeDir(dir1)
  652. assert.NoError(t, err)
  653. err = client.MakeDir(dir2)
  654. assert.NoError(t, err)
  655. testFilePath := filepath.Join(homeBasePath, testFileName)
  656. testFileSize := int64(65535)
  657. err = createTestFile(testFilePath, testFileSize)
  658. assert.NoError(t, err)
  659. fileName := "file[a-z]e.dat"
  660. err = ftpUploadFile(testFilePath, fileName, testFileSize, client, 0)
  661. assert.NoError(t, err)
  662. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  663. err = ftpDownloadFile(fileName, localDownloadPath, testFileSize, client, 0)
  664. assert.NoError(t, err)
  665. entries, err := client.List(fileName)
  666. require.NoError(t, err)
  667. require.Len(t, entries, 1)
  668. assert.Equal(t, fileName, entries[0].Name)
  669. nListEntries, err := client.NameList(fileName)
  670. require.NoError(t, err)
  671. require.Len(t, entries, 1)
  672. assert.Contains(t, nListEntries, fileName)
  673. entries, err = client.List(".")
  674. require.NoError(t, err)
  675. require.Len(t, entries, 3)
  676. nListEntries, err = client.NameList(".")
  677. require.NoError(t, err)
  678. require.Len(t, nListEntries, 3)
  679. entries, err = client.List("/test.*")
  680. require.NoError(t, err)
  681. require.Len(t, entries, 2)
  682. found := 0
  683. for _, e := range entries {
  684. switch e.Name {
  685. case dir1, dir2:
  686. found++
  687. }
  688. }
  689. assert.Equal(t, 2, found)
  690. nListEntries, err = client.NameList("/test.*")
  691. require.NoError(t, err)
  692. require.Len(t, entries, 2)
  693. assert.Contains(t, nListEntries, dir1)
  694. assert.Contains(t, nListEntries, dir2)
  695. entries, err = client.List("/*.dir?")
  696. require.NoError(t, err)
  697. assert.Len(t, entries, 1)
  698. assert.Equal(t, dir2, entries[0].Name)
  699. nListEntries, err = client.NameList("/*.dir?")
  700. require.NoError(t, err)
  701. require.Len(t, entries, 1)
  702. assert.Contains(t, nListEntries, dir2)
  703. entries, err = client.List("/test.???")
  704. require.NoError(t, err)
  705. require.Len(t, entries, 1)
  706. assert.Equal(t, dir1, entries[0].Name)
  707. nListEntries, err = client.NameList("/test.???")
  708. require.NoError(t, err)
  709. require.Len(t, entries, 1)
  710. assert.Contains(t, nListEntries, dir1)
  711. _, err = client.NameList("/missingdir/test.*")
  712. assert.Error(t, err)
  713. _, err = client.List("/missingdir/test.*")
  714. assert.Error(t, err)
  715. _, err = client.NameList("test[-]")
  716. if assert.Error(t, err) {
  717. assert.Contains(t, err.Error(), path.ErrBadPattern.Error())
  718. }
  719. _, err = client.List("test[-]")
  720. if assert.Error(t, err) {
  721. assert.Contains(t, err.Error(), path.ErrBadPattern.Error())
  722. }
  723. subDir := path.Join(dir1, "sub.d")
  724. err = client.MakeDir(subDir)
  725. assert.NoError(t, err)
  726. err = client.ChangeDir(path.Dir(subDir))
  727. assert.NoError(t, err)
  728. entries, err = client.List("sub.?")
  729. require.NoError(t, err)
  730. require.Len(t, entries, 1)
  731. assert.Contains(t, path.Base(subDir), entries[0].Name)
  732. nListEntries, err = client.NameList("sub.?")
  733. require.NoError(t, err)
  734. require.Len(t, entries, 1)
  735. assert.Contains(t, nListEntries, path.Base(subDir))
  736. entries, err = client.List("../*.dir?")
  737. require.NoError(t, err)
  738. require.Len(t, entries, 1)
  739. assert.Equal(t, path.Join("../", dir2), entries[0].Name)
  740. nListEntries, err = client.NameList("../*.dir?")
  741. require.NoError(t, err)
  742. require.Len(t, entries, 1)
  743. assert.Contains(t, nListEntries, path.Join("../", dir2))
  744. err = client.ChangeDir("/")
  745. assert.NoError(t, err)
  746. entries, err = client.List(path.Join(dir1, "sub.*"))
  747. require.NoError(t, err)
  748. require.Len(t, entries, 1)
  749. assert.Equal(t, path.Join(dir1, "sub.d"), entries[0].Name)
  750. nListEntries, err = client.NameList(path.Join(dir1, "sub.*"))
  751. require.NoError(t, err)
  752. require.Len(t, entries, 1)
  753. assert.Contains(t, nListEntries, path.Join(dir1, "sub.d"))
  754. err = client.RemoveDir(subDir)
  755. assert.NoError(t, err)
  756. err = client.RemoveDir(dir1)
  757. assert.NoError(t, err)
  758. err = client.RemoveDir(dir2)
  759. assert.NoError(t, err)
  760. err = os.Remove(testFilePath)
  761. assert.NoError(t, err)
  762. err = os.Remove(localDownloadPath)
  763. assert.NoError(t, err)
  764. err = client.Quit()
  765. assert.NoError(t, err)
  766. }
  767. }
  768. }
  769. func TestStartDirectory(t *testing.T) {
  770. startDir := "/start/dir"
  771. u := getTestUser()
  772. u.Filters.StartDirectory = startDir
  773. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  774. assert.NoError(t, err)
  775. u = getTestSFTPUser()
  776. u.Filters.StartDirectory = startDir
  777. sftpUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  778. assert.NoError(t, err)
  779. for _, user := range []dataprovider.User{localUser, sftpUser} {
  780. client, err := getFTPClient(user, true, nil)
  781. if assert.NoError(t, err) {
  782. currentDir, err := client.CurrentDir()
  783. assert.NoError(t, err)
  784. assert.Equal(t, startDir, currentDir)
  785. testFilePath := filepath.Join(homeBasePath, testFileName)
  786. testFileSize := int64(65535)
  787. err = createTestFile(testFilePath, testFileSize)
  788. assert.NoError(t, err)
  789. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  790. assert.NoError(t, err)
  791. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  792. err = ftpDownloadFile(testFileName, localDownloadPath, testFileSize, client, 0)
  793. assert.NoError(t, err)
  794. entries, err := client.List(".")
  795. assert.NoError(t, err)
  796. if assert.Len(t, entries, 1) {
  797. assert.Equal(t, testFileName, entries[0].Name)
  798. }
  799. entries, err = client.List("/")
  800. assert.NoError(t, err)
  801. if assert.Len(t, entries, 1) {
  802. assert.Equal(t, "start", entries[0].Name)
  803. }
  804. err = client.ChangeDirToParent()
  805. assert.NoError(t, err)
  806. currentDir, err = client.CurrentDir()
  807. assert.NoError(t, err)
  808. assert.Equal(t, path.Dir(startDir), currentDir)
  809. err = client.ChangeDirToParent()
  810. assert.NoError(t, err)
  811. currentDir, err = client.CurrentDir()
  812. assert.NoError(t, err)
  813. assert.Equal(t, "/", currentDir)
  814. err = os.Remove(testFilePath)
  815. assert.NoError(t, err)
  816. err = os.Remove(localDownloadPath)
  817. assert.NoError(t, err)
  818. err = client.Quit()
  819. assert.NoError(t, err)
  820. }
  821. }
  822. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  823. assert.NoError(t, err)
  824. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  825. assert.NoError(t, err)
  826. err = os.RemoveAll(localUser.GetHomeDir())
  827. assert.NoError(t, err)
  828. }
  829. func TestLoginEmptyPassword(t *testing.T) {
  830. u := getTestUser()
  831. u.Password = ""
  832. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  833. assert.NoError(t, err)
  834. user.Password = emptyPwdPlaceholder
  835. _, err = getFTPClient(user, true, nil)
  836. assert.Error(t, err)
  837. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  838. assert.NoError(t, err)
  839. err = os.RemoveAll(user.GetHomeDir())
  840. assert.NoError(t, err)
  841. }
  842. func TestAnonymousUser(t *testing.T) {
  843. u := getTestUser()
  844. u.Password = ""
  845. u.Filters.IsAnonymous = true
  846. _, _, err := httpdtest.AddUser(u, http.StatusCreated)
  847. assert.Error(t, err)
  848. user, _, err := httpdtest.GetUserByUsername(u.Username, http.StatusOK)
  849. assert.NoError(t, err)
  850. assert.True(t, user.Filters.IsAnonymous)
  851. assert.Equal(t, []string{dataprovider.PermListItems, dataprovider.PermDownload}, user.Permissions["/"])
  852. assert.Equal(t, []string{common.ProtocolSSH, common.ProtocolHTTP}, user.Filters.DeniedProtocols)
  853. assert.Equal(t, []string{dataprovider.SSHLoginMethodPublicKey, dataprovider.SSHLoginMethodPassword,
  854. dataprovider.SSHLoginMethodKeyboardInteractive, dataprovider.SSHLoginMethodKeyAndPassword,
  855. dataprovider.SSHLoginMethodKeyAndKeyboardInt, dataprovider.LoginMethodTLSCertificate,
  856. dataprovider.LoginMethodTLSCertificateAndPwd}, user.Filters.DeniedLoginMethods)
  857. user.Password = emptyPwdPlaceholder
  858. client, err := getFTPClient(user, true, nil)
  859. if assert.NoError(t, err) {
  860. err = checkBasicFTP(client)
  861. assert.NoError(t, err)
  862. testFilePath := filepath.Join(homeBasePath, testFileName)
  863. testFileSize := int64(65535)
  864. err = createTestFile(testFilePath, testFileSize)
  865. assert.NoError(t, err)
  866. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  867. if assert.Error(t, err) {
  868. assert.Contains(t, err.Error(), "permission")
  869. }
  870. err = os.Rename(testFilePath, filepath.Join(user.GetHomeDir(), testFileName))
  871. assert.NoError(t, err)
  872. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  873. err = ftpDownloadFile(testFileName, localDownloadPath, testFileSize, client, 0)
  874. assert.NoError(t, err)
  875. err = client.MakeDir("adir")
  876. if assert.Error(t, err) {
  877. assert.Contains(t, err.Error(), "permission")
  878. }
  879. err = client.Quit()
  880. assert.NoError(t, err)
  881. err = os.Remove(localDownloadPath)
  882. assert.NoError(t, err)
  883. }
  884. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  885. assert.NoError(t, err)
  886. err = os.RemoveAll(user.GetHomeDir())
  887. assert.NoError(t, err)
  888. }
  889. func TestAnonymousGroupInheritance(t *testing.T) {
  890. g := getTestGroup()
  891. g.UserSettings.Filters.IsAnonymous = true
  892. g.UserSettings.Permissions = make(map[string][]string)
  893. g.UserSettings.Permissions["/"] = allPerms
  894. g.UserSettings.Permissions["/testsub"] = allPerms
  895. group, _, err := httpdtest.AddGroup(g, http.StatusCreated)
  896. assert.NoError(t, err)
  897. u := getTestUser()
  898. u.Groups = []sdk.GroupMapping{
  899. {
  900. Name: group.Name,
  901. Type: sdk.GroupTypePrimary,
  902. },
  903. }
  904. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  905. assert.NoError(t, err)
  906. user.Password = emptyPwdPlaceholder
  907. client, err := getFTPClient(user, true, nil)
  908. if assert.NoError(t, err) {
  909. err = checkBasicFTP(client)
  910. assert.NoError(t, err)
  911. testFilePath := filepath.Join(homeBasePath, testFileName)
  912. testFileSize := int64(65535)
  913. err = createTestFile(testFilePath, testFileSize)
  914. assert.NoError(t, err)
  915. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  916. if assert.Error(t, err) {
  917. assert.Contains(t, err.Error(), "permission")
  918. }
  919. err = client.MakeDir("adir")
  920. if assert.Error(t, err) {
  921. assert.Contains(t, err.Error(), "permission")
  922. }
  923. err = client.MakeDir("/testsub/adir")
  924. if assert.Error(t, err) {
  925. assert.Contains(t, err.Error(), "permission")
  926. }
  927. err = os.Rename(testFilePath, filepath.Join(user.GetHomeDir(), testFileName))
  928. assert.NoError(t, err)
  929. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  930. err = ftpDownloadFile(testFileName, localDownloadPath, testFileSize, client, 0)
  931. assert.NoError(t, err)
  932. err = client.Quit()
  933. assert.NoError(t, err)
  934. err = os.Remove(localDownloadPath)
  935. assert.NoError(t, err)
  936. }
  937. user.Password = defaultPassword
  938. client, err = getFTPClient(user, true, nil)
  939. if assert.NoError(t, err) {
  940. err = checkBasicFTP(client)
  941. assert.NoError(t, err)
  942. err := client.Quit()
  943. assert.NoError(t, err)
  944. }
  945. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  946. assert.NoError(t, err)
  947. err = os.RemoveAll(user.GetHomeDir())
  948. assert.NoError(t, err)
  949. _, err = httpdtest.RemoveGroup(group, http.StatusOK)
  950. assert.NoError(t, err)
  951. }
  952. func TestMultiFactorAuth(t *testing.T) {
  953. u := getTestUser()
  954. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  955. assert.NoError(t, err)
  956. configName, _, secret, _, err := mfa.GenerateTOTPSecret(mfa.GetAvailableTOTPConfigNames()[0], user.Username)
  957. assert.NoError(t, err)
  958. user.Password = defaultPassword
  959. user.Filters.TOTPConfig = dataprovider.UserTOTPConfig{
  960. Enabled: true,
  961. ConfigName: configName,
  962. Secret: kms.NewPlainSecret(secret),
  963. Protocols: []string{common.ProtocolFTP},
  964. }
  965. err = dataprovider.UpdateUser(&user, "", "")
  966. assert.NoError(t, err)
  967. user.Password = defaultPassword
  968. _, err = getFTPClient(user, true, nil)
  969. if assert.Error(t, err) {
  970. assert.Contains(t, err.Error(), dataprovider.ErrInvalidCredentials.Error())
  971. }
  972. passcode, err := generateTOTPPasscode(secret, otp.AlgorithmSHA1)
  973. assert.NoError(t, err)
  974. user.Password = defaultPassword + passcode
  975. client, err := getFTPClient(user, true, nil)
  976. if assert.NoError(t, err) {
  977. err = checkBasicFTP(client)
  978. assert.NoError(t, err)
  979. err := client.Quit()
  980. assert.NoError(t, err)
  981. }
  982. // reusing the same passcode should not work
  983. _, err = getFTPClient(user, true, nil)
  984. if assert.Error(t, err) {
  985. assert.Contains(t, err.Error(), dataprovider.ErrInvalidCredentials.Error())
  986. }
  987. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  988. assert.NoError(t, err)
  989. err = os.RemoveAll(user.GetHomeDir())
  990. assert.NoError(t, err)
  991. }
  992. func TestSecondFactorRequirement(t *testing.T) {
  993. u := getTestUser()
  994. u.Filters.TwoFactorAuthProtocols = []string{common.ProtocolFTP}
  995. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  996. assert.NoError(t, err)
  997. _, err = getFTPClient(user, true, nil)
  998. if assert.Error(t, err) {
  999. assert.Contains(t, err.Error(), "second factor authentication is not set")
  1000. }
  1001. configName, _, secret, _, err := mfa.GenerateTOTPSecret(mfa.GetAvailableTOTPConfigNames()[0], user.Username)
  1002. assert.NoError(t, err)
  1003. user.Password = defaultPassword
  1004. user.Filters.TOTPConfig = dataprovider.UserTOTPConfig{
  1005. Enabled: true,
  1006. ConfigName: configName,
  1007. Secret: kms.NewPlainSecret(secret),
  1008. Protocols: []string{common.ProtocolFTP},
  1009. }
  1010. err = dataprovider.UpdateUser(&user, "", "")
  1011. assert.NoError(t, err)
  1012. passcode, err := generateTOTPPasscode(secret, otp.AlgorithmSHA1)
  1013. assert.NoError(t, err)
  1014. user.Password = defaultPassword + passcode
  1015. client, err := getFTPClient(user, true, nil)
  1016. if assert.NoError(t, err) {
  1017. err = checkBasicFTP(client)
  1018. assert.NoError(t, err)
  1019. err := client.Quit()
  1020. assert.NoError(t, err)
  1021. }
  1022. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1023. assert.NoError(t, err)
  1024. err = os.RemoveAll(user.GetHomeDir())
  1025. assert.NoError(t, err)
  1026. }
  1027. func TestLoginInvalidCredentials(t *testing.T) {
  1028. u := getTestUser()
  1029. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1030. assert.NoError(t, err)
  1031. user.Username = "wrong username"
  1032. _, err = getFTPClient(user, false, nil)
  1033. if assert.Error(t, err) {
  1034. assert.Contains(t, err.Error(), dataprovider.ErrInvalidCredentials.Error())
  1035. }
  1036. user.Username = u.Username
  1037. user.Password = "wrong pwd"
  1038. _, err = getFTPClient(user, false, nil)
  1039. if assert.Error(t, err) {
  1040. assert.Contains(t, err.Error(), dataprovider.ErrInvalidCredentials.Error())
  1041. }
  1042. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1043. assert.NoError(t, err)
  1044. }
  1045. func TestLoginNonExistentUser(t *testing.T) {
  1046. user := getTestUser()
  1047. _, err := getFTPClient(user, false, nil)
  1048. assert.Error(t, err)
  1049. }
  1050. func TestFTPSecurity(t *testing.T) {
  1051. u := getTestUser()
  1052. u.Filters.FTPSecurity = 1
  1053. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1054. assert.NoError(t, err)
  1055. client, err := getFTPClient(user, true, nil)
  1056. if assert.NoError(t, err) {
  1057. err = checkBasicFTP(client)
  1058. assert.NoError(t, err)
  1059. err := client.Quit()
  1060. assert.NoError(t, err)
  1061. }
  1062. _, err = getFTPClient(user, false, nil)
  1063. if assert.Error(t, err) {
  1064. assert.Contains(t, err.Error(), "TLS is required")
  1065. }
  1066. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1067. assert.NoError(t, err)
  1068. err = os.RemoveAll(user.GetHomeDir())
  1069. assert.NoError(t, err)
  1070. }
  1071. func TestGroupFTPSecurity(t *testing.T) {
  1072. g := getTestGroup()
  1073. g.UserSettings.Filters.FTPSecurity = 1
  1074. group, _, err := httpdtest.AddGroup(g, http.StatusCreated)
  1075. assert.NoError(t, err)
  1076. u := getTestUser()
  1077. u.Groups = []sdk.GroupMapping{
  1078. {
  1079. Name: group.Name,
  1080. Type: sdk.GroupTypePrimary,
  1081. },
  1082. }
  1083. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1084. assert.NoError(t, err)
  1085. client, err := getFTPClient(user, true, nil)
  1086. if assert.NoError(t, err) {
  1087. err = checkBasicFTP(client)
  1088. assert.NoError(t, err)
  1089. err := client.Quit()
  1090. assert.NoError(t, err)
  1091. }
  1092. _, err = getFTPClient(user, false, nil)
  1093. if assert.Error(t, err) {
  1094. assert.Contains(t, err.Error(), "TLS is required")
  1095. }
  1096. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1097. assert.NoError(t, err)
  1098. err = os.RemoveAll(user.GetHomeDir())
  1099. assert.NoError(t, err)
  1100. _, err = httpdtest.RemoveGroup(group, http.StatusOK)
  1101. assert.NoError(t, err)
  1102. }
  1103. func TestLoginExternalAuth(t *testing.T) {
  1104. if runtime.GOOS == osWindows {
  1105. t.Skip("this test is not available on Windows")
  1106. }
  1107. u := getTestUser()
  1108. err := dataprovider.Close()
  1109. assert.NoError(t, err)
  1110. err = config.LoadConfig(configDir, "")
  1111. assert.NoError(t, err)
  1112. providerConf := config.GetProviderConf()
  1113. err = os.WriteFile(extAuthPath, getExtAuthScriptContent(u), os.ModePerm)
  1114. assert.NoError(t, err)
  1115. providerConf.ExternalAuthHook = extAuthPath
  1116. providerConf.ExternalAuthScope = 0
  1117. err = dataprovider.Initialize(providerConf, configDir, true)
  1118. assert.NoError(t, err)
  1119. g := getTestGroup()
  1120. g.UserSettings.Filters.DeniedProtocols = []string{common.ProtocolFTP}
  1121. group, _, err := httpdtest.AddGroup(g, http.StatusCreated)
  1122. assert.NoError(t, err)
  1123. client, err := getFTPClient(u, true, nil)
  1124. if assert.NoError(t, err) {
  1125. err = checkBasicFTP(client)
  1126. assert.NoError(t, err)
  1127. err := client.Quit()
  1128. assert.NoError(t, err)
  1129. }
  1130. u.Groups = []sdk.GroupMapping{
  1131. {
  1132. Name: group.Name,
  1133. Type: sdk.GroupTypePrimary,
  1134. },
  1135. }
  1136. err = os.WriteFile(extAuthPath, getExtAuthScriptContent(u), os.ModePerm)
  1137. assert.NoError(t, err)
  1138. _, err = getFTPClient(u, true, nil)
  1139. if !assert.Error(t, err) {
  1140. err := client.Quit()
  1141. assert.NoError(t, err)
  1142. } else {
  1143. assert.Contains(t, err.Error(), "protocol FTP is not allowed")
  1144. }
  1145. u.Groups = nil
  1146. err = os.WriteFile(extAuthPath, getExtAuthScriptContent(u), os.ModePerm)
  1147. assert.NoError(t, err)
  1148. u.Username = defaultUsername + "1"
  1149. client, err = getFTPClient(u, true, nil)
  1150. if !assert.Error(t, err) {
  1151. err := client.Quit()
  1152. assert.NoError(t, err)
  1153. } else {
  1154. assert.Contains(t, err.Error(), "invalid credentials")
  1155. }
  1156. user, _, err := httpdtest.GetUserByUsername(defaultUsername, http.StatusOK)
  1157. assert.NoError(t, err)
  1158. assert.Equal(t, defaultUsername, user.Username)
  1159. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1160. assert.NoError(t, err)
  1161. err = os.RemoveAll(user.GetHomeDir())
  1162. assert.NoError(t, err)
  1163. _, err = httpdtest.RemoveGroup(group, http.StatusOK)
  1164. assert.NoError(t, err)
  1165. err = dataprovider.Close()
  1166. assert.NoError(t, err)
  1167. err = config.LoadConfig(configDir, "")
  1168. assert.NoError(t, err)
  1169. providerConf = config.GetProviderConf()
  1170. err = dataprovider.Initialize(providerConf, configDir, true)
  1171. assert.NoError(t, err)
  1172. err = os.Remove(extAuthPath)
  1173. assert.NoError(t, err)
  1174. }
  1175. func TestPreLoginHook(t *testing.T) {
  1176. if runtime.GOOS == osWindows {
  1177. t.Skip("this test is not available on Windows")
  1178. }
  1179. u := getTestUser()
  1180. err := dataprovider.Close()
  1181. assert.NoError(t, err)
  1182. err = config.LoadConfig(configDir, "")
  1183. assert.NoError(t, err)
  1184. providerConf := config.GetProviderConf()
  1185. err = os.WriteFile(preLoginPath, getPreLoginScriptContent(u, false), os.ModePerm)
  1186. assert.NoError(t, err)
  1187. providerConf.PreLoginHook = preLoginPath
  1188. err = dataprovider.Initialize(providerConf, configDir, true)
  1189. assert.NoError(t, err)
  1190. _, _, err = httpdtest.GetUserByUsername(defaultUsername, http.StatusNotFound)
  1191. assert.NoError(t, err)
  1192. client, err := getFTPClient(u, false, nil)
  1193. if assert.NoError(t, err) {
  1194. err = checkBasicFTP(client)
  1195. assert.NoError(t, err)
  1196. err := client.Quit()
  1197. assert.NoError(t, err)
  1198. }
  1199. user, _, err := httpdtest.GetUserByUsername(defaultUsername, http.StatusOK)
  1200. assert.NoError(t, err)
  1201. // test login with an existing user
  1202. client, err = getFTPClient(user, true, nil)
  1203. if assert.NoError(t, err) {
  1204. err = checkBasicFTP(client)
  1205. assert.NoError(t, err)
  1206. err := client.Quit()
  1207. assert.NoError(t, err)
  1208. }
  1209. err = os.WriteFile(preLoginPath, getPreLoginScriptContent(user, true), os.ModePerm)
  1210. assert.NoError(t, err)
  1211. client, err = getFTPClient(u, false, nil)
  1212. if !assert.Error(t, err) {
  1213. err := client.Quit()
  1214. assert.NoError(t, err)
  1215. }
  1216. user.Status = 0
  1217. err = os.WriteFile(preLoginPath, getPreLoginScriptContent(user, false), os.ModePerm)
  1218. assert.NoError(t, err)
  1219. client, err = getFTPClient(u, false, nil)
  1220. if !assert.Error(t, err, "pre-login script returned a disabled user, login must fail") {
  1221. err := client.Quit()
  1222. assert.NoError(t, err)
  1223. }
  1224. user.Status = 0
  1225. user.Filters.FTPSecurity = 1
  1226. err = os.WriteFile(preLoginPath, getPreLoginScriptContent(user, false), os.ModePerm)
  1227. assert.NoError(t, err)
  1228. client, err = getFTPClient(u, true, nil)
  1229. if !assert.Error(t, err) {
  1230. err := client.Quit()
  1231. assert.NoError(t, err)
  1232. }
  1233. _, err = getFTPClient(user, false, nil)
  1234. if assert.Error(t, err) {
  1235. assert.Contains(t, err.Error(), "TLS is required")
  1236. }
  1237. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1238. assert.NoError(t, err)
  1239. err = os.RemoveAll(user.GetHomeDir())
  1240. assert.NoError(t, err)
  1241. err = dataprovider.Close()
  1242. assert.NoError(t, err)
  1243. err = config.LoadConfig(configDir, "")
  1244. assert.NoError(t, err)
  1245. providerConf = config.GetProviderConf()
  1246. err = dataprovider.Initialize(providerConf, configDir, true)
  1247. assert.NoError(t, err)
  1248. err = os.Remove(preLoginPath)
  1249. assert.NoError(t, err)
  1250. }
  1251. func TestPreLoginHookReturningAnonymousUser(t *testing.T) {
  1252. if runtime.GOOS == osWindows {
  1253. t.Skip("this test is not available on Windows")
  1254. }
  1255. u := getTestUser()
  1256. u.Filters.IsAnonymous = true
  1257. u.Filters.DeniedProtocols = []string{common.ProtocolSSH}
  1258. u.Password = ""
  1259. err := dataprovider.Close()
  1260. assert.NoError(t, err)
  1261. err = config.LoadConfig(configDir, "")
  1262. assert.NoError(t, err)
  1263. providerConf := config.GetProviderConf()
  1264. err = os.WriteFile(preLoginPath, getPreLoginScriptContent(u, false), os.ModePerm)
  1265. assert.NoError(t, err)
  1266. providerConf.PreLoginHook = preLoginPath
  1267. err = dataprovider.Initialize(providerConf, configDir, true)
  1268. assert.NoError(t, err)
  1269. // the pre-login hook create the anonymous user
  1270. client, err := getFTPClient(u, false, nil)
  1271. if assert.NoError(t, err) {
  1272. err = checkBasicFTP(client)
  1273. assert.NoError(t, err)
  1274. testFilePath := filepath.Join(homeBasePath, testFileName)
  1275. testFileSize := int64(65535)
  1276. err = createTestFile(testFilePath, testFileSize)
  1277. assert.NoError(t, err)
  1278. err = client.MakeDir("tdiranonymous")
  1279. if assert.Error(t, err) {
  1280. assert.Contains(t, err.Error(), "permission")
  1281. }
  1282. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  1283. if assert.Error(t, err) {
  1284. assert.Contains(t, err.Error(), "permission")
  1285. }
  1286. err = os.Rename(testFilePath, filepath.Join(u.GetHomeDir(), testFileName))
  1287. assert.NoError(t, err)
  1288. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  1289. err = ftpDownloadFile(testFileName, localDownloadPath, testFileSize, client, 0)
  1290. assert.NoError(t, err)
  1291. err := client.Quit()
  1292. assert.NoError(t, err)
  1293. }
  1294. user, _, err := httpdtest.GetUserByUsername(defaultUsername, http.StatusOK)
  1295. assert.NoError(t, err)
  1296. assert.True(t, user.Filters.IsAnonymous)
  1297. assert.Equal(t, []string{dataprovider.PermListItems, dataprovider.PermDownload}, user.Permissions["/"])
  1298. assert.Equal(t, []string{common.ProtocolSSH, common.ProtocolHTTP}, user.Filters.DeniedProtocols)
  1299. assert.Equal(t, []string{dataprovider.SSHLoginMethodPublicKey, dataprovider.SSHLoginMethodPassword,
  1300. dataprovider.SSHLoginMethodKeyboardInteractive, dataprovider.SSHLoginMethodKeyAndPassword,
  1301. dataprovider.SSHLoginMethodKeyAndKeyboardInt, dataprovider.LoginMethodTLSCertificate,
  1302. dataprovider.LoginMethodTLSCertificateAndPwd}, user.Filters.DeniedLoginMethods)
  1303. // now the same with an existing user
  1304. client, err = getFTPClient(u, false, nil)
  1305. if assert.NoError(t, err) {
  1306. err = checkBasicFTP(client)
  1307. assert.NoError(t, err)
  1308. testFilePath := filepath.Join(homeBasePath, testFileName)
  1309. testFileSize := int64(65535)
  1310. err = createTestFile(testFilePath, testFileSize)
  1311. assert.NoError(t, err)
  1312. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  1313. if assert.Error(t, err) {
  1314. assert.Contains(t, err.Error(), "permission")
  1315. }
  1316. err = os.Rename(testFilePath, filepath.Join(u.GetHomeDir(), testFileName))
  1317. assert.NoError(t, err)
  1318. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  1319. err = ftpDownloadFile(testFileName, localDownloadPath, testFileSize, client, 0)
  1320. assert.NoError(t, err)
  1321. err := client.Quit()
  1322. assert.NoError(t, err)
  1323. }
  1324. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1325. assert.NoError(t, err)
  1326. err = os.RemoveAll(user.GetHomeDir())
  1327. assert.NoError(t, err)
  1328. err = dataprovider.Close()
  1329. assert.NoError(t, err)
  1330. err = config.LoadConfig(configDir, "")
  1331. assert.NoError(t, err)
  1332. providerConf = config.GetProviderConf()
  1333. err = dataprovider.Initialize(providerConf, configDir, true)
  1334. assert.NoError(t, err)
  1335. err = os.Remove(preLoginPath)
  1336. assert.NoError(t, err)
  1337. }
  1338. func TestPreDownloadHook(t *testing.T) {
  1339. if runtime.GOOS == osWindows {
  1340. t.Skip("this test is not available on Windows")
  1341. }
  1342. oldExecuteOn := common.Config.Actions.ExecuteOn
  1343. oldHook := common.Config.Actions.Hook
  1344. common.Config.Actions.ExecuteOn = []string{common.OperationPreDownload}
  1345. common.Config.Actions.Hook = preDownloadPath
  1346. user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
  1347. assert.NoError(t, err)
  1348. err = os.WriteFile(preDownloadPath, getExitCodeScriptContent(0), os.ModePerm)
  1349. assert.NoError(t, err)
  1350. testFilePath := filepath.Join(homeBasePath, testFileName)
  1351. testFileSize := int64(65535)
  1352. err = createTestFile(testFilePath, testFileSize)
  1353. assert.NoError(t, err)
  1354. client, err := getFTPClient(user, true, nil)
  1355. if assert.NoError(t, err) {
  1356. err = checkBasicFTP(client)
  1357. assert.NoError(t, err)
  1358. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  1359. assert.NoError(t, err)
  1360. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  1361. err = ftpDownloadFile(testFileName, localDownloadPath, testFileSize, client, 0)
  1362. assert.NoError(t, err)
  1363. err := client.Quit()
  1364. assert.NoError(t, err)
  1365. err = os.Remove(localDownloadPath)
  1366. assert.NoError(t, err)
  1367. }
  1368. // now return an error from the pre-download hook
  1369. err = os.WriteFile(preDownloadPath, getExitCodeScriptContent(1), os.ModePerm)
  1370. assert.NoError(t, err)
  1371. client, err = getFTPClient(user, true, nil)
  1372. if assert.NoError(t, err) {
  1373. err = checkBasicFTP(client)
  1374. assert.NoError(t, err)
  1375. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  1376. assert.NoError(t, err)
  1377. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  1378. err = ftpDownloadFile(testFileName, localDownloadPath, testFileSize, client, 0)
  1379. if assert.Error(t, err) {
  1380. assert.Contains(t, err.Error(), "permission denied")
  1381. }
  1382. err := client.Quit()
  1383. assert.NoError(t, err)
  1384. err = os.Remove(localDownloadPath)
  1385. assert.NoError(t, err)
  1386. }
  1387. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1388. assert.NoError(t, err)
  1389. err = os.RemoveAll(user.GetHomeDir())
  1390. assert.NoError(t, err)
  1391. err = os.Remove(testFilePath)
  1392. assert.NoError(t, err)
  1393. common.Config.Actions.ExecuteOn = oldExecuteOn
  1394. common.Config.Actions.Hook = oldHook
  1395. }
  1396. func TestPreUploadHook(t *testing.T) {
  1397. if runtime.GOOS == osWindows {
  1398. t.Skip("this test is not available on Windows")
  1399. }
  1400. oldExecuteOn := common.Config.Actions.ExecuteOn
  1401. oldHook := common.Config.Actions.Hook
  1402. common.Config.Actions.ExecuteOn = []string{common.OperationPreUpload}
  1403. common.Config.Actions.Hook = preUploadPath
  1404. user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
  1405. assert.NoError(t, err)
  1406. err = os.WriteFile(preUploadPath, getExitCodeScriptContent(0), os.ModePerm)
  1407. assert.NoError(t, err)
  1408. testFilePath := filepath.Join(homeBasePath, testFileName)
  1409. testFileSize := int64(65535)
  1410. err = createTestFile(testFilePath, testFileSize)
  1411. assert.NoError(t, err)
  1412. client, err := getFTPClient(user, true, nil)
  1413. if assert.NoError(t, err) {
  1414. err = checkBasicFTP(client)
  1415. assert.NoError(t, err)
  1416. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  1417. assert.NoError(t, err)
  1418. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  1419. err = ftpDownloadFile(testFileName, localDownloadPath, testFileSize, client, 0)
  1420. assert.NoError(t, err)
  1421. err := client.Quit()
  1422. assert.NoError(t, err)
  1423. err = os.Remove(localDownloadPath)
  1424. assert.NoError(t, err)
  1425. }
  1426. // now return an error from the pre-upload hook
  1427. err = os.WriteFile(preUploadPath, getExitCodeScriptContent(1), os.ModePerm)
  1428. assert.NoError(t, err)
  1429. client, err = getFTPClient(user, true, nil)
  1430. if assert.NoError(t, err) {
  1431. err = checkBasicFTP(client)
  1432. assert.NoError(t, err)
  1433. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  1434. if assert.Error(t, err) {
  1435. assert.Contains(t, err.Error(), ftpserver.ErrFileNameNotAllowed.Error())
  1436. }
  1437. err = ftpUploadFile(testFilePath, testFileName+"1", testFileSize, client, 0)
  1438. if assert.Error(t, err) {
  1439. assert.Contains(t, err.Error(), ftpserver.ErrFileNameNotAllowed.Error())
  1440. }
  1441. err := client.Quit()
  1442. assert.NoError(t, err)
  1443. }
  1444. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1445. assert.NoError(t, err)
  1446. err = os.RemoveAll(user.GetHomeDir())
  1447. assert.NoError(t, err)
  1448. err = os.Remove(testFilePath)
  1449. assert.NoError(t, err)
  1450. common.Config.Actions.ExecuteOn = oldExecuteOn
  1451. common.Config.Actions.Hook = oldHook
  1452. }
  1453. func TestPostConnectHook(t *testing.T) {
  1454. if runtime.GOOS == osWindows {
  1455. t.Skip("this test is not available on Windows")
  1456. }
  1457. common.Config.PostConnectHook = postConnectPath
  1458. u := getTestUser()
  1459. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1460. assert.NoError(t, err)
  1461. err = os.WriteFile(postConnectPath, getExitCodeScriptContent(0), os.ModePerm)
  1462. assert.NoError(t, err)
  1463. client, err := getFTPClient(user, true, nil)
  1464. if assert.NoError(t, err) {
  1465. err = checkBasicFTP(client)
  1466. assert.NoError(t, err)
  1467. err := client.Quit()
  1468. assert.NoError(t, err)
  1469. }
  1470. err = os.WriteFile(postConnectPath, getExitCodeScriptContent(1), os.ModePerm)
  1471. assert.NoError(t, err)
  1472. client, err = getFTPClient(user, true, nil)
  1473. if !assert.Error(t, err) {
  1474. err := client.Quit()
  1475. assert.NoError(t, err)
  1476. }
  1477. common.Config.PostConnectHook = "http://127.0.0.1:8079/healthz"
  1478. client, err = getFTPClient(user, false, nil)
  1479. if assert.NoError(t, err) {
  1480. err = checkBasicFTP(client)
  1481. assert.NoError(t, err)
  1482. err := client.Quit()
  1483. assert.NoError(t, err)
  1484. }
  1485. common.Config.PostConnectHook = "http://127.0.0.1:8079/notfound"
  1486. client, err = getFTPClient(user, true, nil)
  1487. if !assert.Error(t, err) {
  1488. err := client.Quit()
  1489. assert.NoError(t, err)
  1490. }
  1491. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1492. assert.NoError(t, err)
  1493. err = os.RemoveAll(user.GetHomeDir())
  1494. assert.NoError(t, err)
  1495. common.Config.PostConnectHook = ""
  1496. }
  1497. //nolint:dupl
  1498. func TestMaxConnections(t *testing.T) {
  1499. oldValue := common.Config.MaxTotalConnections
  1500. common.Config.MaxTotalConnections = 1
  1501. assert.Eventually(t, func() bool {
  1502. return common.Connections.GetClientConnections() == 0
  1503. }, 1000*time.Millisecond, 50*time.Millisecond)
  1504. user := getTestUser()
  1505. err := dataprovider.AddUser(&user, "", "")
  1506. assert.NoError(t, err)
  1507. user.Password = ""
  1508. client, err := getFTPClient(user, true, nil)
  1509. if assert.NoError(t, err) {
  1510. err = checkBasicFTP(client)
  1511. assert.NoError(t, err)
  1512. _, err = getFTPClient(user, false, nil)
  1513. assert.Error(t, err)
  1514. err = client.Quit()
  1515. assert.NoError(t, err)
  1516. }
  1517. err = dataprovider.DeleteUser(user.Username, "", "")
  1518. assert.NoError(t, err)
  1519. err = os.RemoveAll(user.GetHomeDir())
  1520. assert.NoError(t, err)
  1521. common.Config.MaxTotalConnections = oldValue
  1522. }
  1523. //nolint:dupl
  1524. func TestMaxPerHostConnections(t *testing.T) {
  1525. oldValue := common.Config.MaxPerHostConnections
  1526. common.Config.MaxPerHostConnections = 1
  1527. assert.Eventually(t, func() bool {
  1528. return common.Connections.GetClientConnections() == 0
  1529. }, 1000*time.Millisecond, 50*time.Millisecond)
  1530. user := getTestUser()
  1531. err := dataprovider.AddUser(&user, "", "")
  1532. assert.NoError(t, err)
  1533. user.Password = ""
  1534. client, err := getFTPClient(user, true, nil)
  1535. if assert.NoError(t, err) {
  1536. err = checkBasicFTP(client)
  1537. assert.NoError(t, err)
  1538. _, err = getFTPClient(user, false, nil)
  1539. assert.Error(t, err)
  1540. err = client.Quit()
  1541. assert.NoError(t, err)
  1542. }
  1543. err = dataprovider.DeleteUser(user.Username, "", "")
  1544. assert.NoError(t, err)
  1545. err = os.RemoveAll(user.GetHomeDir())
  1546. assert.NoError(t, err)
  1547. common.Config.MaxPerHostConnections = oldValue
  1548. }
  1549. func TestRateLimiter(t *testing.T) {
  1550. oldConfig := config.GetCommonConfig()
  1551. cfg := config.GetCommonConfig()
  1552. cfg.DefenderConfig.Enabled = true
  1553. cfg.DefenderConfig.Threshold = 5
  1554. cfg.DefenderConfig.ScoreLimitExceeded = 3
  1555. cfg.RateLimitersConfig = []common.RateLimiterConfig{
  1556. {
  1557. Average: 1,
  1558. Period: 1000,
  1559. Burst: 1,
  1560. Type: 2,
  1561. Protocols: []string{common.ProtocolFTP},
  1562. GenerateDefenderEvents: true,
  1563. EntriesSoftLimit: 100,
  1564. EntriesHardLimit: 150,
  1565. },
  1566. }
  1567. err := common.Initialize(cfg, 0)
  1568. assert.NoError(t, err)
  1569. user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
  1570. assert.NoError(t, err)
  1571. client, err := getFTPClient(user, false, nil)
  1572. if assert.NoError(t, err) {
  1573. err = checkBasicFTP(client)
  1574. assert.NoError(t, err)
  1575. err = client.Quit()
  1576. assert.NoError(t, err)
  1577. }
  1578. _, err = getFTPClient(user, true, nil)
  1579. if assert.Error(t, err) {
  1580. assert.Contains(t, err.Error(), "rate limit exceed")
  1581. }
  1582. _, err = getFTPClient(user, false, nil)
  1583. if assert.Error(t, err) {
  1584. assert.Contains(t, err.Error(), "rate limit exceed")
  1585. }
  1586. _, err = getFTPClient(user, true, nil)
  1587. if assert.Error(t, err) {
  1588. assert.Contains(t, err.Error(), "banned client IP")
  1589. }
  1590. err = dataprovider.DeleteUser(user.Username, "", "")
  1591. assert.NoError(t, err)
  1592. err = os.RemoveAll(user.GetHomeDir())
  1593. assert.NoError(t, err)
  1594. err = common.Initialize(oldConfig, 0)
  1595. assert.NoError(t, err)
  1596. }
  1597. func TestDefender(t *testing.T) {
  1598. oldConfig := config.GetCommonConfig()
  1599. cfg := config.GetCommonConfig()
  1600. cfg.DefenderConfig.Enabled = true
  1601. cfg.DefenderConfig.Threshold = 3
  1602. cfg.DefenderConfig.ScoreLimitExceeded = 2
  1603. err := common.Initialize(cfg, 0)
  1604. assert.NoError(t, err)
  1605. user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
  1606. assert.NoError(t, err)
  1607. client, err := getFTPClient(user, false, nil)
  1608. if assert.NoError(t, err) {
  1609. err = checkBasicFTP(client)
  1610. assert.NoError(t, err)
  1611. err = client.Quit()
  1612. assert.NoError(t, err)
  1613. }
  1614. for i := 0; i < 3; i++ {
  1615. user.Password = "wrong_pwd"
  1616. _, err = getFTPClient(user, false, nil)
  1617. assert.Error(t, err)
  1618. }
  1619. user.Password = defaultPassword
  1620. _, err = getFTPClient(user, false, nil)
  1621. if assert.Error(t, err) {
  1622. assert.Contains(t, err.Error(), "banned client IP")
  1623. }
  1624. err = dataprovider.DeleteUser(user.Username, "", "")
  1625. assert.NoError(t, err)
  1626. err = os.RemoveAll(user.GetHomeDir())
  1627. assert.NoError(t, err)
  1628. err = common.Initialize(oldConfig, 0)
  1629. assert.NoError(t, err)
  1630. }
  1631. func TestMaxSessions(t *testing.T) {
  1632. u := getTestUser()
  1633. u.MaxSessions = 1
  1634. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1635. assert.NoError(t, err)
  1636. client, err := getFTPClient(user, true, nil)
  1637. if assert.NoError(t, err) {
  1638. err = checkBasicFTP(client)
  1639. assert.NoError(t, err)
  1640. _, err = getFTPClient(user, false, nil)
  1641. assert.Error(t, err)
  1642. err = client.Quit()
  1643. assert.NoError(t, err)
  1644. }
  1645. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1646. assert.NoError(t, err)
  1647. err = os.RemoveAll(user.GetHomeDir())
  1648. assert.NoError(t, err)
  1649. }
  1650. func TestZeroBytesTransfers(t *testing.T) {
  1651. u := getTestUser()
  1652. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1653. assert.NoError(t, err)
  1654. for _, useTLS := range []bool{true, false} {
  1655. client, err := getFTPClient(user, useTLS, nil)
  1656. if assert.NoError(t, err) {
  1657. testFileName := "testfilename"
  1658. err = checkBasicFTP(client)
  1659. assert.NoError(t, err)
  1660. localDownloadPath := filepath.Join(homeBasePath, "empty_download")
  1661. err = os.WriteFile(localDownloadPath, []byte(""), os.ModePerm)
  1662. assert.NoError(t, err)
  1663. err = ftpUploadFile(localDownloadPath, testFileName, 0, client, 0)
  1664. assert.NoError(t, err)
  1665. size, err := client.FileSize(testFileName)
  1666. assert.NoError(t, err)
  1667. assert.Equal(t, int64(0), size)
  1668. err = os.Remove(localDownloadPath)
  1669. assert.NoError(t, err)
  1670. assert.NoFileExists(t, localDownloadPath)
  1671. err = ftpDownloadFile(testFileName, localDownloadPath, 0, client, 0)
  1672. assert.NoError(t, err)
  1673. assert.FileExists(t, localDownloadPath)
  1674. err = client.Quit()
  1675. assert.NoError(t, err)
  1676. err = os.Remove(localDownloadPath)
  1677. assert.NoError(t, err)
  1678. }
  1679. }
  1680. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1681. assert.NoError(t, err)
  1682. err = os.RemoveAll(user.GetHomeDir())
  1683. assert.NoError(t, err)
  1684. }
  1685. func TestDownloadErrors(t *testing.T) {
  1686. u := getTestUser()
  1687. u.QuotaFiles = 1
  1688. subDir1 := "sub1"
  1689. subDir2 := "sub2"
  1690. u.Permissions[path.Join("/", subDir1)] = []string{dataprovider.PermListItems}
  1691. u.Permissions[path.Join("/", subDir2)] = []string{dataprovider.PermListItems, dataprovider.PermUpload,
  1692. dataprovider.PermDelete, dataprovider.PermDownload}
  1693. u.Filters.FilePatterns = []sdk.PatternsFilter{
  1694. {
  1695. Path: "/sub2",
  1696. AllowedPatterns: []string{},
  1697. DeniedPatterns: []string{"*.jpg", "*.zip"},
  1698. },
  1699. }
  1700. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1701. assert.NoError(t, err)
  1702. client, err := getFTPClient(user, true, nil)
  1703. if assert.NoError(t, err) {
  1704. testFilePath1 := filepath.Join(user.HomeDir, subDir1, "file.zip")
  1705. testFilePath2 := filepath.Join(user.HomeDir, subDir2, "file.zip")
  1706. testFilePath3 := filepath.Join(user.HomeDir, subDir2, "file.jpg")
  1707. err = os.MkdirAll(filepath.Dir(testFilePath1), os.ModePerm)
  1708. assert.NoError(t, err)
  1709. err = os.MkdirAll(filepath.Dir(testFilePath2), os.ModePerm)
  1710. assert.NoError(t, err)
  1711. err = os.WriteFile(testFilePath1, []byte("file1"), os.ModePerm)
  1712. assert.NoError(t, err)
  1713. err = os.WriteFile(testFilePath2, []byte("file2"), os.ModePerm)
  1714. assert.NoError(t, err)
  1715. err = os.WriteFile(testFilePath3, []byte("file3"), os.ModePerm)
  1716. assert.NoError(t, err)
  1717. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  1718. err = ftpDownloadFile(path.Join("/", subDir1, "file.zip"), localDownloadPath, 5, client, 0)
  1719. assert.Error(t, err)
  1720. err = ftpDownloadFile(path.Join("/", subDir2, "file.zip"), localDownloadPath, 5, client, 0)
  1721. assert.Error(t, err)
  1722. err = ftpDownloadFile(path.Join("/", subDir2, "file.jpg"), localDownloadPath, 5, client, 0)
  1723. assert.Error(t, err)
  1724. err = ftpDownloadFile("/missing.zip", localDownloadPath, 5, client, 0)
  1725. assert.Error(t, err)
  1726. err = client.Quit()
  1727. assert.NoError(t, err)
  1728. err = os.Remove(localDownloadPath)
  1729. assert.NoError(t, err)
  1730. }
  1731. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1732. assert.NoError(t, err)
  1733. err = os.RemoveAll(user.GetHomeDir())
  1734. assert.NoError(t, err)
  1735. }
  1736. func TestUploadErrors(t *testing.T) {
  1737. u := getTestUser()
  1738. u.QuotaSize = 65535
  1739. subDir1 := "sub1"
  1740. subDir2 := "sub2"
  1741. u.Permissions[path.Join("/", subDir1)] = []string{dataprovider.PermListItems}
  1742. u.Permissions[path.Join("/", subDir2)] = []string{dataprovider.PermListItems, dataprovider.PermUpload,
  1743. dataprovider.PermDelete}
  1744. u.Filters.FilePatterns = []sdk.PatternsFilter{
  1745. {
  1746. Path: "/sub2",
  1747. AllowedPatterns: []string{},
  1748. DeniedPatterns: []string{"*.zip"},
  1749. },
  1750. }
  1751. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1752. assert.NoError(t, err)
  1753. client, err := getFTPClient(user, true, nil)
  1754. if assert.NoError(t, err) {
  1755. testFilePath := filepath.Join(homeBasePath, testFileName)
  1756. testFileSize := user.QuotaSize
  1757. err = createTestFile(testFilePath, testFileSize)
  1758. assert.NoError(t, err)
  1759. err = client.MakeDir(subDir1)
  1760. assert.NoError(t, err)
  1761. err = client.MakeDir(subDir2)
  1762. assert.NoError(t, err)
  1763. err = client.ChangeDir(subDir1)
  1764. assert.NoError(t, err)
  1765. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  1766. assert.Error(t, err)
  1767. err = client.ChangeDirToParent()
  1768. assert.NoError(t, err)
  1769. err = client.ChangeDir(subDir2)
  1770. assert.NoError(t, err)
  1771. err = ftpUploadFile(testFilePath, testFileName+".zip", testFileSize, client, 0)
  1772. assert.Error(t, err)
  1773. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  1774. assert.NoError(t, err)
  1775. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  1776. assert.Error(t, err)
  1777. err = client.ChangeDir("/")
  1778. assert.NoError(t, err)
  1779. err = ftpUploadFile(testFilePath, subDir1, testFileSize, client, 0)
  1780. assert.Error(t, err)
  1781. // overquota
  1782. err = ftpUploadFile(testFilePath, testFileName+"1", testFileSize, client, 0)
  1783. assert.Error(t, err)
  1784. err = client.Delete(path.Join("/", subDir2, testFileName))
  1785. assert.NoError(t, err)
  1786. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  1787. assert.NoError(t, err)
  1788. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  1789. assert.Error(t, err)
  1790. err = client.Quit()
  1791. assert.NoError(t, err)
  1792. err = os.Remove(testFilePath)
  1793. assert.NoError(t, err)
  1794. }
  1795. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1796. assert.NoError(t, err)
  1797. err = os.RemoveAll(user.GetHomeDir())
  1798. assert.NoError(t, err)
  1799. }
  1800. func TestSFTPBuffered(t *testing.T) {
  1801. u := getTestUser()
  1802. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1803. assert.NoError(t, err)
  1804. u = getTestSFTPUser()
  1805. u.QuotaFiles = 100
  1806. u.FsConfig.SFTPConfig.BufferSize = 2
  1807. u.HomeDir = filepath.Join(os.TempDir(), u.Username)
  1808. sftpUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1809. assert.NoError(t, err)
  1810. client, err := getFTPClient(sftpUser, true, nil)
  1811. if assert.NoError(t, err) {
  1812. testFilePath := filepath.Join(homeBasePath, testFileName)
  1813. testFileSize := int64(65535)
  1814. expectedQuotaSize := testFileSize
  1815. expectedQuotaFiles := 1
  1816. err = createTestFile(testFilePath, testFileSize)
  1817. assert.NoError(t, err)
  1818. err = checkBasicFTP(client)
  1819. assert.NoError(t, err)
  1820. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  1821. assert.NoError(t, err)
  1822. // overwrite an existing file
  1823. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  1824. assert.NoError(t, err)
  1825. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  1826. err = ftpDownloadFile(testFileName, localDownloadPath, testFileSize, client, 0)
  1827. assert.NoError(t, err)
  1828. user, _, err := httpdtest.GetUserByUsername(sftpUser.Username, http.StatusOK)
  1829. assert.NoError(t, err)
  1830. assert.Equal(t, expectedQuotaFiles, user.UsedQuotaFiles)
  1831. assert.Equal(t, expectedQuotaSize, user.UsedQuotaSize)
  1832. data := []byte("test data")
  1833. err = os.WriteFile(testFilePath, data, os.ModePerm)
  1834. assert.NoError(t, err)
  1835. err = ftpUploadFile(testFilePath, testFileName, int64(len(data)), client, 0)
  1836. assert.NoError(t, err)
  1837. err = ftpUploadFile(testFilePath, testFileName, int64(len(data)+5), client, 5)
  1838. if assert.Error(t, err) {
  1839. assert.Contains(t, err.Error(), "operation unsupported")
  1840. }
  1841. err = ftpDownloadFile(testFileName, localDownloadPath, int64(4), client, 5)
  1842. assert.NoError(t, err)
  1843. readed, err := os.ReadFile(localDownloadPath)
  1844. assert.NoError(t, err)
  1845. assert.Equal(t, []byte("data"), readed)
  1846. // try to append to a file, it should fail
  1847. // now append to a file
  1848. srcFile, err := os.Open(testFilePath)
  1849. if assert.NoError(t, err) {
  1850. err = client.Append(testFileName, srcFile)
  1851. if assert.Error(t, err) {
  1852. assert.Contains(t, err.Error(), "operation unsupported")
  1853. }
  1854. err = srcFile.Close()
  1855. assert.NoError(t, err)
  1856. size, err := client.FileSize(testFileName)
  1857. assert.NoError(t, err)
  1858. assert.Equal(t, int64(len(data)), size)
  1859. err = ftpDownloadFile(testFileName, localDownloadPath, int64(len(data)), client, 0)
  1860. assert.NoError(t, err)
  1861. }
  1862. err = os.Remove(testFilePath)
  1863. assert.NoError(t, err)
  1864. err = os.Remove(localDownloadPath)
  1865. assert.NoError(t, err)
  1866. err = client.Quit()
  1867. assert.NoError(t, err)
  1868. }
  1869. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  1870. assert.NoError(t, err)
  1871. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  1872. assert.NoError(t, err)
  1873. err = os.RemoveAll(localUser.GetHomeDir())
  1874. assert.NoError(t, err)
  1875. err = os.RemoveAll(sftpUser.GetHomeDir())
  1876. assert.NoError(t, err)
  1877. }
  1878. func TestResume(t *testing.T) {
  1879. u := getTestUser()
  1880. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1881. assert.NoError(t, err)
  1882. sftpUser, _, err := httpdtest.AddUser(getTestSFTPUser(), http.StatusCreated)
  1883. assert.NoError(t, err)
  1884. for _, user := range []dataprovider.User{localUser, sftpUser} {
  1885. client, err := getFTPClient(user, true, nil)
  1886. if assert.NoError(t, err) {
  1887. testFilePath := filepath.Join(homeBasePath, testFileName)
  1888. data := []byte("test data")
  1889. err = os.WriteFile(testFilePath, data, os.ModePerm)
  1890. assert.NoError(t, err)
  1891. err = ftpUploadFile(testFilePath, testFileName, int64(len(data)), client, 0)
  1892. assert.NoError(t, err)
  1893. err = ftpUploadFile(testFilePath, testFileName, int64(len(data)+5), client, 5)
  1894. assert.NoError(t, err)
  1895. readed, err := os.ReadFile(filepath.Join(user.GetHomeDir(), testFileName))
  1896. assert.NoError(t, err)
  1897. assert.Equal(t, "test test data", string(readed))
  1898. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  1899. err = ftpDownloadFile(testFileName, localDownloadPath, int64(len(data)), client, 5)
  1900. assert.NoError(t, err)
  1901. readed, err = os.ReadFile(localDownloadPath)
  1902. assert.NoError(t, err)
  1903. assert.Equal(t, data, readed)
  1904. err = client.Delete(testFileName)
  1905. assert.NoError(t, err)
  1906. err = ftpUploadFile(testFilePath, testFileName, int64(len(data)), client, 0)
  1907. assert.NoError(t, err)
  1908. // now append to a file
  1909. srcFile, err := os.Open(testFilePath)
  1910. if assert.NoError(t, err) {
  1911. err = client.Append(testFileName, srcFile)
  1912. assert.NoError(t, err)
  1913. err = srcFile.Close()
  1914. assert.NoError(t, err)
  1915. size, err := client.FileSize(testFileName)
  1916. assert.NoError(t, err)
  1917. assert.Equal(t, int64(2*len(data)), size)
  1918. err = ftpDownloadFile(testFileName, localDownloadPath, int64(2*len(data)), client, 0)
  1919. assert.NoError(t, err)
  1920. readed, err = os.ReadFile(localDownloadPath)
  1921. assert.NoError(t, err)
  1922. expected := append(data, data...)
  1923. assert.Equal(t, expected, readed)
  1924. }
  1925. // append to a new file
  1926. srcFile, err = os.Open(testFilePath)
  1927. if assert.NoError(t, err) {
  1928. newFileName := testFileName + "_new"
  1929. err = client.Append(newFileName, srcFile)
  1930. assert.NoError(t, err)
  1931. err = srcFile.Close()
  1932. assert.NoError(t, err)
  1933. size, err := client.FileSize(newFileName)
  1934. assert.NoError(t, err)
  1935. assert.Equal(t, int64(len(data)), size)
  1936. err = ftpDownloadFile(newFileName, localDownloadPath, int64(len(data)), client, 0)
  1937. assert.NoError(t, err)
  1938. readed, err = os.ReadFile(localDownloadPath)
  1939. assert.NoError(t, err)
  1940. assert.Equal(t, data, readed)
  1941. }
  1942. err = client.Quit()
  1943. assert.NoError(t, err)
  1944. err = os.Remove(testFilePath)
  1945. assert.NoError(t, err)
  1946. err = os.Remove(localDownloadPath)
  1947. assert.NoError(t, err)
  1948. if user.Username == defaultUsername {
  1949. err = os.RemoveAll(user.GetHomeDir())
  1950. assert.NoError(t, err)
  1951. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1952. assert.NoError(t, err)
  1953. user.Password = defaultPassword
  1954. user.ID = 0
  1955. user.CreatedAt = 0
  1956. _, resp, err := httpdtest.AddUser(user, http.StatusCreated)
  1957. assert.NoError(t, err, string(resp))
  1958. }
  1959. }
  1960. }
  1961. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  1962. assert.NoError(t, err)
  1963. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  1964. assert.NoError(t, err)
  1965. err = os.RemoveAll(localUser.GetHomeDir())
  1966. assert.NoError(t, err)
  1967. }
  1968. //nolint:dupl
  1969. func TestDeniedLoginMethod(t *testing.T) {
  1970. u := getTestUser()
  1971. u.Filters.DeniedLoginMethods = []string{dataprovider.LoginMethodPassword}
  1972. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1973. assert.NoError(t, err)
  1974. _, err = getFTPClient(user, false, nil)
  1975. assert.Error(t, err)
  1976. user.Filters.DeniedLoginMethods = []string{dataprovider.SSHLoginMethodPublicKey, dataprovider.SSHLoginMethodKeyAndPassword}
  1977. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  1978. assert.NoError(t, err)
  1979. client, err := getFTPClient(user, true, nil)
  1980. if assert.NoError(t, err) {
  1981. assert.NoError(t, checkBasicFTP(client))
  1982. err = client.Quit()
  1983. assert.NoError(t, err)
  1984. }
  1985. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1986. assert.NoError(t, err)
  1987. err = os.RemoveAll(user.GetHomeDir())
  1988. assert.NoError(t, err)
  1989. }
  1990. //nolint:dupl
  1991. func TestDeniedProtocols(t *testing.T) {
  1992. u := getTestUser()
  1993. u.Filters.DeniedProtocols = []string{common.ProtocolFTP}
  1994. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1995. assert.NoError(t, err)
  1996. _, err = getFTPClient(user, false, nil)
  1997. assert.Error(t, err)
  1998. user.Filters.DeniedProtocols = []string{common.ProtocolSSH, common.ProtocolWebDAV}
  1999. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  2000. assert.NoError(t, err)
  2001. client, err := getFTPClient(user, true, nil)
  2002. if assert.NoError(t, err) {
  2003. assert.NoError(t, checkBasicFTP(client))
  2004. err = client.Quit()
  2005. assert.NoError(t, err)
  2006. }
  2007. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2008. assert.NoError(t, err)
  2009. err = os.RemoveAll(user.GetHomeDir())
  2010. assert.NoError(t, err)
  2011. }
  2012. func TestQuotaLimits(t *testing.T) {
  2013. u := getTestUser()
  2014. u.QuotaFiles = 1
  2015. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2016. assert.NoError(t, err)
  2017. u = getTestSFTPUser()
  2018. u.QuotaFiles = 1
  2019. sftpUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2020. assert.NoError(t, err)
  2021. for _, user := range []dataprovider.User{localUser, sftpUser} {
  2022. testFileSize := int64(65535)
  2023. testFilePath := filepath.Join(homeBasePath, testFileName)
  2024. err = createTestFile(testFilePath, testFileSize)
  2025. assert.NoError(t, err)
  2026. testFileSize1 := int64(131072)
  2027. testFileName1 := "test_file1.dat"
  2028. testFilePath1 := filepath.Join(homeBasePath, testFileName1)
  2029. err = createTestFile(testFilePath1, testFileSize1)
  2030. assert.NoError(t, err)
  2031. testFileSize2 := int64(32768)
  2032. testFileName2 := "test_file2.dat"
  2033. testFilePath2 := filepath.Join(homeBasePath, testFileName2)
  2034. err = createTestFile(testFilePath2, testFileSize2)
  2035. assert.NoError(t, err)
  2036. // test quota files
  2037. client, err := getFTPClient(user, false, nil)
  2038. if assert.NoError(t, err) {
  2039. err = ftpUploadFile(testFilePath, testFileName+".quota", testFileSize, client, 0)
  2040. assert.NoError(t, err)
  2041. err = ftpUploadFile(testFilePath, testFileName+".quota1", testFileSize, client, 0)
  2042. assert.Error(t, err)
  2043. err = client.Rename(testFileName+".quota", testFileName)
  2044. assert.NoError(t, err)
  2045. err = client.Quit()
  2046. assert.NoError(t, err)
  2047. }
  2048. // test quota size
  2049. user.QuotaSize = testFileSize - 1
  2050. user.QuotaFiles = 0
  2051. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  2052. assert.NoError(t, err)
  2053. client, err = getFTPClient(user, true, nil)
  2054. if assert.NoError(t, err) {
  2055. err = ftpUploadFile(testFilePath, testFileName+".quota", testFileSize, client, 0)
  2056. assert.Error(t, err)
  2057. err = client.Rename(testFileName, testFileName+".quota")
  2058. assert.NoError(t, err)
  2059. err = client.Quit()
  2060. assert.NoError(t, err)
  2061. }
  2062. // now test quota limits while uploading the current file, we have 1 bytes remaining
  2063. user.QuotaSize = testFileSize + 1
  2064. user.QuotaFiles = 0
  2065. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  2066. assert.NoError(t, err)
  2067. client, err = getFTPClient(user, false, nil)
  2068. if assert.NoError(t, err) {
  2069. err = ftpUploadFile(testFilePath1, testFileName1, testFileSize1, client, 0)
  2070. assert.Error(t, err)
  2071. _, err = client.FileSize(testFileName1)
  2072. assert.Error(t, err)
  2073. err = client.Rename(testFileName+".quota", testFileName)
  2074. assert.NoError(t, err)
  2075. // overwriting an existing file will work if the resulting size is lesser or equal than the current one
  2076. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  2077. assert.NoError(t, err)
  2078. err = ftpUploadFile(testFilePath2, testFileName, testFileSize2, client, 0)
  2079. assert.NoError(t, err)
  2080. err = ftpUploadFile(testFilePath1, testFileName, testFileSize1, client, 0)
  2081. assert.Error(t, err)
  2082. err = ftpUploadFile(testFilePath1, testFileName, testFileSize1, client, 10)
  2083. assert.Error(t, err)
  2084. err = ftpUploadFile(testFilePath2, testFileName, testFileSize2, client, 0)
  2085. assert.NoError(t, err)
  2086. err = client.Quit()
  2087. assert.NoError(t, err)
  2088. }
  2089. err = os.Remove(testFilePath)
  2090. assert.NoError(t, err)
  2091. err = os.Remove(testFilePath1)
  2092. assert.NoError(t, err)
  2093. err = os.Remove(testFilePath2)
  2094. assert.NoError(t, err)
  2095. if user.Username == defaultUsername {
  2096. err = os.RemoveAll(user.GetHomeDir())
  2097. assert.NoError(t, err)
  2098. user.QuotaFiles = 0
  2099. user.QuotaSize = 0
  2100. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2101. assert.NoError(t, err)
  2102. user.Password = defaultPassword
  2103. user.QuotaSize = 0
  2104. user.ID = 0
  2105. user.CreatedAt = 0
  2106. _, resp, err := httpdtest.AddUser(user, http.StatusCreated)
  2107. assert.NoError(t, err, string(resp))
  2108. }
  2109. }
  2110. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  2111. assert.NoError(t, err)
  2112. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  2113. assert.NoError(t, err)
  2114. err = os.RemoveAll(localUser.GetHomeDir())
  2115. assert.NoError(t, err)
  2116. }
  2117. func TestUploadMaxSize(t *testing.T) {
  2118. testFileSize := int64(65535)
  2119. u := getTestUser()
  2120. u.Filters.MaxUploadFileSize = testFileSize + 1
  2121. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2122. assert.NoError(t, err)
  2123. u = getTestSFTPUser()
  2124. u.Filters.MaxUploadFileSize = testFileSize + 1
  2125. sftpUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2126. assert.NoError(t, err)
  2127. for _, user := range []dataprovider.User{localUser, sftpUser} {
  2128. testFilePath := filepath.Join(homeBasePath, testFileName)
  2129. err = createTestFile(testFilePath, testFileSize)
  2130. assert.NoError(t, err)
  2131. testFileSize1 := int64(131072)
  2132. testFileName1 := "test_file1.dat"
  2133. testFilePath1 := filepath.Join(homeBasePath, testFileName1)
  2134. err = createTestFile(testFilePath1, testFileSize1)
  2135. assert.NoError(t, err)
  2136. client, err := getFTPClient(user, false, nil)
  2137. if assert.NoError(t, err) {
  2138. err = ftpUploadFile(testFilePath1, testFileName1, testFileSize1, client, 0)
  2139. assert.Error(t, err)
  2140. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  2141. assert.NoError(t, err)
  2142. // now test overwrite an existing file with a size bigger than the allowed one
  2143. err = createTestFile(filepath.Join(user.GetHomeDir(), testFileName1), testFileSize1)
  2144. assert.NoError(t, err)
  2145. err = ftpUploadFile(testFilePath1, testFileName1, testFileSize1, client, 0)
  2146. assert.Error(t, err)
  2147. err = client.Quit()
  2148. assert.NoError(t, err)
  2149. }
  2150. err = os.Remove(testFilePath)
  2151. assert.NoError(t, err)
  2152. err = os.Remove(testFilePath1)
  2153. assert.NoError(t, err)
  2154. if user.Username == defaultUsername {
  2155. err = os.RemoveAll(user.GetHomeDir())
  2156. assert.NoError(t, err)
  2157. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2158. assert.NoError(t, err)
  2159. user.Password = defaultPassword
  2160. user.Filters.MaxUploadFileSize = 65536000
  2161. user.ID = 0
  2162. user.CreatedAt = 0
  2163. _, resp, err := httpdtest.AddUser(user, http.StatusCreated)
  2164. assert.NoError(t, err, string(resp))
  2165. }
  2166. }
  2167. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  2168. assert.NoError(t, err)
  2169. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  2170. assert.NoError(t, err)
  2171. err = os.RemoveAll(localUser.GetHomeDir())
  2172. assert.NoError(t, err)
  2173. }
  2174. func TestLoginWithIPilters(t *testing.T) {
  2175. u := getTestUser()
  2176. u.Filters.DeniedIP = []string{"192.167.0.0/24", "172.18.0.0/16"}
  2177. u.Filters.AllowedIP = []string{"172.19.0.0/16"}
  2178. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2179. assert.NoError(t, err)
  2180. client, err := getFTPClient(user, true, nil)
  2181. if !assert.Error(t, err) {
  2182. err = client.Quit()
  2183. assert.NoError(t, err)
  2184. }
  2185. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2186. assert.NoError(t, err)
  2187. err = os.RemoveAll(user.GetHomeDir())
  2188. assert.NoError(t, err)
  2189. }
  2190. func TestLoginWithDatabaseCredentials(t *testing.T) {
  2191. u := getTestUser()
  2192. u.FsConfig.Provider = sdk.GCSFilesystemProvider
  2193. u.FsConfig.GCSConfig.Bucket = "test"
  2194. u.FsConfig.GCSConfig.Credentials = kms.NewPlainSecret(`{ "type": "service_account" }`)
  2195. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2196. assert.NoError(t, err)
  2197. assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.GCSConfig.Credentials.GetStatus())
  2198. assert.NotEmpty(t, user.FsConfig.GCSConfig.Credentials.GetPayload())
  2199. assert.Empty(t, user.FsConfig.GCSConfig.Credentials.GetAdditionalData())
  2200. assert.Empty(t, user.FsConfig.GCSConfig.Credentials.GetKey())
  2201. client, err := getFTPClient(user, false, nil)
  2202. if assert.NoError(t, err) {
  2203. err = client.Quit()
  2204. assert.NoError(t, err)
  2205. }
  2206. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2207. assert.NoError(t, err)
  2208. err = os.RemoveAll(user.GetHomeDir())
  2209. assert.NoError(t, err)
  2210. }
  2211. func TestLoginInvalidFs(t *testing.T) {
  2212. u := getTestUser()
  2213. u.FsConfig.Provider = sdk.GCSFilesystemProvider
  2214. u.FsConfig.GCSConfig.Bucket = "test"
  2215. u.FsConfig.GCSConfig.Credentials = kms.NewPlainSecret("invalid JSON for credentials")
  2216. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2217. assert.NoError(t, err)
  2218. client, err := getFTPClient(user, false, nil)
  2219. if !assert.Error(t, err) {
  2220. err = client.Quit()
  2221. assert.NoError(t, err)
  2222. }
  2223. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2224. assert.NoError(t, err)
  2225. err = os.RemoveAll(user.GetHomeDir())
  2226. assert.NoError(t, err)
  2227. }
  2228. func TestClientClose(t *testing.T) {
  2229. u := getTestUser()
  2230. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2231. assert.NoError(t, err)
  2232. client, err := getFTPClient(user, true, nil)
  2233. if assert.NoError(t, err) {
  2234. err = checkBasicFTP(client)
  2235. assert.NoError(t, err)
  2236. stats := common.Connections.GetStats()
  2237. if assert.Len(t, stats, 1) {
  2238. common.Connections.Close(stats[0].ConnectionID)
  2239. assert.Eventually(t, func() bool { return len(common.Connections.GetStats()) == 0 },
  2240. 1*time.Second, 50*time.Millisecond)
  2241. }
  2242. }
  2243. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2244. assert.NoError(t, err)
  2245. err = os.RemoveAll(user.GetHomeDir())
  2246. assert.NoError(t, err)
  2247. }
  2248. func TestRename(t *testing.T) {
  2249. u := getTestUser()
  2250. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2251. assert.NoError(t, err)
  2252. sftpUser, _, err := httpdtest.AddUser(getTestSFTPUser(), http.StatusCreated)
  2253. assert.NoError(t, err)
  2254. for _, user := range []dataprovider.User{localUser, sftpUser} {
  2255. testDir := "adir"
  2256. testFilePath := filepath.Join(homeBasePath, testFileName)
  2257. testFileSize := int64(65535)
  2258. err = createTestFile(testFilePath, testFileSize)
  2259. assert.NoError(t, err)
  2260. client, err := getFTPClient(user, false, nil)
  2261. if assert.NoError(t, err) {
  2262. err = checkBasicFTP(client)
  2263. assert.NoError(t, err)
  2264. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  2265. assert.NoError(t, err)
  2266. err = client.MakeDir(testDir)
  2267. assert.NoError(t, err)
  2268. err = client.Rename(testFileName, path.Join("missing", testFileName))
  2269. assert.Error(t, err)
  2270. err = client.Rename(testFileName, path.Join(testDir, testFileName))
  2271. assert.NoError(t, err)
  2272. size, err := client.FileSize(path.Join(testDir, testFileName))
  2273. assert.NoError(t, err)
  2274. assert.Equal(t, testFileSize, size)
  2275. if runtime.GOOS != osWindows {
  2276. otherDir := "dir"
  2277. err = client.MakeDir(otherDir)
  2278. assert.NoError(t, err)
  2279. err = client.MakeDir(path.Join(otherDir, testDir))
  2280. assert.NoError(t, err)
  2281. code, response, err := client.SendCustomCommand(fmt.Sprintf("SITE CHMOD 0001 %v", otherDir))
  2282. assert.NoError(t, err)
  2283. assert.Equal(t, ftp.StatusCommandOK, code)
  2284. assert.Equal(t, "SITE CHMOD command successful", response)
  2285. err = client.Rename(testDir, path.Join(otherDir, testDir))
  2286. assert.Error(t, err)
  2287. code, response, err = client.SendCustomCommand(fmt.Sprintf("SITE CHMOD 755 %v", otherDir))
  2288. assert.NoError(t, err)
  2289. assert.Equal(t, ftp.StatusCommandOK, code)
  2290. assert.Equal(t, "SITE CHMOD command successful", response)
  2291. }
  2292. err = client.Quit()
  2293. assert.NoError(t, err)
  2294. }
  2295. user.Permissions[path.Join("/", testDir)] = []string{dataprovider.PermListItems}
  2296. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  2297. assert.NoError(t, err)
  2298. client, err = getFTPClient(user, false, nil)
  2299. if assert.NoError(t, err) {
  2300. err = client.Rename(path.Join(testDir, testFileName), testFileName)
  2301. assert.Error(t, err)
  2302. err := client.Quit()
  2303. assert.NoError(t, err)
  2304. }
  2305. err = os.Remove(testFilePath)
  2306. assert.NoError(t, err)
  2307. if user.Username == defaultUsername {
  2308. err = os.RemoveAll(user.GetHomeDir())
  2309. assert.NoError(t, err)
  2310. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2311. assert.NoError(t, err)
  2312. user.Permissions = make(map[string][]string)
  2313. user.Permissions["/"] = allPerms
  2314. user.Password = defaultPassword
  2315. user.ID = 0
  2316. user.CreatedAt = 0
  2317. _, resp, err := httpdtest.AddUser(user, http.StatusCreated)
  2318. assert.NoError(t, err, string(resp))
  2319. }
  2320. }
  2321. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  2322. assert.NoError(t, err)
  2323. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  2324. assert.NoError(t, err)
  2325. err = os.RemoveAll(localUser.GetHomeDir())
  2326. assert.NoError(t, err)
  2327. }
  2328. func TestSymlink(t *testing.T) {
  2329. u := getTestUser()
  2330. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2331. assert.NoError(t, err)
  2332. sftpUser, _, err := httpdtest.AddUser(getTestSFTPUser(), http.StatusCreated)
  2333. assert.NoError(t, err)
  2334. testFilePath := filepath.Join(homeBasePath, testFileName)
  2335. testFileSize := int64(65535)
  2336. for _, user := range []dataprovider.User{localUser, sftpUser} {
  2337. err = createTestFile(testFilePath, testFileSize)
  2338. assert.NoError(t, err)
  2339. client, err := getFTPClient(user, false, nil)
  2340. if assert.NoError(t, err) {
  2341. err = checkBasicFTP(client)
  2342. assert.NoError(t, err)
  2343. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  2344. assert.NoError(t, err)
  2345. code, _, err := client.SendCustomCommand(fmt.Sprintf("SITE SYMLINK %v %v", testFileName, testFileName+".link"))
  2346. assert.NoError(t, err)
  2347. assert.Equal(t, ftp.StatusCommandOK, code)
  2348. if runtime.GOOS != osWindows {
  2349. testDir := "adir"
  2350. otherDir := "dir"
  2351. err = client.MakeDir(otherDir)
  2352. assert.NoError(t, err)
  2353. err = client.MakeDir(path.Join(otherDir, testDir))
  2354. assert.NoError(t, err)
  2355. code, response, err := client.SendCustomCommand(fmt.Sprintf("SITE CHMOD 0001 %v", otherDir))
  2356. assert.NoError(t, err)
  2357. assert.Equal(t, ftp.StatusCommandOK, code)
  2358. assert.Equal(t, "SITE CHMOD command successful", response)
  2359. code, _, err = client.SendCustomCommand(fmt.Sprintf("SITE SYMLINK %v %v", testDir, path.Join(otherDir, testDir)))
  2360. assert.NoError(t, err)
  2361. assert.Equal(t, ftp.StatusFileUnavailable, code)
  2362. code, response, err = client.SendCustomCommand(fmt.Sprintf("SITE CHMOD 755 %v", otherDir))
  2363. assert.NoError(t, err)
  2364. assert.Equal(t, ftp.StatusCommandOK, code)
  2365. assert.Equal(t, "SITE CHMOD command successful", response)
  2366. }
  2367. err = client.Quit()
  2368. assert.NoError(t, err)
  2369. if user.Username == defaultUsername {
  2370. err = os.RemoveAll(user.GetHomeDir())
  2371. assert.NoError(t, err)
  2372. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2373. assert.NoError(t, err)
  2374. user.Password = defaultPassword
  2375. user.ID = 0
  2376. user.CreatedAt = 0
  2377. _, resp, err := httpdtest.AddUser(user, http.StatusCreated)
  2378. assert.NoError(t, err, string(resp))
  2379. }
  2380. }
  2381. err = os.Remove(testFilePath)
  2382. assert.NoError(t, err)
  2383. }
  2384. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  2385. assert.NoError(t, err)
  2386. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  2387. assert.NoError(t, err)
  2388. err = os.RemoveAll(localUser.GetHomeDir())
  2389. assert.NoError(t, err)
  2390. }
  2391. func TestStat(t *testing.T) {
  2392. u := getTestUser()
  2393. u.Permissions["/subdir"] = []string{dataprovider.PermUpload}
  2394. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2395. assert.NoError(t, err)
  2396. sftpUser, _, err := httpdtest.AddUser(getTestSFTPUser(), http.StatusCreated)
  2397. assert.NoError(t, err)
  2398. for _, user := range []dataprovider.User{localUser, sftpUser} {
  2399. client, err := getFTPClient(user, false, nil)
  2400. if assert.NoError(t, err) {
  2401. subDir := "subdir"
  2402. testFilePath := filepath.Join(homeBasePath, testFileName)
  2403. testFileSize := int64(65535)
  2404. err = createTestFile(testFilePath, testFileSize)
  2405. assert.NoError(t, err)
  2406. err = client.MakeDir(subDir)
  2407. assert.NoError(t, err)
  2408. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  2409. assert.NoError(t, err)
  2410. err = ftpUploadFile(testFilePath, path.Join("/", subDir, testFileName), testFileSize, client, 0)
  2411. assert.Error(t, err)
  2412. size, err := client.FileSize(testFileName)
  2413. assert.NoError(t, err)
  2414. assert.Equal(t, testFileSize, size)
  2415. _, err = client.FileSize(path.Join("/", subDir, testFileName))
  2416. assert.Error(t, err)
  2417. _, err = client.FileSize("missing file")
  2418. assert.Error(t, err)
  2419. err = client.Quit()
  2420. assert.NoError(t, err)
  2421. err = os.Remove(testFilePath)
  2422. assert.NoError(t, err)
  2423. if user.Username == defaultUsername {
  2424. err = os.RemoveAll(user.GetHomeDir())
  2425. assert.NoError(t, err)
  2426. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2427. assert.NoError(t, err)
  2428. user.Password = defaultPassword
  2429. user.ID = 0
  2430. user.CreatedAt = 0
  2431. _, resp, err := httpdtest.AddUser(user, http.StatusCreated)
  2432. assert.NoError(t, err, string(resp))
  2433. }
  2434. }
  2435. }
  2436. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  2437. assert.NoError(t, err)
  2438. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  2439. assert.NoError(t, err)
  2440. err = os.RemoveAll(localUser.GetHomeDir())
  2441. assert.NoError(t, err)
  2442. }
  2443. func TestUploadOverwriteVfolder(t *testing.T) {
  2444. u := getTestUser()
  2445. vdir := "/vdir"
  2446. mappedPath := filepath.Join(os.TempDir(), "vdir")
  2447. folderName := filepath.Base(mappedPath)
  2448. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  2449. BaseVirtualFolder: vfs.BaseVirtualFolder{
  2450. Name: folderName,
  2451. MappedPath: mappedPath,
  2452. },
  2453. VirtualPath: vdir,
  2454. QuotaSize: -1,
  2455. QuotaFiles: -1,
  2456. })
  2457. err := os.MkdirAll(mappedPath, os.ModePerm)
  2458. assert.NoError(t, err)
  2459. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2460. assert.NoError(t, err)
  2461. client, err := getFTPClient(user, false, nil)
  2462. if assert.NoError(t, err) {
  2463. testFilePath := filepath.Join(homeBasePath, testFileName)
  2464. testFileSize := int64(65535)
  2465. err = createTestFile(testFilePath, testFileSize)
  2466. assert.NoError(t, err)
  2467. err = ftpUploadFile(testFilePath, path.Join(vdir, testFileName), testFileSize, client, 0)
  2468. assert.NoError(t, err)
  2469. folder, _, err := httpdtest.GetFolderByName(folderName, http.StatusOK)
  2470. assert.NoError(t, err)
  2471. assert.Equal(t, testFileSize, folder.UsedQuotaSize)
  2472. assert.Equal(t, 1, folder.UsedQuotaFiles)
  2473. err = ftpUploadFile(testFilePath, path.Join(vdir, testFileName), testFileSize, client, 0)
  2474. assert.NoError(t, err)
  2475. folder, _, err = httpdtest.GetFolderByName(folderName, http.StatusOK)
  2476. assert.NoError(t, err)
  2477. assert.Equal(t, testFileSize, folder.UsedQuotaSize)
  2478. assert.Equal(t, 1, folder.UsedQuotaFiles)
  2479. err = client.Quit()
  2480. assert.NoError(t, err)
  2481. err = os.Remove(testFilePath)
  2482. assert.NoError(t, err)
  2483. }
  2484. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2485. assert.NoError(t, err)
  2486. _, err = httpdtest.RemoveFolder(vfs.BaseVirtualFolder{Name: folderName}, http.StatusOK)
  2487. assert.NoError(t, err)
  2488. err = os.RemoveAll(user.GetHomeDir())
  2489. assert.NoError(t, err)
  2490. err = os.RemoveAll(mappedPath)
  2491. assert.NoError(t, err)
  2492. }
  2493. func TestTransferQuotaLimits(t *testing.T) {
  2494. u := getTestUser()
  2495. u.DownloadDataTransfer = 1
  2496. u.UploadDataTransfer = 1
  2497. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2498. assert.NoError(t, err)
  2499. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  2500. testFilePath := filepath.Join(homeBasePath, testFileName)
  2501. testFileSize := int64(524288)
  2502. err = createTestFile(testFilePath, testFileSize)
  2503. assert.NoError(t, err)
  2504. client, err := getFTPClient(user, false, nil)
  2505. if assert.NoError(t, err) {
  2506. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  2507. assert.NoError(t, err)
  2508. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  2509. assert.NoError(t, err)
  2510. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  2511. if assert.Error(t, err) {
  2512. assert.Contains(t, err.Error(), ftpserver.ErrStorageExceeded.Error())
  2513. }
  2514. err = ftpDownloadFile(testFileName, localDownloadPath, testFileSize, client, 0)
  2515. assert.NoError(t, err)
  2516. err = ftpDownloadFile(testFileName, localDownloadPath, testFileSize, client, 0)
  2517. assert.NoError(t, err)
  2518. err = ftpDownloadFile(testFileName, localDownloadPath, testFileSize, client, 0)
  2519. if assert.Error(t, err) {
  2520. assert.Contains(t, err.Error(), common.ErrReadQuotaExceeded.Error())
  2521. }
  2522. err = client.Quit()
  2523. assert.NoError(t, err)
  2524. }
  2525. testFileSize = int64(600000)
  2526. err = createTestFile(testFilePath, testFileSize)
  2527. assert.NoError(t, err)
  2528. user.DownloadDataTransfer = 2
  2529. user.UploadDataTransfer = 2
  2530. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  2531. assert.NoError(t, err)
  2532. client, err = getFTPClient(user, false, nil)
  2533. if assert.NoError(t, err) {
  2534. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  2535. assert.NoError(t, err)
  2536. err = ftpDownloadFile(testFileName, localDownloadPath, testFileSize, client, 0)
  2537. assert.NoError(t, err)
  2538. err = ftpDownloadFile(testFileName, localDownloadPath, testFileSize, client, 0)
  2539. assert.Error(t, err)
  2540. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  2541. assert.Error(t, err)
  2542. err = client.Quit()
  2543. assert.NoError(t, err)
  2544. }
  2545. err = os.Remove(localDownloadPath)
  2546. assert.NoError(t, err)
  2547. err = os.Remove(testFilePath)
  2548. assert.NoError(t, err)
  2549. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2550. assert.NoError(t, err)
  2551. err = os.RemoveAll(user.GetHomeDir())
  2552. assert.NoError(t, err)
  2553. }
  2554. func TestAllocateAvailable(t *testing.T) {
  2555. u := getTestUser()
  2556. mappedPath := filepath.Join(os.TempDir(), "vdir")
  2557. folderName := filepath.Base(mappedPath)
  2558. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  2559. BaseVirtualFolder: vfs.BaseVirtualFolder{
  2560. Name: folderName,
  2561. MappedPath: mappedPath,
  2562. },
  2563. VirtualPath: "/vdir",
  2564. QuotaSize: 110,
  2565. })
  2566. err := os.MkdirAll(mappedPath, os.ModePerm)
  2567. assert.NoError(t, err)
  2568. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2569. assert.NoError(t, err)
  2570. client, err := getFTPClient(user, false, nil)
  2571. if assert.NoError(t, err) {
  2572. code, response, err := client.SendCustomCommand("allo 2000000")
  2573. assert.NoError(t, err)
  2574. assert.Equal(t, ftp.StatusCommandOK, code)
  2575. assert.Equal(t, "Done !", response)
  2576. code, response, err = client.SendCustomCommand("AVBL /vdir")
  2577. assert.NoError(t, err)
  2578. assert.Equal(t, ftp.StatusFile, code)
  2579. assert.Equal(t, "110", response)
  2580. code, _, err = client.SendCustomCommand("AVBL")
  2581. assert.NoError(t, err)
  2582. assert.Equal(t, ftp.StatusFile, code)
  2583. err = client.Quit()
  2584. assert.NoError(t, err)
  2585. }
  2586. user.QuotaSize = 100
  2587. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  2588. assert.NoError(t, err)
  2589. client, err = getFTPClient(user, false, nil)
  2590. if assert.NoError(t, err) {
  2591. testFilePath := filepath.Join(homeBasePath, testFileName)
  2592. testFileSize := user.QuotaSize - 1
  2593. err = createTestFile(testFilePath, testFileSize)
  2594. assert.NoError(t, err)
  2595. code, response, err := client.SendCustomCommand("allo 1000")
  2596. assert.NoError(t, err)
  2597. assert.Equal(t, ftp.StatusCommandOK, code)
  2598. assert.Equal(t, "Done !", response)
  2599. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  2600. assert.NoError(t, err)
  2601. code, response, err = client.SendCustomCommand("AVBL")
  2602. assert.NoError(t, err)
  2603. assert.Equal(t, ftp.StatusFile, code)
  2604. assert.Equal(t, "1", response)
  2605. err = client.Quit()
  2606. assert.NoError(t, err)
  2607. err = os.Remove(testFilePath)
  2608. assert.NoError(t, err)
  2609. }
  2610. user.TotalDataTransfer = 1
  2611. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  2612. assert.NoError(t, err)
  2613. client, err = getFTPClient(user, false, nil)
  2614. if assert.NoError(t, err) {
  2615. code, response, err := client.SendCustomCommand("AVBL")
  2616. assert.NoError(t, err)
  2617. assert.Equal(t, ftp.StatusFile, code)
  2618. assert.Equal(t, "1", response)
  2619. err = client.Quit()
  2620. assert.NoError(t, err)
  2621. }
  2622. user.TotalDataTransfer = 0
  2623. user.UploadDataTransfer = 5
  2624. user.QuotaSize = 6 * 1024 * 1024
  2625. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  2626. assert.NoError(t, err)
  2627. client, err = getFTPClient(user, false, nil)
  2628. if assert.NoError(t, err) {
  2629. code, response, err := client.SendCustomCommand("AVBL")
  2630. assert.NoError(t, err)
  2631. assert.Equal(t, ftp.StatusFile, code)
  2632. assert.Equal(t, "5242880", response)
  2633. err = client.Quit()
  2634. assert.NoError(t, err)
  2635. }
  2636. user.TotalDataTransfer = 0
  2637. user.UploadDataTransfer = 5
  2638. user.QuotaSize = 0
  2639. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  2640. assert.NoError(t, err)
  2641. client, err = getFTPClient(user, false, nil)
  2642. if assert.NoError(t, err) {
  2643. code, response, err := client.SendCustomCommand("AVBL")
  2644. assert.NoError(t, err)
  2645. assert.Equal(t, ftp.StatusFile, code)
  2646. assert.Equal(t, "5242880", response)
  2647. err = client.Quit()
  2648. assert.NoError(t, err)
  2649. }
  2650. user.Filters.MaxUploadFileSize = 100
  2651. user.QuotaSize = 0
  2652. user.TotalDataTransfer = 0
  2653. user.UploadDataTransfer = 0
  2654. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  2655. assert.NoError(t, err)
  2656. client, err = getFTPClient(user, false, nil)
  2657. if assert.NoError(t, err) {
  2658. code, response, err := client.SendCustomCommand("allo 10000")
  2659. assert.NoError(t, err)
  2660. assert.Equal(t, ftp.StatusCommandOK, code)
  2661. assert.Equal(t, "Done !", response)
  2662. code, response, err = client.SendCustomCommand("AVBL")
  2663. assert.NoError(t, err)
  2664. assert.Equal(t, ftp.StatusFile, code)
  2665. assert.Equal(t, "100", response)
  2666. err = client.Quit()
  2667. assert.NoError(t, err)
  2668. }
  2669. user.QuotaSize = 50
  2670. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  2671. assert.NoError(t, err)
  2672. client, err = getFTPClient(user, false, nil)
  2673. if assert.NoError(t, err) {
  2674. code, response, err := client.SendCustomCommand("AVBL")
  2675. assert.NoError(t, err)
  2676. assert.Equal(t, ftp.StatusFile, code)
  2677. assert.Equal(t, "0", response)
  2678. }
  2679. user.QuotaSize = 1000
  2680. user.Filters.MaxUploadFileSize = 1
  2681. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  2682. assert.NoError(t, err)
  2683. client, err = getFTPClient(user, false, nil)
  2684. if assert.NoError(t, err) {
  2685. code, response, err := client.SendCustomCommand("AVBL")
  2686. assert.NoError(t, err)
  2687. assert.Equal(t, ftp.StatusFile, code)
  2688. assert.Equal(t, "1", response)
  2689. }
  2690. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2691. assert.NoError(t, err)
  2692. _, err = httpdtest.RemoveFolder(vfs.BaseVirtualFolder{Name: folderName}, http.StatusOK)
  2693. assert.NoError(t, err)
  2694. err = os.RemoveAll(user.GetHomeDir())
  2695. assert.NoError(t, err)
  2696. err = os.RemoveAll(mappedPath)
  2697. assert.NoError(t, err)
  2698. }
  2699. func TestAvailableSFTPFs(t *testing.T) {
  2700. u := getTestUser()
  2701. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2702. assert.NoError(t, err)
  2703. sftpUser, _, err := httpdtest.AddUser(getTestSFTPUser(), http.StatusCreated)
  2704. assert.NoError(t, err)
  2705. client, err := getFTPClient(sftpUser, false, nil)
  2706. if assert.NoError(t, err) {
  2707. code, response, err := client.SendCustomCommand("AVBL /")
  2708. assert.NoError(t, err)
  2709. assert.Equal(t, ftp.StatusFile, code)
  2710. avblSize, err := strconv.ParseInt(response, 10, 64)
  2711. assert.NoError(t, err)
  2712. assert.Greater(t, avblSize, int64(0))
  2713. err = client.Quit()
  2714. assert.NoError(t, err)
  2715. }
  2716. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  2717. assert.NoError(t, err)
  2718. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  2719. assert.NoError(t, err)
  2720. err = os.RemoveAll(localUser.GetHomeDir())
  2721. assert.NoError(t, err)
  2722. }
  2723. func TestChtimes(t *testing.T) {
  2724. u := getTestUser()
  2725. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2726. assert.NoError(t, err)
  2727. sftpUser, _, err := httpdtest.AddUser(getTestSFTPUser(), http.StatusCreated)
  2728. assert.NoError(t, err)
  2729. for _, user := range []dataprovider.User{localUser, sftpUser} {
  2730. client, err := getFTPClient(user, false, nil)
  2731. if assert.NoError(t, err) {
  2732. testFilePath := filepath.Join(homeBasePath, testFileName)
  2733. testFileSize := int64(65535)
  2734. err = createTestFile(testFilePath, testFileSize)
  2735. assert.NoError(t, err)
  2736. err = checkBasicFTP(client)
  2737. assert.NoError(t, err)
  2738. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  2739. assert.NoError(t, err)
  2740. mtime := time.Now().Format("20060102150405")
  2741. code, response, err := client.SendCustomCommand(fmt.Sprintf("MFMT %v %v", mtime, testFileName))
  2742. assert.NoError(t, err)
  2743. assert.Equal(t, ftp.StatusFile, code)
  2744. assert.Equal(t, fmt.Sprintf("Modify=%v; %v", mtime, testFileName), response)
  2745. err = client.Quit()
  2746. assert.NoError(t, err)
  2747. err = os.Remove(testFilePath)
  2748. assert.NoError(t, err)
  2749. if user.Username == defaultUsername {
  2750. err = os.RemoveAll(user.GetHomeDir())
  2751. assert.NoError(t, err)
  2752. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2753. assert.NoError(t, err)
  2754. user.Password = defaultPassword
  2755. user.ID = 0
  2756. user.CreatedAt = 0
  2757. _, resp, err := httpdtest.AddUser(user, http.StatusCreated)
  2758. assert.NoError(t, err, string(resp))
  2759. }
  2760. }
  2761. }
  2762. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  2763. assert.NoError(t, err)
  2764. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  2765. assert.NoError(t, err)
  2766. err = os.RemoveAll(localUser.GetHomeDir())
  2767. assert.NoError(t, err)
  2768. }
  2769. func TestChown(t *testing.T) {
  2770. if runtime.GOOS == osWindows {
  2771. t.Skip("chown is not supported on Windows")
  2772. }
  2773. user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
  2774. assert.NoError(t, err)
  2775. client, err := getFTPClient(user, true, nil)
  2776. if assert.NoError(t, err) {
  2777. testFilePath := filepath.Join(homeBasePath, testFileName)
  2778. testFileSize := int64(131072)
  2779. err = createTestFile(testFilePath, testFileSize)
  2780. assert.NoError(t, err)
  2781. err = checkBasicFTP(client)
  2782. assert.NoError(t, err)
  2783. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  2784. assert.NoError(t, err)
  2785. code, response, err := client.SendCustomCommand(fmt.Sprintf("SITE CHOWN 1000:1000 %v", testFileName))
  2786. assert.NoError(t, err)
  2787. assert.Equal(t, ftp.StatusFileUnavailable, code)
  2788. assert.Equal(t, "Couldn't chown: operation unsupported", response)
  2789. err = client.Quit()
  2790. assert.NoError(t, err)
  2791. err = os.Remove(testFilePath)
  2792. assert.NoError(t, err)
  2793. }
  2794. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2795. assert.NoError(t, err)
  2796. err = os.RemoveAll(user.GetHomeDir())
  2797. assert.NoError(t, err)
  2798. }
  2799. func TestChmod(t *testing.T) {
  2800. if runtime.GOOS == osWindows {
  2801. t.Skip("chmod is partially supported on Windows")
  2802. }
  2803. u := getTestUser()
  2804. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2805. assert.NoError(t, err)
  2806. sftpUser, _, err := httpdtest.AddUser(getTestSFTPUser(), http.StatusCreated)
  2807. assert.NoError(t, err)
  2808. for _, user := range []dataprovider.User{localUser, sftpUser} {
  2809. client, err := getFTPClient(user, true, nil)
  2810. if assert.NoError(t, err) {
  2811. testFilePath := filepath.Join(homeBasePath, testFileName)
  2812. testFileSize := int64(131072)
  2813. err = createTestFile(testFilePath, testFileSize)
  2814. assert.NoError(t, err)
  2815. err = checkBasicFTP(client)
  2816. assert.NoError(t, err)
  2817. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  2818. assert.NoError(t, err)
  2819. code, response, err := client.SendCustomCommand(fmt.Sprintf("SITE CHMOD 600 %v", testFileName))
  2820. assert.NoError(t, err)
  2821. assert.Equal(t, ftp.StatusCommandOK, code)
  2822. assert.Equal(t, "SITE CHMOD command successful", response)
  2823. fi, err := os.Stat(filepath.Join(user.HomeDir, testFileName))
  2824. if assert.NoError(t, err) {
  2825. assert.Equal(t, os.FileMode(0600), fi.Mode().Perm())
  2826. }
  2827. err = client.Quit()
  2828. assert.NoError(t, err)
  2829. err = os.Remove(testFilePath)
  2830. assert.NoError(t, err)
  2831. if user.Username == defaultUsername {
  2832. err = os.RemoveAll(user.GetHomeDir())
  2833. assert.NoError(t, err)
  2834. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2835. assert.NoError(t, err)
  2836. user.Password = defaultPassword
  2837. user.ID = 0
  2838. user.CreatedAt = 0
  2839. _, resp, err := httpdtest.AddUser(user, http.StatusCreated)
  2840. assert.NoError(t, err, string(resp))
  2841. }
  2842. }
  2843. }
  2844. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  2845. assert.NoError(t, err)
  2846. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  2847. assert.NoError(t, err)
  2848. err = os.RemoveAll(localUser.GetHomeDir())
  2849. assert.NoError(t, err)
  2850. }
  2851. func TestCombineDisabled(t *testing.T) {
  2852. u := getTestUser()
  2853. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2854. assert.NoError(t, err)
  2855. sftpUser, _, err := httpdtest.AddUser(getTestSFTPUser(), http.StatusCreated)
  2856. assert.NoError(t, err)
  2857. for _, user := range []dataprovider.User{localUser, sftpUser} {
  2858. client, err := getFTPClient(user, true, nil)
  2859. if assert.NoError(t, err) {
  2860. err = checkBasicFTP(client)
  2861. assert.NoError(t, err)
  2862. code, response, err := client.SendCustomCommand("COMB file file.1 file.2")
  2863. assert.NoError(t, err)
  2864. assert.Equal(t, ftp.StatusNotImplemented, code)
  2865. assert.Equal(t, "COMB support is disabled", response)
  2866. err = client.Quit()
  2867. assert.NoError(t, err)
  2868. }
  2869. }
  2870. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  2871. assert.NoError(t, err)
  2872. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  2873. assert.NoError(t, err)
  2874. err = os.RemoveAll(localUser.GetHomeDir())
  2875. assert.NoError(t, err)
  2876. }
  2877. func TestActiveModeDisabled(t *testing.T) {
  2878. u := getTestUser()
  2879. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2880. assert.NoError(t, err)
  2881. client, err := getFTPClientImplicitTLS(user)
  2882. if assert.NoError(t, err) {
  2883. err = checkBasicFTP(client)
  2884. assert.NoError(t, err)
  2885. code, response, err := client.SendCustomCommand("PORT 10,2,0,2,4,31")
  2886. assert.NoError(t, err)
  2887. assert.Equal(t, ftp.StatusNotAvailable, code)
  2888. assert.Equal(t, "PORT command is disabled", response)
  2889. code, response, err = client.SendCustomCommand("EPRT |1|132.235.1.2|6275|")
  2890. assert.NoError(t, err)
  2891. assert.Equal(t, ftp.StatusNotAvailable, code)
  2892. assert.Equal(t, "EPRT command is disabled", response)
  2893. err = client.Quit()
  2894. assert.NoError(t, err)
  2895. }
  2896. client, err = getFTPClient(user, false, nil)
  2897. if assert.NoError(t, err) {
  2898. code, response, err := client.SendCustomCommand("PORT 10,2,0,2,4,31")
  2899. assert.NoError(t, err)
  2900. assert.Equal(t, ftp.StatusBadArguments, code)
  2901. assert.Equal(t, "Your request does not meet the configured security requirements", response)
  2902. code, response, err = client.SendCustomCommand("EPRT |1|132.235.1.2|6275|")
  2903. assert.NoError(t, err)
  2904. assert.Equal(t, ftp.StatusBadArguments, code)
  2905. assert.Equal(t, "Your request does not meet the configured security requirements", response)
  2906. err = client.Quit()
  2907. assert.NoError(t, err)
  2908. }
  2909. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2910. assert.NoError(t, err)
  2911. err = os.RemoveAll(user.GetHomeDir())
  2912. assert.NoError(t, err)
  2913. }
  2914. func TestSITEDisabled(t *testing.T) {
  2915. u := getTestUser()
  2916. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2917. assert.NoError(t, err)
  2918. client, err := getFTPClientImplicitTLS(user)
  2919. if assert.NoError(t, err) {
  2920. err = checkBasicFTP(client)
  2921. assert.NoError(t, err)
  2922. code, response, err := client.SendCustomCommand("SITE CHMOD 600 afile.txt")
  2923. assert.NoError(t, err)
  2924. assert.Equal(t, ftp.StatusBadCommand, code)
  2925. assert.Equal(t, "SITE support is disabled", response)
  2926. err = client.Quit()
  2927. assert.NoError(t, err)
  2928. }
  2929. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2930. assert.NoError(t, err)
  2931. err = os.RemoveAll(user.GetHomeDir())
  2932. assert.NoError(t, err)
  2933. }
  2934. func TestHASH(t *testing.T) {
  2935. u := getTestUser()
  2936. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2937. assert.NoError(t, err)
  2938. sftpUser, _, err := httpdtest.AddUser(getTestSFTPUser(), http.StatusCreated)
  2939. assert.NoError(t, err)
  2940. u = getTestUserWithCryptFs()
  2941. u.Username += "_crypt"
  2942. cryptUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2943. assert.NoError(t, err)
  2944. for _, user := range []dataprovider.User{localUser, sftpUser, cryptUser} {
  2945. client, err := getFTPClientImplicitTLS(user)
  2946. if assert.NoError(t, err) {
  2947. testFilePath := filepath.Join(homeBasePath, testFileName)
  2948. testFileSize := int64(131072)
  2949. err = createTestFile(testFilePath, testFileSize)
  2950. assert.NoError(t, err)
  2951. err = checkBasicFTP(client)
  2952. assert.NoError(t, err)
  2953. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  2954. assert.NoError(t, err)
  2955. h := sha256.New()
  2956. f, err := os.Open(testFilePath)
  2957. assert.NoError(t, err)
  2958. _, err = io.Copy(h, f)
  2959. assert.NoError(t, err)
  2960. hash := hex.EncodeToString(h.Sum(nil))
  2961. err = f.Close()
  2962. assert.NoError(t, err)
  2963. code, response, err := client.SendCustomCommand(fmt.Sprintf("XSHA256 %v", testFileName))
  2964. assert.NoError(t, err)
  2965. assert.Equal(t, ftp.StatusRequestedFileActionOK, code)
  2966. assert.Contains(t, response, hash)
  2967. code, response, err = client.SendCustomCommand(fmt.Sprintf("HASH %v", testFileName))
  2968. assert.NoError(t, err)
  2969. assert.Equal(t, ftp.StatusFile, code)
  2970. assert.Contains(t, response, hash)
  2971. err = client.Quit()
  2972. assert.NoError(t, err)
  2973. err = os.Remove(testFilePath)
  2974. assert.NoError(t, err)
  2975. if user.Username == defaultUsername {
  2976. err = os.RemoveAll(user.GetHomeDir())
  2977. assert.NoError(t, err)
  2978. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2979. assert.NoError(t, err)
  2980. user.Password = defaultPassword
  2981. user.ID = 0
  2982. user.CreatedAt = 0
  2983. _, resp, err := httpdtest.AddUser(user, http.StatusCreated)
  2984. assert.NoError(t, err, string(resp))
  2985. }
  2986. }
  2987. }
  2988. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  2989. assert.NoError(t, err)
  2990. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  2991. assert.NoError(t, err)
  2992. err = os.RemoveAll(localUser.GetHomeDir())
  2993. assert.NoError(t, err)
  2994. _, err = httpdtest.RemoveUser(cryptUser, http.StatusOK)
  2995. assert.NoError(t, err)
  2996. err = os.RemoveAll(cryptUser.GetHomeDir())
  2997. assert.NoError(t, err)
  2998. }
  2999. func TestCombine(t *testing.T) {
  3000. u := getTestUser()
  3001. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  3002. assert.NoError(t, err)
  3003. sftpUser, _, err := httpdtest.AddUser(getTestSFTPUser(), http.StatusCreated)
  3004. assert.NoError(t, err)
  3005. for _, user := range []dataprovider.User{localUser, sftpUser} {
  3006. client, err := getFTPClientImplicitTLS(user)
  3007. if assert.NoError(t, err) {
  3008. testFilePath := filepath.Join(homeBasePath, testFileName)
  3009. testFileSize := int64(131072)
  3010. err = createTestFile(testFilePath, testFileSize)
  3011. assert.NoError(t, err)
  3012. err = checkBasicFTP(client)
  3013. assert.NoError(t, err)
  3014. err = ftpUploadFile(testFilePath, testFileName+".1", testFileSize, client, 0)
  3015. assert.NoError(t, err)
  3016. err = ftpUploadFile(testFilePath, testFileName+".2", testFileSize, client, 0)
  3017. assert.NoError(t, err)
  3018. code, response, err := client.SendCustomCommand(fmt.Sprintf("COMB %v %v %v", testFileName, testFileName+".1", testFileName+".2"))
  3019. assert.NoError(t, err)
  3020. if user.Username == defaultUsername {
  3021. assert.Equal(t, ftp.StatusRequestedFileActionOK, code)
  3022. assert.Equal(t, "COMB succeeded!", response)
  3023. } else {
  3024. assert.Equal(t, ftp.StatusFileUnavailable, code)
  3025. assert.Contains(t, response, "COMB is not supported for this filesystem")
  3026. }
  3027. err = client.Quit()
  3028. assert.NoError(t, err)
  3029. err = os.Remove(testFilePath)
  3030. assert.NoError(t, err)
  3031. if user.Username == defaultUsername {
  3032. err = os.RemoveAll(user.GetHomeDir())
  3033. assert.NoError(t, err)
  3034. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  3035. assert.NoError(t, err)
  3036. user.Password = defaultPassword
  3037. user.ID = 0
  3038. user.CreatedAt = 0
  3039. _, resp, err := httpdtest.AddUser(user, http.StatusCreated)
  3040. assert.NoError(t, err, string(resp))
  3041. }
  3042. }
  3043. }
  3044. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  3045. assert.NoError(t, err)
  3046. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  3047. assert.NoError(t, err)
  3048. err = os.RemoveAll(localUser.GetHomeDir())
  3049. assert.NoError(t, err)
  3050. }
  3051. func TestClientCertificateAuthRevokedCert(t *testing.T) {
  3052. u := getTestUser()
  3053. u.Username = tlsClient2Username
  3054. u.Filters.TLSUsername = sdk.TLSUsernameCN
  3055. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  3056. assert.NoError(t, err)
  3057. tlsConfig := &tls.Config{
  3058. ServerName: "localhost",
  3059. InsecureSkipVerify: true, // use this for tests only
  3060. MinVersion: tls.VersionTLS12,
  3061. }
  3062. tlsCert, err := tls.X509KeyPair([]byte(client2Crt), []byte(client2Key))
  3063. assert.NoError(t, err)
  3064. tlsConfig.Certificates = append(tlsConfig.Certificates, tlsCert)
  3065. _, err = getFTPClient(user, true, tlsConfig)
  3066. if assert.Error(t, err) {
  3067. assert.Contains(t, err.Error(), "bad certificate")
  3068. }
  3069. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  3070. assert.NoError(t, err)
  3071. err = os.RemoveAll(user.GetHomeDir())
  3072. assert.NoError(t, err)
  3073. }
  3074. func TestClientCertificateAuth(t *testing.T) {
  3075. u := getTestUser()
  3076. u.Username = tlsClient1Username
  3077. u.Filters.DeniedLoginMethods = []string{dataprovider.LoginMethodPassword}
  3078. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  3079. assert.NoError(t, err)
  3080. tlsConfig := &tls.Config{
  3081. ServerName: "localhost",
  3082. InsecureSkipVerify: true, // use this for tests only
  3083. MinVersion: tls.VersionTLS12,
  3084. }
  3085. tlsCert, err := tls.X509KeyPair([]byte(client1Crt), []byte(client1Key))
  3086. assert.NoError(t, err)
  3087. tlsConfig.Certificates = append(tlsConfig.Certificates, tlsCert)
  3088. // TLS username is not enabled, mutual TLS should fail
  3089. _, err = getFTPClient(user, true, tlsConfig)
  3090. if assert.Error(t, err) {
  3091. assert.Contains(t, err.Error(), "login method password is not allowed")
  3092. }
  3093. user.Filters.TLSUsername = sdk.TLSUsernameCN
  3094. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  3095. assert.NoError(t, err)
  3096. client, err := getFTPClient(user, true, tlsConfig)
  3097. if assert.NoError(t, err) {
  3098. err = checkBasicFTP(client)
  3099. assert.NoError(t, err)
  3100. err = client.Quit()
  3101. assert.NoError(t, err)
  3102. }
  3103. // now use a valid certificate with a CN different from username
  3104. u = getTestUser()
  3105. u.Username = tlsClient2Username
  3106. u.Filters.TLSUsername = sdk.TLSUsernameCN
  3107. u.Filters.DeniedLoginMethods = []string{dataprovider.LoginMethodPassword}
  3108. user2, _, err := httpdtest.AddUser(u, http.StatusCreated)
  3109. assert.NoError(t, err)
  3110. _, err = getFTPClient(user2, true, tlsConfig)
  3111. if assert.Error(t, err) {
  3112. assert.Contains(t, err.Error(), "does not match username")
  3113. }
  3114. // now disable certificate authentication
  3115. user.Filters.DeniedLoginMethods = append(user.Filters.DeniedLoginMethods, dataprovider.LoginMethodTLSCertificate,
  3116. dataprovider.LoginMethodTLSCertificateAndPwd)
  3117. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  3118. assert.NoError(t, err)
  3119. _, err = getFTPClient(user, true, tlsConfig)
  3120. if assert.Error(t, err) {
  3121. assert.Contains(t, err.Error(), "login method TLSCertificate+password is not allowed")
  3122. }
  3123. // disable FTP protocol
  3124. user.Filters.DeniedLoginMethods = []string{dataprovider.LoginMethodPassword}
  3125. user.Filters.DeniedProtocols = append(user.Filters.DeniedProtocols, common.ProtocolFTP)
  3126. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  3127. assert.NoError(t, err)
  3128. _, err = getFTPClient(user, true, tlsConfig)
  3129. if assert.Error(t, err) {
  3130. assert.Contains(t, err.Error(), "protocol FTP is not allowed")
  3131. }
  3132. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  3133. assert.NoError(t, err)
  3134. err = os.RemoveAll(user.GetHomeDir())
  3135. assert.NoError(t, err)
  3136. _, err = httpdtest.RemoveUser(user2, http.StatusOK)
  3137. assert.NoError(t, err)
  3138. err = os.RemoveAll(user2.GetHomeDir())
  3139. assert.NoError(t, err)
  3140. _, err = getFTPClient(user, true, tlsConfig)
  3141. assert.Error(t, err)
  3142. }
  3143. func TestClientCertificateAndPwdAuth(t *testing.T) {
  3144. u := getTestUser()
  3145. u.Username = tlsClient1Username
  3146. u.Filters.TLSUsername = sdk.TLSUsernameCN
  3147. u.Filters.DeniedLoginMethods = []string{dataprovider.LoginMethodPassword, dataprovider.LoginMethodTLSCertificate}
  3148. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  3149. assert.NoError(t, err)
  3150. tlsConfig := &tls.Config{
  3151. ServerName: "localhost",
  3152. InsecureSkipVerify: true, // use this for tests only
  3153. MinVersion: tls.VersionTLS12,
  3154. }
  3155. tlsCert, err := tls.X509KeyPair([]byte(client1Crt), []byte(client1Key))
  3156. assert.NoError(t, err)
  3157. tlsConfig.Certificates = append(tlsConfig.Certificates, tlsCert)
  3158. client, err := getFTPClient(user, true, tlsConfig)
  3159. if assert.NoError(t, err) {
  3160. err = checkBasicFTP(client)
  3161. assert.NoError(t, err)
  3162. err = client.Quit()
  3163. assert.NoError(t, err)
  3164. }
  3165. _, err = getFTPClient(user, true, nil)
  3166. if assert.Error(t, err) {
  3167. assert.Contains(t, err.Error(), "login method password is not allowed")
  3168. }
  3169. user.Password = defaultPassword + "1"
  3170. _, err = getFTPClient(user, true, tlsConfig)
  3171. if assert.Error(t, err) {
  3172. assert.Contains(t, err.Error(), "invalid credentials")
  3173. }
  3174. tlsCert, err = tls.X509KeyPair([]byte(client2Crt), []byte(client2Key))
  3175. assert.NoError(t, err)
  3176. tlsConfig.Certificates = []tls.Certificate{tlsCert}
  3177. _, err = getFTPClient(user, true, tlsConfig)
  3178. if assert.Error(t, err) {
  3179. assert.Contains(t, err.Error(), "bad certificate")
  3180. }
  3181. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  3182. assert.NoError(t, err)
  3183. err = os.RemoveAll(user.GetHomeDir())
  3184. assert.NoError(t, err)
  3185. }
  3186. func TestExternalAuthWithClientCert(t *testing.T) {
  3187. if runtime.GOOS == osWindows {
  3188. t.Skip("this test is not available on Windows")
  3189. }
  3190. u := getTestUser()
  3191. u.Username = tlsClient1Username
  3192. u.Filters.DeniedLoginMethods = append(u.Filters.DeniedLoginMethods, dataprovider.LoginMethodPassword)
  3193. u.Filters.TLSUsername = sdk.TLSUsernameCN
  3194. err := dataprovider.Close()
  3195. assert.NoError(t, err)
  3196. err = config.LoadConfig(configDir, "")
  3197. assert.NoError(t, err)
  3198. providerConf := config.GetProviderConf()
  3199. err = os.WriteFile(extAuthPath, getExtAuthScriptContent(u), os.ModePerm)
  3200. assert.NoError(t, err)
  3201. providerConf.ExternalAuthHook = extAuthPath
  3202. providerConf.ExternalAuthScope = 8
  3203. err = dataprovider.Initialize(providerConf, configDir, true)
  3204. assert.NoError(t, err)
  3205. // external auth not called, auth scope is 8
  3206. _, err = getFTPClient(u, true, nil)
  3207. assert.Error(t, err)
  3208. _, _, err = httpdtest.GetUserByUsername(u.Username, http.StatusNotFound)
  3209. assert.NoError(t, err)
  3210. tlsConfig := &tls.Config{
  3211. ServerName: "localhost",
  3212. InsecureSkipVerify: true, // use this for tests only
  3213. MinVersion: tls.VersionTLS12,
  3214. }
  3215. tlsCert, err := tls.X509KeyPair([]byte(client1Crt), []byte(client1Key))
  3216. assert.NoError(t, err)
  3217. tlsConfig.Certificates = append(tlsConfig.Certificates, tlsCert)
  3218. client, err := getFTPClient(u, true, tlsConfig)
  3219. if assert.NoError(t, err) {
  3220. err = checkBasicFTP(client)
  3221. assert.NoError(t, err)
  3222. err := client.Quit()
  3223. assert.NoError(t, err)
  3224. }
  3225. user, _, err := httpdtest.GetUserByUsername(u.Username, http.StatusOK)
  3226. assert.NoError(t, err)
  3227. assert.Equal(t, u.Username, user.Username)
  3228. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  3229. assert.NoError(t, err)
  3230. err = os.RemoveAll(user.GetHomeDir())
  3231. assert.NoError(t, err)
  3232. u.Username = tlsClient2Username
  3233. _, err = getFTPClient(u, true, tlsConfig)
  3234. if assert.Error(t, err) {
  3235. assert.Contains(t, err.Error(), "invalid credentials")
  3236. }
  3237. err = dataprovider.Close()
  3238. assert.NoError(t, err)
  3239. err = config.LoadConfig(configDir, "")
  3240. assert.NoError(t, err)
  3241. providerConf = config.GetProviderConf()
  3242. err = dataprovider.Initialize(providerConf, configDir, true)
  3243. assert.NoError(t, err)
  3244. err = os.Remove(extAuthPath)
  3245. assert.NoError(t, err)
  3246. }
  3247. func TestPreLoginHookWithClientCert(t *testing.T) {
  3248. if runtime.GOOS == osWindows {
  3249. t.Skip("this test is not available on Windows")
  3250. }
  3251. u := getTestUser()
  3252. u.Username = tlsClient1Username
  3253. u.Filters.DeniedLoginMethods = append(u.Filters.DeniedLoginMethods, dataprovider.LoginMethodPassword)
  3254. u.Filters.TLSUsername = sdk.TLSUsernameCN
  3255. err := dataprovider.Close()
  3256. assert.NoError(t, err)
  3257. err = config.LoadConfig(configDir, "")
  3258. assert.NoError(t, err)
  3259. providerConf := config.GetProviderConf()
  3260. err = os.WriteFile(preLoginPath, getPreLoginScriptContent(u, false), os.ModePerm)
  3261. assert.NoError(t, err)
  3262. providerConf.PreLoginHook = preLoginPath
  3263. err = dataprovider.Initialize(providerConf, configDir, true)
  3264. assert.NoError(t, err)
  3265. _, _, err = httpdtest.GetUserByUsername(tlsClient1Username, http.StatusNotFound)
  3266. assert.NoError(t, err)
  3267. tlsConfig := &tls.Config{
  3268. ServerName: "localhost",
  3269. InsecureSkipVerify: true, // use this for tests only
  3270. MinVersion: tls.VersionTLS12,
  3271. }
  3272. tlsCert, err := tls.X509KeyPair([]byte(client1Crt), []byte(client1Key))
  3273. assert.NoError(t, err)
  3274. tlsConfig.Certificates = append(tlsConfig.Certificates, tlsCert)
  3275. client, err := getFTPClient(u, true, tlsConfig)
  3276. if assert.NoError(t, err) {
  3277. err = checkBasicFTP(client)
  3278. assert.NoError(t, err)
  3279. err := client.Quit()
  3280. assert.NoError(t, err)
  3281. }
  3282. user, _, err := httpdtest.GetUserByUsername(tlsClient1Username, http.StatusOK)
  3283. assert.NoError(t, err)
  3284. // test login with an existing user
  3285. client, err = getFTPClient(user, true, tlsConfig)
  3286. if assert.NoError(t, err) {
  3287. err = checkBasicFTP(client)
  3288. assert.NoError(t, err)
  3289. err := client.Quit()
  3290. assert.NoError(t, err)
  3291. }
  3292. u.Username = tlsClient2Username
  3293. err = os.WriteFile(preLoginPath, getPreLoginScriptContent(u, false), os.ModePerm)
  3294. assert.NoError(t, err)
  3295. _, err = getFTPClient(u, true, tlsConfig)
  3296. if assert.Error(t, err) {
  3297. assert.Contains(t, err.Error(), "does not match username")
  3298. }
  3299. user2, _, err := httpdtest.GetUserByUsername(tlsClient2Username, http.StatusOK)
  3300. assert.NoError(t, err)
  3301. _, err = httpdtest.RemoveUser(user2, http.StatusOK)
  3302. assert.NoError(t, err)
  3303. err = os.RemoveAll(user2.GetHomeDir())
  3304. assert.NoError(t, err)
  3305. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  3306. assert.NoError(t, err)
  3307. err = os.RemoveAll(user.GetHomeDir())
  3308. assert.NoError(t, err)
  3309. err = dataprovider.Close()
  3310. assert.NoError(t, err)
  3311. err = config.LoadConfig(configDir, "")
  3312. assert.NoError(t, err)
  3313. providerConf = config.GetProviderConf()
  3314. err = dataprovider.Initialize(providerConf, configDir, true)
  3315. assert.NoError(t, err)
  3316. err = os.Remove(preLoginPath)
  3317. assert.NoError(t, err)
  3318. }
  3319. func TestNestedVirtualFolders(t *testing.T) {
  3320. u := getTestUser()
  3321. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  3322. assert.NoError(t, err)
  3323. u = getTestSFTPUser()
  3324. mappedPathCrypt := filepath.Join(os.TempDir(), "crypt")
  3325. folderNameCrypt := filepath.Base(mappedPathCrypt)
  3326. vdirCryptPath := "/vdir/crypt"
  3327. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  3328. BaseVirtualFolder: vfs.BaseVirtualFolder{
  3329. Name: folderNameCrypt,
  3330. FsConfig: vfs.Filesystem{
  3331. Provider: sdk.CryptedFilesystemProvider,
  3332. CryptConfig: vfs.CryptFsConfig{
  3333. Passphrase: kms.NewPlainSecret(defaultPassword),
  3334. },
  3335. },
  3336. MappedPath: mappedPathCrypt,
  3337. },
  3338. VirtualPath: vdirCryptPath,
  3339. })
  3340. mappedPath := filepath.Join(os.TempDir(), "local")
  3341. folderName := filepath.Base(mappedPath)
  3342. vdirPath := "/vdir/local"
  3343. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  3344. BaseVirtualFolder: vfs.BaseVirtualFolder{
  3345. Name: folderName,
  3346. MappedPath: mappedPath,
  3347. },
  3348. VirtualPath: vdirPath,
  3349. })
  3350. mappedPathNested := filepath.Join(os.TempDir(), "nested")
  3351. folderNameNested := filepath.Base(mappedPathNested)
  3352. vdirNestedPath := "/vdir/crypt/nested"
  3353. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  3354. BaseVirtualFolder: vfs.BaseVirtualFolder{
  3355. Name: folderNameNested,
  3356. MappedPath: mappedPathNested,
  3357. },
  3358. VirtualPath: vdirNestedPath,
  3359. QuotaFiles: -1,
  3360. QuotaSize: -1,
  3361. })
  3362. sftpUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  3363. assert.NoError(t, err)
  3364. client, err := getFTPClient(sftpUser, false, nil)
  3365. if assert.NoError(t, err) {
  3366. err = checkBasicFTP(client)
  3367. assert.NoError(t, err)
  3368. testFilePath := filepath.Join(homeBasePath, testFileName)
  3369. testFileSize := int64(65535)
  3370. err = createTestFile(testFilePath, testFileSize)
  3371. assert.NoError(t, err)
  3372. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  3373. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  3374. assert.NoError(t, err)
  3375. err = ftpDownloadFile(testFileName, localDownloadPath, testFileSize, client, 0)
  3376. assert.NoError(t, err)
  3377. err = ftpUploadFile(testFilePath, path.Join("/vdir", testFileName), testFileSize, client, 0)
  3378. assert.NoError(t, err)
  3379. err = ftpDownloadFile(path.Join("/vdir", testFileName), localDownloadPath, testFileSize, client, 0)
  3380. assert.NoError(t, err)
  3381. err = ftpUploadFile(testFilePath, path.Join(vdirPath, testFileName), testFileSize, client, 0)
  3382. assert.NoError(t, err)
  3383. err = ftpDownloadFile(path.Join(vdirPath, testFileName), localDownloadPath, testFileSize, client, 0)
  3384. assert.NoError(t, err)
  3385. err = ftpUploadFile(testFilePath, path.Join(vdirCryptPath, testFileName), testFileSize, client, 0)
  3386. assert.NoError(t, err)
  3387. err = ftpDownloadFile(path.Join(vdirCryptPath, testFileName), localDownloadPath, testFileSize, client, 0)
  3388. assert.NoError(t, err)
  3389. err = ftpUploadFile(testFilePath, path.Join(vdirNestedPath, testFileName), testFileSize, client, 0)
  3390. assert.NoError(t, err)
  3391. err = ftpDownloadFile(path.Join(vdirNestedPath, testFileName), localDownloadPath, testFileSize, client, 0)
  3392. assert.NoError(t, err)
  3393. err = client.Quit()
  3394. assert.NoError(t, err)
  3395. err = os.Remove(testFilePath)
  3396. assert.NoError(t, err)
  3397. err = os.Remove(localDownloadPath)
  3398. assert.NoError(t, err)
  3399. }
  3400. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  3401. assert.NoError(t, err)
  3402. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  3403. assert.NoError(t, err)
  3404. _, err = httpdtest.RemoveFolder(vfs.BaseVirtualFolder{Name: folderNameCrypt}, http.StatusOK)
  3405. assert.NoError(t, err)
  3406. _, err = httpdtest.RemoveFolder(vfs.BaseVirtualFolder{Name: folderName}, http.StatusOK)
  3407. assert.NoError(t, err)
  3408. _, err = httpdtest.RemoveFolder(vfs.BaseVirtualFolder{Name: folderNameNested}, http.StatusOK)
  3409. assert.NoError(t, err)
  3410. err = os.RemoveAll(mappedPathCrypt)
  3411. assert.NoError(t, err)
  3412. err = os.RemoveAll(mappedPath)
  3413. assert.NoError(t, err)
  3414. err = os.RemoveAll(mappedPathNested)
  3415. assert.NoError(t, err)
  3416. err = os.RemoveAll(localUser.GetHomeDir())
  3417. assert.NoError(t, err)
  3418. assert.Eventually(t, func() bool { return len(common.Connections.GetStats()) == 0 }, 1*time.Second, 50*time.Millisecond)
  3419. assert.Eventually(t, func() bool { return common.Connections.GetClientConnections() == 0 }, 1000*time.Millisecond,
  3420. 50*time.Millisecond)
  3421. }
  3422. func checkBasicFTP(client *ftp.ServerConn) error {
  3423. _, err := client.CurrentDir()
  3424. if err != nil {
  3425. return err
  3426. }
  3427. err = client.NoOp()
  3428. if err != nil {
  3429. return err
  3430. }
  3431. _, err = client.List(".")
  3432. if err != nil {
  3433. return err
  3434. }
  3435. return nil
  3436. }
  3437. func ftpUploadFile(localSourcePath string, remoteDestPath string, expectedSize int64, client *ftp.ServerConn, offset uint64) error {
  3438. srcFile, err := os.Open(localSourcePath)
  3439. if err != nil {
  3440. return err
  3441. }
  3442. defer srcFile.Close()
  3443. if offset > 0 {
  3444. err = client.StorFrom(remoteDestPath, srcFile, offset)
  3445. } else {
  3446. err = client.Stor(remoteDestPath, srcFile)
  3447. }
  3448. if err != nil {
  3449. return err
  3450. }
  3451. if expectedSize > 0 {
  3452. size, err := client.FileSize(remoteDestPath)
  3453. if err != nil {
  3454. return err
  3455. }
  3456. if size != expectedSize {
  3457. return fmt.Errorf("uploaded file size does not match, actual: %v, expected: %v", size, expectedSize)
  3458. }
  3459. }
  3460. return nil
  3461. }
  3462. func ftpDownloadFile(remoteSourcePath string, localDestPath string, expectedSize int64, client *ftp.ServerConn, offset uint64) error {
  3463. downloadDest, err := os.Create(localDestPath)
  3464. if err != nil {
  3465. return err
  3466. }
  3467. defer downloadDest.Close()
  3468. var r *ftp.Response
  3469. if offset > 0 {
  3470. r, err = client.RetrFrom(remoteSourcePath, offset)
  3471. } else {
  3472. r, err = client.Retr(remoteSourcePath)
  3473. }
  3474. if err != nil {
  3475. return err
  3476. }
  3477. defer r.Close()
  3478. written, err := io.Copy(downloadDest, r)
  3479. if err != nil {
  3480. return err
  3481. }
  3482. if written != expectedSize {
  3483. return fmt.Errorf("downloaded file size does not match, actual: %v, expected: %v", written, expectedSize)
  3484. }
  3485. return nil
  3486. }
  3487. func getFTPClientImplicitTLS(user dataprovider.User) (*ftp.ServerConn, error) {
  3488. ftpOptions := []ftp.DialOption{ftp.DialWithTimeout(5 * time.Second)}
  3489. tlsConfig := &tls.Config{
  3490. ServerName: "localhost",
  3491. InsecureSkipVerify: true, // use this for tests only
  3492. MinVersion: tls.VersionTLS12,
  3493. }
  3494. ftpOptions = append(ftpOptions, ftp.DialWithTLS(tlsConfig))
  3495. ftpOptions = append(ftpOptions, ftp.DialWithDisabledEPSV(true))
  3496. client, err := ftp.Dial(ftpSrvAddrTLS, ftpOptions...)
  3497. if err != nil {
  3498. return nil, err
  3499. }
  3500. pwd := defaultPassword
  3501. if user.Password != "" {
  3502. pwd = user.Password
  3503. }
  3504. err = client.Login(user.Username, pwd)
  3505. if err != nil {
  3506. return nil, err
  3507. }
  3508. return client, err
  3509. }
  3510. func getFTPClient(user dataprovider.User, useTLS bool, tlsConfig *tls.Config, dialOptions ...ftp.DialOption,
  3511. ) (*ftp.ServerConn, error) {
  3512. ftpOptions := []ftp.DialOption{ftp.DialWithTimeout(5 * time.Second)}
  3513. ftpOptions = append(ftpOptions, dialOptions...)
  3514. if useTLS {
  3515. if tlsConfig == nil {
  3516. tlsConfig = &tls.Config{
  3517. ServerName: "localhost",
  3518. InsecureSkipVerify: true, // use this for tests only
  3519. MinVersion: tls.VersionTLS12,
  3520. }
  3521. }
  3522. ftpOptions = append(ftpOptions, ftp.DialWithExplicitTLS(tlsConfig))
  3523. }
  3524. client, err := ftp.Dial(ftpServerAddr, ftpOptions...)
  3525. if err != nil {
  3526. return nil, err
  3527. }
  3528. pwd := defaultPassword
  3529. if user.Password != "" {
  3530. if user.Password == emptyPwdPlaceholder {
  3531. pwd = ""
  3532. } else {
  3533. pwd = user.Password
  3534. }
  3535. }
  3536. err = client.Login(user.Username, pwd)
  3537. if err != nil {
  3538. return nil, err
  3539. }
  3540. return client, err
  3541. }
  3542. func waitTCPListening(address string) {
  3543. for {
  3544. conn, err := net.Dial("tcp", address)
  3545. if err != nil {
  3546. logger.WarnToConsole("tcp server %v not listening: %v", address, err)
  3547. time.Sleep(100 * time.Millisecond)
  3548. continue
  3549. }
  3550. logger.InfoToConsole("tcp server %v now listening", address)
  3551. conn.Close()
  3552. break
  3553. }
  3554. }
  3555. func waitNoConnections() {
  3556. time.Sleep(50 * time.Millisecond)
  3557. for len(common.Connections.GetStats()) > 0 {
  3558. time.Sleep(50 * time.Millisecond)
  3559. }
  3560. }
  3561. func getTestGroup() dataprovider.Group {
  3562. return dataprovider.Group{
  3563. BaseGroup: sdk.BaseGroup{
  3564. Name: "test_group",
  3565. Description: "test group description",
  3566. },
  3567. }
  3568. }
  3569. func getTestUser() dataprovider.User {
  3570. user := dataprovider.User{
  3571. BaseUser: sdk.BaseUser{
  3572. Username: defaultUsername,
  3573. Password: defaultPassword,
  3574. HomeDir: filepath.Join(homeBasePath, defaultUsername),
  3575. Status: 1,
  3576. ExpirationDate: 0,
  3577. },
  3578. }
  3579. user.Permissions = make(map[string][]string)
  3580. user.Permissions["/"] = allPerms
  3581. return user
  3582. }
  3583. func getTestSFTPUser() dataprovider.User {
  3584. u := getTestUser()
  3585. u.Username = u.Username + "_sftp"
  3586. u.FsConfig.Provider = sdk.SFTPFilesystemProvider
  3587. u.FsConfig.SFTPConfig.Endpoint = sftpServerAddr
  3588. u.FsConfig.SFTPConfig.Username = defaultUsername
  3589. u.FsConfig.SFTPConfig.Password = kms.NewPlainSecret(defaultPassword)
  3590. return u
  3591. }
  3592. func getTestUserWithHTTPFs() dataprovider.User {
  3593. u := getTestUser()
  3594. u.FsConfig.Provider = sdk.HTTPFilesystemProvider
  3595. u.FsConfig.HTTPConfig = vfs.HTTPFsConfig{
  3596. BaseHTTPFsConfig: sdk.BaseHTTPFsConfig{
  3597. Endpoint: fmt.Sprintf("http://127.0.0.1:%d/api/v1", httpFsPort),
  3598. Username: defaultHTTPFsUsername,
  3599. },
  3600. }
  3601. return u
  3602. }
  3603. func getExtAuthScriptContent(user dataprovider.User) []byte {
  3604. extAuthContent := []byte("#!/bin/sh\n\n")
  3605. extAuthContent = append(extAuthContent, []byte(fmt.Sprintf("if test \"$SFTPGO_AUTHD_USERNAME\" = \"%v\"; then\n", user.Username))...)
  3606. u, _ := json.Marshal(user)
  3607. extAuthContent = append(extAuthContent, []byte(fmt.Sprintf("echo '%v'\n", string(u)))...)
  3608. extAuthContent = append(extAuthContent, []byte("else\n")...)
  3609. extAuthContent = append(extAuthContent, []byte("echo '{\"username\":\"\"}'\n")...)
  3610. extAuthContent = append(extAuthContent, []byte("fi\n")...)
  3611. return extAuthContent
  3612. }
  3613. func getPreLoginScriptContent(user dataprovider.User, nonJSONResponse bool) []byte {
  3614. content := []byte("#!/bin/sh\n\n")
  3615. if nonJSONResponse {
  3616. content = append(content, []byte("echo 'text response'\n")...)
  3617. return content
  3618. }
  3619. if len(user.Username) > 0 {
  3620. u, _ := json.Marshal(user)
  3621. content = append(content, []byte(fmt.Sprintf("echo '%v'\n", string(u)))...)
  3622. }
  3623. return content
  3624. }
  3625. func getExitCodeScriptContent(exitCode int) []byte {
  3626. content := []byte("#!/bin/sh\n\n")
  3627. content = append(content, []byte(fmt.Sprintf("exit %v", exitCode))...)
  3628. return content
  3629. }
  3630. func createTestFile(path string, size int64) error {
  3631. baseDir := filepath.Dir(path)
  3632. if _, err := os.Stat(baseDir); errors.Is(err, fs.ErrNotExist) {
  3633. err = os.MkdirAll(baseDir, os.ModePerm)
  3634. if err != nil {
  3635. return err
  3636. }
  3637. }
  3638. content := make([]byte, size)
  3639. _, err := rand.Read(content)
  3640. if err != nil {
  3641. return err
  3642. }
  3643. return os.WriteFile(path, content, os.ModePerm)
  3644. }
  3645. func writeCerts(certPath, keyPath, caCrtPath, caCRLPath string) error {
  3646. err := os.WriteFile(certPath, []byte(ftpsCert), os.ModePerm)
  3647. if err != nil {
  3648. logger.ErrorToConsole("error writing FTPS certificate: %v", err)
  3649. return err
  3650. }
  3651. err = os.WriteFile(keyPath, []byte(ftpsKey), os.ModePerm)
  3652. if err != nil {
  3653. logger.ErrorToConsole("error writing FTPS private key: %v", err)
  3654. return err
  3655. }
  3656. err = os.WriteFile(caCrtPath, []byte(caCRT), os.ModePerm)
  3657. if err != nil {
  3658. logger.ErrorToConsole("error writing FTPS CA crt: %v", err)
  3659. return err
  3660. }
  3661. err = os.WriteFile(caCRLPath, []byte(caCRL), os.ModePerm)
  3662. if err != nil {
  3663. logger.ErrorToConsole("error writing FTPS CRL: %v", err)
  3664. return err
  3665. }
  3666. return nil
  3667. }
  3668. func generateTOTPPasscode(secret string, algo otp.Algorithm) (string, error) {
  3669. return totp.GenerateCodeCustom(secret, time.Now(), totp.ValidateOpts{
  3670. Period: 30,
  3671. Skew: 1,
  3672. Digits: otp.DigitsSix,
  3673. Algorithm: algo,
  3674. })
  3675. }
  3676. func startHTTPFs() {
  3677. go func() {
  3678. if err := httpdtest.StartTestHTTPFs(httpFsPort); err != nil {
  3679. logger.ErrorToConsole("could not start HTTPfs test server: %v", err)
  3680. os.Exit(1)
  3681. }
  3682. }()
  3683. waitTCPListening(fmt.Sprintf(":%d", httpFsPort))
  3684. }