httpd_test.go 140 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646
  1. package httpd_test
  2. import (
  3. "bytes"
  4. "crypto/rand"
  5. "encoding/json"
  6. "fmt"
  7. "io"
  8. "io/ioutil"
  9. "mime/multipart"
  10. "net"
  11. "net/http"
  12. "net/http/httptest"
  13. "net/url"
  14. "os"
  15. "path/filepath"
  16. "runtime"
  17. "strconv"
  18. "strings"
  19. "testing"
  20. "time"
  21. "github.com/go-chi/render"
  22. _ "github.com/go-sql-driver/mysql"
  23. _ "github.com/lib/pq"
  24. _ "github.com/mattn/go-sqlite3"
  25. "github.com/rs/zerolog"
  26. "github.com/stretchr/testify/assert"
  27. "github.com/stretchr/testify/require"
  28. "github.com/drakkan/sftpgo/common"
  29. "github.com/drakkan/sftpgo/config"
  30. "github.com/drakkan/sftpgo/dataprovider"
  31. "github.com/drakkan/sftpgo/httpd"
  32. "github.com/drakkan/sftpgo/kms"
  33. "github.com/drakkan/sftpgo/logger"
  34. "github.com/drakkan/sftpgo/utils"
  35. "github.com/drakkan/sftpgo/vfs"
  36. )
  37. const (
  38. defaultUsername = "test_user"
  39. defaultPassword = "test_password"
  40. testPubKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC03jj0D+djk7pxIf/0OhrxrchJTRZklofJ1NoIu4752Sq02mdXmarMVsqJ1cAjV5LBVy3D1F5U6XW4rppkXeVtd04Pxb09ehtH0pRRPaoHHlALiJt8CoMpbKYMA8b3KXPPriGxgGomvtU2T2RMURSwOZbMtpsugfjYSWenyYX+VORYhylWnSXL961LTyC21ehd6d6QnW9G7E5hYMITMY9TuQZz3bROYzXiTsgN0+g6Hn7exFQp50p45StUMfV/SftCMdCxlxuyGny2CrN/vfjO7xxOo2uv7q1qm10Q46KPWJQv+pgZ/OfL+EDjy07n5QVSKHlbx+2nT4Q0EgOSQaCTYwn3YjtABfIxWwgAFdyj6YlPulCL22qU4MYhDcA6PSBwDdf8hvxBfvsiHdM+JcSHvv8/VeJhk6CmnZxGY0fxBupov27z3yEO8nAg8k+6PaUiW1MSUfuGMF/ktB8LOstXsEPXSszuyXiOv4DaryOXUiSn7bmRqKcEFlJusO6aZP0= nicola@p1"
  41. userPath = "/api/v1/user"
  42. folderPath = "/api/v1/folder"
  43. activeConnectionsPath = "/api/v1/connection"
  44. quotaScanPath = "/api/v1/quota_scan"
  45. quotaScanVFolderPath = "/api/v1/folder_quota_scan"
  46. updateUsedQuotaPath = "/api/v1/quota_update"
  47. updateFolderUsedQuotaPath = "/api/v1/folder_quota_update"
  48. versionPath = "/api/v1/version"
  49. metricsPath = "/metrics"
  50. pprofPath = "/debug/pprof/"
  51. webBasePath = "/web"
  52. webUsersPath = "/web/users"
  53. webUserPath = "/web/user"
  54. webFoldersPath = "/web/folders"
  55. webFolderPath = "/web/folder"
  56. webConnectionsPath = "/web/connections"
  57. configDir = ".."
  58. httpsCert = `-----BEGIN CERTIFICATE-----
  59. MIICHTCCAaKgAwIBAgIUHnqw7QnB1Bj9oUsNpdb+ZkFPOxMwCgYIKoZIzj0EAwIw
  60. RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
  61. dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDAyMDQwOTUzMDRaFw0zMDAyMDEw
  62. OTUzMDRaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYD
  63. VQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwdjAQBgcqhkjOPQIBBgUrgQQA
  64. IgNiAARCjRMqJ85rzMC998X5z761nJ+xL3bkmGVqWvrJ51t5OxV0v25NsOgR82CA
  65. NXUgvhVYs7vNFN+jxtb2aj6Xg+/2G/BNxkaFspIVCzgWkxiz7XE4lgUwX44FCXZM
  66. 3+JeUbKjUzBRMB0GA1UdDgQWBBRhLw+/o3+Z02MI/d4tmaMui9W16jAfBgNVHSME
  67. GDAWgBRhLw+/o3+Z02MI/d4tmaMui9W16jAPBgNVHRMBAf8EBTADAQH/MAoGCCqG
  68. SM49BAMCA2kAMGYCMQDqLt2lm8mE+tGgtjDmtFgdOcI72HSbRQ74D5rYTzgST1rY
  69. /8wTi5xl8TiFUyLMUsICMQC5ViVxdXbhuG7gX6yEqSkMKZICHpO8hqFwOD/uaFVI
  70. dV4vKmHUzwK/eIx+8Ay3neE=
  71. -----END CERTIFICATE-----`
  72. httpsKey = `-----BEGIN EC PARAMETERS-----
  73. BgUrgQQAIg==
  74. -----END EC PARAMETERS-----
  75. -----BEGIN EC PRIVATE KEY-----
  76. MIGkAgEBBDCfMNsN6miEE3rVyUPwElfiJSWaR5huPCzUenZOfJT04GAcQdWvEju3
  77. UM2lmBLIXpGgBwYFK4EEACKhZANiAARCjRMqJ85rzMC998X5z761nJ+xL3bkmGVq
  78. WvrJ51t5OxV0v25NsOgR82CANXUgvhVYs7vNFN+jxtb2aj6Xg+/2G/BNxkaFspIV
  79. CzgWkxiz7XE4lgUwX44FCXZM3+JeUbI=
  80. -----END EC PRIVATE KEY-----`
  81. )
  82. var (
  83. defaultPerms = []string{dataprovider.PermAny}
  84. homeBasePath string
  85. backupsPath string
  86. credentialsPath string
  87. testServer *httptest.Server
  88. providerDriverName string
  89. )
  90. type fakeConnection struct {
  91. *common.BaseConnection
  92. command string
  93. }
  94. func (c *fakeConnection) Disconnect() error {
  95. common.Connections.Remove(c.GetID())
  96. return nil
  97. }
  98. func (c *fakeConnection) GetClientVersion() string {
  99. return ""
  100. }
  101. func (c *fakeConnection) GetCommand() string {
  102. return c.command
  103. }
  104. func (c *fakeConnection) GetRemoteAddress() string {
  105. return ""
  106. }
  107. func TestMain(m *testing.M) {
  108. homeBasePath = os.TempDir()
  109. logfilePath := filepath.Join(configDir, "sftpgo_api_test.log")
  110. logger.InitLogger(logfilePath, 5, 1, 28, false, zerolog.DebugLevel)
  111. err := config.LoadConfig(configDir, "")
  112. if err != nil {
  113. logger.WarnToConsole("error loading configuration: %v", err)
  114. os.Exit(1)
  115. }
  116. providerConf := config.GetProviderConf()
  117. credentialsPath = filepath.Join(os.TempDir(), "test_credentials")
  118. providerConf.CredentialsPath = credentialsPath
  119. providerDriverName = providerConf.Driver
  120. os.RemoveAll(credentialsPath) //nolint:errcheck
  121. logger.InfoToConsole("Starting HTTPD tests, provider: %v", providerConf.Driver)
  122. common.Initialize(config.GetCommonConfig())
  123. err = dataprovider.Initialize(providerConf, configDir)
  124. if err != nil {
  125. logger.WarnToConsole("error initializing data provider: %v", err)
  126. os.Exit(1)
  127. }
  128. httpConfig := config.GetHTTPConfig()
  129. httpConfig.Initialize(configDir)
  130. kmsConfig := config.GetKMSConfig()
  131. err = kmsConfig.Initialize()
  132. if err != nil {
  133. logger.ErrorToConsole("error initializing kms: %v", err)
  134. os.Exit(1)
  135. }
  136. httpdConf := config.GetHTTPDConfig()
  137. httpdConf.BindPort = 8081
  138. httpd.SetBaseURLAndCredentials("http://127.0.0.1:8081", "", "")
  139. backupsPath = filepath.Join(os.TempDir(), "test_backups")
  140. httpdConf.BackupsPath = backupsPath
  141. err = os.MkdirAll(backupsPath, os.ModePerm)
  142. if err != nil {
  143. logger.ErrorToConsole("error creating backups path: %v", err)
  144. os.Exit(1)
  145. }
  146. go func() {
  147. if err := httpdConf.Initialize(configDir, true); err != nil {
  148. logger.ErrorToConsole("could not start HTTP server: %v", err)
  149. os.Exit(1)
  150. }
  151. }()
  152. waitTCPListening(fmt.Sprintf("%s:%d", httpdConf.BindAddress, httpdConf.BindPort))
  153. // now start an https server
  154. certPath := filepath.Join(os.TempDir(), "test.crt")
  155. keyPath := filepath.Join(os.TempDir(), "test.key")
  156. err = ioutil.WriteFile(certPath, []byte(httpsCert), os.ModePerm)
  157. if err != nil {
  158. logger.ErrorToConsole("error writing HTTPS certificate: %v", err)
  159. os.Exit(1)
  160. }
  161. err = ioutil.WriteFile(keyPath, []byte(httpsKey), os.ModePerm)
  162. if err != nil {
  163. logger.ErrorToConsole("error writing HTTPS private key: %v", err)
  164. os.Exit(1)
  165. }
  166. httpdConf.BindPort = 8443
  167. httpdConf.CertificateFile = certPath
  168. httpdConf.CertificateKeyFile = keyPath
  169. go func() {
  170. if err := httpdConf.Initialize(configDir, true); err != nil {
  171. logger.ErrorToConsole("could not start HTTPS server: %v", err)
  172. os.Exit(1)
  173. }
  174. }()
  175. waitTCPListening(fmt.Sprintf("%s:%d", httpdConf.BindAddress, httpdConf.BindPort))
  176. httpd.ReloadTLSCertificate() //nolint:errcheck
  177. testServer = httptest.NewServer(httpd.GetHTTPRouter())
  178. defer testServer.Close()
  179. exitCode := m.Run()
  180. os.Remove(logfilePath) //nolint:errcheck
  181. os.RemoveAll(backupsPath) //nolint:errcheck
  182. os.RemoveAll(credentialsPath) //nolint:errcheck
  183. os.Remove(certPath) //nolint:errcheck
  184. os.Remove(keyPath) //nolint:errcheck
  185. os.Exit(exitCode) //nolint:errcheck
  186. }
  187. func TestInitialization(t *testing.T) {
  188. err := config.LoadConfig(configDir, "")
  189. assert.NoError(t, err)
  190. invalidFile := "invalid file"
  191. httpdConf := config.GetHTTPDConfig()
  192. httpdConf.BackupsPath = "test_backups"
  193. httpdConf.AuthUserFile = invalidFile
  194. err = httpdConf.Initialize(configDir, true)
  195. assert.Error(t, err)
  196. httpdConf.BackupsPath = backupsPath
  197. httpdConf.AuthUserFile = ""
  198. httpdConf.CertificateFile = invalidFile
  199. httpdConf.CertificateKeyFile = invalidFile
  200. err = httpdConf.Initialize(configDir, true)
  201. assert.Error(t, err)
  202. httpdConf.CertificateFile = ""
  203. httpdConf.CertificateKeyFile = ""
  204. httpdConf.TemplatesPath = "."
  205. err = httpdConf.Initialize(configDir, true)
  206. assert.Error(t, err)
  207. err = httpd.ReloadTLSCertificate()
  208. assert.NoError(t, err, "reloading TLS Certificate must return nil error if no certificate is configured")
  209. httpdConf = config.GetHTTPDConfig()
  210. httpdConf.BackupsPath = ".."
  211. err = httpdConf.Initialize(configDir, true)
  212. assert.Error(t, err)
  213. httpdConf.BackupsPath = backupsPath
  214. httpdConf.CertificateFile = invalidFile
  215. httpdConf.CertificateKeyFile = invalidFile
  216. httpdConf.StaticFilesPath = ""
  217. httpdConf.TemplatesPath = ""
  218. err = httpdConf.Initialize(configDir, true)
  219. assert.Error(t, err)
  220. }
  221. func TestBasicUserHandling(t *testing.T) {
  222. user, _, err := httpd.AddUser(getTestUser(), http.StatusOK)
  223. assert.NoError(t, err)
  224. user.MaxSessions = 10
  225. user.QuotaSize = 4096
  226. user.QuotaFiles = 2
  227. user.UploadBandwidth = 128
  228. user.DownloadBandwidth = 64
  229. user.ExpirationDate = utils.GetTimeAsMsSinceEpoch(time.Now())
  230. user.AdditionalInfo = "some free text"
  231. originalUser := user
  232. user, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  233. assert.NoError(t, err)
  234. assert.Equal(t, originalUser.ID, user.ID)
  235. users, _, err := httpd.GetUsers(0, 0, defaultUsername, http.StatusOK)
  236. assert.NoError(t, err)
  237. assert.Equal(t, 1, len(users))
  238. _, err = httpd.RemoveUser(user, http.StatusOK)
  239. assert.NoError(t, err)
  240. }
  241. func TestUserStatus(t *testing.T) {
  242. u := getTestUser()
  243. u.Status = 3
  244. _, _, err := httpd.AddUser(u, http.StatusBadRequest)
  245. assert.NoError(t, err)
  246. u.Status = 0
  247. user, _, err := httpd.AddUser(u, http.StatusOK)
  248. assert.NoError(t, err)
  249. user.Status = 2
  250. _, _, err = httpd.UpdateUser(user, http.StatusBadRequest, "")
  251. assert.NoError(t, err)
  252. user.Status = 1
  253. user, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  254. assert.NoError(t, err)
  255. _, err = httpd.RemoveUser(user, http.StatusOK)
  256. assert.NoError(t, err)
  257. }
  258. func TestAddUserNoCredentials(t *testing.T) {
  259. u := getTestUser()
  260. u.Password = ""
  261. u.PublicKeys = []string{}
  262. _, _, err := httpd.AddUser(u, http.StatusBadRequest)
  263. assert.NoError(t, err)
  264. }
  265. func TestAddUserNoUsername(t *testing.T) {
  266. u := getTestUser()
  267. u.Username = ""
  268. _, _, err := httpd.AddUser(u, http.StatusBadRequest)
  269. assert.NoError(t, err)
  270. }
  271. func TestAddUserNoHomeDir(t *testing.T) {
  272. u := getTestUser()
  273. u.HomeDir = ""
  274. _, _, err := httpd.AddUser(u, http.StatusBadRequest)
  275. assert.NoError(t, err)
  276. }
  277. func TestAddUserInvalidHomeDir(t *testing.T) {
  278. u := getTestUser()
  279. u.HomeDir = "relative_path" //nolint:goconst
  280. _, _, err := httpd.AddUser(u, http.StatusBadRequest)
  281. assert.NoError(t, err)
  282. }
  283. func TestAddUserNoPerms(t *testing.T) {
  284. u := getTestUser()
  285. u.Permissions = make(map[string][]string)
  286. _, _, err := httpd.AddUser(u, http.StatusBadRequest)
  287. assert.NoError(t, err)
  288. u.Permissions["/"] = []string{}
  289. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  290. assert.NoError(t, err)
  291. }
  292. func TestAddUserInvalidPerms(t *testing.T) {
  293. u := getTestUser()
  294. u.Permissions["/"] = []string{"invalidPerm"}
  295. _, _, err := httpd.AddUser(u, http.StatusBadRequest)
  296. assert.NoError(t, err)
  297. // permissions for root dir are mandatory
  298. u.Permissions["/"] = []string{}
  299. u.Permissions["/somedir"] = []string{dataprovider.PermAny}
  300. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  301. assert.NoError(t, err)
  302. u.Permissions["/"] = []string{dataprovider.PermAny}
  303. u.Permissions["/subdir/.."] = []string{dataprovider.PermAny}
  304. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  305. assert.NoError(t, err)
  306. }
  307. func TestAddUserInvalidFilters(t *testing.T) {
  308. u := getTestUser()
  309. u.Filters.AllowedIP = []string{"192.168.1.0/24", "192.168.2.0"}
  310. _, _, err := httpd.AddUser(u, http.StatusBadRequest)
  311. assert.NoError(t, err)
  312. u.Filters.AllowedIP = []string{}
  313. u.Filters.DeniedIP = []string{"192.168.3.0/16", "invalid"}
  314. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  315. assert.NoError(t, err)
  316. u.Filters.DeniedIP = []string{}
  317. u.Filters.DeniedLoginMethods = []string{"invalid"}
  318. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  319. assert.NoError(t, err)
  320. u.Filters.DeniedLoginMethods = dataprovider.ValidSSHLoginMethods
  321. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  322. assert.NoError(t, err)
  323. u.Filters.DeniedLoginMethods = []string{}
  324. u.Filters.FileExtensions = []dataprovider.ExtensionsFilter{
  325. {
  326. Path: "relative",
  327. AllowedExtensions: []string{},
  328. DeniedExtensions: []string{},
  329. },
  330. }
  331. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  332. assert.NoError(t, err)
  333. u.Filters.FileExtensions = []dataprovider.ExtensionsFilter{
  334. {
  335. Path: "/",
  336. AllowedExtensions: []string{},
  337. DeniedExtensions: []string{},
  338. },
  339. }
  340. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  341. assert.NoError(t, err)
  342. u.Filters.FileExtensions = []dataprovider.ExtensionsFilter{
  343. {
  344. Path: "/subdir",
  345. AllowedExtensions: []string{".zip"},
  346. DeniedExtensions: []string{},
  347. },
  348. {
  349. Path: "/subdir",
  350. AllowedExtensions: []string{".rar"},
  351. DeniedExtensions: []string{".jpg"},
  352. },
  353. }
  354. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  355. assert.NoError(t, err)
  356. u.Filters.FileExtensions = nil
  357. u.Filters.FilePatterns = []dataprovider.PatternsFilter{
  358. {
  359. Path: "relative",
  360. AllowedPatterns: []string{},
  361. DeniedPatterns: []string{},
  362. },
  363. }
  364. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  365. assert.NoError(t, err)
  366. u.Filters.FilePatterns = []dataprovider.PatternsFilter{
  367. {
  368. Path: "/",
  369. AllowedPatterns: []string{},
  370. DeniedPatterns: []string{},
  371. },
  372. }
  373. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  374. assert.NoError(t, err)
  375. u.Filters.FilePatterns = []dataprovider.PatternsFilter{
  376. {
  377. Path: "/subdir",
  378. AllowedPatterns: []string{"*.zip"},
  379. },
  380. {
  381. Path: "/subdir",
  382. AllowedPatterns: []string{"*.rar"},
  383. DeniedPatterns: []string{"*.jpg"},
  384. },
  385. }
  386. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  387. assert.NoError(t, err)
  388. u.Filters.FilePatterns = []dataprovider.PatternsFilter{
  389. {
  390. Path: "/subdir",
  391. AllowedPatterns: []string{"a\\"},
  392. },
  393. }
  394. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  395. assert.NoError(t, err)
  396. u.Filters.DeniedProtocols = []string{"invalid"}
  397. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  398. assert.NoError(t, err)
  399. u.Filters.DeniedProtocols = dataprovider.ValidProtocols
  400. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  401. assert.NoError(t, err)
  402. }
  403. func TestAddUserInvalidFsConfig(t *testing.T) {
  404. u := getTestUser()
  405. u.FsConfig.Provider = dataprovider.S3FilesystemProvider
  406. u.FsConfig.S3Config.Bucket = ""
  407. _, _, err := httpd.AddUser(u, http.StatusBadRequest)
  408. assert.NoError(t, err)
  409. err = os.RemoveAll(credentialsPath)
  410. assert.NoError(t, err)
  411. err = os.MkdirAll(credentialsPath, 0700)
  412. assert.NoError(t, err)
  413. u.FsConfig.S3Config.Bucket = "testbucket"
  414. u.FsConfig.S3Config.Region = "eu-west-1"
  415. u.FsConfig.S3Config.AccessKey = "access-key"
  416. u.FsConfig.S3Config.AccessSecret = kms.NewSecret(kms.SecretStatusRedacted, "access-secret", "", "")
  417. u.FsConfig.S3Config.Endpoint = "http://127.0.0.1:9000/path?a=b"
  418. u.FsConfig.S3Config.StorageClass = "Standard" //nolint:goconst
  419. u.FsConfig.S3Config.KeyPrefix = "/adir/subdir/"
  420. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  421. assert.NoError(t, err)
  422. u.FsConfig.S3Config.AccessSecret.SetStatus(kms.SecretStatusPlain)
  423. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  424. assert.NoError(t, err)
  425. u.FsConfig.S3Config.KeyPrefix = ""
  426. u.FsConfig.S3Config.UploadPartSize = 3
  427. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  428. assert.NoError(t, err)
  429. u.FsConfig.S3Config.UploadPartSize = 5001
  430. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  431. assert.NoError(t, err)
  432. u.FsConfig.S3Config.UploadPartSize = 0
  433. u.FsConfig.S3Config.UploadConcurrency = -1
  434. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  435. assert.NoError(t, err)
  436. u = getTestUser()
  437. u.FsConfig.Provider = dataprovider.GCSFilesystemProvider
  438. u.FsConfig.GCSConfig.Bucket = ""
  439. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  440. assert.NoError(t, err)
  441. u.FsConfig.GCSConfig.Bucket = "abucket"
  442. u.FsConfig.GCSConfig.StorageClass = "Standard"
  443. u.FsConfig.GCSConfig.KeyPrefix = "/somedir/subdir/"
  444. u.FsConfig.GCSConfig.Credentials = kms.NewSecret(kms.SecretStatusRedacted, "test", "", "") //nolint:goconst
  445. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  446. assert.NoError(t, err)
  447. u.FsConfig.GCSConfig.Credentials.SetStatus(kms.SecretStatusPlain)
  448. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  449. assert.NoError(t, err)
  450. u.FsConfig.GCSConfig.KeyPrefix = "somedir/subdir/" //nolint:goconst
  451. u.FsConfig.GCSConfig.Credentials = kms.NewEmptySecret()
  452. u.FsConfig.GCSConfig.AutomaticCredentials = 0
  453. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  454. assert.NoError(t, err)
  455. u.FsConfig.GCSConfig.Credentials = kms.NewSecret(kms.SecretStatusSecretBox, "invalid", "", "")
  456. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  457. assert.NoError(t, err)
  458. u = getTestUser()
  459. u.FsConfig.Provider = dataprovider.AzureBlobFilesystemProvider
  460. u.FsConfig.AzBlobConfig.SASURL = "http://foo\x7f.com/"
  461. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  462. assert.NoError(t, err)
  463. u.FsConfig.AzBlobConfig.SASURL = ""
  464. u.FsConfig.AzBlobConfig.AccountName = "name"
  465. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  466. assert.NoError(t, err)
  467. u.FsConfig.AzBlobConfig.Container = "container"
  468. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  469. assert.NoError(t, err)
  470. u.FsConfig.AzBlobConfig.AccountKey = kms.NewSecret(kms.SecretStatusRedacted, "key", "", "")
  471. u.FsConfig.AzBlobConfig.KeyPrefix = "/amedir/subdir/"
  472. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  473. assert.NoError(t, err)
  474. u.FsConfig.AzBlobConfig.AccountKey.SetStatus(kms.SecretStatusPlain)
  475. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  476. assert.NoError(t, err)
  477. u.FsConfig.AzBlobConfig.KeyPrefix = "amedir/subdir/"
  478. u.FsConfig.AzBlobConfig.UploadPartSize = -1
  479. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  480. assert.NoError(t, err)
  481. u.FsConfig.AzBlobConfig.UploadPartSize = 101
  482. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  483. assert.NoError(t, err)
  484. }
  485. func TestAddUserInvalidVirtualFolders(t *testing.T) {
  486. u := getTestUser()
  487. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  488. BaseVirtualFolder: vfs.BaseVirtualFolder{
  489. MappedPath: filepath.Join(os.TempDir(), "mapped_dir"),
  490. },
  491. VirtualPath: "vdir",
  492. })
  493. _, _, err := httpd.AddUser(u, http.StatusBadRequest)
  494. assert.NoError(t, err)
  495. u.VirtualFolders = nil
  496. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  497. BaseVirtualFolder: vfs.BaseVirtualFolder{
  498. MappedPath: filepath.Join(os.TempDir(), "mapped_dir"),
  499. },
  500. VirtualPath: "/",
  501. })
  502. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  503. assert.NoError(t, err)
  504. u.VirtualFolders = nil
  505. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  506. BaseVirtualFolder: vfs.BaseVirtualFolder{
  507. MappedPath: filepath.Join(u.GetHomeDir(), "mapped_dir"),
  508. },
  509. VirtualPath: "/vdir",
  510. })
  511. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  512. assert.NoError(t, err)
  513. u.VirtualFolders = nil
  514. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  515. BaseVirtualFolder: vfs.BaseVirtualFolder{
  516. MappedPath: u.GetHomeDir(),
  517. },
  518. VirtualPath: "/vdir",
  519. })
  520. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  521. assert.NoError(t, err)
  522. u.VirtualFolders = nil
  523. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  524. BaseVirtualFolder: vfs.BaseVirtualFolder{
  525. MappedPath: filepath.Join(u.GetHomeDir(), ".."),
  526. },
  527. VirtualPath: "/vdir",
  528. })
  529. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  530. assert.NoError(t, err)
  531. u.VirtualFolders = nil
  532. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  533. BaseVirtualFolder: vfs.BaseVirtualFolder{
  534. MappedPath: filepath.Join(os.TempDir(), "mapped_dir"),
  535. },
  536. VirtualPath: "/vdir",
  537. })
  538. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  539. BaseVirtualFolder: vfs.BaseVirtualFolder{
  540. MappedPath: filepath.Join(os.TempDir(), "mapped_dir1"),
  541. },
  542. VirtualPath: "/vdir",
  543. })
  544. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  545. assert.NoError(t, err)
  546. u.VirtualFolders = nil
  547. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  548. BaseVirtualFolder: vfs.BaseVirtualFolder{
  549. MappedPath: filepath.Join(os.TempDir(), "mapped_dir"),
  550. },
  551. VirtualPath: "/vdir1",
  552. })
  553. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  554. BaseVirtualFolder: vfs.BaseVirtualFolder{
  555. MappedPath: filepath.Join(os.TempDir(), "mapped_dir"),
  556. },
  557. VirtualPath: "/vdir2",
  558. })
  559. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  560. assert.NoError(t, err)
  561. u.VirtualFolders = nil
  562. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  563. BaseVirtualFolder: vfs.BaseVirtualFolder{
  564. MappedPath: filepath.Join(os.TempDir(), "mapped_dir", "subdir"),
  565. },
  566. VirtualPath: "/vdir1",
  567. })
  568. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  569. BaseVirtualFolder: vfs.BaseVirtualFolder{
  570. MappedPath: filepath.Join(os.TempDir(), "mapped_dir"),
  571. },
  572. VirtualPath: "/vdir2",
  573. })
  574. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  575. assert.NoError(t, err)
  576. u.VirtualFolders = nil
  577. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  578. BaseVirtualFolder: vfs.BaseVirtualFolder{
  579. MappedPath: filepath.Join(os.TempDir(), "mapped_dir"),
  580. },
  581. VirtualPath: "/vdir1",
  582. })
  583. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  584. BaseVirtualFolder: vfs.BaseVirtualFolder{
  585. MappedPath: filepath.Join(os.TempDir(), "mapped_dir", "subdir"),
  586. },
  587. VirtualPath: "/vdir2",
  588. })
  589. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  590. assert.NoError(t, err)
  591. u.VirtualFolders = nil
  592. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  593. BaseVirtualFolder: vfs.BaseVirtualFolder{
  594. MappedPath: filepath.Join(os.TempDir(), "mapped_dir1"),
  595. },
  596. VirtualPath: "/vdir1/subdir",
  597. })
  598. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  599. BaseVirtualFolder: vfs.BaseVirtualFolder{
  600. MappedPath: filepath.Join(os.TempDir(), "mapped_dir2"),
  601. },
  602. VirtualPath: "/vdir1/../vdir1",
  603. })
  604. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  605. assert.NoError(t, err)
  606. u.VirtualFolders = nil
  607. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  608. BaseVirtualFolder: vfs.BaseVirtualFolder{
  609. MappedPath: filepath.Join(os.TempDir(), "mapped_dir1"),
  610. },
  611. VirtualPath: "/vdir1/",
  612. })
  613. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  614. BaseVirtualFolder: vfs.BaseVirtualFolder{
  615. MappedPath: filepath.Join(os.TempDir(), "mapped_dir2"),
  616. },
  617. VirtualPath: "/vdir1/subdir",
  618. })
  619. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  620. assert.NoError(t, err)
  621. u.VirtualFolders = nil
  622. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  623. BaseVirtualFolder: vfs.BaseVirtualFolder{
  624. MappedPath: filepath.Join(os.TempDir(), "mapped_dir1"),
  625. },
  626. VirtualPath: "/vdir1/",
  627. QuotaSize: -1,
  628. QuotaFiles: 1,
  629. })
  630. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  631. assert.NoError(t, err)
  632. u.VirtualFolders = nil
  633. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  634. BaseVirtualFolder: vfs.BaseVirtualFolder{
  635. MappedPath: filepath.Join(os.TempDir(), "mapped_dir1"),
  636. },
  637. VirtualPath: "/vdir1/",
  638. QuotaSize: 1,
  639. QuotaFiles: -1,
  640. })
  641. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  642. assert.NoError(t, err)
  643. u.VirtualFolders = nil
  644. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  645. BaseVirtualFolder: vfs.BaseVirtualFolder{
  646. MappedPath: filepath.Join(os.TempDir(), "mapped_dir1"),
  647. },
  648. VirtualPath: "/vdir1/",
  649. QuotaSize: -2,
  650. QuotaFiles: 0,
  651. })
  652. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  653. assert.NoError(t, err)
  654. u.VirtualFolders = nil
  655. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  656. BaseVirtualFolder: vfs.BaseVirtualFolder{
  657. MappedPath: filepath.Join(os.TempDir(), "mapped_dir1"),
  658. },
  659. VirtualPath: "/vdir1/",
  660. QuotaSize: 0,
  661. QuotaFiles: -2,
  662. })
  663. _, _, err = httpd.AddUser(u, http.StatusBadRequest)
  664. assert.NoError(t, err)
  665. }
  666. func TestUserPublicKey(t *testing.T) {
  667. u := getTestUser()
  668. invalidPubKey := "invalid"
  669. validPubKey := "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC03jj0D+djk7pxIf/0OhrxrchJTRZklofJ1NoIu4752Sq02mdXmarMVsqJ1cAjV5LBVy3D1F5U6XW4rppkXeVtd04Pxb09ehtH0pRRPaoHHlALiJt8CoMpbKYMA8b3KXPPriGxgGomvtU2T2RMURSwOZbMtpsugfjYSWenyYX+VORYhylWnSXL961LTyC21ehd6d6QnW9G7E5hYMITMY9TuQZz3bROYzXiTsgN0+g6Hn7exFQp50p45StUMfV/SftCMdCxlxuyGny2CrN/vfjO7xxOo2uv7q1qm10Q46KPWJQv+pgZ/OfL+EDjy07n5QVSKHlbx+2nT4Q0EgOSQaCTYwn3YjtABfIxWwgAFdyj6YlPulCL22qU4MYhDcA6PSBwDdf8hvxBfvsiHdM+JcSHvv8/VeJhk6CmnZxGY0fxBupov27z3yEO8nAg8k+6PaUiW1MSUfuGMF/ktB8LOstXsEPXSszuyXiOv4DaryOXUiSn7bmRqKcEFlJusO6aZP0= nicola@p1"
  670. u.PublicKeys = []string{invalidPubKey}
  671. _, _, err := httpd.AddUser(u, http.StatusBadRequest)
  672. assert.NoError(t, err)
  673. u.PublicKeys = []string{validPubKey}
  674. user, _, err := httpd.AddUser(u, http.StatusOK)
  675. assert.NoError(t, err)
  676. user.PublicKeys = []string{validPubKey, invalidPubKey}
  677. _, _, err = httpd.UpdateUser(user, http.StatusBadRequest, "")
  678. assert.NoError(t, err)
  679. user.PublicKeys = []string{validPubKey, validPubKey, validPubKey}
  680. _, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  681. assert.NoError(t, err)
  682. _, err = httpd.RemoveUser(user, http.StatusOK)
  683. assert.NoError(t, err)
  684. }
  685. func TestUpdateUser(t *testing.T) {
  686. u := getTestUser()
  687. u.UsedQuotaFiles = 1
  688. u.UsedQuotaSize = 2
  689. user, _, err := httpd.AddUser(u, http.StatusOK)
  690. assert.NoError(t, err)
  691. assert.Equal(t, 0, user.UsedQuotaFiles)
  692. assert.Equal(t, int64(0), user.UsedQuotaSize)
  693. user.HomeDir = filepath.Join(homeBasePath, "testmod")
  694. user.UID = 33
  695. user.GID = 101
  696. user.MaxSessions = 10
  697. user.QuotaSize = 4096
  698. user.QuotaFiles = 2
  699. user.Permissions["/"] = []string{dataprovider.PermCreateDirs, dataprovider.PermDelete, dataprovider.PermDownload}
  700. user.Permissions["/subdir"] = []string{dataprovider.PermListItems, dataprovider.PermUpload}
  701. user.Filters.AllowedIP = []string{"192.168.1.0/24", "192.168.2.0/24"}
  702. user.Filters.DeniedIP = []string{"192.168.3.0/24", "192.168.4.0/24"}
  703. user.Filters.DeniedLoginMethods = []string{dataprovider.LoginMethodPassword}
  704. user.Filters.DeniedProtocols = []string{common.ProtocolWebDAV}
  705. user.Filters.FileExtensions = append(user.Filters.FileExtensions, dataprovider.ExtensionsFilter{
  706. Path: "/subdir",
  707. AllowedExtensions: []string{".zip", ".rar"},
  708. DeniedExtensions: []string{".jpg", ".png"},
  709. })
  710. user.Filters.FilePatterns = append(user.Filters.FilePatterns, dataprovider.PatternsFilter{
  711. Path: "/subdir",
  712. AllowedPatterns: []string{"*.zip", "*.rar"},
  713. DeniedPatterns: []string{"*.jpg", "*.png"},
  714. })
  715. user.Filters.MaxUploadFileSize = 4096
  716. user.UploadBandwidth = 1024
  717. user.DownloadBandwidth = 512
  718. user.VirtualFolders = nil
  719. mappedPath1 := filepath.Join(os.TempDir(), "mapped_dir1")
  720. mappedPath2 := filepath.Join(os.TempDir(), "mapped_dir2")
  721. user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{
  722. BaseVirtualFolder: vfs.BaseVirtualFolder{
  723. MappedPath: mappedPath1,
  724. },
  725. VirtualPath: "/vdir1",
  726. })
  727. user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{
  728. BaseVirtualFolder: vfs.BaseVirtualFolder{
  729. MappedPath: mappedPath2,
  730. },
  731. VirtualPath: "/vdir12/subdir",
  732. QuotaSize: 123,
  733. QuotaFiles: 2,
  734. })
  735. user, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  736. assert.NoError(t, err)
  737. _, _, err = httpd.UpdateUser(user, http.StatusBadRequest, "invalid")
  738. assert.NoError(t, err)
  739. user, _, err = httpd.UpdateUser(user, http.StatusOK, "0")
  740. assert.NoError(t, err)
  741. user, _, err = httpd.UpdateUser(user, http.StatusOK, "1")
  742. assert.NoError(t, err)
  743. user.Permissions["/subdir"] = []string{}
  744. user, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  745. assert.NoError(t, err)
  746. assert.Len(t, user.Permissions["/subdir"], 0)
  747. assert.Len(t, user.VirtualFolders, 2)
  748. for _, folder := range user.VirtualFolders {
  749. assert.Greater(t, folder.ID, int64(0))
  750. if folder.VirtualPath == "/vdir12/subdir" {
  751. assert.Equal(t, int64(123), folder.QuotaSize)
  752. assert.Equal(t, 2, folder.QuotaFiles)
  753. }
  754. }
  755. folder, _, err := httpd.GetFolders(0, 0, mappedPath1, http.StatusOK)
  756. assert.NoError(t, err)
  757. if assert.Len(t, folder, 1) {
  758. f := folder[0]
  759. assert.Len(t, f.Users, 1)
  760. assert.Contains(t, f.Users, user.Username)
  761. }
  762. _, err = httpd.RemoveUser(user, http.StatusOK)
  763. assert.NoError(t, err)
  764. // removing the user must remove folder mapping
  765. folder, _, err = httpd.GetFolders(0, 0, mappedPath1, http.StatusOK)
  766. assert.NoError(t, err)
  767. if assert.Len(t, folder, 1) {
  768. f := folder[0]
  769. assert.Len(t, f.Users, 0)
  770. _, err = httpd.RemoveFolder(f, http.StatusOK)
  771. assert.NoError(t, err)
  772. }
  773. folder, _, err = httpd.GetFolders(0, 0, mappedPath2, http.StatusOK)
  774. assert.NoError(t, err)
  775. if assert.Len(t, folder, 1) {
  776. f := folder[0]
  777. assert.Len(t, f.Users, 0)
  778. _, err = httpd.RemoveFolder(f, http.StatusOK)
  779. assert.NoError(t, err)
  780. }
  781. }
  782. func TestUpdateUserQuotaUsage(t *testing.T) {
  783. u := getTestUser()
  784. usedQuotaFiles := 1
  785. usedQuotaSize := int64(65535)
  786. u.UsedQuotaFiles = usedQuotaFiles
  787. u.UsedQuotaSize = usedQuotaSize
  788. user, _, err := httpd.AddUser(u, http.StatusOK)
  789. assert.NoError(t, err)
  790. _, err = httpd.UpdateQuotaUsage(u, "invalid_mode", http.StatusBadRequest)
  791. assert.NoError(t, err)
  792. _, err = httpd.UpdateQuotaUsage(u, "", http.StatusOK)
  793. assert.NoError(t, err)
  794. user, _, err = httpd.GetUserByID(user.ID, http.StatusOK)
  795. assert.NoError(t, err)
  796. assert.Equal(t, usedQuotaFiles, user.UsedQuotaFiles)
  797. assert.Equal(t, usedQuotaSize, user.UsedQuotaSize)
  798. _, err = httpd.UpdateQuotaUsage(u, "add", http.StatusBadRequest)
  799. assert.NoError(t, err, "user has no quota restrictions add mode should fail")
  800. user, _, err = httpd.GetUserByID(user.ID, http.StatusOK)
  801. assert.NoError(t, err)
  802. assert.Equal(t, usedQuotaFiles, user.UsedQuotaFiles)
  803. assert.Equal(t, usedQuotaSize, user.UsedQuotaSize)
  804. user.QuotaFiles = 100
  805. user, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  806. assert.NoError(t, err)
  807. _, err = httpd.UpdateQuotaUsage(u, "add", http.StatusOK)
  808. assert.NoError(t, err)
  809. user, _, err = httpd.GetUserByID(user.ID, http.StatusOK)
  810. assert.NoError(t, err)
  811. assert.Equal(t, 2*usedQuotaFiles, user.UsedQuotaFiles)
  812. assert.Equal(t, 2*usedQuotaSize, user.UsedQuotaSize)
  813. u.UsedQuotaFiles = -1
  814. _, err = httpd.UpdateQuotaUsage(u, "", http.StatusBadRequest)
  815. assert.NoError(t, err)
  816. u.UsedQuotaFiles = usedQuotaFiles
  817. u.Username = u.Username + "1"
  818. _, err = httpd.UpdateQuotaUsage(u, "", http.StatusNotFound)
  819. assert.NoError(t, err)
  820. _, err = httpd.RemoveUser(user, http.StatusOK)
  821. assert.NoError(t, err)
  822. }
  823. func TestUserFolderMapping(t *testing.T) {
  824. mappedPath1 := filepath.Join(os.TempDir(), "mapped_dir1")
  825. mappedPath2 := filepath.Join(os.TempDir(), "mapped_dir2")
  826. u1 := getTestUser()
  827. u1.VirtualFolders = append(u1.VirtualFolders, vfs.VirtualFolder{
  828. BaseVirtualFolder: vfs.BaseVirtualFolder{
  829. MappedPath: mappedPath1,
  830. UsedQuotaFiles: 2,
  831. UsedQuotaSize: 123,
  832. },
  833. VirtualPath: "/vdir",
  834. QuotaSize: -1,
  835. QuotaFiles: -1,
  836. })
  837. user1, _, err := httpd.AddUser(u1, http.StatusOK)
  838. assert.NoError(t, err)
  839. // virtual folder must be auto created
  840. folders, _, err := httpd.GetFolders(0, 0, mappedPath1, http.StatusOK)
  841. assert.NoError(t, err)
  842. if assert.Len(t, folders, 1) {
  843. folder := folders[0]
  844. assert.Len(t, folder.Users, 1)
  845. assert.Contains(t, folder.Users, user1.Username)
  846. assert.Equal(t, 0, folder.UsedQuotaFiles)
  847. assert.Equal(t, int64(0), folder.UsedQuotaSize)
  848. }
  849. u2 := getTestUser()
  850. u2.Username = defaultUsername + "2"
  851. u2.VirtualFolders = append(u2.VirtualFolders, vfs.VirtualFolder{
  852. BaseVirtualFolder: vfs.BaseVirtualFolder{
  853. MappedPath: mappedPath1,
  854. },
  855. VirtualPath: "/vdir1",
  856. QuotaSize: 0,
  857. QuotaFiles: 0,
  858. })
  859. u2.VirtualFolders = append(u2.VirtualFolders, vfs.VirtualFolder{
  860. BaseVirtualFolder: vfs.BaseVirtualFolder{
  861. MappedPath: mappedPath2,
  862. },
  863. VirtualPath: "/vdir2",
  864. QuotaSize: -1,
  865. QuotaFiles: -1,
  866. })
  867. user2, _, err := httpd.AddUser(u2, http.StatusOK)
  868. assert.NoError(t, err)
  869. folders, _, err = httpd.GetFolders(0, 0, mappedPath2, http.StatusOK)
  870. assert.NoError(t, err)
  871. if assert.Len(t, folders, 1) {
  872. folder := folders[0]
  873. assert.Len(t, folder.Users, 1)
  874. assert.Contains(t, folder.Users, user2.Username)
  875. }
  876. folders, _, err = httpd.GetFolders(0, 0, mappedPath1, http.StatusOK)
  877. assert.NoError(t, err)
  878. if assert.Len(t, folders, 1) {
  879. folder := folders[0]
  880. assert.Len(t, folder.Users, 2)
  881. assert.Contains(t, folder.Users, user1.Username)
  882. assert.Contains(t, folder.Users, user2.Username)
  883. }
  884. // now update user2 removing mappedPath1
  885. user2.VirtualFolders = nil
  886. user2.VirtualFolders = append(user2.VirtualFolders, vfs.VirtualFolder{
  887. BaseVirtualFolder: vfs.BaseVirtualFolder{
  888. MappedPath: mappedPath2,
  889. UsedQuotaFiles: 2,
  890. UsedQuotaSize: 123,
  891. },
  892. VirtualPath: "/vdir",
  893. QuotaSize: 0,
  894. QuotaFiles: 0,
  895. })
  896. user2, _, err = httpd.UpdateUser(user2, http.StatusOK, "")
  897. assert.NoError(t, err)
  898. folders, _, err = httpd.GetFolders(0, 0, mappedPath2, http.StatusOK)
  899. assert.NoError(t, err)
  900. if assert.Len(t, folders, 1) {
  901. folder := folders[0]
  902. assert.Len(t, folder.Users, 1)
  903. assert.Contains(t, folder.Users, user2.Username)
  904. assert.Equal(t, 0, folder.UsedQuotaFiles)
  905. assert.Equal(t, int64(0), folder.UsedQuotaSize)
  906. }
  907. folders, _, err = httpd.GetFolders(0, 0, mappedPath1, http.StatusOK)
  908. assert.NoError(t, err)
  909. if assert.Len(t, folders, 1) {
  910. folder := folders[0]
  911. assert.Len(t, folder.Users, 1)
  912. assert.Contains(t, folder.Users, user1.Username)
  913. }
  914. // add mappedPath1 again to user2
  915. user2.VirtualFolders = append(user2.VirtualFolders, vfs.VirtualFolder{
  916. BaseVirtualFolder: vfs.BaseVirtualFolder{
  917. MappedPath: mappedPath1,
  918. },
  919. VirtualPath: "/vdir1",
  920. })
  921. user2, _, err = httpd.UpdateUser(user2, http.StatusOK, "")
  922. assert.NoError(t, err)
  923. folders, _, err = httpd.GetFolders(0, 0, mappedPath2, http.StatusOK)
  924. assert.NoError(t, err)
  925. if assert.Len(t, folders, 1) {
  926. folder := folders[0]
  927. assert.Len(t, folder.Users, 1)
  928. assert.Contains(t, folder.Users, user2.Username)
  929. }
  930. // removing virtual folders should clear relations on both side
  931. _, err = httpd.RemoveFolder(vfs.BaseVirtualFolder{MappedPath: mappedPath2}, http.StatusOK)
  932. assert.NoError(t, err)
  933. user2, _, err = httpd.GetUserByID(user2.ID, http.StatusOK)
  934. assert.NoError(t, err)
  935. if assert.Len(t, user2.VirtualFolders, 1) {
  936. folder := user2.VirtualFolders[0]
  937. assert.Equal(t, mappedPath1, folder.MappedPath)
  938. }
  939. user1, _, err = httpd.GetUserByID(user1.ID, http.StatusOK)
  940. assert.NoError(t, err)
  941. if assert.Len(t, user2.VirtualFolders, 1) {
  942. folder := user2.VirtualFolders[0]
  943. assert.Equal(t, mappedPath1, folder.MappedPath)
  944. }
  945. folders, _, err = httpd.GetFolders(0, 0, mappedPath1, http.StatusOK)
  946. assert.NoError(t, err)
  947. if assert.Len(t, folders, 1) {
  948. folder := folders[0]
  949. assert.Len(t, folder.Users, 2)
  950. }
  951. // removing a user should clear virtual folder mapping
  952. _, err = httpd.RemoveUser(user1, http.StatusOK)
  953. assert.NoError(t, err)
  954. folders, _, err = httpd.GetFolders(0, 0, mappedPath1, http.StatusOK)
  955. assert.NoError(t, err)
  956. if assert.Len(t, folders, 1) {
  957. folder := folders[0]
  958. assert.Len(t, folder.Users, 1)
  959. assert.Contains(t, folder.Users, user2.Username)
  960. }
  961. // removing a folder should clear mapping on the user side too
  962. _, err = httpd.RemoveFolder(vfs.BaseVirtualFolder{MappedPath: mappedPath1}, http.StatusOK)
  963. assert.NoError(t, err)
  964. user2, _, err = httpd.GetUserByID(user2.ID, http.StatusOK)
  965. assert.NoError(t, err)
  966. assert.Len(t, user2.VirtualFolders, 0)
  967. _, err = httpd.RemoveUser(user2, http.StatusOK)
  968. assert.NoError(t, err)
  969. }
  970. func TestUserS3Config(t *testing.T) {
  971. user, _, err := httpd.AddUser(getTestUser(), http.StatusOK)
  972. assert.NoError(t, err)
  973. user.FsConfig.Provider = dataprovider.S3FilesystemProvider
  974. user.FsConfig.S3Config.Bucket = "test" //nolint:goconst
  975. user.FsConfig.S3Config.Region = "us-east-1" //nolint:goconst
  976. user.FsConfig.S3Config.AccessKey = "Server-Access-Key"
  977. user.FsConfig.S3Config.AccessSecret = kms.NewPlainSecret("Server-Access-Secret")
  978. user.FsConfig.S3Config.Endpoint = "http://127.0.0.1:9000"
  979. user.FsConfig.S3Config.UploadPartSize = 8
  980. user, body, err := httpd.UpdateUser(user, http.StatusOK, "")
  981. assert.NoError(t, err, string(body))
  982. assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.S3Config.AccessSecret.GetStatus())
  983. assert.NotEmpty(t, user.FsConfig.S3Config.AccessSecret.GetPayload())
  984. assert.Empty(t, user.FsConfig.S3Config.AccessSecret.GetAdditionalData())
  985. assert.Empty(t, user.FsConfig.S3Config.AccessSecret.GetKey())
  986. _, err = httpd.RemoveUser(user, http.StatusOK)
  987. assert.NoError(t, err)
  988. user.Password = defaultPassword
  989. user.ID = 0
  990. secret := kms.NewSecret(kms.SecretStatusSecretBox, "Server-Access-Secret", "", "")
  991. user.FsConfig.S3Config.AccessSecret = secret
  992. _, _, err = httpd.AddUser(user, http.StatusOK)
  993. assert.Error(t, err)
  994. user.FsConfig.S3Config.AccessSecret.SetStatus(kms.SecretStatusPlain)
  995. user, _, err = httpd.AddUser(user, http.StatusOK)
  996. assert.NoError(t, err)
  997. initialSecretPayload := user.FsConfig.S3Config.AccessSecret.GetPayload()
  998. assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.S3Config.AccessSecret.GetStatus())
  999. assert.NotEmpty(t, initialSecretPayload)
  1000. assert.Empty(t, user.FsConfig.S3Config.AccessSecret.GetAdditionalData())
  1001. assert.Empty(t, user.FsConfig.S3Config.AccessSecret.GetKey())
  1002. user.FsConfig.Provider = dataprovider.S3FilesystemProvider
  1003. user.FsConfig.S3Config.Bucket = "test-bucket"
  1004. user.FsConfig.S3Config.Region = "us-east-1" //nolint:goconst
  1005. user.FsConfig.S3Config.AccessKey = "Server-Access-Key1"
  1006. user.FsConfig.S3Config.Endpoint = "http://localhost:9000"
  1007. user.FsConfig.S3Config.KeyPrefix = "somedir/subdir" //nolint:goconst
  1008. user.FsConfig.S3Config.UploadConcurrency = 5
  1009. user, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  1010. assert.NoError(t, err)
  1011. assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.S3Config.AccessSecret.GetStatus())
  1012. assert.Equal(t, initialSecretPayload, user.FsConfig.S3Config.AccessSecret.GetPayload())
  1013. assert.Empty(t, user.FsConfig.S3Config.AccessSecret.GetAdditionalData())
  1014. assert.Empty(t, user.FsConfig.S3Config.AccessSecret.GetKey())
  1015. // test user without access key and access secret (shared config state)
  1016. user.FsConfig.Provider = dataprovider.S3FilesystemProvider
  1017. user.FsConfig.S3Config.Bucket = "testbucket"
  1018. user.FsConfig.S3Config.Region = "us-east-1"
  1019. user.FsConfig.S3Config.AccessKey = ""
  1020. user.FsConfig.S3Config.AccessSecret = kms.NewEmptySecret()
  1021. user.FsConfig.S3Config.Endpoint = ""
  1022. user.FsConfig.S3Config.KeyPrefix = "somedir/subdir"
  1023. user.FsConfig.S3Config.UploadPartSize = 6
  1024. user.FsConfig.S3Config.UploadConcurrency = 4
  1025. user, body, err = httpd.UpdateUser(user, http.StatusOK, "")
  1026. assert.NoError(t, err, string(body))
  1027. assert.True(t, user.FsConfig.S3Config.AccessSecret.IsEmpty())
  1028. _, err = httpd.RemoveUser(user, http.StatusOK)
  1029. assert.NoError(t, err)
  1030. user.Password = defaultPassword
  1031. user.ID = 0
  1032. // shared credential test for add instead of update
  1033. user, _, err = httpd.AddUser(user, http.StatusOK)
  1034. assert.NoError(t, err)
  1035. assert.True(t, user.FsConfig.S3Config.AccessSecret.IsEmpty())
  1036. _, err = httpd.RemoveUser(user, http.StatusOK)
  1037. assert.NoError(t, err)
  1038. }
  1039. func TestUserGCSConfig(t *testing.T) {
  1040. user, _, err := httpd.AddUser(getTestUser(), http.StatusOK)
  1041. assert.NoError(t, err)
  1042. err = os.RemoveAll(credentialsPath)
  1043. assert.NoError(t, err)
  1044. err = os.MkdirAll(credentialsPath, 0700)
  1045. assert.NoError(t, err)
  1046. user.FsConfig.Provider = dataprovider.GCSFilesystemProvider
  1047. user.FsConfig.GCSConfig.Bucket = "test"
  1048. user.FsConfig.GCSConfig.Credentials = kms.NewPlainSecret("fake credentials") //nolint:goconst
  1049. user, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  1050. assert.NoError(t, err)
  1051. credentialFile := filepath.Join(credentialsPath, fmt.Sprintf("%v_gcs_credentials.json", user.Username))
  1052. assert.FileExists(t, credentialFile)
  1053. creds, err := ioutil.ReadFile(credentialFile)
  1054. assert.NoError(t, err)
  1055. secret := kms.NewEmptySecret()
  1056. err = json.Unmarshal(creds, secret)
  1057. assert.NoError(t, err)
  1058. err = secret.Decrypt()
  1059. assert.NoError(t, err)
  1060. assert.Equal(t, "fake credentials", secret.GetPayload())
  1061. user.FsConfig.GCSConfig.Credentials = kms.NewSecret(kms.SecretStatusSecretBox, "fake encrypted credentials", "", "")
  1062. user, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  1063. assert.NoError(t, err)
  1064. assert.FileExists(t, credentialFile)
  1065. creds, err = ioutil.ReadFile(credentialFile)
  1066. assert.NoError(t, err)
  1067. secret = kms.NewEmptySecret()
  1068. err = json.Unmarshal(creds, secret)
  1069. assert.NoError(t, err)
  1070. err = secret.Decrypt()
  1071. assert.NoError(t, err)
  1072. assert.Equal(t, "fake credentials", secret.GetPayload())
  1073. _, err = httpd.RemoveUser(user, http.StatusOK)
  1074. assert.NoError(t, err)
  1075. user.Password = defaultPassword
  1076. user.ID = 0
  1077. user.FsConfig.GCSConfig.Credentials = kms.NewSecret(kms.SecretStatusSecretBox, "fake credentials", "", "")
  1078. _, _, err = httpd.AddUser(user, http.StatusOK)
  1079. assert.Error(t, err)
  1080. user.FsConfig.GCSConfig.Credentials.SetStatus(kms.SecretStatusPlain)
  1081. user, body, err := httpd.AddUser(user, http.StatusOK)
  1082. assert.NoError(t, err, string(body))
  1083. err = os.RemoveAll(credentialsPath)
  1084. assert.NoError(t, err)
  1085. err = os.MkdirAll(credentialsPath, 0700)
  1086. assert.NoError(t, err)
  1087. user.FsConfig.GCSConfig.Credentials = kms.NewEmptySecret()
  1088. user.FsConfig.GCSConfig.AutomaticCredentials = 1
  1089. user, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  1090. assert.NoError(t, err)
  1091. assert.NoFileExists(t, credentialFile)
  1092. user.FsConfig.GCSConfig = vfs.GCSFsConfig{}
  1093. user.FsConfig.Provider = dataprovider.S3FilesystemProvider
  1094. user.FsConfig.S3Config.Bucket = "test1"
  1095. user.FsConfig.S3Config.Region = "us-east-1"
  1096. user.FsConfig.S3Config.AccessKey = "Server-Access-Key1"
  1097. user.FsConfig.S3Config.AccessSecret = kms.NewPlainSecret("secret")
  1098. user.FsConfig.S3Config.Endpoint = "http://localhost:9000"
  1099. user.FsConfig.S3Config.KeyPrefix = "somedir/subdir"
  1100. user, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  1101. assert.NoError(t, err)
  1102. user.FsConfig.S3Config = vfs.S3FsConfig{}
  1103. user.FsConfig.Provider = dataprovider.GCSFilesystemProvider
  1104. user.FsConfig.GCSConfig.Bucket = "test1"
  1105. user.FsConfig.GCSConfig.Credentials = kms.NewPlainSecret("fake credentials")
  1106. user, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  1107. assert.NoError(t, err)
  1108. _, err = httpd.RemoveUser(user, http.StatusOK)
  1109. assert.NoError(t, err)
  1110. }
  1111. func TestUserAzureBlobConfig(t *testing.T) {
  1112. user, _, err := httpd.AddUser(getTestUser(), http.StatusOK)
  1113. assert.NoError(t, err)
  1114. user.FsConfig.Provider = dataprovider.AzureBlobFilesystemProvider
  1115. user.FsConfig.AzBlobConfig.Container = "test"
  1116. user.FsConfig.AzBlobConfig.AccountName = "Server-Account-Name"
  1117. user.FsConfig.AzBlobConfig.AccountKey = kms.NewPlainSecret("Server-Account-Key")
  1118. user.FsConfig.AzBlobConfig.Endpoint = "http://127.0.0.1:9000"
  1119. user.FsConfig.AzBlobConfig.UploadPartSize = 8
  1120. user, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  1121. assert.NoError(t, err)
  1122. initialPayload := user.FsConfig.AzBlobConfig.AccountKey.GetPayload()
  1123. assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.AzBlobConfig.AccountKey.GetStatus())
  1124. assert.NotEmpty(t, initialPayload)
  1125. assert.Empty(t, user.FsConfig.AzBlobConfig.AccountKey.GetAdditionalData())
  1126. assert.Empty(t, user.FsConfig.AzBlobConfig.AccountKey.GetKey())
  1127. user.FsConfig.AzBlobConfig.AccountKey.SetStatus(kms.SecretStatusSecretBox)
  1128. user.FsConfig.AzBlobConfig.AccountKey.SetAdditionalData("data")
  1129. user.FsConfig.AzBlobConfig.AccountKey.SetKey("fake key")
  1130. user, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  1131. assert.NoError(t, err)
  1132. assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.AzBlobConfig.AccountKey.GetStatus())
  1133. assert.Equal(t, initialPayload, user.FsConfig.AzBlobConfig.AccountKey.GetPayload())
  1134. assert.Empty(t, user.FsConfig.AzBlobConfig.AccountKey.GetAdditionalData())
  1135. assert.Empty(t, user.FsConfig.AzBlobConfig.AccountKey.GetKey())
  1136. _, err = httpd.RemoveUser(user, http.StatusOK)
  1137. assert.NoError(t, err)
  1138. user.Password = defaultPassword
  1139. user.ID = 0
  1140. secret := kms.NewSecret(kms.SecretStatusSecretBox, "Server-Account-Key", "", "")
  1141. user.FsConfig.AzBlobConfig.AccountKey = secret
  1142. _, _, err = httpd.AddUser(user, http.StatusOK)
  1143. assert.Error(t, err)
  1144. user.FsConfig.AzBlobConfig.AccountKey = kms.NewPlainSecret("Server-Account-Key-Test")
  1145. user, _, err = httpd.AddUser(user, http.StatusOK)
  1146. assert.NoError(t, err)
  1147. initialPayload = user.FsConfig.AzBlobConfig.AccountKey.GetPayload()
  1148. assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.AzBlobConfig.AccountKey.GetStatus())
  1149. assert.NotEmpty(t, initialPayload)
  1150. assert.Empty(t, user.FsConfig.AzBlobConfig.AccountKey.GetAdditionalData())
  1151. assert.Empty(t, user.FsConfig.AzBlobConfig.AccountKey.GetKey())
  1152. user.FsConfig.Provider = dataprovider.AzureBlobFilesystemProvider
  1153. user.FsConfig.AzBlobConfig.Container = "test-container"
  1154. user.FsConfig.AzBlobConfig.Endpoint = "http://localhost:9001"
  1155. user.FsConfig.AzBlobConfig.KeyPrefix = "somedir/subdir"
  1156. user.FsConfig.AzBlobConfig.UploadConcurrency = 5
  1157. user, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  1158. assert.NoError(t, err)
  1159. assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.AzBlobConfig.AccountKey.GetStatus())
  1160. assert.NotEmpty(t, initialPayload)
  1161. assert.Empty(t, user.FsConfig.AzBlobConfig.AccountKey.GetAdditionalData())
  1162. assert.Empty(t, user.FsConfig.AzBlobConfig.AccountKey.GetKey())
  1163. // test user without access key and access secret (sas)
  1164. user.FsConfig.Provider = dataprovider.AzureBlobFilesystemProvider
  1165. user.FsConfig.AzBlobConfig.SASURL = "https://myaccount.blob.core.windows.net/pictures/profile.jpg?sv=2012-02-12&st=2009-02-09&se=2009-02-10&sr=c&sp=r&si=YWJjZGVmZw%3d%3d&sig=dD80ihBh5jfNpymO5Hg1IdiJIEvHcJpCMiCMnN%2fRnbI%3d"
  1166. user.FsConfig.AzBlobConfig.KeyPrefix = "somedir/subdir"
  1167. user.FsConfig.AzBlobConfig.AccountName = ""
  1168. user.FsConfig.AzBlobConfig.AccountKey = kms.NewEmptySecret()
  1169. user.FsConfig.AzBlobConfig.UploadPartSize = 6
  1170. user.FsConfig.AzBlobConfig.UploadConcurrency = 4
  1171. user, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  1172. assert.NoError(t, err)
  1173. assert.True(t, user.FsConfig.AzBlobConfig.AccountKey.IsEmpty())
  1174. _, err = httpd.RemoveUser(user, http.StatusOK)
  1175. assert.NoError(t, err)
  1176. user.Password = defaultPassword
  1177. user.ID = 0
  1178. // sas test for add instead of update
  1179. user, _, err = httpd.AddUser(user, http.StatusOK)
  1180. assert.NoError(t, err)
  1181. assert.True(t, user.FsConfig.AzBlobConfig.AccountKey.IsEmpty())
  1182. _, err = httpd.RemoveUser(user, http.StatusOK)
  1183. assert.NoError(t, err)
  1184. }
  1185. func TestUserHiddenFields(t *testing.T) {
  1186. err := dataprovider.Close()
  1187. assert.NoError(t, err)
  1188. err = config.LoadConfig(configDir, "")
  1189. assert.NoError(t, err)
  1190. providerConf := config.GetProviderConf()
  1191. providerConf.PreferDatabaseCredentials = true
  1192. err = dataprovider.Initialize(providerConf, configDir)
  1193. assert.NoError(t, err)
  1194. // sensitive data must be hidden but not deleted from the dataprovider
  1195. usernames := []string{"user1", "user2", "user3"}
  1196. u1 := getTestUser()
  1197. u1.Username = usernames[0]
  1198. u1.FsConfig.Provider = dataprovider.S3FilesystemProvider
  1199. u1.FsConfig.S3Config.Bucket = "test"
  1200. u1.FsConfig.S3Config.Region = "us-east-1"
  1201. u1.FsConfig.S3Config.AccessKey = "S3-Access-Key"
  1202. u1.FsConfig.S3Config.AccessSecret = kms.NewPlainSecret("S3-Access-Secret")
  1203. user1, _, err := httpd.AddUser(u1, http.StatusOK)
  1204. assert.NoError(t, err)
  1205. u2 := getTestUser()
  1206. u2.Username = usernames[1]
  1207. u2.FsConfig.Provider = dataprovider.GCSFilesystemProvider
  1208. u2.FsConfig.GCSConfig.Bucket = "test"
  1209. u2.FsConfig.GCSConfig.Credentials = kms.NewPlainSecret("fake credentials")
  1210. user2, _, err := httpd.AddUser(u2, http.StatusOK)
  1211. assert.NoError(t, err)
  1212. u3 := getTestUser()
  1213. u3.Username = usernames[2]
  1214. u3.FsConfig.Provider = dataprovider.AzureBlobFilesystemProvider
  1215. u3.FsConfig.AzBlobConfig.Container = "test"
  1216. u3.FsConfig.AzBlobConfig.AccountName = "Server-Account-Name"
  1217. u3.FsConfig.AzBlobConfig.AccountKey = kms.NewPlainSecret("Server-Account-Key")
  1218. user3, _, err := httpd.AddUser(u3, http.StatusOK)
  1219. assert.NoError(t, err)
  1220. users, _, err := httpd.GetUsers(0, 0, "", http.StatusOK)
  1221. assert.NoError(t, err)
  1222. assert.GreaterOrEqual(t, len(users), 3)
  1223. for _, username := range usernames {
  1224. users, _, err = httpd.GetUsers(0, 0, username, http.StatusOK)
  1225. assert.NoError(t, err)
  1226. if assert.Len(t, users, 1) {
  1227. user := users[0]
  1228. assert.Empty(t, user.Password)
  1229. }
  1230. }
  1231. user1, _, err = httpd.GetUserByID(user1.ID, http.StatusOK)
  1232. assert.NoError(t, err)
  1233. assert.Empty(t, user1.Password)
  1234. assert.Empty(t, user1.FsConfig.S3Config.AccessSecret.GetKey())
  1235. assert.Empty(t, user1.FsConfig.S3Config.AccessSecret.GetAdditionalData())
  1236. assert.NotEmpty(t, user1.FsConfig.S3Config.AccessSecret.GetStatus())
  1237. assert.NotEmpty(t, user1.FsConfig.S3Config.AccessSecret.GetPayload())
  1238. user2, _, err = httpd.GetUserByID(user2.ID, http.StatusOK)
  1239. assert.NoError(t, err)
  1240. assert.Empty(t, user2.Password)
  1241. assert.Empty(t, user2.FsConfig.GCSConfig.Credentials.GetKey())
  1242. assert.Empty(t, user2.FsConfig.GCSConfig.Credentials.GetAdditionalData())
  1243. assert.NotEmpty(t, user2.FsConfig.GCSConfig.Credentials.GetStatus())
  1244. assert.NotEmpty(t, user2.FsConfig.GCSConfig.Credentials.GetPayload())
  1245. user3, _, err = httpd.GetUserByID(user3.ID, http.StatusOK)
  1246. assert.NoError(t, err)
  1247. assert.Empty(t, user3.Password)
  1248. assert.Empty(t, user3.FsConfig.AzBlobConfig.AccountKey.GetKey())
  1249. assert.Empty(t, user3.FsConfig.AzBlobConfig.AccountKey.GetAdditionalData())
  1250. assert.NotEmpty(t, user3.FsConfig.AzBlobConfig.AccountKey.GetStatus())
  1251. assert.NotEmpty(t, user3.FsConfig.AzBlobConfig.AccountKey.GetPayload())
  1252. // finally check that we have all the data inside the data provider
  1253. user1, err = dataprovider.GetUserByID(user1.ID)
  1254. assert.NoError(t, err)
  1255. assert.NotEmpty(t, user1.Password)
  1256. assert.NotEmpty(t, user1.FsConfig.S3Config.AccessSecret.GetKey())
  1257. assert.NotEmpty(t, user1.FsConfig.S3Config.AccessSecret.GetAdditionalData())
  1258. assert.NotEmpty(t, user1.FsConfig.S3Config.AccessSecret.GetStatus())
  1259. assert.NotEmpty(t, user1.FsConfig.S3Config.AccessSecret.GetPayload())
  1260. err = user1.FsConfig.S3Config.AccessSecret.Decrypt()
  1261. assert.NoError(t, err)
  1262. assert.Equal(t, kms.SecretStatusPlain, user1.FsConfig.S3Config.AccessSecret.GetStatus())
  1263. assert.Equal(t, u1.FsConfig.S3Config.AccessSecret.GetPayload(), user1.FsConfig.S3Config.AccessSecret.GetPayload())
  1264. assert.Empty(t, user1.FsConfig.S3Config.AccessSecret.GetKey())
  1265. assert.Empty(t, user1.FsConfig.S3Config.AccessSecret.GetAdditionalData())
  1266. user2, err = dataprovider.GetUserByID(user2.ID)
  1267. assert.NoError(t, err)
  1268. assert.NotEmpty(t, user2.Password)
  1269. assert.NotEmpty(t, user2.FsConfig.GCSConfig.Credentials.GetKey())
  1270. assert.NotEmpty(t, user2.FsConfig.GCSConfig.Credentials.GetAdditionalData())
  1271. assert.NotEmpty(t, user2.FsConfig.GCSConfig.Credentials.GetStatus())
  1272. assert.NotEmpty(t, user2.FsConfig.GCSConfig.Credentials.GetPayload())
  1273. err = user2.FsConfig.GCSConfig.Credentials.Decrypt()
  1274. assert.NoError(t, err)
  1275. assert.Equal(t, kms.SecretStatusPlain, user2.FsConfig.GCSConfig.Credentials.GetStatus())
  1276. assert.Equal(t, u2.FsConfig.GCSConfig.Credentials.GetPayload(), user2.FsConfig.GCSConfig.Credentials.GetPayload())
  1277. assert.Empty(t, user2.FsConfig.GCSConfig.Credentials.GetKey())
  1278. assert.Empty(t, user2.FsConfig.GCSConfig.Credentials.GetAdditionalData())
  1279. user3, err = dataprovider.GetUserByID(user3.ID)
  1280. assert.NoError(t, err)
  1281. assert.NotEmpty(t, user3.Password)
  1282. assert.NotEmpty(t, user3.FsConfig.AzBlobConfig.AccountKey.GetKey())
  1283. assert.NotEmpty(t, user3.FsConfig.AzBlobConfig.AccountKey.GetAdditionalData())
  1284. assert.NotEmpty(t, user3.FsConfig.AzBlobConfig.AccountKey.GetStatus())
  1285. assert.NotEmpty(t, user3.FsConfig.AzBlobConfig.AccountKey.GetPayload())
  1286. err = user3.FsConfig.AzBlobConfig.AccountKey.Decrypt()
  1287. assert.NoError(t, err)
  1288. assert.Equal(t, kms.SecretStatusPlain, user3.FsConfig.AzBlobConfig.AccountKey.GetStatus())
  1289. assert.Equal(t, u3.FsConfig.AzBlobConfig.AccountKey.GetPayload(), user3.FsConfig.AzBlobConfig.AccountKey.GetPayload())
  1290. assert.Empty(t, user3.FsConfig.AzBlobConfig.AccountKey.GetKey())
  1291. assert.Empty(t, user3.FsConfig.AzBlobConfig.AccountKey.GetAdditionalData())
  1292. _, err = httpd.RemoveUser(user1, http.StatusOK)
  1293. assert.NoError(t, err)
  1294. _, err = httpd.RemoveUser(user2, http.StatusOK)
  1295. assert.NoError(t, err)
  1296. _, err = httpd.RemoveUser(user3, http.StatusOK)
  1297. assert.NoError(t, err)
  1298. err = dataprovider.Close()
  1299. assert.NoError(t, err)
  1300. err = config.LoadConfig(configDir, "")
  1301. assert.NoError(t, err)
  1302. providerConf = config.GetProviderConf()
  1303. providerConf.CredentialsPath = credentialsPath
  1304. err = os.RemoveAll(credentialsPath)
  1305. assert.NoError(t, err)
  1306. err = dataprovider.Initialize(providerConf, configDir)
  1307. assert.NoError(t, err)
  1308. }
  1309. func TestSecretObject(t *testing.T) {
  1310. s := kms.NewPlainSecret("test data")
  1311. s.SetAdditionalData("username")
  1312. require.True(t, s.IsValid())
  1313. err := s.Encrypt()
  1314. require.NoError(t, err)
  1315. require.Equal(t, kms.SecretStatusSecretBox, s.GetStatus())
  1316. require.NotEmpty(t, s.GetPayload())
  1317. require.NotEmpty(t, s.GetKey())
  1318. require.True(t, s.IsValid())
  1319. err = s.Decrypt()
  1320. require.NoError(t, err)
  1321. require.Equal(t, kms.SecretStatusPlain, s.GetStatus())
  1322. require.Equal(t, "test data", s.GetPayload())
  1323. require.Empty(t, s.GetKey())
  1324. oldFormat := "$aes$5b97e3a3324a2f53e2357483383367c0$0ed3132b584742ab217866219da633266782b69b13e50ebc6ddfb7c4fbf2f2a414c6d5f813"
  1325. s, err = kms.GetSecretFromCompatString(oldFormat)
  1326. require.NoError(t, err)
  1327. require.True(t, s.IsValid())
  1328. require.Equal(t, kms.SecretStatusPlain, s.GetStatus())
  1329. require.Equal(t, "test data", s.GetPayload())
  1330. require.Empty(t, s.GetKey())
  1331. }
  1332. func TestSecretObjectCompatibility(t *testing.T) {
  1333. // this is manually tested against vault too
  1334. testPayload := "test payload"
  1335. s := kms.NewPlainSecret(testPayload)
  1336. require.True(t, s.IsValid())
  1337. err := s.Encrypt()
  1338. require.NoError(t, err)
  1339. localAsJSON, err := json.Marshal(s)
  1340. assert.NoError(t, err)
  1341. for _, provider := range []string{kms.SecretStatusRedacted} {
  1342. kmsConfig := config.GetKMSConfig()
  1343. assert.Empty(t, kmsConfig.Secrets.MasterKeyPath)
  1344. if provider == kms.SecretStatusVaultTransit {
  1345. os.Setenv("VAULT_SERVER_URL", "http://127.0.0.1:8200")
  1346. os.Setenv("VAULT_SERVER_TOKEN", "s.9lYGq83MbgG5KR5kfebXVyhJ")
  1347. kmsConfig.Secrets.URL = "hashivault://mykey"
  1348. }
  1349. err := kmsConfig.Initialize()
  1350. assert.NoError(t, err)
  1351. // encrypt without a master key
  1352. secret := kms.NewPlainSecret(testPayload)
  1353. secret.SetAdditionalData("add data")
  1354. err = secret.Encrypt()
  1355. assert.NoError(t, err)
  1356. assert.Equal(t, 0, secret.GetMode())
  1357. secretClone := secret.Clone()
  1358. err = secretClone.Decrypt()
  1359. assert.NoError(t, err)
  1360. assert.Equal(t, testPayload, secretClone.GetPayload())
  1361. if provider == kms.SecretStatusVaultTransit {
  1362. // decrypt the local secret now that the provider is vault
  1363. secretLocal := kms.NewEmptySecret()
  1364. err = json.Unmarshal(localAsJSON, secretLocal)
  1365. assert.NoError(t, err)
  1366. assert.Equal(t, kms.SecretStatusSecretBox, secretLocal.GetStatus())
  1367. assert.Equal(t, 0, secretLocal.GetMode())
  1368. err = secretLocal.Decrypt()
  1369. assert.NoError(t, err)
  1370. assert.Equal(t, testPayload, secretLocal.GetPayload())
  1371. assert.Equal(t, kms.SecretStatusPlain, secretLocal.GetStatus())
  1372. err = secretLocal.Encrypt()
  1373. assert.NoError(t, err)
  1374. assert.Equal(t, kms.SecretStatusSecretBox, secretLocal.GetStatus())
  1375. assert.Equal(t, 0, secretLocal.GetMode())
  1376. }
  1377. asJSON, err := json.Marshal(secret)
  1378. assert.NoError(t, err)
  1379. masterKeyPath := filepath.Join(os.TempDir(), "mkey")
  1380. err = ioutil.WriteFile(masterKeyPath, []byte("test key"), os.ModePerm)
  1381. assert.NoError(t, err)
  1382. config := kms.Configuration{
  1383. Secrets: kms.Secrets{
  1384. MasterKeyPath: masterKeyPath,
  1385. },
  1386. }
  1387. if provider == kms.SecretStatusVaultTransit {
  1388. config.Secrets.URL = "hashivault://mykey"
  1389. }
  1390. err = config.Initialize()
  1391. assert.NoError(t, err)
  1392. // now build the secret from JSON
  1393. secret = kms.NewEmptySecret()
  1394. err = json.Unmarshal(asJSON, secret)
  1395. assert.NoError(t, err)
  1396. assert.Equal(t, 0, secret.GetMode())
  1397. err = secret.Decrypt()
  1398. assert.NoError(t, err)
  1399. assert.Equal(t, testPayload, secret.GetPayload())
  1400. err = secret.Encrypt()
  1401. assert.NoError(t, err)
  1402. assert.Equal(t, 1, secret.GetMode())
  1403. err = secret.Decrypt()
  1404. assert.NoError(t, err)
  1405. assert.Equal(t, testPayload, secret.GetPayload())
  1406. if provider == kms.SecretStatusVaultTransit {
  1407. // decrypt the local secret encryped without a master key now that
  1408. // the provider is vault and a master key is set.
  1409. // The provider will not change, the master key will be used
  1410. secretLocal := kms.NewEmptySecret()
  1411. err = json.Unmarshal(localAsJSON, secretLocal)
  1412. assert.NoError(t, err)
  1413. assert.Equal(t, kms.SecretStatusSecretBox, secretLocal.GetStatus())
  1414. assert.Equal(t, 0, secretLocal.GetMode())
  1415. err = secretLocal.Decrypt()
  1416. assert.NoError(t, err)
  1417. assert.Equal(t, testPayload, secretLocal.GetPayload())
  1418. assert.Equal(t, kms.SecretStatusPlain, secretLocal.GetStatus())
  1419. err = secretLocal.Encrypt()
  1420. assert.NoError(t, err)
  1421. assert.Equal(t, kms.SecretStatusSecretBox, secretLocal.GetStatus())
  1422. assert.Equal(t, 1, secretLocal.GetMode())
  1423. }
  1424. err = kmsConfig.Initialize()
  1425. assert.NoError(t, err)
  1426. err = os.Remove(masterKeyPath)
  1427. assert.NoError(t, err)
  1428. if provider == kms.SecretStatusVaultTransit {
  1429. os.Unsetenv("VAULT_SERVER_URL")
  1430. os.Unsetenv("VAULT_SERVER_TOKEN")
  1431. }
  1432. }
  1433. }
  1434. func TestUpdateUserNoCredentials(t *testing.T) {
  1435. user, _, err := httpd.AddUser(getTestUser(), http.StatusOK)
  1436. assert.NoError(t, err)
  1437. user.Password = ""
  1438. user.PublicKeys = []string{}
  1439. // password and public key will be omitted from json serialization if empty and so they will remain unchanged
  1440. // and no validation error will be raised
  1441. _, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  1442. assert.NoError(t, err)
  1443. _, err = httpd.RemoveUser(user, http.StatusOK)
  1444. assert.NoError(t, err)
  1445. }
  1446. func TestUpdateUserEmptyHomeDir(t *testing.T) {
  1447. user, _, err := httpd.AddUser(getTestUser(), http.StatusOK)
  1448. assert.NoError(t, err)
  1449. user.HomeDir = ""
  1450. _, _, err = httpd.UpdateUser(user, http.StatusBadRequest, "")
  1451. assert.NoError(t, err)
  1452. _, err = httpd.RemoveUser(user, http.StatusOK)
  1453. assert.NoError(t, err)
  1454. }
  1455. func TestUpdateUserInvalidHomeDir(t *testing.T) {
  1456. user, _, err := httpd.AddUser(getTestUser(), http.StatusOK)
  1457. assert.NoError(t, err)
  1458. user.HomeDir = "relative_path"
  1459. _, _, err = httpd.UpdateUser(user, http.StatusBadRequest, "")
  1460. assert.NoError(t, err)
  1461. _, err = httpd.RemoveUser(user, http.StatusOK)
  1462. assert.NoError(t, err)
  1463. }
  1464. func TestUpdateNonExistentUser(t *testing.T) {
  1465. _, _, err := httpd.UpdateUser(getTestUser(), http.StatusNotFound, "")
  1466. assert.NoError(t, err)
  1467. }
  1468. func TestGetNonExistentUser(t *testing.T) {
  1469. _, _, err := httpd.GetUserByID(0, http.StatusNotFound)
  1470. assert.NoError(t, err)
  1471. }
  1472. func TestDeleteNonExistentUser(t *testing.T) {
  1473. _, err := httpd.RemoveUser(getTestUser(), http.StatusNotFound)
  1474. assert.NoError(t, err)
  1475. }
  1476. func TestAddDuplicateUser(t *testing.T) {
  1477. user, _, err := httpd.AddUser(getTestUser(), http.StatusOK)
  1478. assert.NoError(t, err)
  1479. _, _, err = httpd.AddUser(getTestUser(), http.StatusInternalServerError)
  1480. assert.NoError(t, err)
  1481. _, _, err = httpd.AddUser(getTestUser(), http.StatusOK)
  1482. assert.Error(t, err, "adding a duplicate user must fail")
  1483. _, err = httpd.RemoveUser(user, http.StatusOK)
  1484. assert.NoError(t, err)
  1485. }
  1486. func TestGetUsers(t *testing.T) {
  1487. user1, _, err := httpd.AddUser(getTestUser(), http.StatusOK)
  1488. assert.NoError(t, err)
  1489. u := getTestUser()
  1490. u.Username = defaultUsername + "1"
  1491. user2, _, err := httpd.AddUser(u, http.StatusOK)
  1492. assert.NoError(t, err)
  1493. users, _, err := httpd.GetUsers(0, 0, "", http.StatusOK)
  1494. assert.NoError(t, err)
  1495. assert.GreaterOrEqual(t, len(users), 2)
  1496. users, _, err = httpd.GetUsers(1, 0, "", http.StatusOK)
  1497. assert.NoError(t, err)
  1498. assert.Equal(t, 1, len(users))
  1499. users, _, err = httpd.GetUsers(1, 1, "", http.StatusOK)
  1500. assert.NoError(t, err)
  1501. assert.Equal(t, 1, len(users))
  1502. _, _, err = httpd.GetUsers(1, 1, "", http.StatusInternalServerError)
  1503. assert.Error(t, err)
  1504. _, err = httpd.RemoveUser(user1, http.StatusOK)
  1505. assert.NoError(t, err)
  1506. _, err = httpd.RemoveUser(user2, http.StatusOK)
  1507. assert.NoError(t, err)
  1508. }
  1509. func TestGetQuotaScans(t *testing.T) {
  1510. _, _, err := httpd.GetQuotaScans(http.StatusOK)
  1511. assert.NoError(t, err)
  1512. _, _, err = httpd.GetQuotaScans(http.StatusInternalServerError)
  1513. assert.Error(t, err)
  1514. _, _, err = httpd.GetFoldersQuotaScans(http.StatusOK)
  1515. assert.NoError(t, err)
  1516. _, _, err = httpd.GetFoldersQuotaScans(http.StatusInternalServerError)
  1517. assert.Error(t, err)
  1518. }
  1519. func TestStartQuotaScan(t *testing.T) {
  1520. user, _, err := httpd.AddUser(getTestUser(), http.StatusOK)
  1521. assert.NoError(t, err)
  1522. _, err = httpd.StartQuotaScan(user, http.StatusAccepted)
  1523. assert.NoError(t, err)
  1524. _, err = httpd.RemoveUser(user, http.StatusOK)
  1525. assert.NoError(t, err)
  1526. folder := vfs.BaseVirtualFolder{
  1527. MappedPath: filepath.Join(os.TempDir(), "folder"),
  1528. }
  1529. _, _, err = httpd.AddFolder(folder, http.StatusOK)
  1530. assert.NoError(t, err)
  1531. _, err = httpd.StartFolderQuotaScan(folder, http.StatusAccepted)
  1532. assert.NoError(t, err)
  1533. for {
  1534. quotaScan, _, err := httpd.GetFoldersQuotaScans(http.StatusOK)
  1535. if !assert.NoError(t, err, "Error getting active scans") {
  1536. break
  1537. }
  1538. if len(quotaScan) == 0 {
  1539. break
  1540. }
  1541. time.Sleep(100 * time.Millisecond)
  1542. }
  1543. _, err = httpd.RemoveFolder(folder, http.StatusOK)
  1544. assert.NoError(t, err)
  1545. }
  1546. func TestUpdateFolderQuotaUsage(t *testing.T) {
  1547. f := vfs.BaseVirtualFolder{
  1548. MappedPath: filepath.Join(os.TempDir(), "folder"),
  1549. }
  1550. usedQuotaFiles := 1
  1551. usedQuotaSize := int64(65535)
  1552. f.UsedQuotaFiles = usedQuotaFiles
  1553. f.UsedQuotaSize = usedQuotaSize
  1554. folder, _, err := httpd.AddFolder(f, http.StatusOK)
  1555. if assert.NoError(t, err) {
  1556. assert.Equal(t, usedQuotaFiles, folder.UsedQuotaFiles)
  1557. assert.Equal(t, usedQuotaSize, folder.UsedQuotaSize)
  1558. }
  1559. _, err = httpd.UpdateFolderQuotaUsage(folder, "invalid mode", http.StatusBadRequest)
  1560. assert.NoError(t, err)
  1561. _, err = httpd.UpdateFolderQuotaUsage(f, "reset", http.StatusOK)
  1562. assert.NoError(t, err)
  1563. folders, _, err := httpd.GetFolders(0, 0, f.MappedPath, http.StatusOK)
  1564. assert.NoError(t, err)
  1565. if assert.Len(t, folders, 1) {
  1566. folder = folders[0]
  1567. assert.Equal(t, usedQuotaFiles, folder.UsedQuotaFiles)
  1568. assert.Equal(t, usedQuotaSize, folder.UsedQuotaSize)
  1569. }
  1570. _, err = httpd.UpdateFolderQuotaUsage(f, "add", http.StatusOK)
  1571. assert.NoError(t, err)
  1572. folders, _, err = httpd.GetFolders(0, 0, f.MappedPath, http.StatusOK)
  1573. assert.NoError(t, err)
  1574. if assert.Len(t, folders, 1) {
  1575. folder = folders[0]
  1576. assert.Equal(t, 2*usedQuotaFiles, folder.UsedQuotaFiles)
  1577. assert.Equal(t, 2*usedQuotaSize, folder.UsedQuotaSize)
  1578. }
  1579. f.UsedQuotaSize = -1
  1580. _, err = httpd.UpdateFolderQuotaUsage(f, "", http.StatusBadRequest)
  1581. assert.NoError(t, err)
  1582. f.UsedQuotaSize = usedQuotaSize
  1583. f.MappedPath = f.MappedPath + "1"
  1584. _, err = httpd.UpdateFolderQuotaUsage(f, "", http.StatusNotFound)
  1585. assert.NoError(t, err)
  1586. _, err = httpd.RemoveFolder(folder, http.StatusOK)
  1587. assert.NoError(t, err)
  1588. }
  1589. func TestGetVersion(t *testing.T) {
  1590. _, _, err := httpd.GetVersion(http.StatusOK)
  1591. assert.NoError(t, err)
  1592. _, _, err = httpd.GetVersion(http.StatusInternalServerError)
  1593. assert.Error(t, err, "get version request must succeed, we requested to check a wrong status code")
  1594. }
  1595. func TestGetProviderStatus(t *testing.T) {
  1596. _, _, err := httpd.GetProviderStatus(http.StatusOK)
  1597. assert.NoError(t, err)
  1598. _, _, err = httpd.GetProviderStatus(http.StatusBadRequest)
  1599. assert.Error(t, err, "get provider status request must succeed, we requested to check a wrong status code")
  1600. }
  1601. func TestGetConnections(t *testing.T) {
  1602. _, _, err := httpd.GetConnections(http.StatusOK)
  1603. assert.NoError(t, err)
  1604. _, _, err = httpd.GetConnections(http.StatusInternalServerError)
  1605. assert.Error(t, err, "get sftp connections request must succeed, we requested to check a wrong status code")
  1606. }
  1607. func TestCloseActiveConnection(t *testing.T) {
  1608. _, err := httpd.CloseConnection("non_existent_id", http.StatusNotFound)
  1609. assert.NoError(t, err)
  1610. user := getTestUser()
  1611. c := common.NewBaseConnection("connID", common.ProtocolSFTP, user, nil)
  1612. fakeConn := &fakeConnection{
  1613. BaseConnection: c,
  1614. }
  1615. common.Connections.Add(fakeConn)
  1616. _, err = httpd.CloseConnection(c.GetID(), http.StatusOK)
  1617. assert.NoError(t, err)
  1618. assert.Len(t, common.Connections.GetStats(), 0)
  1619. }
  1620. func TestCloseConnectionAfterUserUpdateDelete(t *testing.T) {
  1621. user, _, err := httpd.AddUser(getTestUser(), http.StatusOK)
  1622. assert.NoError(t, err)
  1623. c := common.NewBaseConnection("connID", common.ProtocolFTP, user, nil)
  1624. fakeConn := &fakeConnection{
  1625. BaseConnection: c,
  1626. }
  1627. common.Connections.Add(fakeConn)
  1628. c1 := common.NewBaseConnection("connID1", common.ProtocolSFTP, user, nil)
  1629. fakeConn1 := &fakeConnection{
  1630. BaseConnection: c1,
  1631. }
  1632. common.Connections.Add(fakeConn1)
  1633. user, _, err = httpd.UpdateUser(user, http.StatusOK, "0")
  1634. assert.NoError(t, err)
  1635. assert.Len(t, common.Connections.GetStats(), 2)
  1636. user, _, err = httpd.UpdateUser(user, http.StatusOK, "1")
  1637. assert.NoError(t, err)
  1638. assert.Len(t, common.Connections.GetStats(), 0)
  1639. common.Connections.Add(fakeConn)
  1640. common.Connections.Add(fakeConn1)
  1641. assert.Len(t, common.Connections.GetStats(), 2)
  1642. _, err = httpd.RemoveUser(user, http.StatusOK)
  1643. assert.NoError(t, err)
  1644. assert.Len(t, common.Connections.GetStats(), 0)
  1645. }
  1646. func TestUserBaseDir(t *testing.T) {
  1647. err := dataprovider.Close()
  1648. assert.NoError(t, err)
  1649. err = config.LoadConfig(configDir, "")
  1650. assert.NoError(t, err)
  1651. providerConf := config.GetProviderConf()
  1652. providerConf.UsersBaseDir = homeBasePath
  1653. err = dataprovider.Initialize(providerConf, configDir)
  1654. assert.NoError(t, err)
  1655. u := getTestUser()
  1656. u.HomeDir = ""
  1657. user, _, err := httpd.AddUser(u, http.StatusOK)
  1658. if assert.Error(t, err) {
  1659. assert.EqualError(t, err, "HomeDir mismatch")
  1660. }
  1661. assert.Equal(t, filepath.Join(providerConf.UsersBaseDir, u.Username), user.HomeDir)
  1662. _, err = httpd.RemoveUser(user, http.StatusOK)
  1663. assert.NoError(t, err)
  1664. err = dataprovider.Close()
  1665. assert.NoError(t, err)
  1666. err = config.LoadConfig(configDir, "")
  1667. assert.NoError(t, err)
  1668. providerConf = config.GetProviderConf()
  1669. providerConf.CredentialsPath = credentialsPath
  1670. err = os.RemoveAll(credentialsPath)
  1671. assert.NoError(t, err)
  1672. err = dataprovider.Initialize(providerConf, configDir)
  1673. assert.NoError(t, err)
  1674. }
  1675. func TestQuotaTrackingDisabled(t *testing.T) {
  1676. err := dataprovider.Close()
  1677. assert.NoError(t, err)
  1678. err = config.LoadConfig(configDir, "")
  1679. assert.NoError(t, err)
  1680. providerConf := config.GetProviderConf()
  1681. providerConf.TrackQuota = 0
  1682. err = dataprovider.Initialize(providerConf, configDir)
  1683. assert.NoError(t, err)
  1684. // user quota scan must fail
  1685. user, _, err := httpd.AddUser(getTestUser(), http.StatusOK)
  1686. assert.NoError(t, err)
  1687. _, err = httpd.StartQuotaScan(user, http.StatusForbidden)
  1688. assert.NoError(t, err)
  1689. _, err = httpd.UpdateQuotaUsage(user, "", http.StatusForbidden)
  1690. assert.NoError(t, err)
  1691. _, err = httpd.RemoveUser(user, http.StatusOK)
  1692. assert.NoError(t, err)
  1693. // folder quota scan must fail
  1694. folder := vfs.BaseVirtualFolder{
  1695. MappedPath: filepath.Clean(os.TempDir()),
  1696. }
  1697. folder, _, err = httpd.AddFolder(folder, http.StatusOK)
  1698. assert.NoError(t, err)
  1699. _, err = httpd.StartFolderQuotaScan(folder, http.StatusForbidden)
  1700. assert.NoError(t, err)
  1701. _, err = httpd.UpdateFolderQuotaUsage(folder, "", http.StatusForbidden)
  1702. assert.NoError(t, err)
  1703. _, err = httpd.RemoveFolder(folder, http.StatusOK)
  1704. assert.NoError(t, err)
  1705. err = dataprovider.Close()
  1706. assert.NoError(t, err)
  1707. err = config.LoadConfig(configDir, "")
  1708. assert.NoError(t, err)
  1709. providerConf = config.GetProviderConf()
  1710. providerConf.CredentialsPath = credentialsPath
  1711. err = os.RemoveAll(credentialsPath)
  1712. assert.NoError(t, err)
  1713. err = dataprovider.Initialize(providerConf, configDir)
  1714. assert.NoError(t, err)
  1715. }
  1716. func TestProviderErrors(t *testing.T) {
  1717. err := dataprovider.Close()
  1718. assert.NoError(t, err)
  1719. _, _, err = httpd.GetUserByID(0, http.StatusInternalServerError)
  1720. assert.NoError(t, err)
  1721. _, _, err = httpd.GetUsers(1, 0, defaultUsername, http.StatusInternalServerError)
  1722. assert.NoError(t, err)
  1723. _, _, err = httpd.UpdateUser(dataprovider.User{}, http.StatusInternalServerError, "")
  1724. assert.NoError(t, err)
  1725. _, err = httpd.RemoveUser(dataprovider.User{}, http.StatusInternalServerError)
  1726. assert.NoError(t, err)
  1727. _, err = httpd.RemoveFolder(vfs.BaseVirtualFolder{MappedPath: "apath"}, http.StatusInternalServerError)
  1728. assert.NoError(t, err)
  1729. _, _, err = httpd.GetProviderStatus(http.StatusInternalServerError)
  1730. assert.NoError(t, err)
  1731. _, _, err = httpd.Dumpdata("backup.json", "", http.StatusInternalServerError)
  1732. assert.NoError(t, err)
  1733. _, _, err = httpd.GetFolders(0, 0, "", http.StatusInternalServerError)
  1734. assert.NoError(t, err)
  1735. user := getTestUser()
  1736. user.ID = 1
  1737. backupData := dataprovider.BackupData{}
  1738. backupData.Users = append(backupData.Users, user)
  1739. backupContent, err := json.Marshal(backupData)
  1740. assert.NoError(t, err)
  1741. backupFilePath := filepath.Join(backupsPath, "backup.json")
  1742. err = ioutil.WriteFile(backupFilePath, backupContent, os.ModePerm)
  1743. assert.NoError(t, err)
  1744. _, _, err = httpd.Loaddata(backupFilePath, "", "", http.StatusInternalServerError)
  1745. assert.NoError(t, err)
  1746. backupData.Folders = append(backupData.Folders, vfs.BaseVirtualFolder{MappedPath: os.TempDir()})
  1747. backupContent, err = json.Marshal(backupData)
  1748. assert.NoError(t, err)
  1749. err = ioutil.WriteFile(backupFilePath, backupContent, os.ModePerm)
  1750. assert.NoError(t, err)
  1751. _, _, err = httpd.Loaddata(backupFilePath, "", "", http.StatusInternalServerError)
  1752. assert.NoError(t, err)
  1753. err = os.Remove(backupFilePath)
  1754. assert.NoError(t, err)
  1755. err = config.LoadConfig(configDir, "")
  1756. assert.NoError(t, err)
  1757. providerConf := config.GetProviderConf()
  1758. providerConf.CredentialsPath = credentialsPath
  1759. err = os.RemoveAll(credentialsPath)
  1760. assert.NoError(t, err)
  1761. err = dataprovider.Initialize(providerConf, configDir)
  1762. assert.NoError(t, err)
  1763. }
  1764. func TestFolders(t *testing.T) {
  1765. folder := vfs.BaseVirtualFolder{
  1766. MappedPath: "relative path",
  1767. }
  1768. _, _, err := httpd.AddFolder(folder, http.StatusBadRequest)
  1769. assert.NoError(t, err)
  1770. folder.MappedPath = filepath.Clean(os.TempDir())
  1771. folder1, _, err := httpd.AddFolder(folder, http.StatusOK)
  1772. assert.NoError(t, err)
  1773. assert.Equal(t, folder.MappedPath, folder1.MappedPath)
  1774. assert.Equal(t, 0, folder1.UsedQuotaFiles)
  1775. assert.Equal(t, int64(0), folder1.UsedQuotaSize)
  1776. assert.Equal(t, int64(0), folder1.LastQuotaUpdate)
  1777. // adding a duplicate folder must fail
  1778. _, _, err = httpd.AddFolder(folder, http.StatusOK)
  1779. assert.Error(t, err)
  1780. folder.MappedPath = filepath.Join(os.TempDir(), "vfolder")
  1781. folder.UsedQuotaFiles = 1
  1782. folder.UsedQuotaSize = 345
  1783. folder.LastQuotaUpdate = 10
  1784. folder2, _, err := httpd.AddFolder(folder, http.StatusOK)
  1785. assert.NoError(t, err)
  1786. assert.Equal(t, 1, folder2.UsedQuotaFiles)
  1787. assert.Equal(t, int64(345), folder2.UsedQuotaSize)
  1788. assert.Equal(t, int64(10), folder2.LastQuotaUpdate)
  1789. folders, _, err := httpd.GetFolders(0, 0, "", http.StatusOK)
  1790. assert.NoError(t, err)
  1791. numResults := len(folders)
  1792. assert.GreaterOrEqual(t, numResults, 2)
  1793. folders, _, err = httpd.GetFolders(0, 1, "", http.StatusOK)
  1794. assert.NoError(t, err)
  1795. assert.Len(t, folders, numResults-1)
  1796. folders, _, err = httpd.GetFolders(1, 0, "", http.StatusOK)
  1797. assert.NoError(t, err)
  1798. assert.Len(t, folders, 1)
  1799. folders, _, err = httpd.GetFolders(0, 0, folder1.MappedPath, http.StatusOK)
  1800. assert.NoError(t, err)
  1801. if assert.Len(t, folders, 1) {
  1802. f := folders[0]
  1803. assert.Equal(t, folder1.MappedPath, f.MappedPath)
  1804. }
  1805. folders, _, err = httpd.GetFolders(0, 0, folder2.MappedPath, http.StatusOK)
  1806. assert.NoError(t, err)
  1807. if assert.Len(t, folders, 1) {
  1808. f := folders[0]
  1809. assert.Equal(t, folder2.MappedPath, f.MappedPath)
  1810. }
  1811. _, err = httpd.RemoveFolder(vfs.BaseVirtualFolder{}, http.StatusBadRequest)
  1812. assert.NoError(t, err)
  1813. _, err = httpd.RemoveFolder(vfs.BaseVirtualFolder{
  1814. MappedPath: "invalid",
  1815. }, http.StatusNotFound)
  1816. assert.NoError(t, err)
  1817. _, err = httpd.RemoveFolder(folder1, http.StatusOK)
  1818. assert.NoError(t, err)
  1819. _, err = httpd.RemoveFolder(folder2, http.StatusOK)
  1820. assert.NoError(t, err)
  1821. }
  1822. func TestDumpdata(t *testing.T) {
  1823. err := dataprovider.Close()
  1824. assert.NoError(t, err)
  1825. err = config.LoadConfig(configDir, "")
  1826. assert.NoError(t, err)
  1827. providerConf := config.GetProviderConf()
  1828. err = dataprovider.Initialize(providerConf, configDir)
  1829. assert.NoError(t, err)
  1830. _, _, err = httpd.Dumpdata("", "", http.StatusBadRequest)
  1831. assert.NoError(t, err)
  1832. _, _, err = httpd.Dumpdata(filepath.Join(backupsPath, "backup.json"), "", http.StatusBadRequest)
  1833. assert.NoError(t, err)
  1834. _, _, err = httpd.Dumpdata("../backup.json", "", http.StatusBadRequest)
  1835. assert.NoError(t, err)
  1836. _, _, err = httpd.Dumpdata("backup.json", "0", http.StatusOK)
  1837. assert.NoError(t, err)
  1838. _, _, err = httpd.Dumpdata("backup.json", "1", http.StatusOK)
  1839. assert.NoError(t, err)
  1840. err = os.Remove(filepath.Join(backupsPath, "backup.json"))
  1841. assert.NoError(t, err)
  1842. if runtime.GOOS != "windows" {
  1843. err = os.Chmod(backupsPath, 0001)
  1844. assert.NoError(t, err)
  1845. _, _, err = httpd.Dumpdata("bck.json", "", http.StatusInternalServerError)
  1846. assert.NoError(t, err)
  1847. // subdir cannot be created
  1848. _, _, err = httpd.Dumpdata(filepath.Join("subdir", "bck.json"), "", http.StatusInternalServerError)
  1849. assert.NoError(t, err)
  1850. err = os.Chmod(backupsPath, 0755)
  1851. assert.NoError(t, err)
  1852. }
  1853. err = dataprovider.Close()
  1854. assert.NoError(t, err)
  1855. err = config.LoadConfig(configDir, "")
  1856. assert.NoError(t, err)
  1857. providerConf = config.GetProviderConf()
  1858. providerConf.CredentialsPath = credentialsPath
  1859. err = os.RemoveAll(credentialsPath)
  1860. assert.NoError(t, err)
  1861. err = dataprovider.Initialize(providerConf, configDir)
  1862. assert.NoError(t, err)
  1863. }
  1864. func TestLoaddata(t *testing.T) {
  1865. mappedPath := filepath.Join(os.TempDir(), "restored_folder")
  1866. user := getTestUser()
  1867. user.ID = 1
  1868. user.Username = "test_user_restore"
  1869. backupData := dataprovider.BackupData{}
  1870. backupData.Users = append(backupData.Users, user)
  1871. backupData.Folders = []vfs.BaseVirtualFolder{
  1872. {
  1873. MappedPath: mappedPath,
  1874. UsedQuotaSize: 123,
  1875. UsedQuotaFiles: 456,
  1876. LastQuotaUpdate: 789,
  1877. Users: []string{"user"},
  1878. },
  1879. {
  1880. MappedPath: mappedPath,
  1881. },
  1882. }
  1883. backupContent, err := json.Marshal(backupData)
  1884. assert.NoError(t, err)
  1885. backupFilePath := filepath.Join(backupsPath, "backup.json")
  1886. err = ioutil.WriteFile(backupFilePath, backupContent, os.ModePerm)
  1887. assert.NoError(t, err)
  1888. _, _, err = httpd.Loaddata(backupFilePath, "a", "", http.StatusBadRequest)
  1889. assert.NoError(t, err)
  1890. _, _, err = httpd.Loaddata(backupFilePath, "", "a", http.StatusBadRequest)
  1891. assert.NoError(t, err)
  1892. _, _, err = httpd.Loaddata("backup.json", "1", "", http.StatusBadRequest)
  1893. assert.NoError(t, err)
  1894. _, _, err = httpd.Loaddata(backupFilePath+"a", "1", "", http.StatusBadRequest)
  1895. assert.NoError(t, err)
  1896. if runtime.GOOS != "windows" {
  1897. err = os.Chmod(backupFilePath, 0111)
  1898. assert.NoError(t, err)
  1899. _, _, err = httpd.Loaddata(backupFilePath, "1", "", http.StatusInternalServerError)
  1900. assert.NoError(t, err)
  1901. err = os.Chmod(backupFilePath, 0644)
  1902. assert.NoError(t, err)
  1903. }
  1904. // add user and folder from backup
  1905. _, _, err = httpd.Loaddata(backupFilePath, "1", "", http.StatusOK)
  1906. assert.NoError(t, err)
  1907. // update user from backup
  1908. _, _, err = httpd.Loaddata(backupFilePath, "2", "", http.StatusOK)
  1909. assert.NoError(t, err)
  1910. users, _, err := httpd.GetUsers(1, 0, user.Username, http.StatusOK)
  1911. assert.NoError(t, err)
  1912. if assert.Len(t, users, 1) {
  1913. user = users[0]
  1914. _, err = httpd.RemoveUser(user, http.StatusOK)
  1915. assert.NoError(t, err)
  1916. }
  1917. folders, _, err := httpd.GetFolders(1, 0, mappedPath, http.StatusOK)
  1918. assert.NoError(t, err)
  1919. if assert.Len(t, folders, 1) {
  1920. folder := folders[0]
  1921. assert.Equal(t, mappedPath, folder.MappedPath)
  1922. assert.Equal(t, int64(123), folder.UsedQuotaSize)
  1923. assert.Equal(t, 456, folder.UsedQuotaFiles)
  1924. assert.Equal(t, int64(789), folder.LastQuotaUpdate)
  1925. assert.Len(t, folder.Users, 0)
  1926. _, err = httpd.RemoveFolder(folder, http.StatusOK)
  1927. assert.NoError(t, err)
  1928. }
  1929. err = os.Remove(backupFilePath)
  1930. assert.NoError(t, err)
  1931. err = createTestFile(backupFilePath, 10485761)
  1932. assert.NoError(t, err)
  1933. _, _, err = httpd.Loaddata(backupFilePath, "1", "0", http.StatusBadRequest)
  1934. assert.NoError(t, err)
  1935. err = os.Remove(backupFilePath)
  1936. assert.NoError(t, err)
  1937. err = createTestFile(backupFilePath, 65535)
  1938. assert.NoError(t, err)
  1939. _, _, err = httpd.Loaddata(backupFilePath, "1", "0", http.StatusBadRequest)
  1940. assert.NoError(t, err)
  1941. err = os.Remove(backupFilePath)
  1942. assert.NoError(t, err)
  1943. }
  1944. func TestLoaddataMode(t *testing.T) {
  1945. user := getTestUser()
  1946. user.ID = 1
  1947. user.Username = "test_user_restore"
  1948. backupData := dataprovider.BackupData{}
  1949. backupData.Users = append(backupData.Users, user)
  1950. backupContent, _ := json.Marshal(backupData)
  1951. backupFilePath := filepath.Join(backupsPath, "backup.json")
  1952. err := ioutil.WriteFile(backupFilePath, backupContent, os.ModePerm)
  1953. assert.NoError(t, err)
  1954. _, _, err = httpd.Loaddata(backupFilePath, "0", "0", http.StatusOK)
  1955. assert.NoError(t, err)
  1956. users, _, err := httpd.GetUsers(1, 0, user.Username, http.StatusOK)
  1957. assert.NoError(t, err)
  1958. assert.Equal(t, 1, len(users))
  1959. user = users[0]
  1960. oldUploadBandwidth := user.UploadBandwidth
  1961. user.UploadBandwidth = oldUploadBandwidth + 128
  1962. user, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  1963. assert.NoError(t, err)
  1964. _, _, err = httpd.Loaddata(backupFilePath, "0", "1", http.StatusOK)
  1965. assert.NoError(t, err)
  1966. c := common.NewBaseConnection("connID", common.ProtocolFTP, user, nil)
  1967. fakeConn := &fakeConnection{
  1968. BaseConnection: c,
  1969. }
  1970. common.Connections.Add(fakeConn)
  1971. assert.Len(t, common.Connections.GetStats(), 1)
  1972. users, _, err = httpd.GetUsers(1, 0, user.Username, http.StatusOK)
  1973. assert.NoError(t, err)
  1974. assert.Equal(t, 1, len(users))
  1975. user = users[0]
  1976. assert.NotEqual(t, oldUploadBandwidth, user.UploadBandwidth)
  1977. _, _, err = httpd.Loaddata(backupFilePath, "0", "2", http.StatusOK)
  1978. assert.NoError(t, err)
  1979. // mode 2 will update the user and close the previous connection
  1980. assert.Len(t, common.Connections.GetStats(), 0)
  1981. users, _, err = httpd.GetUsers(1, 0, user.Username, http.StatusOK)
  1982. assert.NoError(t, err)
  1983. assert.Equal(t, 1, len(users))
  1984. user = users[0]
  1985. assert.Equal(t, oldUploadBandwidth, user.UploadBandwidth)
  1986. _, err = httpd.RemoveUser(user, http.StatusOK)
  1987. assert.NoError(t, err)
  1988. err = os.Remove(backupFilePath)
  1989. assert.NoError(t, err)
  1990. }
  1991. func TestHTTPSConnection(t *testing.T) {
  1992. client := &http.Client{
  1993. Timeout: 5 * time.Second,
  1994. }
  1995. resp, err := client.Get("https://localhost:8443" + metricsPath)
  1996. if assert.Error(t, err) {
  1997. if !strings.Contains(err.Error(), "certificate is not valid") &&
  1998. !strings.Contains(err.Error(), "certificate signed by unknown authority") {
  1999. assert.Fail(t, err.Error())
  2000. }
  2001. } else {
  2002. resp.Body.Close()
  2003. }
  2004. }
  2005. // test using mock http server
  2006. func TestBasicUserHandlingMock(t *testing.T) {
  2007. user := getTestUser()
  2008. userAsJSON := getUserAsJSON(t, user)
  2009. req, err := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
  2010. assert.NoError(t, err)
  2011. rr := executeRequest(req)
  2012. checkResponseCode(t, http.StatusOK, rr.Code)
  2013. err = render.DecodeJSON(rr.Body, &user)
  2014. assert.NoError(t, err)
  2015. req, _ = http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
  2016. rr = executeRequest(req)
  2017. checkResponseCode(t, http.StatusInternalServerError, rr.Code)
  2018. user.MaxSessions = 10
  2019. user.UploadBandwidth = 128
  2020. user.Permissions["/"] = []string{dataprovider.PermAny, dataprovider.PermDelete, dataprovider.PermDownload}
  2021. userAsJSON = getUserAsJSON(t, user)
  2022. req, _ = http.NewRequest(http.MethodPut, userPath+"/"+strconv.FormatInt(user.ID, 10), bytes.NewBuffer(userAsJSON))
  2023. rr = executeRequest(req)
  2024. checkResponseCode(t, http.StatusOK, rr.Code)
  2025. req, _ = http.NewRequest(http.MethodGet, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
  2026. rr = executeRequest(req)
  2027. checkResponseCode(t, http.StatusOK, rr.Code)
  2028. var updatedUser dataprovider.User
  2029. err = render.DecodeJSON(rr.Body, &updatedUser)
  2030. assert.NoError(t, err)
  2031. assert.Equal(t, user.MaxSessions, updatedUser.MaxSessions)
  2032. assert.Equal(t, user.UploadBandwidth, updatedUser.UploadBandwidth)
  2033. assert.Equal(t, 1, len(updatedUser.Permissions["/"]))
  2034. assert.True(t, utils.IsStringInSlice(dataprovider.PermAny, updatedUser.Permissions["/"]))
  2035. req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
  2036. rr = executeRequest(req)
  2037. checkResponseCode(t, http.StatusOK, rr.Code)
  2038. }
  2039. func TestGetUserByIdInvalidParamsMock(t *testing.T) {
  2040. req, _ := http.NewRequest(http.MethodGet, userPath+"/0", nil)
  2041. rr := executeRequest(req)
  2042. checkResponseCode(t, http.StatusNotFound, rr.Code)
  2043. req, _ = http.NewRequest(http.MethodGet, userPath+"/a", nil)
  2044. rr = executeRequest(req)
  2045. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  2046. }
  2047. func TestAddUserNoUsernameMock(t *testing.T) {
  2048. user := getTestUser()
  2049. user.Username = ""
  2050. userAsJSON := getUserAsJSON(t, user)
  2051. req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
  2052. rr := executeRequest(req)
  2053. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  2054. }
  2055. func TestAddUserInvalidHomeDirMock(t *testing.T) {
  2056. user := getTestUser()
  2057. user.HomeDir = "relative_path"
  2058. userAsJSON := getUserAsJSON(t, user)
  2059. req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
  2060. rr := executeRequest(req)
  2061. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  2062. }
  2063. func TestAddUserInvalidPermsMock(t *testing.T) {
  2064. user := getTestUser()
  2065. user.Permissions["/"] = []string{}
  2066. userAsJSON := getUserAsJSON(t, user)
  2067. req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
  2068. rr := executeRequest(req)
  2069. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  2070. }
  2071. func TestAddFolderInvalidJsonMock(t *testing.T) {
  2072. req, _ := http.NewRequest(http.MethodPost, folderPath, bytes.NewBuffer([]byte("invalid json")))
  2073. rr := executeRequest(req)
  2074. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  2075. }
  2076. func TestAddUserInvalidJsonMock(t *testing.T) {
  2077. req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer([]byte("invalid json")))
  2078. rr := executeRequest(req)
  2079. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  2080. }
  2081. func TestUpdateUserMock(t *testing.T) {
  2082. user := getTestUser()
  2083. userAsJSON := getUserAsJSON(t, user)
  2084. req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
  2085. rr := executeRequest(req)
  2086. checkResponseCode(t, http.StatusOK, rr.Code)
  2087. err := render.DecodeJSON(rr.Body, &user)
  2088. assert.NoError(t, err)
  2089. // permissions should not change if empty or nil
  2090. permissions := user.Permissions
  2091. user.Permissions = make(map[string][]string)
  2092. userAsJSON = getUserAsJSON(t, user)
  2093. req, _ = http.NewRequest(http.MethodPut, userPath+"/"+strconv.FormatInt(user.ID, 10), bytes.NewBuffer(userAsJSON))
  2094. rr = executeRequest(req)
  2095. checkResponseCode(t, http.StatusOK, rr.Code)
  2096. req, _ = http.NewRequest(http.MethodGet, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
  2097. rr = executeRequest(req)
  2098. checkResponseCode(t, http.StatusOK, rr.Code)
  2099. var updatedUser dataprovider.User
  2100. err = render.DecodeJSON(rr.Body, &updatedUser)
  2101. assert.NoError(t, err)
  2102. for dir, perms := range permissions {
  2103. if actualPerms, ok := updatedUser.Permissions[dir]; ok {
  2104. for _, v := range actualPerms {
  2105. assert.True(t, utils.IsStringInSlice(v, perms))
  2106. }
  2107. } else {
  2108. assert.Fail(t, "Permissions directories mismatch")
  2109. }
  2110. }
  2111. req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
  2112. rr = executeRequest(req)
  2113. checkResponseCode(t, http.StatusOK, rr.Code)
  2114. }
  2115. func TestUpdateUserQuotaUsageMock(t *testing.T) {
  2116. var user dataprovider.User
  2117. u := getTestUser()
  2118. usedQuotaFiles := 1
  2119. usedQuotaSize := int64(65535)
  2120. u.UsedQuotaFiles = usedQuotaFiles
  2121. u.UsedQuotaSize = usedQuotaSize
  2122. userAsJSON := getUserAsJSON(t, u)
  2123. req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
  2124. rr := executeRequest(req)
  2125. checkResponseCode(t, http.StatusOK, rr.Code)
  2126. err := render.DecodeJSON(rr.Body, &user)
  2127. assert.NoError(t, err)
  2128. req, _ = http.NewRequest(http.MethodPut, updateUsedQuotaPath, bytes.NewBuffer(userAsJSON))
  2129. rr = executeRequest(req)
  2130. checkResponseCode(t, http.StatusOK, rr.Code)
  2131. req, _ = http.NewRequest(http.MethodGet, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
  2132. rr = executeRequest(req)
  2133. checkResponseCode(t, http.StatusOK, rr.Code)
  2134. err = render.DecodeJSON(rr.Body, &user)
  2135. assert.NoError(t, err)
  2136. assert.Equal(t, usedQuotaFiles, user.UsedQuotaFiles)
  2137. assert.Equal(t, usedQuotaSize, user.UsedQuotaSize)
  2138. req, _ = http.NewRequest(http.MethodPut, updateUsedQuotaPath, bytes.NewBuffer([]byte("string")))
  2139. rr = executeRequest(req)
  2140. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  2141. assert.True(t, common.QuotaScans.AddUserQuotaScan(user.Username))
  2142. req, _ = http.NewRequest(http.MethodPut, updateUsedQuotaPath, bytes.NewBuffer(userAsJSON))
  2143. rr = executeRequest(req)
  2144. checkResponseCode(t, http.StatusConflict, rr.Code)
  2145. assert.True(t, common.QuotaScans.RemoveUserQuotaScan(user.Username))
  2146. req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
  2147. rr = executeRequest(req)
  2148. checkResponseCode(t, http.StatusOK, rr.Code)
  2149. }
  2150. func TestUserPermissionsMock(t *testing.T) {
  2151. user := getTestUser()
  2152. user.Permissions = make(map[string][]string)
  2153. user.Permissions["/somedir"] = []string{dataprovider.PermAny}
  2154. userAsJSON := getUserAsJSON(t, user)
  2155. req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
  2156. rr := executeRequest(req)
  2157. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  2158. user.Permissions = make(map[string][]string)
  2159. user.Permissions["/"] = []string{dataprovider.PermAny}
  2160. user.Permissions[".."] = []string{dataprovider.PermAny}
  2161. userAsJSON = getUserAsJSON(t, user)
  2162. req, _ = http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
  2163. rr = executeRequest(req)
  2164. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  2165. user.Permissions = make(map[string][]string)
  2166. user.Permissions["/"] = []string{dataprovider.PermAny}
  2167. userAsJSON = getUserAsJSON(t, user)
  2168. req, _ = http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
  2169. rr = executeRequest(req)
  2170. checkResponseCode(t, http.StatusOK, rr.Code)
  2171. err := render.DecodeJSON(rr.Body, &user)
  2172. assert.NoError(t, err)
  2173. user.Permissions["/somedir"] = []string{"invalid"}
  2174. userAsJSON = getUserAsJSON(t, user)
  2175. req, _ = http.NewRequest(http.MethodPut, userPath+"/"+strconv.FormatInt(user.ID, 10), bytes.NewBuffer(userAsJSON))
  2176. rr = executeRequest(req)
  2177. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  2178. delete(user.Permissions, "/somedir")
  2179. user.Permissions["/somedir/.."] = []string{dataprovider.PermAny}
  2180. userAsJSON = getUserAsJSON(t, user)
  2181. req, _ = http.NewRequest(http.MethodPut, userPath+"/"+strconv.FormatInt(user.ID, 10), bytes.NewBuffer(userAsJSON))
  2182. rr = executeRequest(req)
  2183. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  2184. delete(user.Permissions, "/somedir/..")
  2185. user.Permissions["not_abs_path"] = []string{dataprovider.PermAny}
  2186. userAsJSON = getUserAsJSON(t, user)
  2187. req, _ = http.NewRequest(http.MethodPut, userPath+"/"+strconv.FormatInt(user.ID, 10), bytes.NewBuffer(userAsJSON))
  2188. rr = executeRequest(req)
  2189. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  2190. delete(user.Permissions, "not_abs_path")
  2191. user.Permissions["/somedir/../otherdir/"] = []string{dataprovider.PermListItems}
  2192. userAsJSON = getUserAsJSON(t, user)
  2193. req, _ = http.NewRequest(http.MethodPut, userPath+"/"+strconv.FormatInt(user.ID, 10), bytes.NewBuffer(userAsJSON))
  2194. rr = executeRequest(req)
  2195. checkResponseCode(t, http.StatusOK, rr.Code)
  2196. req, _ = http.NewRequest(http.MethodGet, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
  2197. rr = executeRequest(req)
  2198. checkResponseCode(t, http.StatusOK, rr.Code)
  2199. var updatedUser dataprovider.User
  2200. err = render.DecodeJSON(rr.Body, &updatedUser)
  2201. assert.NoError(t, err)
  2202. if val, ok := updatedUser.Permissions["/otherdir"]; ok {
  2203. assert.True(t, utils.IsStringInSlice(dataprovider.PermListItems, val))
  2204. assert.Equal(t, 1, len(val))
  2205. } else {
  2206. assert.Fail(t, "expected dir not found in permissions")
  2207. }
  2208. req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
  2209. rr = executeRequest(req)
  2210. checkResponseCode(t, http.StatusOK, rr.Code)
  2211. }
  2212. func TestUpdateUserInvalidJsonMock(t *testing.T) {
  2213. user := getTestUser()
  2214. userAsJSON := getUserAsJSON(t, user)
  2215. req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
  2216. rr := executeRequest(req)
  2217. checkResponseCode(t, http.StatusOK, rr.Code)
  2218. err := render.DecodeJSON(rr.Body, &user)
  2219. assert.NoError(t, err)
  2220. req, _ = http.NewRequest(http.MethodPut, userPath+"/"+strconv.FormatInt(user.ID, 10), bytes.NewBuffer([]byte("Invalid json")))
  2221. rr = executeRequest(req)
  2222. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  2223. req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
  2224. rr = executeRequest(req)
  2225. checkResponseCode(t, http.StatusOK, rr.Code)
  2226. }
  2227. func TestUpdateUserInvalidParamsMock(t *testing.T) {
  2228. user := getTestUser()
  2229. userAsJSON := getUserAsJSON(t, user)
  2230. req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
  2231. rr := executeRequest(req)
  2232. checkResponseCode(t, http.StatusOK, rr.Code)
  2233. err := render.DecodeJSON(rr.Body, &user)
  2234. assert.NoError(t, err)
  2235. user.HomeDir = ""
  2236. userAsJSON = getUserAsJSON(t, user)
  2237. req, _ = http.NewRequest(http.MethodPut, userPath+"/"+strconv.FormatInt(user.ID, 10), bytes.NewBuffer(userAsJSON))
  2238. rr = executeRequest(req)
  2239. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  2240. userID := user.ID
  2241. user.ID = 0
  2242. userAsJSON = getUserAsJSON(t, user)
  2243. req, _ = http.NewRequest(http.MethodPut, userPath+"/"+strconv.FormatInt(userID, 10), bytes.NewBuffer(userAsJSON))
  2244. rr = executeRequest(req)
  2245. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  2246. user.ID = userID
  2247. req, _ = http.NewRequest(http.MethodPut, userPath+"/0", bytes.NewBuffer(userAsJSON))
  2248. rr = executeRequest(req)
  2249. checkResponseCode(t, http.StatusNotFound, rr.Code)
  2250. req, _ = http.NewRequest(http.MethodPut, userPath+"/a", bytes.NewBuffer(userAsJSON))
  2251. rr = executeRequest(req)
  2252. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  2253. req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
  2254. rr = executeRequest(req)
  2255. checkResponseCode(t, http.StatusOK, rr.Code)
  2256. }
  2257. func TestGetUsersMock(t *testing.T) {
  2258. user := getTestUser()
  2259. userAsJSON := getUserAsJSON(t, user)
  2260. req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
  2261. rr := executeRequest(req)
  2262. checkResponseCode(t, http.StatusOK, rr.Code)
  2263. err := render.DecodeJSON(rr.Body, &user)
  2264. assert.NoError(t, err)
  2265. req, _ = http.NewRequest(http.MethodGet, userPath+"?limit=510&offset=0&order=ASC&username="+defaultUsername, nil)
  2266. rr = executeRequest(req)
  2267. checkResponseCode(t, http.StatusOK, rr.Code)
  2268. var users []dataprovider.User
  2269. err = render.DecodeJSON(rr.Body, &users)
  2270. assert.NoError(t, err)
  2271. assert.Equal(t, 1, len(users))
  2272. req, _ = http.NewRequest(http.MethodGet, userPath+"?limit=a&offset=0&order=ASC", nil)
  2273. rr = executeRequest(req)
  2274. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  2275. req, _ = http.NewRequest(http.MethodGet, userPath+"?limit=1&offset=a&order=ASC", nil)
  2276. rr = executeRequest(req)
  2277. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  2278. req, _ = http.NewRequest(http.MethodGet, userPath+"?limit=1&offset=0&order=ASCa", nil)
  2279. rr = executeRequest(req)
  2280. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  2281. req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
  2282. rr = executeRequest(req)
  2283. checkResponseCode(t, http.StatusOK, rr.Code)
  2284. }
  2285. func TestDeleteUserInvalidParamsMock(t *testing.T) {
  2286. req, _ := http.NewRequest(http.MethodDelete, userPath+"/0", nil)
  2287. rr := executeRequest(req)
  2288. checkResponseCode(t, http.StatusNotFound, rr.Code)
  2289. req, _ = http.NewRequest(http.MethodDelete, userPath+"/a", nil)
  2290. rr = executeRequest(req)
  2291. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  2292. }
  2293. func TestGetQuotaScansMock(t *testing.T) {
  2294. req, err := http.NewRequest("GET", quotaScanPath, nil)
  2295. assert.NoError(t, err)
  2296. rr := executeRequest(req)
  2297. checkResponseCode(t, http.StatusOK, rr.Code)
  2298. }
  2299. func TestStartQuotaScanMock(t *testing.T) {
  2300. user := getTestUser()
  2301. userAsJSON := getUserAsJSON(t, user)
  2302. req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
  2303. rr := executeRequest(req)
  2304. checkResponseCode(t, http.StatusOK, rr.Code)
  2305. err := render.DecodeJSON(rr.Body, &user)
  2306. assert.NoError(t, err)
  2307. _, err = os.Stat(user.HomeDir)
  2308. if err == nil {
  2309. err = os.Remove(user.HomeDir)
  2310. assert.NoError(t, err)
  2311. }
  2312. // simulate a duplicate quota scan
  2313. userAsJSON = getUserAsJSON(t, user)
  2314. common.QuotaScans.AddUserQuotaScan(user.Username)
  2315. req, _ = http.NewRequest(http.MethodPost, quotaScanPath, bytes.NewBuffer(userAsJSON))
  2316. rr = executeRequest(req)
  2317. checkResponseCode(t, http.StatusConflict, rr.Code)
  2318. assert.True(t, common.QuotaScans.RemoveUserQuotaScan(user.Username))
  2319. userAsJSON = getUserAsJSON(t, user)
  2320. req, _ = http.NewRequest(http.MethodPost, quotaScanPath, bytes.NewBuffer(userAsJSON))
  2321. rr = executeRequest(req)
  2322. checkResponseCode(t, http.StatusAccepted, rr.Code)
  2323. for {
  2324. var scans []common.ActiveQuotaScan
  2325. req, _ = http.NewRequest(http.MethodGet, quotaScanPath, nil)
  2326. rr = executeRequest(req)
  2327. checkResponseCode(t, http.StatusOK, rr.Code)
  2328. err = render.DecodeJSON(rr.Body, &scans)
  2329. if !assert.NoError(t, err, "Error getting active scans") {
  2330. break
  2331. }
  2332. if len(scans) == 0 {
  2333. break
  2334. }
  2335. time.Sleep(100 * time.Millisecond)
  2336. }
  2337. _, err = os.Stat(user.HomeDir)
  2338. if err != nil && os.IsNotExist(err) {
  2339. err = os.MkdirAll(user.HomeDir, os.ModePerm)
  2340. assert.NoError(t, err)
  2341. }
  2342. req, _ = http.NewRequest(http.MethodPost, quotaScanPath, bytes.NewBuffer(userAsJSON))
  2343. rr = executeRequest(req)
  2344. checkResponseCode(t, http.StatusAccepted, rr.Code)
  2345. for {
  2346. var scans []common.ActiveQuotaScan
  2347. req, _ = http.NewRequest(http.MethodGet, quotaScanPath, nil)
  2348. rr = executeRequest(req)
  2349. checkResponseCode(t, http.StatusOK, rr.Code)
  2350. err = render.DecodeJSON(rr.Body, &scans)
  2351. if !assert.NoError(t, err) {
  2352. assert.Fail(t, err.Error(), "Error getting active scans")
  2353. break
  2354. }
  2355. if len(scans) == 0 {
  2356. break
  2357. }
  2358. time.Sleep(100 * time.Millisecond)
  2359. }
  2360. req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
  2361. rr = executeRequest(req)
  2362. checkResponseCode(t, http.StatusOK, rr.Code)
  2363. err = os.RemoveAll(user.GetHomeDir())
  2364. assert.NoError(t, err)
  2365. }
  2366. func TestUpdateFolderQuotaUsageMock(t *testing.T) {
  2367. mappedPath := filepath.Join(os.TempDir(), "vfolder")
  2368. f := vfs.BaseVirtualFolder{
  2369. MappedPath: mappedPath,
  2370. }
  2371. usedQuotaFiles := 1
  2372. usedQuotaSize := int64(65535)
  2373. f.UsedQuotaFiles = usedQuotaFiles
  2374. f.UsedQuotaSize = usedQuotaSize
  2375. var folder vfs.BaseVirtualFolder
  2376. folderAsJSON, err := json.Marshal(f)
  2377. assert.NoError(t, err)
  2378. req, _ := http.NewRequest(http.MethodPost, folderPath, bytes.NewBuffer(folderAsJSON))
  2379. rr := executeRequest(req)
  2380. checkResponseCode(t, http.StatusOK, rr.Code)
  2381. err = render.DecodeJSON(rr.Body, &folder)
  2382. assert.NoError(t, err)
  2383. req, _ = http.NewRequest(http.MethodPut, updateFolderUsedQuotaPath, bytes.NewBuffer(folderAsJSON))
  2384. rr = executeRequest(req)
  2385. checkResponseCode(t, http.StatusOK, rr.Code)
  2386. var folders []vfs.BaseVirtualFolder
  2387. url, err := url.Parse(folderPath)
  2388. assert.NoError(t, err)
  2389. q := url.Query()
  2390. q.Add("folder_path", mappedPath)
  2391. url.RawQuery = q.Encode()
  2392. req, _ = http.NewRequest(http.MethodGet, url.String(), nil)
  2393. rr = executeRequest(req)
  2394. checkResponseCode(t, http.StatusOK, rr.Code)
  2395. err = render.DecodeJSON(rr.Body, &folders)
  2396. assert.NoError(t, err)
  2397. if assert.Len(t, folders, 1) {
  2398. folder = folders[0]
  2399. assert.Equal(t, usedQuotaFiles, folder.UsedQuotaFiles)
  2400. assert.Equal(t, usedQuotaSize, folder.UsedQuotaSize)
  2401. }
  2402. req, _ = http.NewRequest(http.MethodPut, updateFolderUsedQuotaPath, bytes.NewBuffer([]byte("string")))
  2403. rr = executeRequest(req)
  2404. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  2405. assert.True(t, common.QuotaScans.AddVFolderQuotaScan(mappedPath))
  2406. req, _ = http.NewRequest(http.MethodPut, updateFolderUsedQuotaPath, bytes.NewBuffer(folderAsJSON))
  2407. rr = executeRequest(req)
  2408. checkResponseCode(t, http.StatusConflict, rr.Code)
  2409. assert.True(t, common.QuotaScans.RemoveVFolderQuotaScan(mappedPath))
  2410. url, err = url.Parse(folderPath)
  2411. assert.NoError(t, err)
  2412. q = url.Query()
  2413. q.Add("folder_path", mappedPath)
  2414. url.RawQuery = q.Encode()
  2415. req, _ = http.NewRequest(http.MethodDelete, url.String(), nil)
  2416. rr = executeRequest(req)
  2417. checkResponseCode(t, http.StatusOK, rr.Code)
  2418. }
  2419. func TestStartFolderQuotaScanMock(t *testing.T) {
  2420. mappedPath := filepath.Join(os.TempDir(), "vfolder")
  2421. folder := vfs.BaseVirtualFolder{
  2422. MappedPath: mappedPath,
  2423. }
  2424. folderAsJSON, err := json.Marshal(folder)
  2425. assert.NoError(t, err)
  2426. req, _ := http.NewRequest(http.MethodPost, folderPath, bytes.NewBuffer(folderAsJSON))
  2427. rr := executeRequest(req)
  2428. checkResponseCode(t, http.StatusOK, rr.Code)
  2429. _, err = os.Stat(mappedPath)
  2430. if err == nil {
  2431. err = os.Remove(mappedPath)
  2432. assert.NoError(t, err)
  2433. }
  2434. // simulate a duplicate quota scan
  2435. common.QuotaScans.AddVFolderQuotaScan(mappedPath)
  2436. req, _ = http.NewRequest(http.MethodPost, quotaScanVFolderPath, bytes.NewBuffer(folderAsJSON))
  2437. rr = executeRequest(req)
  2438. checkResponseCode(t, http.StatusConflict, rr.Code)
  2439. assert.True(t, common.QuotaScans.RemoveVFolderQuotaScan(mappedPath))
  2440. // and now a real quota scan
  2441. _, err = os.Stat(mappedPath)
  2442. if err != nil && os.IsNotExist(err) {
  2443. err = os.MkdirAll(mappedPath, os.ModePerm)
  2444. assert.NoError(t, err)
  2445. }
  2446. req, _ = http.NewRequest(http.MethodPost, quotaScanVFolderPath, bytes.NewBuffer(folderAsJSON))
  2447. rr = executeRequest(req)
  2448. checkResponseCode(t, http.StatusAccepted, rr.Code)
  2449. var scans []common.ActiveVirtualFolderQuotaScan
  2450. for {
  2451. req, _ = http.NewRequest(http.MethodGet, quotaScanVFolderPath, nil)
  2452. rr = executeRequest(req)
  2453. checkResponseCode(t, http.StatusOK, rr.Code)
  2454. err = render.DecodeJSON(rr.Body, &scans)
  2455. if !assert.NoError(t, err, "Error getting active folders scans") {
  2456. break
  2457. }
  2458. if len(scans) == 0 {
  2459. break
  2460. }
  2461. time.Sleep(100 * time.Millisecond)
  2462. }
  2463. // cleanup
  2464. url, err := url.Parse(folderPath)
  2465. assert.NoError(t, err)
  2466. q := url.Query()
  2467. q.Add("folder_path", mappedPath)
  2468. url.RawQuery = q.Encode()
  2469. req, _ = http.NewRequest(http.MethodDelete, url.String(), nil)
  2470. rr = executeRequest(req)
  2471. checkResponseCode(t, http.StatusOK, rr.Code)
  2472. err = os.RemoveAll(folderPath)
  2473. assert.NoError(t, err)
  2474. err = os.RemoveAll(mappedPath)
  2475. assert.NoError(t, err)
  2476. }
  2477. func TestStartQuotaScanNonExistentUserMock(t *testing.T) {
  2478. user := getTestUser()
  2479. userAsJSON := getUserAsJSON(t, user)
  2480. req, _ := http.NewRequest(http.MethodPost, quotaScanPath, bytes.NewBuffer(userAsJSON))
  2481. rr := executeRequest(req)
  2482. checkResponseCode(t, http.StatusNotFound, rr.Code)
  2483. }
  2484. func TestStartQuotaScanBadUserMock(t *testing.T) {
  2485. req, _ := http.NewRequest(http.MethodPost, quotaScanPath, bytes.NewBuffer([]byte("invalid json")))
  2486. rr := executeRequest(req)
  2487. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  2488. }
  2489. func TestStartQuotaScanBadFolderMock(t *testing.T) {
  2490. req, _ := http.NewRequest(http.MethodPost, quotaScanVFolderPath, bytes.NewBuffer([]byte("invalid json")))
  2491. rr := executeRequest(req)
  2492. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  2493. }
  2494. func TestStartQuotaScanNonExistentFolderMock(t *testing.T) {
  2495. folder := vfs.BaseVirtualFolder{
  2496. MappedPath: os.TempDir(),
  2497. }
  2498. folderAsJSON, err := json.Marshal(folder)
  2499. assert.NoError(t, err)
  2500. req, _ := http.NewRequest(http.MethodPost, quotaScanVFolderPath, bytes.NewBuffer(folderAsJSON))
  2501. rr := executeRequest(req)
  2502. checkResponseCode(t, http.StatusNotFound, rr.Code)
  2503. }
  2504. func TestGetFoldersMock(t *testing.T) {
  2505. mappedPath := filepath.Join(os.TempDir(), "vfolder")
  2506. folder := vfs.BaseVirtualFolder{
  2507. MappedPath: mappedPath,
  2508. }
  2509. folderAsJSON, err := json.Marshal(folder)
  2510. assert.NoError(t, err)
  2511. req, _ := http.NewRequest(http.MethodPost, folderPath, bytes.NewBuffer(folderAsJSON))
  2512. rr := executeRequest(req)
  2513. checkResponseCode(t, http.StatusOK, rr.Code)
  2514. err = render.DecodeJSON(rr.Body, &folder)
  2515. assert.NoError(t, err)
  2516. var folders []vfs.BaseVirtualFolder
  2517. url, err := url.Parse(folderPath + "?limit=510&offset=0&order=DESC")
  2518. assert.NoError(t, err)
  2519. q := url.Query()
  2520. q.Add("folder_path", mappedPath)
  2521. url.RawQuery = q.Encode()
  2522. req, _ = http.NewRequest(http.MethodGet, url.String(), nil)
  2523. rr = executeRequest(req)
  2524. checkResponseCode(t, http.StatusOK, rr.Code)
  2525. err = render.DecodeJSON(rr.Body, &folders)
  2526. assert.NoError(t, err)
  2527. assert.Len(t, folders, 1)
  2528. req, _ = http.NewRequest(http.MethodGet, folderPath+"?limit=a&offset=0&order=ASC", nil)
  2529. rr = executeRequest(req)
  2530. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  2531. req, _ = http.NewRequest(http.MethodGet, folderPath+"?limit=1&offset=a&order=ASC", nil)
  2532. rr = executeRequest(req)
  2533. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  2534. req, _ = http.NewRequest(http.MethodGet, folderPath+"?limit=1&offset=0&order=ASCa", nil)
  2535. rr = executeRequest(req)
  2536. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  2537. url, err = url.Parse(folderPath)
  2538. assert.NoError(t, err)
  2539. q = url.Query()
  2540. q.Add("folder_path", mappedPath)
  2541. url.RawQuery = q.Encode()
  2542. req, _ = http.NewRequest(http.MethodDelete, url.String(), nil)
  2543. rr = executeRequest(req)
  2544. checkResponseCode(t, http.StatusOK, rr.Code)
  2545. }
  2546. func TestGetVersionMock(t *testing.T) {
  2547. req, _ := http.NewRequest(http.MethodGet, versionPath, nil)
  2548. rr := executeRequest(req)
  2549. checkResponseCode(t, http.StatusOK, rr.Code)
  2550. }
  2551. func TestGetConnectionsMock(t *testing.T) {
  2552. req, _ := http.NewRequest(http.MethodGet, activeConnectionsPath, nil)
  2553. rr := executeRequest(req)
  2554. checkResponseCode(t, http.StatusOK, rr.Code)
  2555. }
  2556. func TestDeleteActiveConnectionMock(t *testing.T) {
  2557. req, _ := http.NewRequest(http.MethodDelete, activeConnectionsPath+"/connectionID", nil)
  2558. rr := executeRequest(req)
  2559. checkResponseCode(t, http.StatusNotFound, rr.Code)
  2560. }
  2561. func TestNotFoundMock(t *testing.T) {
  2562. req, _ := http.NewRequest(http.MethodGet, "/non/existing/path", nil)
  2563. rr := executeRequest(req)
  2564. checkResponseCode(t, http.StatusNotFound, rr.Code)
  2565. }
  2566. func TestMethodNotAllowedMock(t *testing.T) {
  2567. req, _ := http.NewRequest(http.MethodPost, activeConnectionsPath, nil)
  2568. rr := executeRequest(req)
  2569. checkResponseCode(t, http.StatusMethodNotAllowed, rr.Code)
  2570. }
  2571. func TestMetricsMock(t *testing.T) {
  2572. req, _ := http.NewRequest(http.MethodGet, metricsPath, nil)
  2573. rr := executeRequest(req)
  2574. checkResponseCode(t, http.StatusOK, rr.Code)
  2575. }
  2576. func TestHealthCheck(t *testing.T) {
  2577. req, _ := http.NewRequest(http.MethodGet, "/healthz", nil)
  2578. rr := executeRequest(req)
  2579. checkResponseCode(t, http.StatusOK, rr.Code)
  2580. assert.Equal(t, "ok", rr.Body.String())
  2581. }
  2582. func TestPProfEndPointMock(t *testing.T) {
  2583. req, _ := http.NewRequest(http.MethodGet, pprofPath, nil)
  2584. rr := executeRequest(req)
  2585. checkResponseCode(t, http.StatusOK, rr.Code)
  2586. }
  2587. func TestGetWebRootMock(t *testing.T) {
  2588. req, _ := http.NewRequest(http.MethodGet, "/", nil)
  2589. rr := executeRequest(req)
  2590. checkResponseCode(t, http.StatusMovedPermanently, rr.Code)
  2591. req, _ = http.NewRequest(http.MethodGet, webBasePath, nil)
  2592. rr = executeRequest(req)
  2593. checkResponseCode(t, http.StatusMovedPermanently, rr.Code)
  2594. }
  2595. func TestBasicWebUsersMock(t *testing.T) {
  2596. user := getTestUser()
  2597. userAsJSON := getUserAsJSON(t, user)
  2598. req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
  2599. rr := executeRequest(req)
  2600. checkResponseCode(t, http.StatusOK, rr.Code)
  2601. err := render.DecodeJSON(rr.Body, &user)
  2602. assert.NoError(t, err)
  2603. user1 := getTestUser()
  2604. user1.Username += "1"
  2605. user1AsJSON := getUserAsJSON(t, user1)
  2606. req, _ = http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(user1AsJSON))
  2607. rr = executeRequest(req)
  2608. checkResponseCode(t, http.StatusOK, rr.Code)
  2609. err = render.DecodeJSON(rr.Body, &user1)
  2610. assert.NoError(t, err)
  2611. req, _ = http.NewRequest(http.MethodGet, webUsersPath, nil)
  2612. rr = executeRequest(req)
  2613. checkResponseCode(t, http.StatusOK, rr.Code)
  2614. req, _ = http.NewRequest(http.MethodGet, webUsersPath+"?qlimit=a", nil)
  2615. rr = executeRequest(req)
  2616. checkResponseCode(t, http.StatusOK, rr.Code)
  2617. req, _ = http.NewRequest(http.MethodGet, webUsersPath+"?qlimit=1", nil)
  2618. rr = executeRequest(req)
  2619. checkResponseCode(t, http.StatusOK, rr.Code)
  2620. req, _ = http.NewRequest(http.MethodGet, webUserPath, nil)
  2621. rr = executeRequest(req)
  2622. checkResponseCode(t, http.StatusOK, rr.Code)
  2623. req, _ = http.NewRequest(http.MethodGet, webUserPath+"/"+strconv.FormatInt(user.ID, 10), nil)
  2624. rr = executeRequest(req)
  2625. checkResponseCode(t, http.StatusOK, rr.Code)
  2626. req, _ = http.NewRequest(http.MethodGet, webUserPath+"/0", nil)
  2627. rr = executeRequest(req)
  2628. checkResponseCode(t, http.StatusNotFound, rr.Code)
  2629. req, _ = http.NewRequest(http.MethodGet, webUserPath+"/a", nil)
  2630. rr = executeRequest(req)
  2631. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  2632. form := make(url.Values)
  2633. form.Set("username", user.Username)
  2634. b, contentType, _ := getMultipartFormData(form, "", "")
  2635. req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
  2636. req.Header.Set("Content-Type", contentType)
  2637. rr = executeRequest(req)
  2638. checkResponseCode(t, http.StatusOK, rr.Code)
  2639. b, contentType, _ = getMultipartFormData(form, "", "")
  2640. req, _ = http.NewRequest(http.MethodPost, webUserPath+"/"+strconv.FormatInt(user.ID, 10), &b)
  2641. req.Header.Set("Content-Type", contentType)
  2642. rr = executeRequest(req)
  2643. checkResponseCode(t, http.StatusOK, rr.Code)
  2644. b, contentType, _ = getMultipartFormData(form, "", "")
  2645. req, _ = http.NewRequest(http.MethodPost, webUserPath+"/0", &b)
  2646. req.Header.Set("Content-Type", contentType)
  2647. rr = executeRequest(req)
  2648. checkResponseCode(t, http.StatusNotFound, rr.Code)
  2649. req, _ = http.NewRequest(http.MethodPost, webUserPath+"/a", &b)
  2650. req.Header.Set("Content-Type", contentType)
  2651. rr = executeRequest(req)
  2652. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  2653. req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
  2654. rr = executeRequest(req)
  2655. checkResponseCode(t, http.StatusOK, rr.Code)
  2656. req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(user1.ID, 10), nil)
  2657. rr = executeRequest(req)
  2658. checkResponseCode(t, http.StatusOK, rr.Code)
  2659. }
  2660. func TestWebUserAddMock(t *testing.T) {
  2661. user := getTestUser()
  2662. user.UploadBandwidth = 32
  2663. user.DownloadBandwidth = 64
  2664. user.UID = 1000
  2665. user.AdditionalInfo = "info"
  2666. mappedDir := filepath.Join(os.TempDir(), "mapped")
  2667. form := make(url.Values)
  2668. form.Set("username", user.Username)
  2669. form.Set("home_dir", user.HomeDir)
  2670. form.Set("password", user.Password)
  2671. form.Set("status", strconv.Itoa(user.Status))
  2672. form.Set("expiration_date", "")
  2673. form.Set("permissions", "*")
  2674. form.Set("sub_dirs_permissions", " /subdir::list ,download ")
  2675. form.Set("virtual_folders", fmt.Sprintf(" /vdir:: %v :: 2 :: 1024", mappedDir))
  2676. form.Set("allowed_extensions", "/dir2::.jpg,.png\n/dir2::.ico\n/dir1::.rar")
  2677. form.Set("denied_extensions", "/dir2::.webp,.webp\n/dir2::.tiff\n/dir1::.zip")
  2678. form.Set("allowed_patterns", "/dir2::*.jpg,*.png\n/dir1::*.png")
  2679. form.Set("denied_patterns", "/dir1::*.zip\n/dir3::*.rar\n/dir2::*.mkv")
  2680. form.Set("additional_info", user.AdditionalInfo)
  2681. b, contentType, _ := getMultipartFormData(form, "", "")
  2682. // test invalid url escape
  2683. req, _ := http.NewRequest(http.MethodPost, webUserPath+"?a=%2", &b)
  2684. req.Header.Set("Content-Type", contentType)
  2685. rr := executeRequest(req)
  2686. checkResponseCode(t, http.StatusOK, rr.Code)
  2687. form.Set("public_keys", testPubKey)
  2688. form.Set("uid", strconv.FormatInt(int64(user.UID), 10))
  2689. form.Set("gid", "a")
  2690. b, contentType, _ = getMultipartFormData(form, "", "")
  2691. // test invalid gid
  2692. req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
  2693. req.Header.Set("Content-Type", contentType)
  2694. rr = executeRequest(req)
  2695. checkResponseCode(t, http.StatusOK, rr.Code)
  2696. form.Set("gid", "0")
  2697. form.Set("max_sessions", "a")
  2698. b, contentType, _ = getMultipartFormData(form, "", "")
  2699. // test invalid max sessions
  2700. req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
  2701. req.Header.Set("Content-Type", contentType)
  2702. rr = executeRequest(req)
  2703. checkResponseCode(t, http.StatusOK, rr.Code)
  2704. form.Set("max_sessions", "0")
  2705. form.Set("quota_size", "a")
  2706. b, contentType, _ = getMultipartFormData(form, "", "")
  2707. // test invalid quota size
  2708. req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
  2709. req.Header.Set("Content-Type", contentType)
  2710. rr = executeRequest(req)
  2711. checkResponseCode(t, http.StatusOK, rr.Code)
  2712. form.Set("quota_size", "0")
  2713. form.Set("quota_files", "a")
  2714. b, contentType, _ = getMultipartFormData(form, "", "")
  2715. // test invalid quota files
  2716. req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
  2717. req.Header.Set("Content-Type", contentType)
  2718. rr = executeRequest(req)
  2719. checkResponseCode(t, http.StatusOK, rr.Code)
  2720. form.Set("quota_files", "0")
  2721. form.Set("upload_bandwidth", "a")
  2722. b, contentType, _ = getMultipartFormData(form, "", "")
  2723. // test invalid upload bandwidth
  2724. req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
  2725. req.Header.Set("Content-Type", contentType)
  2726. rr = executeRequest(req)
  2727. checkResponseCode(t, http.StatusOK, rr.Code)
  2728. form.Set("upload_bandwidth", strconv.FormatInt(user.UploadBandwidth, 10))
  2729. form.Set("download_bandwidth", "a")
  2730. b, contentType, _ = getMultipartFormData(form, "", "")
  2731. // test invalid download bandwidth
  2732. req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
  2733. req.Header.Set("Content-Type", contentType)
  2734. rr = executeRequest(req)
  2735. checkResponseCode(t, http.StatusOK, rr.Code)
  2736. form.Set("download_bandwidth", strconv.FormatInt(user.DownloadBandwidth, 10))
  2737. form.Set("status", "a")
  2738. b, contentType, _ = getMultipartFormData(form, "", "")
  2739. // test invalid status
  2740. req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
  2741. req.Header.Set("Content-Type", contentType)
  2742. rr = executeRequest(req)
  2743. checkResponseCode(t, http.StatusOK, rr.Code)
  2744. form.Set("status", strconv.Itoa(user.Status))
  2745. form.Set("expiration_date", "123")
  2746. b, contentType, _ = getMultipartFormData(form, "", "")
  2747. // test invalid expiration date
  2748. req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
  2749. req.Header.Set("Content-Type", contentType)
  2750. rr = executeRequest(req)
  2751. checkResponseCode(t, http.StatusOK, rr.Code)
  2752. form.Set("expiration_date", "")
  2753. form.Set("allowed_ip", "invalid,ip")
  2754. b, contentType, _ = getMultipartFormData(form, "", "")
  2755. // test invalid allowed_ip
  2756. req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
  2757. req.Header.Set("Content-Type", contentType)
  2758. rr = executeRequest(req)
  2759. checkResponseCode(t, http.StatusOK, rr.Code)
  2760. form.Set("allowed_ip", "")
  2761. form.Set("denied_ip", "192.168.1.2") // it should be 192.168.1.2/32
  2762. b, contentType, _ = getMultipartFormData(form, "", "")
  2763. // test invalid denied_ip
  2764. req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
  2765. req.Header.Set("Content-Type", contentType)
  2766. rr = executeRequest(req)
  2767. checkResponseCode(t, http.StatusOK, rr.Code)
  2768. form.Set("denied_ip", "")
  2769. // test invalid max file upload size
  2770. form.Set("max_upload_file_size", "a")
  2771. b, contentType, _ = getMultipartFormData(form, "", "")
  2772. req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
  2773. req.Header.Set("Content-Type", contentType)
  2774. rr = executeRequest(req)
  2775. checkResponseCode(t, http.StatusOK, rr.Code)
  2776. form.Set("max_upload_file_size", "1000")
  2777. b, contentType, _ = getMultipartFormData(form, "", "")
  2778. req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
  2779. req.Header.Set("Content-Type", contentType)
  2780. rr = executeRequest(req)
  2781. checkResponseCode(t, http.StatusSeeOther, rr.Code)
  2782. // the user already exists, was created with the above request
  2783. b, contentType, _ = getMultipartFormData(form, "", "")
  2784. req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
  2785. req.Header.Set("Content-Type", contentType)
  2786. rr = executeRequest(req)
  2787. checkResponseCode(t, http.StatusOK, rr.Code)
  2788. req, _ = http.NewRequest(http.MethodGet, userPath+"?limit=1&offset=0&order=ASC&username="+user.Username, nil)
  2789. rr = executeRequest(req)
  2790. checkResponseCode(t, http.StatusOK, rr.Code)
  2791. var users []dataprovider.User
  2792. err := render.DecodeJSON(rr.Body, &users)
  2793. assert.NoError(t, err)
  2794. assert.Equal(t, 1, len(users))
  2795. newUser := users[0]
  2796. assert.Equal(t, user.UID, newUser.UID)
  2797. assert.Equal(t, user.UploadBandwidth, newUser.UploadBandwidth)
  2798. assert.Equal(t, user.DownloadBandwidth, newUser.DownloadBandwidth)
  2799. assert.Equal(t, int64(1000), newUser.Filters.MaxUploadFileSize)
  2800. assert.Equal(t, user.AdditionalInfo, newUser.AdditionalInfo)
  2801. assert.True(t, utils.IsStringInSlice(testPubKey, newUser.PublicKeys))
  2802. if val, ok := newUser.Permissions["/subdir"]; ok {
  2803. assert.True(t, utils.IsStringInSlice(dataprovider.PermListItems, val))
  2804. assert.True(t, utils.IsStringInSlice(dataprovider.PermDownload, val))
  2805. } else {
  2806. assert.Fail(t, "user permissions must contain /somedir", "actual: %v", newUser.Permissions)
  2807. }
  2808. assert.Len(t, newUser.VirtualFolders, 1)
  2809. for _, v := range newUser.VirtualFolders {
  2810. assert.Equal(t, v.VirtualPath, "/vdir")
  2811. assert.Equal(t, v.MappedPath, mappedDir)
  2812. assert.Equal(t, v.QuotaFiles, 2)
  2813. assert.Equal(t, v.QuotaSize, int64(1024))
  2814. }
  2815. assert.Len(t, newUser.Filters.FileExtensions, 2)
  2816. for _, filter := range newUser.Filters.FileExtensions {
  2817. if filter.Path == "/dir1" {
  2818. assert.Len(t, filter.DeniedExtensions, 1)
  2819. assert.Len(t, filter.AllowedExtensions, 1)
  2820. assert.True(t, utils.IsStringInSlice(".zip", filter.DeniedExtensions))
  2821. assert.True(t, utils.IsStringInSlice(".rar", filter.AllowedExtensions))
  2822. }
  2823. if filter.Path == "/dir2" {
  2824. assert.Len(t, filter.DeniedExtensions, 2)
  2825. assert.Len(t, filter.AllowedExtensions, 3)
  2826. assert.True(t, utils.IsStringInSlice(".jpg", filter.AllowedExtensions))
  2827. assert.True(t, utils.IsStringInSlice(".png", filter.AllowedExtensions))
  2828. assert.True(t, utils.IsStringInSlice(".ico", filter.AllowedExtensions))
  2829. assert.True(t, utils.IsStringInSlice(".webp", filter.DeniedExtensions))
  2830. assert.True(t, utils.IsStringInSlice(".tiff", filter.DeniedExtensions))
  2831. }
  2832. }
  2833. assert.Len(t, newUser.Filters.FilePatterns, 3)
  2834. for _, filter := range newUser.Filters.FilePatterns {
  2835. if filter.Path == "/dir1" {
  2836. assert.Len(t, filter.DeniedPatterns, 1)
  2837. assert.Len(t, filter.AllowedPatterns, 1)
  2838. assert.True(t, utils.IsStringInSlice("*.png", filter.AllowedPatterns))
  2839. assert.True(t, utils.IsStringInSlice("*.zip", filter.DeniedPatterns))
  2840. }
  2841. if filter.Path == "/dir2" {
  2842. assert.Len(t, filter.DeniedPatterns, 1)
  2843. assert.Len(t, filter.AllowedPatterns, 2)
  2844. assert.True(t, utils.IsStringInSlice("*.jpg", filter.AllowedPatterns))
  2845. assert.True(t, utils.IsStringInSlice("*.png", filter.AllowedPatterns))
  2846. assert.True(t, utils.IsStringInSlice("*.mkv", filter.DeniedPatterns))
  2847. }
  2848. if filter.Path == "/dir3" {
  2849. assert.Len(t, filter.DeniedPatterns, 1)
  2850. assert.Len(t, filter.AllowedPatterns, 0)
  2851. assert.True(t, utils.IsStringInSlice("*.rar", filter.DeniedPatterns))
  2852. }
  2853. }
  2854. req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(newUser.ID, 10), nil)
  2855. rr = executeRequest(req)
  2856. checkResponseCode(t, http.StatusOK, rr.Code)
  2857. url, err := url.Parse(folderPath)
  2858. assert.NoError(t, err)
  2859. q := url.Query()
  2860. q.Add("folder_path", mappedDir)
  2861. url.RawQuery = q.Encode()
  2862. req, _ = http.NewRequest(http.MethodDelete, url.String(), nil)
  2863. rr = executeRequest(req)
  2864. checkResponseCode(t, http.StatusOK, rr.Code)
  2865. }
  2866. func TestWebUserUpdateMock(t *testing.T) {
  2867. user := getTestUser()
  2868. userAsJSON := getUserAsJSON(t, user)
  2869. req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
  2870. rr := executeRequest(req)
  2871. checkResponseCode(t, http.StatusOK, rr.Code)
  2872. err := render.DecodeJSON(rr.Body, &user)
  2873. assert.NoError(t, err)
  2874. user.MaxSessions = 1
  2875. user.QuotaFiles = 2
  2876. user.QuotaSize = 3
  2877. user.GID = 1000
  2878. user.AdditionalInfo = "new additional info"
  2879. form := make(url.Values)
  2880. form.Set("username", user.Username)
  2881. form.Set("home_dir", user.HomeDir)
  2882. form.Set("uid", "0")
  2883. form.Set("gid", strconv.FormatInt(int64(user.GID), 10))
  2884. form.Set("max_sessions", strconv.FormatInt(int64(user.MaxSessions), 10))
  2885. form.Set("quota_size", strconv.FormatInt(user.QuotaSize, 10))
  2886. form.Set("quota_files", strconv.FormatInt(int64(user.QuotaFiles), 10))
  2887. form.Set("upload_bandwidth", "0")
  2888. form.Set("download_bandwidth", "0")
  2889. form.Set("permissions", "*")
  2890. form.Set("sub_dirs_permissions", "/otherdir :: list ,upload ")
  2891. form.Set("status", strconv.Itoa(user.Status))
  2892. form.Set("expiration_date", "2020-01-01 00:00:00")
  2893. form.Set("allowed_ip", " 192.168.1.3/32, 192.168.2.0/24 ")
  2894. form.Set("denied_ip", " 10.0.0.2/32 ")
  2895. form.Set("denied_extensions", "/dir1::.zip")
  2896. form.Set("ssh_login_methods", dataprovider.SSHLoginMethodKeyboardInteractive)
  2897. form.Set("denied_protocols", common.ProtocolFTP)
  2898. form.Set("max_upload_file_size", "100")
  2899. form.Set("disconnect", "1")
  2900. form.Set("additional_info", user.AdditionalInfo)
  2901. b, contentType, _ := getMultipartFormData(form, "", "")
  2902. req, _ = http.NewRequest(http.MethodPost, webUserPath+"/"+strconv.FormatInt(user.ID, 10), &b)
  2903. req.Header.Set("Content-Type", contentType)
  2904. rr = executeRequest(req)
  2905. checkResponseCode(t, http.StatusSeeOther, rr.Code)
  2906. req, _ = http.NewRequest(http.MethodGet, userPath+"?limit=1&offset=0&order=ASC&username="+user.Username, nil)
  2907. rr = executeRequest(req)
  2908. checkResponseCode(t, http.StatusOK, rr.Code)
  2909. var users []dataprovider.User
  2910. err = render.DecodeJSON(rr.Body, &users)
  2911. assert.NoError(t, err)
  2912. assert.Equal(t, 1, len(users))
  2913. updateUser := users[0]
  2914. assert.Equal(t, user.HomeDir, updateUser.HomeDir)
  2915. assert.Equal(t, user.MaxSessions, updateUser.MaxSessions)
  2916. assert.Equal(t, user.QuotaFiles, updateUser.QuotaFiles)
  2917. assert.Equal(t, user.QuotaSize, updateUser.QuotaSize)
  2918. assert.Equal(t, user.UID, updateUser.UID)
  2919. assert.Equal(t, user.GID, updateUser.GID)
  2920. assert.Equal(t, user.AdditionalInfo, updateUser.AdditionalInfo)
  2921. assert.Equal(t, int64(100), updateUser.Filters.MaxUploadFileSize)
  2922. if val, ok := updateUser.Permissions["/otherdir"]; ok {
  2923. assert.True(t, utils.IsStringInSlice(dataprovider.PermListItems, val))
  2924. assert.True(t, utils.IsStringInSlice(dataprovider.PermUpload, val))
  2925. } else {
  2926. assert.Fail(t, "user permissions must contains /otherdir", "actual: %v", updateUser.Permissions)
  2927. }
  2928. assert.True(t, utils.IsStringInSlice("192.168.1.3/32", updateUser.Filters.AllowedIP))
  2929. assert.True(t, utils.IsStringInSlice("10.0.0.2/32", updateUser.Filters.DeniedIP))
  2930. assert.True(t, utils.IsStringInSlice(dataprovider.SSHLoginMethodKeyboardInteractive, updateUser.Filters.DeniedLoginMethods))
  2931. assert.True(t, utils.IsStringInSlice(common.ProtocolFTP, updateUser.Filters.DeniedProtocols))
  2932. assert.True(t, utils.IsStringInSlice(".zip", updateUser.Filters.FileExtensions[0].DeniedExtensions))
  2933. req, err = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
  2934. assert.NoError(t, err)
  2935. rr = executeRequest(req)
  2936. checkResponseCode(t, http.StatusOK, rr.Code)
  2937. }
  2938. func TestWebUserS3Mock(t *testing.T) {
  2939. user := getTestUser()
  2940. userAsJSON := getUserAsJSON(t, user)
  2941. req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
  2942. rr := executeRequest(req)
  2943. checkResponseCode(t, http.StatusOK, rr.Code)
  2944. err := render.DecodeJSON(rr.Body, &user)
  2945. assert.NoError(t, err)
  2946. user.FsConfig.Provider = dataprovider.S3FilesystemProvider
  2947. user.FsConfig.S3Config.Bucket = "test"
  2948. user.FsConfig.S3Config.Region = "eu-west-1"
  2949. user.FsConfig.S3Config.AccessKey = "access-key"
  2950. user.FsConfig.S3Config.AccessSecret = kms.NewPlainSecret("access-secret")
  2951. user.FsConfig.S3Config.Endpoint = "http://127.0.0.1:9000/path?a=b"
  2952. user.FsConfig.S3Config.StorageClass = "Standard"
  2953. user.FsConfig.S3Config.KeyPrefix = "somedir/subdir/"
  2954. user.FsConfig.S3Config.UploadPartSize = 5
  2955. user.FsConfig.S3Config.UploadConcurrency = 4
  2956. form := make(url.Values)
  2957. form.Set("username", user.Username)
  2958. form.Set("home_dir", user.HomeDir)
  2959. form.Set("uid", "0")
  2960. form.Set("gid", strconv.FormatInt(int64(user.GID), 10))
  2961. form.Set("max_sessions", strconv.FormatInt(int64(user.MaxSessions), 10))
  2962. form.Set("quota_size", strconv.FormatInt(user.QuotaSize, 10))
  2963. form.Set("quota_files", strconv.FormatInt(int64(user.QuotaFiles), 10))
  2964. form.Set("upload_bandwidth", "0")
  2965. form.Set("download_bandwidth", "0")
  2966. form.Set("permissions", "*")
  2967. form.Set("sub_dirs_permissions", "")
  2968. form.Set("status", strconv.Itoa(user.Status))
  2969. form.Set("expiration_date", "2020-01-01 00:00:00")
  2970. form.Set("allowed_ip", "")
  2971. form.Set("denied_ip", "")
  2972. form.Set("fs_provider", "1")
  2973. form.Set("s3_bucket", user.FsConfig.S3Config.Bucket)
  2974. form.Set("s3_region", user.FsConfig.S3Config.Region)
  2975. form.Set("s3_access_key", user.FsConfig.S3Config.AccessKey)
  2976. form.Set("s3_access_secret", user.FsConfig.S3Config.AccessSecret.GetPayload())
  2977. form.Set("s3_storage_class", user.FsConfig.S3Config.StorageClass)
  2978. form.Set("s3_endpoint", user.FsConfig.S3Config.Endpoint)
  2979. form.Set("s3_key_prefix", user.FsConfig.S3Config.KeyPrefix)
  2980. form.Set("allowed_extensions", "/dir1::.jpg,.png")
  2981. form.Set("denied_extensions", "/dir2::.zip")
  2982. form.Set("max_upload_file_size", "0")
  2983. // test invalid s3_upload_part_size
  2984. form.Set("s3_upload_part_size", "a")
  2985. b, contentType, _ := getMultipartFormData(form, "", "")
  2986. req, _ = http.NewRequest(http.MethodPost, webUserPath+"/"+strconv.FormatInt(user.ID, 10), &b)
  2987. req.Header.Set("Content-Type", contentType)
  2988. rr = executeRequest(req)
  2989. checkResponseCode(t, http.StatusOK, rr.Code)
  2990. // test invalid s3_concurrency
  2991. form.Set("s3_upload_part_size", strconv.FormatInt(user.FsConfig.S3Config.UploadPartSize, 10))
  2992. form.Set("s3_upload_concurrency", "a")
  2993. b, contentType, _ = getMultipartFormData(form, "", "")
  2994. req, _ = http.NewRequest(http.MethodPost, webUserPath+"/"+strconv.FormatInt(user.ID, 10), &b)
  2995. req.Header.Set("Content-Type", contentType)
  2996. rr = executeRequest(req)
  2997. checkResponseCode(t, http.StatusOK, rr.Code)
  2998. // now add the user
  2999. form.Set("s3_upload_concurrency", strconv.Itoa(user.FsConfig.S3Config.UploadConcurrency))
  3000. b, contentType, _ = getMultipartFormData(form, "", "")
  3001. req, _ = http.NewRequest(http.MethodPost, webUserPath+"/"+strconv.FormatInt(user.ID, 10), &b)
  3002. req.Header.Set("Content-Type", contentType)
  3003. rr = executeRequest(req)
  3004. checkResponseCode(t, http.StatusSeeOther, rr.Code)
  3005. req, _ = http.NewRequest(http.MethodGet, userPath+"?limit=1&offset=0&order=ASC&username="+user.Username, nil)
  3006. rr = executeRequest(req)
  3007. checkResponseCode(t, http.StatusOK, rr.Code)
  3008. var users []dataprovider.User
  3009. err = render.DecodeJSON(rr.Body, &users)
  3010. assert.NoError(t, err)
  3011. assert.Equal(t, 1, len(users))
  3012. updateUser := users[0]
  3013. assert.Equal(t, int64(1577836800000), updateUser.ExpirationDate)
  3014. assert.Equal(t, updateUser.FsConfig.S3Config.Bucket, user.FsConfig.S3Config.Bucket)
  3015. assert.Equal(t, updateUser.FsConfig.S3Config.Region, user.FsConfig.S3Config.Region)
  3016. assert.Equal(t, updateUser.FsConfig.S3Config.AccessKey, user.FsConfig.S3Config.AccessKey)
  3017. assert.Equal(t, updateUser.FsConfig.S3Config.StorageClass, user.FsConfig.S3Config.StorageClass)
  3018. assert.Equal(t, updateUser.FsConfig.S3Config.Endpoint, user.FsConfig.S3Config.Endpoint)
  3019. assert.Equal(t, updateUser.FsConfig.S3Config.KeyPrefix, user.FsConfig.S3Config.KeyPrefix)
  3020. assert.Equal(t, updateUser.FsConfig.S3Config.UploadPartSize, user.FsConfig.S3Config.UploadPartSize)
  3021. assert.Equal(t, updateUser.FsConfig.S3Config.UploadConcurrency, user.FsConfig.S3Config.UploadConcurrency)
  3022. assert.Equal(t, 2, len(updateUser.Filters.FileExtensions))
  3023. assert.Equal(t, kms.SecretStatusSecretBox, updateUser.FsConfig.S3Config.AccessSecret.GetStatus())
  3024. assert.NotEmpty(t, updateUser.FsConfig.S3Config.AccessSecret.GetPayload())
  3025. assert.Empty(t, updateUser.FsConfig.S3Config.AccessSecret.GetKey())
  3026. assert.Empty(t, updateUser.FsConfig.S3Config.AccessSecret.GetAdditionalData())
  3027. // now check that a redacted password is not saved
  3028. form.Set("s3_access_secret", "[**redacted**] ")
  3029. b, contentType, _ = getMultipartFormData(form, "", "")
  3030. req, _ = http.NewRequest(http.MethodPost, webUserPath+"/"+strconv.FormatInt(user.ID, 10), &b)
  3031. req.Header.Set("Content-Type", contentType)
  3032. rr = executeRequest(req)
  3033. checkResponseCode(t, http.StatusSeeOther, rr.Code)
  3034. req, _ = http.NewRequest(http.MethodGet, userPath+"?limit=1&offset=0&order=ASC&username="+user.Username, nil)
  3035. rr = executeRequest(req)
  3036. checkResponseCode(t, http.StatusOK, rr.Code)
  3037. users = nil
  3038. err = render.DecodeJSON(rr.Body, &users)
  3039. assert.NoError(t, err)
  3040. assert.Equal(t, 1, len(users))
  3041. lastUpdatedUser := users[0]
  3042. assert.Equal(t, kms.SecretStatusSecretBox, lastUpdatedUser.FsConfig.S3Config.AccessSecret.GetStatus())
  3043. assert.Equal(t, updateUser.FsConfig.S3Config.AccessSecret.GetPayload(), lastUpdatedUser.FsConfig.S3Config.AccessSecret.GetPayload())
  3044. assert.Empty(t, lastUpdatedUser.FsConfig.S3Config.AccessSecret.GetKey())
  3045. assert.Empty(t, lastUpdatedUser.FsConfig.S3Config.AccessSecret.GetAdditionalData())
  3046. // now clear credentials
  3047. form.Set("s3_access_key", "")
  3048. form.Set("s3_access_secret", "")
  3049. b, contentType, _ = getMultipartFormData(form, "", "")
  3050. req, _ = http.NewRequest(http.MethodPost, webUserPath+"/"+strconv.FormatInt(user.ID, 10), &b)
  3051. req.Header.Set("Content-Type", contentType)
  3052. rr = executeRequest(req)
  3053. checkResponseCode(t, http.StatusSeeOther, rr.Code)
  3054. req, _ = http.NewRequest(http.MethodGet, userPath+"?limit=1&offset=0&order=ASC&username="+user.Username, nil)
  3055. rr = executeRequest(req)
  3056. checkResponseCode(t, http.StatusOK, rr.Code)
  3057. users = nil
  3058. err = render.DecodeJSON(rr.Body, &users)
  3059. assert.NoError(t, err)
  3060. assert.Equal(t, 1, len(users))
  3061. assert.True(t, users[0].FsConfig.S3Config.AccessSecret.IsEmpty())
  3062. req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
  3063. rr = executeRequest(req)
  3064. checkResponseCode(t, http.StatusOK, rr.Code)
  3065. }
  3066. func TestWebUserGCSMock(t *testing.T) {
  3067. user := getTestUser()
  3068. userAsJSON := getUserAsJSON(t, user)
  3069. req, err := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
  3070. assert.NoError(t, err)
  3071. rr := executeRequest(req)
  3072. checkResponseCode(t, http.StatusOK, rr.Code)
  3073. err = render.DecodeJSON(rr.Body, &user)
  3074. assert.NoError(t, err)
  3075. credentialsFilePath := filepath.Join(os.TempDir(), "gcs.json")
  3076. err = createTestFile(credentialsFilePath, 0)
  3077. assert.NoError(t, err)
  3078. user.FsConfig.Provider = dataprovider.GCSFilesystemProvider
  3079. user.FsConfig.GCSConfig.Bucket = "test"
  3080. user.FsConfig.GCSConfig.KeyPrefix = "somedir/subdir/"
  3081. user.FsConfig.GCSConfig.StorageClass = "standard"
  3082. form := make(url.Values)
  3083. form.Set("username", user.Username)
  3084. form.Set("home_dir", user.HomeDir)
  3085. form.Set("uid", "0")
  3086. form.Set("gid", strconv.FormatInt(int64(user.GID), 10))
  3087. form.Set("max_sessions", strconv.FormatInt(int64(user.MaxSessions), 10))
  3088. form.Set("quota_size", strconv.FormatInt(user.QuotaSize, 10))
  3089. form.Set("quota_files", strconv.FormatInt(int64(user.QuotaFiles), 10))
  3090. form.Set("upload_bandwidth", "0")
  3091. form.Set("download_bandwidth", "0")
  3092. form.Set("permissions", "*")
  3093. form.Set("sub_dirs_permissions", "")
  3094. form.Set("status", strconv.Itoa(user.Status))
  3095. form.Set("expiration_date", "2020-01-01 00:00:00")
  3096. form.Set("allowed_ip", "")
  3097. form.Set("denied_ip", "")
  3098. form.Set("fs_provider", "2")
  3099. form.Set("gcs_bucket", user.FsConfig.GCSConfig.Bucket)
  3100. form.Set("gcs_storage_class", user.FsConfig.GCSConfig.StorageClass)
  3101. form.Set("gcs_key_prefix", user.FsConfig.GCSConfig.KeyPrefix)
  3102. form.Set("allowed_extensions", "/dir1::.jpg,.png")
  3103. form.Set("max_upload_file_size", "0")
  3104. b, contentType, _ := getMultipartFormData(form, "", "")
  3105. req, _ = http.NewRequest(http.MethodPost, webUserPath+"/"+strconv.FormatInt(user.ID, 10), &b)
  3106. req.Header.Set("Content-Type", contentType)
  3107. rr = executeRequest(req)
  3108. checkResponseCode(t, http.StatusOK, rr.Code)
  3109. b, contentType, _ = getMultipartFormData(form, "gcs_credential_file", credentialsFilePath)
  3110. req, _ = http.NewRequest(http.MethodPost, webUserPath+"/"+strconv.FormatInt(user.ID, 10), &b)
  3111. req.Header.Set("Content-Type", contentType)
  3112. rr = executeRequest(req)
  3113. checkResponseCode(t, http.StatusOK, rr.Code)
  3114. err = createTestFile(credentialsFilePath, 4096)
  3115. assert.NoError(t, err)
  3116. b, contentType, _ = getMultipartFormData(form, "gcs_credential_file", credentialsFilePath)
  3117. req, _ = http.NewRequest(http.MethodPost, webUserPath+"/"+strconv.FormatInt(user.ID, 10), &b)
  3118. req.Header.Set("Content-Type", contentType)
  3119. rr = executeRequest(req)
  3120. checkResponseCode(t, http.StatusSeeOther, rr.Code)
  3121. req, _ = http.NewRequest(http.MethodGet, userPath+"?limit=1&offset=0&order=ASC&username="+user.Username, nil)
  3122. rr = executeRequest(req)
  3123. checkResponseCode(t, http.StatusOK, rr.Code)
  3124. var users []dataprovider.User
  3125. err = render.DecodeJSON(rr.Body, &users)
  3126. assert.NoError(t, err)
  3127. assert.Equal(t, 1, len(users))
  3128. updateUser := users[0]
  3129. assert.Equal(t, int64(1577836800000), updateUser.ExpirationDate)
  3130. assert.Equal(t, user.FsConfig.Provider, updateUser.FsConfig.Provider)
  3131. assert.Equal(t, user.FsConfig.GCSConfig.Bucket, updateUser.FsConfig.GCSConfig.Bucket)
  3132. assert.Equal(t, user.FsConfig.GCSConfig.StorageClass, updateUser.FsConfig.GCSConfig.StorageClass)
  3133. assert.Equal(t, user.FsConfig.GCSConfig.KeyPrefix, updateUser.FsConfig.GCSConfig.KeyPrefix)
  3134. assert.Equal(t, "/dir1", updateUser.Filters.FileExtensions[0].Path)
  3135. form.Set("gcs_auto_credentials", "on")
  3136. b, contentType, _ = getMultipartFormData(form, "", "")
  3137. req, _ = http.NewRequest(http.MethodPost, webUserPath+"/"+strconv.FormatInt(user.ID, 10), &b)
  3138. req.Header.Set("Content-Type", contentType)
  3139. rr = executeRequest(req)
  3140. checkResponseCode(t, http.StatusSeeOther, rr.Code)
  3141. req, _ = http.NewRequest(http.MethodGet, userPath+"?limit=1&offset=0&order=ASC&username="+user.Username, nil)
  3142. rr = executeRequest(req)
  3143. checkResponseCode(t, http.StatusOK, rr.Code)
  3144. err = render.DecodeJSON(rr.Body, &users)
  3145. assert.NoError(t, err)
  3146. assert.Equal(t, 1, len(users))
  3147. updateUser = users[0]
  3148. assert.Equal(t, 1, updateUser.FsConfig.GCSConfig.AutomaticCredentials)
  3149. req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
  3150. rr = executeRequest(req)
  3151. checkResponseCode(t, http.StatusOK, rr.Code)
  3152. err = os.Remove(credentialsFilePath)
  3153. assert.NoError(t, err)
  3154. }
  3155. func TestWebUserAzureBlobMock(t *testing.T) {
  3156. user := getTestUser()
  3157. userAsJSON := getUserAsJSON(t, user)
  3158. req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
  3159. rr := executeRequest(req)
  3160. checkResponseCode(t, http.StatusOK, rr.Code)
  3161. err := render.DecodeJSON(rr.Body, &user)
  3162. assert.NoError(t, err)
  3163. user.FsConfig.Provider = dataprovider.AzureBlobFilesystemProvider
  3164. user.FsConfig.AzBlobConfig.Container = "container"
  3165. user.FsConfig.AzBlobConfig.AccountName = "aname"
  3166. user.FsConfig.AzBlobConfig.AccountKey = kms.NewPlainSecret("access-skey")
  3167. user.FsConfig.AzBlobConfig.Endpoint = "http://127.0.0.1:9000/path?b=c"
  3168. user.FsConfig.AzBlobConfig.KeyPrefix = "somedir/subdir/"
  3169. user.FsConfig.AzBlobConfig.UploadPartSize = 5
  3170. user.FsConfig.AzBlobConfig.UploadConcurrency = 4
  3171. user.FsConfig.AzBlobConfig.UseEmulator = true
  3172. form := make(url.Values)
  3173. form.Set("username", user.Username)
  3174. form.Set("home_dir", user.HomeDir)
  3175. form.Set("uid", "0")
  3176. form.Set("gid", strconv.FormatInt(int64(user.GID), 10))
  3177. form.Set("max_sessions", strconv.FormatInt(int64(user.MaxSessions), 10))
  3178. form.Set("quota_size", strconv.FormatInt(user.QuotaSize, 10))
  3179. form.Set("quota_files", strconv.FormatInt(int64(user.QuotaFiles), 10))
  3180. form.Set("upload_bandwidth", "0")
  3181. form.Set("download_bandwidth", "0")
  3182. form.Set("permissions", "*")
  3183. form.Set("sub_dirs_permissions", "")
  3184. form.Set("status", strconv.Itoa(user.Status))
  3185. form.Set("expiration_date", "2020-01-01 00:00:00")
  3186. form.Set("allowed_ip", "")
  3187. form.Set("denied_ip", "")
  3188. form.Set("fs_provider", "3")
  3189. form.Set("az_container", user.FsConfig.AzBlobConfig.Container)
  3190. form.Set("az_account_name", user.FsConfig.AzBlobConfig.AccountName)
  3191. form.Set("az_account_key", user.FsConfig.AzBlobConfig.AccountKey.GetPayload())
  3192. form.Set("az_sas_url", user.FsConfig.AzBlobConfig.SASURL)
  3193. form.Set("az_endpoint", user.FsConfig.AzBlobConfig.Endpoint)
  3194. form.Set("az_key_prefix", user.FsConfig.AzBlobConfig.KeyPrefix)
  3195. form.Set("az_use_emulator", "checked")
  3196. form.Set("allowed_extensions", "/dir1::.jpg,.png")
  3197. form.Set("denied_extensions", "/dir2::.zip")
  3198. form.Set("max_upload_file_size", "0")
  3199. // test invalid az_upload_part_size
  3200. form.Set("az_upload_part_size", "a")
  3201. b, contentType, _ := getMultipartFormData(form, "", "")
  3202. req, _ = http.NewRequest(http.MethodPost, webUserPath+"/"+strconv.FormatInt(user.ID, 10), &b)
  3203. req.Header.Set("Content-Type", contentType)
  3204. rr = executeRequest(req)
  3205. checkResponseCode(t, http.StatusOK, rr.Code)
  3206. // test invalid az_upload_concurrency
  3207. form.Set("az_upload_part_size", strconv.FormatInt(user.FsConfig.AzBlobConfig.UploadPartSize, 10))
  3208. form.Set("az_upload_concurrency", "a")
  3209. b, contentType, _ = getMultipartFormData(form, "", "")
  3210. req, _ = http.NewRequest(http.MethodPost, webUserPath+"/"+strconv.FormatInt(user.ID, 10), &b)
  3211. req.Header.Set("Content-Type", contentType)
  3212. rr = executeRequest(req)
  3213. checkResponseCode(t, http.StatusOK, rr.Code)
  3214. // now add the user
  3215. form.Set("az_upload_concurrency", strconv.Itoa(user.FsConfig.AzBlobConfig.UploadConcurrency))
  3216. b, contentType, _ = getMultipartFormData(form, "", "")
  3217. req, _ = http.NewRequest(http.MethodPost, webUserPath+"/"+strconv.FormatInt(user.ID, 10), &b)
  3218. req.Header.Set("Content-Type", contentType)
  3219. rr = executeRequest(req)
  3220. checkResponseCode(t, http.StatusSeeOther, rr.Code)
  3221. req, _ = http.NewRequest(http.MethodGet, userPath+"?limit=1&offset=0&order=ASC&username="+user.Username, nil)
  3222. rr = executeRequest(req)
  3223. checkResponseCode(t, http.StatusOK, rr.Code)
  3224. var users []dataprovider.User
  3225. err = render.DecodeJSON(rr.Body, &users)
  3226. assert.NoError(t, err)
  3227. assert.Equal(t, 1, len(users))
  3228. updateUser := users[0]
  3229. assert.Equal(t, int64(1577836800000), updateUser.ExpirationDate)
  3230. assert.Equal(t, updateUser.FsConfig.AzBlobConfig.Container, user.FsConfig.AzBlobConfig.Container)
  3231. assert.Equal(t, updateUser.FsConfig.AzBlobConfig.AccountName, user.FsConfig.AzBlobConfig.AccountName)
  3232. assert.Equal(t, updateUser.FsConfig.AzBlobConfig.Endpoint, user.FsConfig.AzBlobConfig.Endpoint)
  3233. assert.Equal(t, updateUser.FsConfig.AzBlobConfig.SASURL, user.FsConfig.AzBlobConfig.SASURL)
  3234. assert.Equal(t, updateUser.FsConfig.AzBlobConfig.KeyPrefix, user.FsConfig.AzBlobConfig.KeyPrefix)
  3235. assert.Equal(t, updateUser.FsConfig.AzBlobConfig.UploadPartSize, user.FsConfig.AzBlobConfig.UploadPartSize)
  3236. assert.Equal(t, updateUser.FsConfig.AzBlobConfig.UploadConcurrency, user.FsConfig.AzBlobConfig.UploadConcurrency)
  3237. assert.Equal(t, 2, len(updateUser.Filters.FileExtensions))
  3238. assert.Equal(t, kms.SecretStatusSecretBox, updateUser.FsConfig.AzBlobConfig.AccountKey.GetStatus())
  3239. assert.NotEmpty(t, updateUser.FsConfig.AzBlobConfig.AccountKey.GetPayload())
  3240. assert.Empty(t, updateUser.FsConfig.AzBlobConfig.AccountKey.GetKey())
  3241. assert.Empty(t, updateUser.FsConfig.AzBlobConfig.AccountKey.GetAdditionalData())
  3242. // now check that a redacted password is not saved
  3243. form.Set("az_account_key", "[**redacted**] ")
  3244. b, contentType, _ = getMultipartFormData(form, "", "")
  3245. req, _ = http.NewRequest(http.MethodPost, webUserPath+"/"+strconv.FormatInt(user.ID, 10), &b)
  3246. req.Header.Set("Content-Type", contentType)
  3247. rr = executeRequest(req)
  3248. checkResponseCode(t, http.StatusSeeOther, rr.Code)
  3249. req, _ = http.NewRequest(http.MethodGet, userPath+"?limit=1&offset=0&order=ASC&username="+user.Username, nil)
  3250. rr = executeRequest(req)
  3251. checkResponseCode(t, http.StatusOK, rr.Code)
  3252. users = nil
  3253. err = render.DecodeJSON(rr.Body, &users)
  3254. assert.NoError(t, err)
  3255. assert.Equal(t, 1, len(users))
  3256. lastUpdatedUser := users[0]
  3257. assert.Equal(t, kms.SecretStatusSecretBox, lastUpdatedUser.FsConfig.AzBlobConfig.AccountKey.GetStatus())
  3258. assert.Equal(t, updateUser.FsConfig.AzBlobConfig.AccountKey.GetPayload(), lastUpdatedUser.FsConfig.AzBlobConfig.AccountKey.GetPayload())
  3259. assert.Empty(t, lastUpdatedUser.FsConfig.AzBlobConfig.AccountKey.GetKey())
  3260. assert.Empty(t, lastUpdatedUser.FsConfig.AzBlobConfig.AccountKey.GetAdditionalData())
  3261. req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
  3262. rr = executeRequest(req)
  3263. checkResponseCode(t, http.StatusOK, rr.Code)
  3264. }
  3265. func TestAddWebFoldersMock(t *testing.T) {
  3266. mappedPath := filepath.Clean(os.TempDir())
  3267. form := make(url.Values)
  3268. form.Set("mapped_path", mappedPath)
  3269. req, err := http.NewRequest(http.MethodPost, webFolderPath, strings.NewReader(form.Encode()))
  3270. assert.NoError(t, err)
  3271. req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
  3272. rr := executeRequest(req)
  3273. checkResponseCode(t, http.StatusSeeOther, rr.Code)
  3274. // adding the same folder will fail since the path must be unique
  3275. req, err = http.NewRequest(http.MethodPost, webFolderPath, strings.NewReader(form.Encode()))
  3276. assert.NoError(t, err)
  3277. req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
  3278. rr = executeRequest(req)
  3279. checkResponseCode(t, http.StatusOK, rr.Code)
  3280. // invalid form
  3281. req, err = http.NewRequest(http.MethodPost, webFolderPath, strings.NewReader(form.Encode()))
  3282. assert.NoError(t, err)
  3283. req.Header.Set("Content-Type", "text/plain; boundary=")
  3284. rr = executeRequest(req)
  3285. checkResponseCode(t, http.StatusOK, rr.Code)
  3286. // now render the add folder page
  3287. req, err = http.NewRequest(http.MethodGet, webFolderPath, nil)
  3288. assert.NoError(t, err)
  3289. rr = executeRequest(req)
  3290. checkResponseCode(t, http.StatusOK, rr.Code)
  3291. var folders []vfs.BaseVirtualFolder
  3292. url, err := url.Parse(folderPath)
  3293. assert.NoError(t, err)
  3294. q := url.Query()
  3295. q.Add("folder_path", mappedPath)
  3296. url.RawQuery = q.Encode()
  3297. req, _ = http.NewRequest(http.MethodGet, url.String(), nil)
  3298. rr = executeRequest(req)
  3299. checkResponseCode(t, http.StatusOK, rr.Code)
  3300. err = render.DecodeJSON(rr.Body, &folders)
  3301. assert.NoError(t, err)
  3302. if assert.Len(t, folders, 1) {
  3303. folder := folders[0]
  3304. assert.Equal(t, mappedPath, folder.MappedPath)
  3305. }
  3306. // cleanup
  3307. url, err = url.Parse(folderPath)
  3308. assert.NoError(t, err)
  3309. q = url.Query()
  3310. q.Add("folder_path", mappedPath)
  3311. url.RawQuery = q.Encode()
  3312. req, _ = http.NewRequest(http.MethodDelete, url.String(), nil)
  3313. rr = executeRequest(req)
  3314. checkResponseCode(t, http.StatusOK, rr.Code)
  3315. }
  3316. func TestWebFoldersMock(t *testing.T) {
  3317. mappedPath1 := filepath.Join(os.TempDir(), "vfolder1")
  3318. mappedPath2 := filepath.Join(os.TempDir(), "vfolder2")
  3319. folders := []vfs.BaseVirtualFolder{
  3320. {
  3321. MappedPath: mappedPath1,
  3322. },
  3323. {
  3324. MappedPath: mappedPath2,
  3325. },
  3326. }
  3327. for _, folder := range folders {
  3328. folderAsJSON, err := json.Marshal(folder)
  3329. assert.NoError(t, err)
  3330. req, _ := http.NewRequest(http.MethodPost, folderPath, bytes.NewBuffer(folderAsJSON))
  3331. rr := executeRequest(req)
  3332. checkResponseCode(t, http.StatusOK, rr.Code)
  3333. }
  3334. req, err := http.NewRequest(http.MethodGet, webFoldersPath, nil)
  3335. assert.NoError(t, err)
  3336. rr := executeRequest(req)
  3337. checkResponseCode(t, http.StatusOK, rr.Code)
  3338. req, err = http.NewRequest(http.MethodGet, webFoldersPath+"?qlimit=a", nil)
  3339. assert.NoError(t, err)
  3340. rr = executeRequest(req)
  3341. checkResponseCode(t, http.StatusOK, rr.Code)
  3342. req, err = http.NewRequest(http.MethodGet, webFoldersPath+"?qlimit=1", nil)
  3343. assert.NoError(t, err)
  3344. rr = executeRequest(req)
  3345. checkResponseCode(t, http.StatusOK, rr.Code)
  3346. for _, folder := range folders {
  3347. url, err := url.Parse(folderPath)
  3348. assert.NoError(t, err)
  3349. q := url.Query()
  3350. q.Add("folder_path", folder.MappedPath)
  3351. url.RawQuery = q.Encode()
  3352. req, _ := http.NewRequest(http.MethodDelete, url.String(), nil)
  3353. rr := executeRequest(req)
  3354. checkResponseCode(t, http.StatusOK, rr.Code)
  3355. }
  3356. }
  3357. func TestProviderClosedMock(t *testing.T) {
  3358. dataprovider.Close()
  3359. req, _ := http.NewRequest(http.MethodGet, webFoldersPath, nil)
  3360. rr := executeRequest(req)
  3361. checkResponseCode(t, http.StatusInternalServerError, rr.Code)
  3362. req, _ = http.NewRequest(http.MethodGet, webUsersPath, nil)
  3363. rr = executeRequest(req)
  3364. checkResponseCode(t, http.StatusInternalServerError, rr.Code)
  3365. req, _ = http.NewRequest(http.MethodGet, webUserPath+"/0", nil)
  3366. rr = executeRequest(req)
  3367. checkResponseCode(t, http.StatusInternalServerError, rr.Code)
  3368. form := make(url.Values)
  3369. form.Set("username", "test")
  3370. req, _ = http.NewRequest(http.MethodPost, webUserPath+"/0", strings.NewReader(form.Encode()))
  3371. rr = executeRequest(req)
  3372. checkResponseCode(t, http.StatusInternalServerError, rr.Code)
  3373. err := config.LoadConfig(configDir, "")
  3374. assert.NoError(t, err)
  3375. providerConf := config.GetProviderConf()
  3376. providerConf.CredentialsPath = credentialsPath
  3377. err = os.RemoveAll(credentialsPath)
  3378. assert.NoError(t, err)
  3379. err = dataprovider.Initialize(providerConf, configDir)
  3380. assert.NoError(t, err)
  3381. }
  3382. func TestGetWebConnectionsMock(t *testing.T) {
  3383. req, _ := http.NewRequest(http.MethodGet, webConnectionsPath, nil)
  3384. rr := executeRequest(req)
  3385. checkResponseCode(t, http.StatusOK, rr.Code)
  3386. }
  3387. func TestStaticFilesMock(t *testing.T) {
  3388. req, _ := http.NewRequest(http.MethodGet, "/static/favicon.ico", nil)
  3389. rr := executeRequest(req)
  3390. checkResponseCode(t, http.StatusOK, rr.Code)
  3391. }
  3392. func waitTCPListening(address string) {
  3393. for {
  3394. conn, err := net.Dial("tcp", address)
  3395. if err != nil {
  3396. logger.WarnToConsole("tcp server %v not listening: %v\n", address, err)
  3397. time.Sleep(100 * time.Millisecond)
  3398. continue
  3399. }
  3400. logger.InfoToConsole("tcp server %v now listening\n", address)
  3401. conn.Close()
  3402. break
  3403. }
  3404. }
  3405. func getTestUser() dataprovider.User {
  3406. user := dataprovider.User{
  3407. Username: defaultUsername,
  3408. Password: defaultPassword,
  3409. HomeDir: filepath.Join(homeBasePath, defaultUsername),
  3410. Status: 1,
  3411. }
  3412. user.Permissions = make(map[string][]string)
  3413. user.Permissions["/"] = defaultPerms
  3414. return user
  3415. }
  3416. func getUserAsJSON(t *testing.T, user dataprovider.User) []byte {
  3417. json, err := json.Marshal(user)
  3418. assert.NoError(t, err)
  3419. return json
  3420. }
  3421. func executeRequest(req *http.Request) *httptest.ResponseRecorder {
  3422. rr := httptest.NewRecorder()
  3423. testServer.Config.Handler.ServeHTTP(rr, req)
  3424. return rr
  3425. }
  3426. func checkResponseCode(t *testing.T, expected, actual int) {
  3427. assert.Equal(t, expected, actual)
  3428. }
  3429. func createTestFile(path string, size int64) error {
  3430. baseDir := filepath.Dir(path)
  3431. if _, err := os.Stat(baseDir); os.IsNotExist(err) {
  3432. err = os.MkdirAll(baseDir, os.ModePerm)
  3433. if err != nil {
  3434. return err
  3435. }
  3436. }
  3437. content := make([]byte, size)
  3438. if size > 0 {
  3439. _, err := rand.Read(content)
  3440. if err != nil {
  3441. return err
  3442. }
  3443. }
  3444. return ioutil.WriteFile(path, content, os.ModePerm)
  3445. }
  3446. func getMultipartFormData(values url.Values, fileFieldName, filePath string) (bytes.Buffer, string, error) {
  3447. var b bytes.Buffer
  3448. w := multipart.NewWriter(&b)
  3449. for k, v := range values {
  3450. for _, s := range v {
  3451. if err := w.WriteField(k, s); err != nil {
  3452. return b, "", err
  3453. }
  3454. }
  3455. }
  3456. if len(fileFieldName) > 0 && len(filePath) > 0 {
  3457. fw, err := w.CreateFormFile(fileFieldName, filepath.Base(filePath))
  3458. if err != nil {
  3459. return b, "", err
  3460. }
  3461. f, err := os.Open(filePath)
  3462. if err != nil {
  3463. return b, "", err
  3464. }
  3465. defer f.Close()
  3466. if _, err = io.Copy(fw, f); err != nil {
  3467. return b, "", err
  3468. }
  3469. }
  3470. err := w.Close()
  3471. return b, w.FormDataContentType(), err
  3472. }
  3473. func BenchmarkSecretDecryption(b *testing.B) {
  3474. s := kms.NewPlainSecret("test data")
  3475. s.SetAdditionalData("username")
  3476. err := s.Encrypt()
  3477. require.NoError(b, err)
  3478. for i := 0; i < b.N; i++ {
  3479. err = s.Clone().Decrypt()
  3480. require.NoError(b, err)
  3481. }
  3482. }