httpdtest.go 57 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721
  1. // Package httpdtest provides utilities for testing the exposed REST API.
  2. package httpdtest
  3. import (
  4. "bytes"
  5. "encoding/hex"
  6. "encoding/json"
  7. "errors"
  8. "fmt"
  9. "io"
  10. "net/http"
  11. "net/url"
  12. "path"
  13. "strconv"
  14. "strings"
  15. "github.com/go-chi/render"
  16. "github.com/drakkan/sftpgo/v2/common"
  17. "github.com/drakkan/sftpgo/v2/dataprovider"
  18. "github.com/drakkan/sftpgo/v2/httpclient"
  19. "github.com/drakkan/sftpgo/v2/httpd"
  20. "github.com/drakkan/sftpgo/v2/kms"
  21. "github.com/drakkan/sftpgo/v2/util"
  22. "github.com/drakkan/sftpgo/v2/version"
  23. "github.com/drakkan/sftpgo/v2/vfs"
  24. )
  25. const (
  26. tokenPath = "/api/v2/token"
  27. activeConnectionsPath = "/api/v2/connections"
  28. quotasBasePath = "/api/v2/quotas"
  29. quotaScanPath = "/api/v2/quotas/users/scans"
  30. quotaScanVFolderPath = "/api/v2/quotas/folders/scans"
  31. userPath = "/api/v2/users"
  32. versionPath = "/api/v2/version"
  33. folderPath = "/api/v2/folders"
  34. serverStatusPath = "/api/v2/status"
  35. dumpDataPath = "/api/v2/dumpdata"
  36. loadDataPath = "/api/v2/loaddata"
  37. defenderHosts = "/api/v2/defender/hosts"
  38. defenderBanTime = "/api/v2/defender/bantime"
  39. defenderUnban = "/api/v2/defender/unban"
  40. defenderScore = "/api/v2/defender/score"
  41. adminPath = "/api/v2/admins"
  42. adminPwdPath = "/api/v2/admin/changepwd"
  43. apiKeysPath = "/api/v2/apikeys"
  44. retentionBasePath = "/api/v2/retention/users"
  45. retentionChecksPath = "/api/v2/retention/users/checks"
  46. )
  47. const (
  48. defaultTokenAuthUser = "admin"
  49. defaultTokenAuthPass = "password"
  50. )
  51. var (
  52. httpBaseURL = "http://127.0.0.1:8080"
  53. jwtToken = ""
  54. )
  55. // SetBaseURL sets the base url to use for HTTP requests.
  56. // Default URL is "http://127.0.0.1:8080"
  57. func SetBaseURL(url string) {
  58. httpBaseURL = url
  59. }
  60. // SetJWTToken sets the JWT token to use
  61. func SetJWTToken(token string) {
  62. jwtToken = token
  63. }
  64. func sendHTTPRequest(method, url string, body io.Reader, contentType, token string) (*http.Response, error) {
  65. req, err := http.NewRequest(method, url, body)
  66. if err != nil {
  67. return nil, err
  68. }
  69. if contentType != "" {
  70. req.Header.Set("Content-Type", "application/json")
  71. }
  72. if token != "" {
  73. req.Header.Set("Authorization", fmt.Sprintf("Bearer %v", token))
  74. }
  75. return httpclient.GetHTTPClient().Do(req)
  76. }
  77. func buildURLRelativeToBase(paths ...string) string {
  78. // we need to use path.Join and not filepath.Join
  79. // since filepath.Join will use backslash separator on Windows
  80. p := path.Join(paths...)
  81. return fmt.Sprintf("%s/%s", strings.TrimRight(httpBaseURL, "/"), strings.TrimLeft(p, "/"))
  82. }
  83. // GetToken tries to return a JWT token
  84. func GetToken(username, password string) (string, map[string]interface{}, error) {
  85. req, err := http.NewRequest(http.MethodGet, buildURLRelativeToBase(tokenPath), nil)
  86. if err != nil {
  87. return "", nil, err
  88. }
  89. req.SetBasicAuth(username, password)
  90. resp, err := httpclient.GetHTTPClient().Do(req)
  91. if err != nil {
  92. return "", nil, err
  93. }
  94. defer resp.Body.Close()
  95. err = checkResponse(resp.StatusCode, http.StatusOK)
  96. if err != nil {
  97. return "", nil, err
  98. }
  99. responseHolder := make(map[string]interface{})
  100. err = render.DecodeJSON(resp.Body, &responseHolder)
  101. if err != nil {
  102. return "", nil, err
  103. }
  104. return responseHolder["access_token"].(string), responseHolder, nil
  105. }
  106. func getDefaultToken() string {
  107. if jwtToken != "" {
  108. return jwtToken
  109. }
  110. token, _, err := GetToken(defaultTokenAuthUser, defaultTokenAuthPass)
  111. if err != nil {
  112. return ""
  113. }
  114. return token
  115. }
  116. // AddUser adds a new user and checks the received HTTP Status code against expectedStatusCode.
  117. func AddUser(user dataprovider.User, expectedStatusCode int) (dataprovider.User, []byte, error) {
  118. var newUser dataprovider.User
  119. var body []byte
  120. userAsJSON, _ := json.Marshal(user)
  121. resp, err := sendHTTPRequest(http.MethodPost, buildURLRelativeToBase(userPath), bytes.NewBuffer(userAsJSON),
  122. "application/json", getDefaultToken())
  123. if err != nil {
  124. return newUser, body, err
  125. }
  126. defer resp.Body.Close()
  127. err = checkResponse(resp.StatusCode, expectedStatusCode)
  128. if expectedStatusCode != http.StatusCreated {
  129. body, _ = getResponseBody(resp)
  130. return newUser, body, err
  131. }
  132. if err == nil {
  133. err = render.DecodeJSON(resp.Body, &newUser)
  134. } else {
  135. body, _ = getResponseBody(resp)
  136. }
  137. if err == nil {
  138. err = checkUser(&user, &newUser)
  139. }
  140. return newUser, body, err
  141. }
  142. // UpdateUserWithJSON update a user using the provided JSON as POST body
  143. func UpdateUserWithJSON(user dataprovider.User, expectedStatusCode int, disconnect string, userAsJSON []byte) (dataprovider.User, []byte, error) {
  144. var newUser dataprovider.User
  145. var body []byte
  146. url, err := addDisconnectQueryParam(buildURLRelativeToBase(userPath, url.PathEscape(user.Username)), disconnect)
  147. if err != nil {
  148. return user, body, err
  149. }
  150. resp, err := sendHTTPRequest(http.MethodPut, url.String(), bytes.NewBuffer(userAsJSON), "application/json",
  151. getDefaultToken())
  152. if err != nil {
  153. return user, body, err
  154. }
  155. defer resp.Body.Close()
  156. body, _ = getResponseBody(resp)
  157. err = checkResponse(resp.StatusCode, expectedStatusCode)
  158. if expectedStatusCode != http.StatusOK {
  159. return newUser, body, err
  160. }
  161. if err == nil {
  162. newUser, body, err = GetUserByUsername(user.Username, expectedStatusCode)
  163. }
  164. if err == nil {
  165. err = checkUser(&user, &newUser)
  166. }
  167. return newUser, body, err
  168. }
  169. // UpdateUser updates an existing user and checks the received HTTP Status code against expectedStatusCode.
  170. func UpdateUser(user dataprovider.User, expectedStatusCode int, disconnect string) (dataprovider.User, []byte, error) {
  171. userAsJSON, _ := json.Marshal(user)
  172. return UpdateUserWithJSON(user, expectedStatusCode, disconnect, userAsJSON)
  173. }
  174. // RemoveUser removes an existing user and checks the received HTTP Status code against expectedStatusCode.
  175. func RemoveUser(user dataprovider.User, expectedStatusCode int) ([]byte, error) {
  176. var body []byte
  177. resp, err := sendHTTPRequest(http.MethodDelete, buildURLRelativeToBase(userPath, url.PathEscape(user.Username)),
  178. nil, "", getDefaultToken())
  179. if err != nil {
  180. return body, err
  181. }
  182. defer resp.Body.Close()
  183. body, _ = getResponseBody(resp)
  184. return body, checkResponse(resp.StatusCode, expectedStatusCode)
  185. }
  186. // GetUserByUsername gets a user by username and checks the received HTTP Status code against expectedStatusCode.
  187. func GetUserByUsername(username string, expectedStatusCode int) (dataprovider.User, []byte, error) {
  188. var user dataprovider.User
  189. var body []byte
  190. resp, err := sendHTTPRequest(http.MethodGet, buildURLRelativeToBase(userPath, url.PathEscape(username)),
  191. nil, "", getDefaultToken())
  192. if err != nil {
  193. return user, body, err
  194. }
  195. defer resp.Body.Close()
  196. err = checkResponse(resp.StatusCode, expectedStatusCode)
  197. if err == nil && expectedStatusCode == http.StatusOK {
  198. err = render.DecodeJSON(resp.Body, &user)
  199. } else {
  200. body, _ = getResponseBody(resp)
  201. }
  202. return user, body, err
  203. }
  204. // GetUsers returns a list of users and checks the received HTTP Status code against expectedStatusCode.
  205. // The number of results can be limited specifying a limit.
  206. // Some results can be skipped specifying an offset.
  207. func GetUsers(limit, offset int64, expectedStatusCode int) ([]dataprovider.User, []byte, error) {
  208. var users []dataprovider.User
  209. var body []byte
  210. url, err := addLimitAndOffsetQueryParams(buildURLRelativeToBase(userPath), limit, offset)
  211. if err != nil {
  212. return users, body, err
  213. }
  214. resp, err := sendHTTPRequest(http.MethodGet, url.String(), nil, "", getDefaultToken())
  215. if err != nil {
  216. return users, body, err
  217. }
  218. defer resp.Body.Close()
  219. err = checkResponse(resp.StatusCode, expectedStatusCode)
  220. if err == nil && expectedStatusCode == http.StatusOK {
  221. err = render.DecodeJSON(resp.Body, &users)
  222. } else {
  223. body, _ = getResponseBody(resp)
  224. }
  225. return users, body, err
  226. }
  227. // AddAdmin adds a new admin and checks the received HTTP Status code against expectedStatusCode.
  228. func AddAdmin(admin dataprovider.Admin, expectedStatusCode int) (dataprovider.Admin, []byte, error) {
  229. var newAdmin dataprovider.Admin
  230. var body []byte
  231. asJSON, _ := json.Marshal(admin)
  232. resp, err := sendHTTPRequest(http.MethodPost, buildURLRelativeToBase(adminPath), bytes.NewBuffer(asJSON),
  233. "application/json", getDefaultToken())
  234. if err != nil {
  235. return newAdmin, body, err
  236. }
  237. defer resp.Body.Close()
  238. err = checkResponse(resp.StatusCode, expectedStatusCode)
  239. if expectedStatusCode != http.StatusCreated {
  240. body, _ = getResponseBody(resp)
  241. return newAdmin, body, err
  242. }
  243. if err == nil {
  244. err = render.DecodeJSON(resp.Body, &newAdmin)
  245. } else {
  246. body, _ = getResponseBody(resp)
  247. }
  248. if err == nil {
  249. err = checkAdmin(&admin, &newAdmin)
  250. }
  251. return newAdmin, body, err
  252. }
  253. // UpdateAdmin updates an existing admin and checks the received HTTP Status code against expectedStatusCode
  254. func UpdateAdmin(admin dataprovider.Admin, expectedStatusCode int) (dataprovider.Admin, []byte, error) {
  255. var newAdmin dataprovider.Admin
  256. var body []byte
  257. asJSON, _ := json.Marshal(admin)
  258. resp, err := sendHTTPRequest(http.MethodPut, buildURLRelativeToBase(adminPath, url.PathEscape(admin.Username)),
  259. bytes.NewBuffer(asJSON), "application/json", getDefaultToken())
  260. if err != nil {
  261. return newAdmin, body, err
  262. }
  263. defer resp.Body.Close()
  264. body, _ = getResponseBody(resp)
  265. err = checkResponse(resp.StatusCode, expectedStatusCode)
  266. if expectedStatusCode != http.StatusOK {
  267. return newAdmin, body, err
  268. }
  269. if err == nil {
  270. newAdmin, body, err = GetAdminByUsername(admin.Username, expectedStatusCode)
  271. }
  272. if err == nil {
  273. err = checkAdmin(&admin, &newAdmin)
  274. }
  275. return newAdmin, body, err
  276. }
  277. // RemoveAdmin removes an existing admin and checks the received HTTP Status code against expectedStatusCode.
  278. func RemoveAdmin(admin dataprovider.Admin, expectedStatusCode int) ([]byte, error) {
  279. var body []byte
  280. resp, err := sendHTTPRequest(http.MethodDelete, buildURLRelativeToBase(adminPath, url.PathEscape(admin.Username)),
  281. nil, "", getDefaultToken())
  282. if err != nil {
  283. return body, err
  284. }
  285. defer resp.Body.Close()
  286. body, _ = getResponseBody(resp)
  287. return body, checkResponse(resp.StatusCode, expectedStatusCode)
  288. }
  289. // GetAdminByUsername gets an admin by username and checks the received HTTP Status code against expectedStatusCode.
  290. func GetAdminByUsername(username string, expectedStatusCode int) (dataprovider.Admin, []byte, error) {
  291. var admin dataprovider.Admin
  292. var body []byte
  293. resp, err := sendHTTPRequest(http.MethodGet, buildURLRelativeToBase(adminPath, url.PathEscape(username)),
  294. nil, "", getDefaultToken())
  295. if err != nil {
  296. return admin, body, err
  297. }
  298. defer resp.Body.Close()
  299. err = checkResponse(resp.StatusCode, expectedStatusCode)
  300. if err == nil && expectedStatusCode == http.StatusOK {
  301. err = render.DecodeJSON(resp.Body, &admin)
  302. } else {
  303. body, _ = getResponseBody(resp)
  304. }
  305. return admin, body, err
  306. }
  307. // GetAdmins returns a list of admins and checks the received HTTP Status code against expectedStatusCode.
  308. // The number of results can be limited specifying a limit.
  309. // Some results can be skipped specifying an offset.
  310. func GetAdmins(limit, offset int64, expectedStatusCode int) ([]dataprovider.Admin, []byte, error) {
  311. var admins []dataprovider.Admin
  312. var body []byte
  313. url, err := addLimitAndOffsetQueryParams(buildURLRelativeToBase(adminPath), limit, offset)
  314. if err != nil {
  315. return admins, body, err
  316. }
  317. resp, err := sendHTTPRequest(http.MethodGet, url.String(), nil, "", getDefaultToken())
  318. if err != nil {
  319. return admins, body, err
  320. }
  321. defer resp.Body.Close()
  322. err = checkResponse(resp.StatusCode, expectedStatusCode)
  323. if err == nil && expectedStatusCode == http.StatusOK {
  324. err = render.DecodeJSON(resp.Body, &admins)
  325. } else {
  326. body, _ = getResponseBody(resp)
  327. }
  328. return admins, body, err
  329. }
  330. // ChangeAdminPassword changes the password for an existing admin
  331. func ChangeAdminPassword(currentPassword, newPassword string, expectedStatusCode int) ([]byte, error) {
  332. var body []byte
  333. pwdChange := make(map[string]string)
  334. pwdChange["current_password"] = currentPassword
  335. pwdChange["new_password"] = newPassword
  336. asJSON, _ := json.Marshal(&pwdChange)
  337. resp, err := sendHTTPRequest(http.MethodPut, buildURLRelativeToBase(adminPwdPath),
  338. bytes.NewBuffer(asJSON), "application/json", getDefaultToken())
  339. if err != nil {
  340. return body, err
  341. }
  342. defer resp.Body.Close()
  343. err = checkResponse(resp.StatusCode, expectedStatusCode)
  344. body, _ = getResponseBody(resp)
  345. return body, err
  346. }
  347. // GetAPIKeys returns a list of API keys and checks the received HTTP Status code against expectedStatusCode.
  348. // The number of results can be limited specifying a limit.
  349. // Some results can be skipped specifying an offset.
  350. func GetAPIKeys(limit, offset int64, expectedStatusCode int) ([]dataprovider.APIKey, []byte, error) {
  351. var apiKeys []dataprovider.APIKey
  352. var body []byte
  353. url, err := addLimitAndOffsetQueryParams(buildURLRelativeToBase(apiKeysPath), limit, offset)
  354. if err != nil {
  355. return apiKeys, body, err
  356. }
  357. resp, err := sendHTTPRequest(http.MethodGet, url.String(), nil, "", getDefaultToken())
  358. if err != nil {
  359. return apiKeys, body, err
  360. }
  361. defer resp.Body.Close()
  362. err = checkResponse(resp.StatusCode, expectedStatusCode)
  363. if err == nil && expectedStatusCode == http.StatusOK {
  364. err = render.DecodeJSON(resp.Body, &apiKeys)
  365. } else {
  366. body, _ = getResponseBody(resp)
  367. }
  368. return apiKeys, body, err
  369. }
  370. // AddAPIKey adds a new API key and checks the received HTTP Status code against expectedStatusCode.
  371. func AddAPIKey(apiKey dataprovider.APIKey, expectedStatusCode int) (dataprovider.APIKey, []byte, error) {
  372. var newAPIKey dataprovider.APIKey
  373. var body []byte
  374. asJSON, _ := json.Marshal(apiKey)
  375. resp, err := sendHTTPRequest(http.MethodPost, buildURLRelativeToBase(apiKeysPath), bytes.NewBuffer(asJSON),
  376. "application/json", getDefaultToken())
  377. if err != nil {
  378. return newAPIKey, body, err
  379. }
  380. defer resp.Body.Close()
  381. err = checkResponse(resp.StatusCode, expectedStatusCode)
  382. if expectedStatusCode != http.StatusCreated {
  383. body, _ = getResponseBody(resp)
  384. return newAPIKey, body, err
  385. }
  386. if err != nil {
  387. body, _ = getResponseBody(resp)
  388. return newAPIKey, body, err
  389. }
  390. response := make(map[string]string)
  391. err = render.DecodeJSON(resp.Body, &response)
  392. if err == nil {
  393. newAPIKey, body, err = GetAPIKeyByID(resp.Header.Get("X-Object-ID"), http.StatusOK)
  394. }
  395. if err == nil {
  396. err = checkAPIKey(&apiKey, &newAPIKey)
  397. }
  398. newAPIKey.Key = response["key"]
  399. return newAPIKey, body, err
  400. }
  401. // UpdateAPIKey updates an existing API key and checks the received HTTP Status code against expectedStatusCode
  402. func UpdateAPIKey(apiKey dataprovider.APIKey, expectedStatusCode int) (dataprovider.APIKey, []byte, error) {
  403. var newAPIKey dataprovider.APIKey
  404. var body []byte
  405. asJSON, _ := json.Marshal(apiKey)
  406. resp, err := sendHTTPRequest(http.MethodPut, buildURLRelativeToBase(apiKeysPath, url.PathEscape(apiKey.KeyID)),
  407. bytes.NewBuffer(asJSON), "application/json", getDefaultToken())
  408. if err != nil {
  409. return newAPIKey, body, err
  410. }
  411. defer resp.Body.Close()
  412. body, _ = getResponseBody(resp)
  413. err = checkResponse(resp.StatusCode, expectedStatusCode)
  414. if expectedStatusCode != http.StatusOK {
  415. return newAPIKey, body, err
  416. }
  417. if err == nil {
  418. newAPIKey, body, err = GetAPIKeyByID(apiKey.KeyID, expectedStatusCode)
  419. }
  420. if err == nil {
  421. err = checkAPIKey(&apiKey, &newAPIKey)
  422. }
  423. return newAPIKey, body, err
  424. }
  425. // RemoveAPIKey removes an existing API key and checks the received HTTP Status code against expectedStatusCode.
  426. func RemoveAPIKey(apiKey dataprovider.APIKey, expectedStatusCode int) ([]byte, error) {
  427. var body []byte
  428. resp, err := sendHTTPRequest(http.MethodDelete, buildURLRelativeToBase(apiKeysPath, url.PathEscape(apiKey.KeyID)),
  429. nil, "", getDefaultToken())
  430. if err != nil {
  431. return body, err
  432. }
  433. defer resp.Body.Close()
  434. body, _ = getResponseBody(resp)
  435. return body, checkResponse(resp.StatusCode, expectedStatusCode)
  436. }
  437. // GetAPIKeyByID gets a API key by ID and checks the received HTTP Status code against expectedStatusCode.
  438. func GetAPIKeyByID(keyID string, expectedStatusCode int) (dataprovider.APIKey, []byte, error) {
  439. var apiKey dataprovider.APIKey
  440. var body []byte
  441. resp, err := sendHTTPRequest(http.MethodGet, buildURLRelativeToBase(apiKeysPath, url.PathEscape(keyID)),
  442. nil, "", getDefaultToken())
  443. if err != nil {
  444. return apiKey, body, err
  445. }
  446. defer resp.Body.Close()
  447. err = checkResponse(resp.StatusCode, expectedStatusCode)
  448. if err == nil && expectedStatusCode == http.StatusOK {
  449. err = render.DecodeJSON(resp.Body, &apiKey)
  450. } else {
  451. body, _ = getResponseBody(resp)
  452. }
  453. return apiKey, body, err
  454. }
  455. // GetQuotaScans gets active quota scans for users and checks the received HTTP Status code against expectedStatusCode.
  456. func GetQuotaScans(expectedStatusCode int) ([]common.ActiveQuotaScan, []byte, error) {
  457. var quotaScans []common.ActiveQuotaScan
  458. var body []byte
  459. resp, err := sendHTTPRequest(http.MethodGet, buildURLRelativeToBase(quotaScanPath), nil, "", getDefaultToken())
  460. if err != nil {
  461. return quotaScans, body, err
  462. }
  463. defer resp.Body.Close()
  464. err = checkResponse(resp.StatusCode, expectedStatusCode)
  465. if err == nil && expectedStatusCode == http.StatusOK {
  466. err = render.DecodeJSON(resp.Body, &quotaScans)
  467. } else {
  468. body, _ = getResponseBody(resp)
  469. }
  470. return quotaScans, body, err
  471. }
  472. // StartQuotaScan starts a new quota scan for the given user and checks the received HTTP Status code against expectedStatusCode.
  473. func StartQuotaScan(user dataprovider.User, expectedStatusCode int) ([]byte, error) {
  474. var body []byte
  475. resp, err := sendHTTPRequest(http.MethodPost, buildURLRelativeToBase(quotasBasePath, "users", user.Username, "scan"),
  476. nil, "", getDefaultToken())
  477. if err != nil {
  478. return body, err
  479. }
  480. defer resp.Body.Close()
  481. body, _ = getResponseBody(resp)
  482. return body, checkResponse(resp.StatusCode, expectedStatusCode)
  483. }
  484. // UpdateQuotaUsage updates the user used quota limits and checks the received
  485. // HTTP Status code against expectedStatusCode.
  486. func UpdateQuotaUsage(user dataprovider.User, mode string, expectedStatusCode int) ([]byte, error) {
  487. var body []byte
  488. userAsJSON, _ := json.Marshal(user)
  489. url, err := addModeQueryParam(buildURLRelativeToBase(quotasBasePath, "users", user.Username, "usage"), mode)
  490. if err != nil {
  491. return body, err
  492. }
  493. resp, err := sendHTTPRequest(http.MethodPut, url.String(), bytes.NewBuffer(userAsJSON), "application/json",
  494. getDefaultToken())
  495. if err != nil {
  496. return body, err
  497. }
  498. defer resp.Body.Close()
  499. body, _ = getResponseBody(resp)
  500. return body, checkResponse(resp.StatusCode, expectedStatusCode)
  501. }
  502. // UpdateTransferQuotaUsage updates the user used transfer quota limits and checks the received
  503. // HTTP Status code against expectedStatusCode.
  504. func UpdateTransferQuotaUsage(user dataprovider.User, mode string, expectedStatusCode int) ([]byte, error) {
  505. var body []byte
  506. userAsJSON, _ := json.Marshal(user)
  507. url, err := addModeQueryParam(buildURLRelativeToBase(quotasBasePath, "users", user.Username, "transfer-usage"), mode)
  508. if err != nil {
  509. return body, err
  510. }
  511. resp, err := sendHTTPRequest(http.MethodPut, url.String(), bytes.NewBuffer(userAsJSON), "application/json",
  512. getDefaultToken())
  513. if err != nil {
  514. return body, err
  515. }
  516. defer resp.Body.Close()
  517. body, _ = getResponseBody(resp)
  518. return body, checkResponse(resp.StatusCode, expectedStatusCode)
  519. }
  520. // GetRetentionChecks returns the active retention checks
  521. func GetRetentionChecks(expectedStatusCode int) ([]common.ActiveRetentionChecks, []byte, error) {
  522. var checks []common.ActiveRetentionChecks
  523. var body []byte
  524. resp, err := sendHTTPRequest(http.MethodGet, buildURLRelativeToBase(retentionChecksPath), nil, "", getDefaultToken())
  525. if err != nil {
  526. return checks, body, err
  527. }
  528. defer resp.Body.Close()
  529. err = checkResponse(resp.StatusCode, expectedStatusCode)
  530. if err == nil && expectedStatusCode == http.StatusOK {
  531. err = render.DecodeJSON(resp.Body, &checks)
  532. } else {
  533. body, _ = getResponseBody(resp)
  534. }
  535. return checks, body, err
  536. }
  537. // StartRetentionCheck starts a new retention check
  538. func StartRetentionCheck(username string, retention []common.FolderRetention, expectedStatusCode int) ([]byte, error) {
  539. var body []byte
  540. asJSON, _ := json.Marshal(retention)
  541. resp, err := sendHTTPRequest(http.MethodPost, buildURLRelativeToBase(retentionBasePath, username, "check"),
  542. bytes.NewBuffer(asJSON), "application/json", getDefaultToken())
  543. if err != nil {
  544. return body, err
  545. }
  546. defer resp.Body.Close()
  547. body, _ = getResponseBody(resp)
  548. return body, checkResponse(resp.StatusCode, expectedStatusCode)
  549. }
  550. // GetConnections returns status and stats for active SFTP/SCP connections
  551. func GetConnections(expectedStatusCode int) ([]common.ConnectionStatus, []byte, error) {
  552. var connections []common.ConnectionStatus
  553. var body []byte
  554. resp, err := sendHTTPRequest(http.MethodGet, buildURLRelativeToBase(activeConnectionsPath), nil, "", getDefaultToken())
  555. if err != nil {
  556. return connections, body, err
  557. }
  558. defer resp.Body.Close()
  559. err = checkResponse(resp.StatusCode, expectedStatusCode)
  560. if err == nil && expectedStatusCode == http.StatusOK {
  561. err = render.DecodeJSON(resp.Body, &connections)
  562. } else {
  563. body, _ = getResponseBody(resp)
  564. }
  565. return connections, body, err
  566. }
  567. // CloseConnection closes an active connection identified by connectionID
  568. func CloseConnection(connectionID string, expectedStatusCode int) ([]byte, error) {
  569. var body []byte
  570. resp, err := sendHTTPRequest(http.MethodDelete, buildURLRelativeToBase(activeConnectionsPath, connectionID),
  571. nil, "", getDefaultToken())
  572. if err != nil {
  573. return body, err
  574. }
  575. defer resp.Body.Close()
  576. err = checkResponse(resp.StatusCode, expectedStatusCode)
  577. body, _ = getResponseBody(resp)
  578. return body, err
  579. }
  580. // AddFolder adds a new folder and checks the received HTTP Status code against expectedStatusCode
  581. func AddFolder(folder vfs.BaseVirtualFolder, expectedStatusCode int) (vfs.BaseVirtualFolder, []byte, error) {
  582. var newFolder vfs.BaseVirtualFolder
  583. var body []byte
  584. folderAsJSON, _ := json.Marshal(folder)
  585. resp, err := sendHTTPRequest(http.MethodPost, buildURLRelativeToBase(folderPath), bytes.NewBuffer(folderAsJSON),
  586. "application/json", getDefaultToken())
  587. if err != nil {
  588. return newFolder, body, err
  589. }
  590. defer resp.Body.Close()
  591. err = checkResponse(resp.StatusCode, expectedStatusCode)
  592. if expectedStatusCode != http.StatusCreated {
  593. body, _ = getResponseBody(resp)
  594. return newFolder, body, err
  595. }
  596. if err == nil {
  597. err = render.DecodeJSON(resp.Body, &newFolder)
  598. } else {
  599. body, _ = getResponseBody(resp)
  600. }
  601. if err == nil {
  602. err = checkFolder(&folder, &newFolder)
  603. }
  604. return newFolder, body, err
  605. }
  606. // UpdateFolder updates an existing folder and checks the received HTTP Status code against expectedStatusCode.
  607. func UpdateFolder(folder vfs.BaseVirtualFolder, expectedStatusCode int) (vfs.BaseVirtualFolder, []byte, error) {
  608. var updatedFolder vfs.BaseVirtualFolder
  609. var body []byte
  610. folderAsJSON, _ := json.Marshal(folder)
  611. resp, err := sendHTTPRequest(http.MethodPut, buildURLRelativeToBase(folderPath, url.PathEscape(folder.Name)),
  612. bytes.NewBuffer(folderAsJSON), "application/json", getDefaultToken())
  613. if err != nil {
  614. return updatedFolder, body, err
  615. }
  616. defer resp.Body.Close()
  617. body, _ = getResponseBody(resp)
  618. err = checkResponse(resp.StatusCode, expectedStatusCode)
  619. if expectedStatusCode != http.StatusOK {
  620. return updatedFolder, body, err
  621. }
  622. if err == nil {
  623. updatedFolder, body, err = GetFolderByName(folder.Name, expectedStatusCode)
  624. }
  625. if err == nil {
  626. err = checkFolder(&folder, &updatedFolder)
  627. }
  628. return updatedFolder, body, err
  629. }
  630. // RemoveFolder removes an existing user and checks the received HTTP Status code against expectedStatusCode.
  631. func RemoveFolder(folder vfs.BaseVirtualFolder, expectedStatusCode int) ([]byte, error) {
  632. var body []byte
  633. resp, err := sendHTTPRequest(http.MethodDelete, buildURLRelativeToBase(folderPath, url.PathEscape(folder.Name)),
  634. nil, "", getDefaultToken())
  635. if err != nil {
  636. return body, err
  637. }
  638. defer resp.Body.Close()
  639. body, _ = getResponseBody(resp)
  640. return body, checkResponse(resp.StatusCode, expectedStatusCode)
  641. }
  642. // GetFolderByName gets a folder by name and checks the received HTTP Status code against expectedStatusCode.
  643. func GetFolderByName(name string, expectedStatusCode int) (vfs.BaseVirtualFolder, []byte, error) {
  644. var folder vfs.BaseVirtualFolder
  645. var body []byte
  646. resp, err := sendHTTPRequest(http.MethodGet, buildURLRelativeToBase(folderPath, url.PathEscape(name)),
  647. nil, "", getDefaultToken())
  648. if err != nil {
  649. return folder, body, err
  650. }
  651. defer resp.Body.Close()
  652. err = checkResponse(resp.StatusCode, expectedStatusCode)
  653. if err == nil && expectedStatusCode == http.StatusOK {
  654. err = render.DecodeJSON(resp.Body, &folder)
  655. } else {
  656. body, _ = getResponseBody(resp)
  657. }
  658. return folder, body, err
  659. }
  660. // GetFolders returns a list of folders and checks the received HTTP Status code against expectedStatusCode.
  661. // The number of results can be limited specifying a limit.
  662. // Some results can be skipped specifying an offset.
  663. // The results can be filtered specifying a folder path, the folder path filter is an exact match
  664. func GetFolders(limit int64, offset int64, expectedStatusCode int) ([]vfs.BaseVirtualFolder, []byte, error) {
  665. var folders []vfs.BaseVirtualFolder
  666. var body []byte
  667. url, err := addLimitAndOffsetQueryParams(buildURLRelativeToBase(folderPath), limit, offset)
  668. if err != nil {
  669. return folders, body, err
  670. }
  671. resp, err := sendHTTPRequest(http.MethodGet, url.String(), nil, "", getDefaultToken())
  672. if err != nil {
  673. return folders, body, err
  674. }
  675. defer resp.Body.Close()
  676. err = checkResponse(resp.StatusCode, expectedStatusCode)
  677. if err == nil && expectedStatusCode == http.StatusOK {
  678. err = render.DecodeJSON(resp.Body, &folders)
  679. } else {
  680. body, _ = getResponseBody(resp)
  681. }
  682. return folders, body, err
  683. }
  684. // GetFoldersQuotaScans gets active quota scans for folders and checks the received HTTP Status code against expectedStatusCode.
  685. func GetFoldersQuotaScans(expectedStatusCode int) ([]common.ActiveVirtualFolderQuotaScan, []byte, error) {
  686. var quotaScans []common.ActiveVirtualFolderQuotaScan
  687. var body []byte
  688. resp, err := sendHTTPRequest(http.MethodGet, buildURLRelativeToBase(quotaScanVFolderPath), nil, "", getDefaultToken())
  689. if err != nil {
  690. return quotaScans, body, err
  691. }
  692. defer resp.Body.Close()
  693. err = checkResponse(resp.StatusCode, expectedStatusCode)
  694. if err == nil && expectedStatusCode == http.StatusOK {
  695. err = render.DecodeJSON(resp.Body, &quotaScans)
  696. } else {
  697. body, _ = getResponseBody(resp)
  698. }
  699. return quotaScans, body, err
  700. }
  701. // StartFolderQuotaScan start a new quota scan for the given folder and checks the received HTTP Status code against expectedStatusCode.
  702. func StartFolderQuotaScan(folder vfs.BaseVirtualFolder, expectedStatusCode int) ([]byte, error) {
  703. var body []byte
  704. resp, err := sendHTTPRequest(http.MethodPost, buildURLRelativeToBase(quotasBasePath, "folders", folder.Name, "scan"),
  705. nil, "", getDefaultToken())
  706. if err != nil {
  707. return body, err
  708. }
  709. defer resp.Body.Close()
  710. body, _ = getResponseBody(resp)
  711. return body, checkResponse(resp.StatusCode, expectedStatusCode)
  712. }
  713. // UpdateFolderQuotaUsage updates the folder used quota limits and checks the received HTTP Status code against expectedStatusCode.
  714. func UpdateFolderQuotaUsage(folder vfs.BaseVirtualFolder, mode string, expectedStatusCode int) ([]byte, error) {
  715. var body []byte
  716. folderAsJSON, _ := json.Marshal(folder)
  717. url, err := addModeQueryParam(buildURLRelativeToBase(quotasBasePath, "folders", folder.Name, "usage"), mode)
  718. if err != nil {
  719. return body, err
  720. }
  721. resp, err := sendHTTPRequest(http.MethodPut, url.String(), bytes.NewBuffer(folderAsJSON), "", getDefaultToken())
  722. if err != nil {
  723. return body, err
  724. }
  725. defer resp.Body.Close()
  726. body, _ = getResponseBody(resp)
  727. return body, checkResponse(resp.StatusCode, expectedStatusCode)
  728. }
  729. // GetVersion returns version details
  730. func GetVersion(expectedStatusCode int) (version.Info, []byte, error) {
  731. var appVersion version.Info
  732. var body []byte
  733. resp, err := sendHTTPRequest(http.MethodGet, buildURLRelativeToBase(versionPath), nil, "", getDefaultToken())
  734. if err != nil {
  735. return appVersion, body, err
  736. }
  737. defer resp.Body.Close()
  738. err = checkResponse(resp.StatusCode, expectedStatusCode)
  739. if err == nil && expectedStatusCode == http.StatusOK {
  740. err = render.DecodeJSON(resp.Body, &appVersion)
  741. } else {
  742. body, _ = getResponseBody(resp)
  743. }
  744. return appVersion, body, err
  745. }
  746. // GetStatus returns the server status
  747. func GetStatus(expectedStatusCode int) (httpd.ServicesStatus, []byte, error) {
  748. var response httpd.ServicesStatus
  749. var body []byte
  750. resp, err := sendHTTPRequest(http.MethodGet, buildURLRelativeToBase(serverStatusPath), nil, "", getDefaultToken())
  751. if err != nil {
  752. return response, body, err
  753. }
  754. defer resp.Body.Close()
  755. err = checkResponse(resp.StatusCode, expectedStatusCode)
  756. if err == nil && (expectedStatusCode == http.StatusOK) {
  757. err = render.DecodeJSON(resp.Body, &response)
  758. } else {
  759. body, _ = getResponseBody(resp)
  760. }
  761. return response, body, err
  762. }
  763. // GetDefenderHosts returns hosts that are banned or for which some violations have been detected
  764. func GetDefenderHosts(expectedStatusCode int) ([]dataprovider.DefenderEntry, []byte, error) {
  765. var response []dataprovider.DefenderEntry
  766. var body []byte
  767. url, err := url.Parse(buildURLRelativeToBase(defenderHosts))
  768. if err != nil {
  769. return response, body, err
  770. }
  771. resp, err := sendHTTPRequest(http.MethodGet, url.String(), nil, "", getDefaultToken())
  772. if err != nil {
  773. return response, body, err
  774. }
  775. defer resp.Body.Close()
  776. err = checkResponse(resp.StatusCode, expectedStatusCode)
  777. if err == nil && expectedStatusCode == http.StatusOK {
  778. err = render.DecodeJSON(resp.Body, &response)
  779. } else {
  780. body, _ = getResponseBody(resp)
  781. }
  782. return response, body, err
  783. }
  784. // GetDefenderHostByIP returns the host with the given IP, if it exists
  785. func GetDefenderHostByIP(ip string, expectedStatusCode int) (dataprovider.DefenderEntry, []byte, error) {
  786. var host dataprovider.DefenderEntry
  787. var body []byte
  788. id := hex.EncodeToString([]byte(ip))
  789. resp, err := sendHTTPRequest(http.MethodGet, buildURLRelativeToBase(defenderHosts, id),
  790. nil, "", getDefaultToken())
  791. if err != nil {
  792. return host, body, err
  793. }
  794. defer resp.Body.Close()
  795. err = checkResponse(resp.StatusCode, expectedStatusCode)
  796. if err == nil && expectedStatusCode == http.StatusOK {
  797. err = render.DecodeJSON(resp.Body, &host)
  798. } else {
  799. body, _ = getResponseBody(resp)
  800. }
  801. return host, body, err
  802. }
  803. // RemoveDefenderHostByIP removes the host with the given IP from the defender list
  804. func RemoveDefenderHostByIP(ip string, expectedStatusCode int) ([]byte, error) {
  805. var body []byte
  806. id := hex.EncodeToString([]byte(ip))
  807. resp, err := sendHTTPRequest(http.MethodDelete, buildURLRelativeToBase(defenderHosts, id), nil, "", getDefaultToken())
  808. if err != nil {
  809. return body, err
  810. }
  811. defer resp.Body.Close()
  812. body, _ = getResponseBody(resp)
  813. return body, checkResponse(resp.StatusCode, expectedStatusCode)
  814. }
  815. // GetBanTime returns the ban time for the given IP address
  816. func GetBanTime(ip string, expectedStatusCode int) (map[string]interface{}, []byte, error) {
  817. var response map[string]interface{}
  818. var body []byte
  819. url, err := url.Parse(buildURLRelativeToBase(defenderBanTime))
  820. if err != nil {
  821. return response, body, err
  822. }
  823. q := url.Query()
  824. q.Add("ip", ip)
  825. url.RawQuery = q.Encode()
  826. resp, err := sendHTTPRequest(http.MethodGet, url.String(), nil, "", getDefaultToken())
  827. if err != nil {
  828. return response, body, err
  829. }
  830. defer resp.Body.Close()
  831. err = checkResponse(resp.StatusCode, expectedStatusCode)
  832. if err == nil && expectedStatusCode == http.StatusOK {
  833. err = render.DecodeJSON(resp.Body, &response)
  834. } else {
  835. body, _ = getResponseBody(resp)
  836. }
  837. return response, body, err
  838. }
  839. // GetScore returns the score for the given IP address
  840. func GetScore(ip string, expectedStatusCode int) (map[string]interface{}, []byte, error) {
  841. var response map[string]interface{}
  842. var body []byte
  843. url, err := url.Parse(buildURLRelativeToBase(defenderScore))
  844. if err != nil {
  845. return response, body, err
  846. }
  847. q := url.Query()
  848. q.Add("ip", ip)
  849. url.RawQuery = q.Encode()
  850. resp, err := sendHTTPRequest(http.MethodGet, url.String(), nil, "", getDefaultToken())
  851. if err != nil {
  852. return response, body, err
  853. }
  854. defer resp.Body.Close()
  855. err = checkResponse(resp.StatusCode, expectedStatusCode)
  856. if err == nil && expectedStatusCode == http.StatusOK {
  857. err = render.DecodeJSON(resp.Body, &response)
  858. } else {
  859. body, _ = getResponseBody(resp)
  860. }
  861. return response, body, err
  862. }
  863. // UnbanIP unbans the given IP address
  864. func UnbanIP(ip string, expectedStatusCode int) error {
  865. postBody := make(map[string]string)
  866. postBody["ip"] = ip
  867. asJSON, _ := json.Marshal(postBody)
  868. resp, err := sendHTTPRequest(http.MethodPost, buildURLRelativeToBase(defenderUnban), bytes.NewBuffer(asJSON),
  869. "", getDefaultToken())
  870. if err != nil {
  871. return err
  872. }
  873. defer resp.Body.Close()
  874. return checkResponse(resp.StatusCode, expectedStatusCode)
  875. }
  876. // Dumpdata requests a backup to outputFile.
  877. // outputFile is relative to the configured backups_path
  878. func Dumpdata(outputFile, outputData, indent string, expectedStatusCode int) (map[string]interface{}, []byte, error) {
  879. var response map[string]interface{}
  880. var body []byte
  881. url, err := url.Parse(buildURLRelativeToBase(dumpDataPath))
  882. if err != nil {
  883. return response, body, err
  884. }
  885. q := url.Query()
  886. if outputData != "" {
  887. q.Add("output-data", outputData)
  888. }
  889. if outputFile != "" {
  890. q.Add("output-file", outputFile)
  891. }
  892. if indent != "" {
  893. q.Add("indent", indent)
  894. }
  895. url.RawQuery = q.Encode()
  896. resp, err := sendHTTPRequest(http.MethodGet, url.String(), nil, "", getDefaultToken())
  897. if err != nil {
  898. return response, body, err
  899. }
  900. defer resp.Body.Close()
  901. err = checkResponse(resp.StatusCode, expectedStatusCode)
  902. if err == nil && expectedStatusCode == http.StatusOK {
  903. err = render.DecodeJSON(resp.Body, &response)
  904. } else {
  905. body, _ = getResponseBody(resp)
  906. }
  907. return response, body, err
  908. }
  909. // Loaddata restores a backup.
  910. func Loaddata(inputFile, scanQuota, mode string, expectedStatusCode int) (map[string]interface{}, []byte, error) {
  911. var response map[string]interface{}
  912. var body []byte
  913. url, err := url.Parse(buildURLRelativeToBase(loadDataPath))
  914. if err != nil {
  915. return response, body, err
  916. }
  917. q := url.Query()
  918. q.Add("input-file", inputFile)
  919. if scanQuota != "" {
  920. q.Add("scan-quota", scanQuota)
  921. }
  922. if mode != "" {
  923. q.Add("mode", mode)
  924. }
  925. url.RawQuery = q.Encode()
  926. resp, err := sendHTTPRequest(http.MethodGet, url.String(), nil, "", getDefaultToken())
  927. if err != nil {
  928. return response, body, err
  929. }
  930. defer resp.Body.Close()
  931. err = checkResponse(resp.StatusCode, expectedStatusCode)
  932. if err == nil && expectedStatusCode == http.StatusOK {
  933. err = render.DecodeJSON(resp.Body, &response)
  934. } else {
  935. body, _ = getResponseBody(resp)
  936. }
  937. return response, body, err
  938. }
  939. // LoaddataFromPostBody restores a backup
  940. func LoaddataFromPostBody(data []byte, scanQuota, mode string, expectedStatusCode int) (map[string]interface{}, []byte, error) {
  941. var response map[string]interface{}
  942. var body []byte
  943. url, err := url.Parse(buildURLRelativeToBase(loadDataPath))
  944. if err != nil {
  945. return response, body, err
  946. }
  947. q := url.Query()
  948. if scanQuota != "" {
  949. q.Add("scan-quota", scanQuota)
  950. }
  951. if mode != "" {
  952. q.Add("mode", mode)
  953. }
  954. url.RawQuery = q.Encode()
  955. resp, err := sendHTTPRequest(http.MethodPost, url.String(), bytes.NewReader(data), "", getDefaultToken())
  956. if err != nil {
  957. return response, body, err
  958. }
  959. defer resp.Body.Close()
  960. err = checkResponse(resp.StatusCode, expectedStatusCode)
  961. if err == nil && expectedStatusCode == http.StatusOK {
  962. err = render.DecodeJSON(resp.Body, &response)
  963. } else {
  964. body, _ = getResponseBody(resp)
  965. }
  966. return response, body, err
  967. }
  968. func checkResponse(actual int, expected int) error {
  969. if expected != actual {
  970. return fmt.Errorf("wrong status code: got %v want %v", actual, expected)
  971. }
  972. return nil
  973. }
  974. func getResponseBody(resp *http.Response) ([]byte, error) {
  975. return io.ReadAll(resp.Body)
  976. }
  977. func checkFolder(expected *vfs.BaseVirtualFolder, actual *vfs.BaseVirtualFolder) error {
  978. if expected.ID <= 0 {
  979. if actual.ID <= 0 {
  980. return errors.New("actual folder ID must be > 0")
  981. }
  982. } else {
  983. if actual.ID != expected.ID {
  984. return errors.New("folder ID mismatch")
  985. }
  986. }
  987. if dataprovider.ConvertName(expected.Name) != actual.Name {
  988. return errors.New("name mismatch")
  989. }
  990. if expected.MappedPath != actual.MappedPath {
  991. return errors.New("mapped path mismatch")
  992. }
  993. if expected.Description != actual.Description {
  994. return errors.New("description mismatch")
  995. }
  996. return compareFsConfig(&expected.FsConfig, &actual.FsConfig)
  997. }
  998. func checkAPIKey(expected, actual *dataprovider.APIKey) error {
  999. if actual.Key != "" {
  1000. return errors.New("key must not be visible")
  1001. }
  1002. if actual.KeyID == "" {
  1003. return errors.New("actual key_id cannot be empty")
  1004. }
  1005. if expected.Name != actual.Name {
  1006. return errors.New("name mismatch")
  1007. }
  1008. if expected.Scope != actual.Scope {
  1009. return errors.New("scope mismatch")
  1010. }
  1011. if actual.CreatedAt == 0 {
  1012. return errors.New("created_at cannot be 0")
  1013. }
  1014. if actual.UpdatedAt == 0 {
  1015. return errors.New("updated_at cannot be 0")
  1016. }
  1017. if expected.ExpiresAt != actual.ExpiresAt {
  1018. return errors.New("expires_at mismatch")
  1019. }
  1020. if expected.Description != actual.Description {
  1021. return errors.New("description mismatch")
  1022. }
  1023. if expected.User != actual.User {
  1024. return errors.New("user mismatch")
  1025. }
  1026. if expected.Admin != actual.Admin {
  1027. return errors.New("admin mismatch")
  1028. }
  1029. return nil
  1030. }
  1031. func checkAdmin(expected, actual *dataprovider.Admin) error {
  1032. if actual.Password != "" {
  1033. return errors.New("admin password must not be visible")
  1034. }
  1035. if expected.ID <= 0 {
  1036. if actual.ID <= 0 {
  1037. return errors.New("actual admin ID must be > 0")
  1038. }
  1039. } else {
  1040. if actual.ID != expected.ID {
  1041. return errors.New("admin ID mismatch")
  1042. }
  1043. }
  1044. if expected.CreatedAt > 0 {
  1045. if expected.CreatedAt != actual.CreatedAt {
  1046. return fmt.Errorf("created_at mismatch %v != %v", expected.CreatedAt, actual.CreatedAt)
  1047. }
  1048. }
  1049. if err := compareAdminEqualFields(expected, actual); err != nil {
  1050. return err
  1051. }
  1052. if len(expected.Permissions) != len(actual.Permissions) {
  1053. return errors.New("permissions mismatch")
  1054. }
  1055. for _, p := range expected.Permissions {
  1056. if !util.IsStringInSlice(p, actual.Permissions) {
  1057. return errors.New("permissions content mismatch")
  1058. }
  1059. }
  1060. if len(expected.Filters.AllowList) != len(actual.Filters.AllowList) {
  1061. return errors.New("allow list mismatch")
  1062. }
  1063. if expected.Filters.AllowAPIKeyAuth != actual.Filters.AllowAPIKeyAuth {
  1064. return errors.New("allow_api_key_auth mismatch")
  1065. }
  1066. for _, v := range expected.Filters.AllowList {
  1067. if !util.IsStringInSlice(v, actual.Filters.AllowList) {
  1068. return errors.New("allow list content mismatch")
  1069. }
  1070. }
  1071. return nil
  1072. }
  1073. func compareAdminEqualFields(expected *dataprovider.Admin, actual *dataprovider.Admin) error {
  1074. if dataprovider.ConvertName(expected.Username) != actual.Username {
  1075. return errors.New("sername mismatch")
  1076. }
  1077. if expected.Email != actual.Email {
  1078. return errors.New("email mismatch")
  1079. }
  1080. if expected.Status != actual.Status {
  1081. return errors.New("status mismatch")
  1082. }
  1083. if expected.Description != actual.Description {
  1084. return errors.New("description mismatch")
  1085. }
  1086. if expected.AdditionalInfo != actual.AdditionalInfo {
  1087. return errors.New("additional info mismatch")
  1088. }
  1089. return nil
  1090. }
  1091. func checkUser(expected *dataprovider.User, actual *dataprovider.User) error {
  1092. if actual.Password != "" {
  1093. return errors.New("user password must not be visible")
  1094. }
  1095. if expected.ID <= 0 {
  1096. if actual.ID <= 0 {
  1097. return errors.New("actual user ID must be > 0")
  1098. }
  1099. } else {
  1100. if actual.ID != expected.ID {
  1101. return errors.New("user ID mismatch")
  1102. }
  1103. }
  1104. if expected.CreatedAt > 0 {
  1105. if expected.CreatedAt != actual.CreatedAt {
  1106. return fmt.Errorf("created_at mismatch %v != %v", expected.CreatedAt, actual.CreatedAt)
  1107. }
  1108. }
  1109. if expected.Email != actual.Email {
  1110. return errors.New("email mismatch")
  1111. }
  1112. if err := compareUserPermissions(expected, actual); err != nil {
  1113. return err
  1114. }
  1115. if err := compareUserFilters(expected, actual); err != nil {
  1116. return err
  1117. }
  1118. if err := compareFsConfig(&expected.FsConfig, &actual.FsConfig); err != nil {
  1119. return err
  1120. }
  1121. if err := compareUserVirtualFolders(expected, actual); err != nil {
  1122. return err
  1123. }
  1124. return compareEqualsUserFields(expected, actual)
  1125. }
  1126. func compareUserPermissions(expected *dataprovider.User, actual *dataprovider.User) error {
  1127. if len(expected.Permissions) != len(actual.Permissions) {
  1128. return errors.New("permissions mismatch")
  1129. }
  1130. for dir, perms := range expected.Permissions {
  1131. if actualPerms, ok := actual.Permissions[dir]; ok {
  1132. for _, v := range actualPerms {
  1133. if !util.IsStringInSlice(v, perms) {
  1134. return errors.New("permissions contents mismatch")
  1135. }
  1136. }
  1137. } else {
  1138. return errors.New("permissions directories mismatch")
  1139. }
  1140. }
  1141. return nil
  1142. }
  1143. func compareUserVirtualFolders(expected *dataprovider.User, actual *dataprovider.User) error {
  1144. if len(actual.VirtualFolders) != len(expected.VirtualFolders) {
  1145. return errors.New("virtual folders len mismatch")
  1146. }
  1147. for _, v := range actual.VirtualFolders {
  1148. found := false
  1149. for _, v1 := range expected.VirtualFolders {
  1150. if path.Clean(v.VirtualPath) == path.Clean(v1.VirtualPath) {
  1151. if err := checkFolder(&v1.BaseVirtualFolder, &v.BaseVirtualFolder); err != nil {
  1152. return err
  1153. }
  1154. if v.QuotaSize != v1.QuotaSize {
  1155. return errors.New("vfolder quota size mismatch")
  1156. }
  1157. if (v.QuotaFiles) != (v1.QuotaFiles) {
  1158. return errors.New("vfolder quota files mismatch")
  1159. }
  1160. found = true
  1161. break
  1162. }
  1163. }
  1164. if !found {
  1165. return errors.New("virtual folders mismatch")
  1166. }
  1167. }
  1168. return nil
  1169. }
  1170. func compareFsConfig(expected *vfs.Filesystem, actual *vfs.Filesystem) error {
  1171. if expected.Provider != actual.Provider {
  1172. return errors.New("fs provider mismatch")
  1173. }
  1174. if err := compareS3Config(expected, actual); err != nil {
  1175. return err
  1176. }
  1177. if err := compareGCSConfig(expected, actual); err != nil {
  1178. return err
  1179. }
  1180. if err := compareAzBlobConfig(expected, actual); err != nil {
  1181. return err
  1182. }
  1183. if err := checkEncryptedSecret(expected.CryptConfig.Passphrase, actual.CryptConfig.Passphrase); err != nil {
  1184. return err
  1185. }
  1186. return compareSFTPFsConfig(expected, actual)
  1187. }
  1188. func compareS3Config(expected *vfs.Filesystem, actual *vfs.Filesystem) error { //nolint:gocyclo
  1189. if expected.S3Config.Bucket != actual.S3Config.Bucket {
  1190. return errors.New("fs S3 bucket mismatch")
  1191. }
  1192. if expected.S3Config.Region != actual.S3Config.Region {
  1193. return errors.New("fs S3 region mismatch")
  1194. }
  1195. if expected.S3Config.AccessKey != actual.S3Config.AccessKey {
  1196. return errors.New("fs S3 access key mismatch")
  1197. }
  1198. if expected.S3Config.SessionToken != actual.S3Config.SessionToken {
  1199. return errors.New("fs S3 session token mismatch")
  1200. }
  1201. if err := checkEncryptedSecret(expected.S3Config.AccessSecret, actual.S3Config.AccessSecret); err != nil {
  1202. return fmt.Errorf("fs S3 access secret mismatch: %v", err)
  1203. }
  1204. if expected.S3Config.Endpoint != actual.S3Config.Endpoint {
  1205. return errors.New("fs S3 endpoint mismatch")
  1206. }
  1207. if expected.S3Config.StorageClass != actual.S3Config.StorageClass {
  1208. return errors.New("fs S3 storage class mismatch")
  1209. }
  1210. if expected.S3Config.ACL != actual.S3Config.ACL {
  1211. return errors.New("fs S3 ACL mismatch")
  1212. }
  1213. if expected.S3Config.UploadPartSize != actual.S3Config.UploadPartSize {
  1214. return errors.New("fs S3 upload part size mismatch")
  1215. }
  1216. if expected.S3Config.UploadConcurrency != actual.S3Config.UploadConcurrency {
  1217. return errors.New("fs S3 upload concurrency mismatch")
  1218. }
  1219. if expected.S3Config.DownloadPartSize != actual.S3Config.DownloadPartSize {
  1220. return errors.New("fs S3 download part size mismatch")
  1221. }
  1222. if expected.S3Config.DownloadConcurrency != actual.S3Config.DownloadConcurrency {
  1223. return errors.New("fs S3 download concurrency mismatch")
  1224. }
  1225. if expected.S3Config.ForcePathStyle != actual.S3Config.ForcePathStyle {
  1226. return errors.New("fs S3 force path style mismatch")
  1227. }
  1228. if expected.S3Config.DownloadPartMaxTime != actual.S3Config.DownloadPartMaxTime {
  1229. return errors.New("fs S3 download part max time mismatch")
  1230. }
  1231. if expected.S3Config.UploadPartMaxTime != actual.S3Config.UploadPartMaxTime {
  1232. return errors.New("fs S3 upload part max time mismatch")
  1233. }
  1234. if expected.S3Config.KeyPrefix != actual.S3Config.KeyPrefix &&
  1235. expected.S3Config.KeyPrefix+"/" != actual.S3Config.KeyPrefix {
  1236. return errors.New("fs S3 key prefix mismatch")
  1237. }
  1238. return nil
  1239. }
  1240. func compareGCSConfig(expected *vfs.Filesystem, actual *vfs.Filesystem) error {
  1241. if expected.GCSConfig.Bucket != actual.GCSConfig.Bucket {
  1242. return errors.New("GCS bucket mismatch")
  1243. }
  1244. if expected.GCSConfig.StorageClass != actual.GCSConfig.StorageClass {
  1245. return errors.New("GCS storage class mismatch")
  1246. }
  1247. if expected.GCSConfig.ACL != actual.GCSConfig.ACL {
  1248. return errors.New("GCS ACL mismatch")
  1249. }
  1250. if expected.GCSConfig.KeyPrefix != actual.GCSConfig.KeyPrefix &&
  1251. expected.GCSConfig.KeyPrefix+"/" != actual.GCSConfig.KeyPrefix {
  1252. return errors.New("GCS key prefix mismatch")
  1253. }
  1254. if expected.GCSConfig.AutomaticCredentials != actual.GCSConfig.AutomaticCredentials {
  1255. return errors.New("GCS automatic credentials mismatch")
  1256. }
  1257. return nil
  1258. }
  1259. func compareSFTPFsConfig(expected *vfs.Filesystem, actual *vfs.Filesystem) error {
  1260. if expected.SFTPConfig.Endpoint != actual.SFTPConfig.Endpoint {
  1261. return errors.New("SFTPFs endpoint mismatch")
  1262. }
  1263. if expected.SFTPConfig.Username != actual.SFTPConfig.Username {
  1264. return errors.New("SFTPFs username mismatch")
  1265. }
  1266. if expected.SFTPConfig.DisableCouncurrentReads != actual.SFTPConfig.DisableCouncurrentReads {
  1267. return errors.New("SFTPFs disable_concurrent_reads mismatch")
  1268. }
  1269. if expected.SFTPConfig.BufferSize != actual.SFTPConfig.BufferSize {
  1270. return errors.New("SFTPFs buffer_size mismatch")
  1271. }
  1272. if err := checkEncryptedSecret(expected.SFTPConfig.Password, actual.SFTPConfig.Password); err != nil {
  1273. return fmt.Errorf("SFTPFs password mismatch: %v", err)
  1274. }
  1275. if err := checkEncryptedSecret(expected.SFTPConfig.PrivateKey, actual.SFTPConfig.PrivateKey); err != nil {
  1276. return fmt.Errorf("SFTPFs private key mismatch: %v", err)
  1277. }
  1278. if expected.SFTPConfig.Prefix != actual.SFTPConfig.Prefix {
  1279. if expected.SFTPConfig.Prefix != "" && actual.SFTPConfig.Prefix != "/" {
  1280. return errors.New("SFTPFs prefix mismatch")
  1281. }
  1282. }
  1283. if len(expected.SFTPConfig.Fingerprints) != len(actual.SFTPConfig.Fingerprints) {
  1284. return errors.New("SFTPFs fingerprints mismatch")
  1285. }
  1286. for _, value := range actual.SFTPConfig.Fingerprints {
  1287. if !util.IsStringInSlice(value, expected.SFTPConfig.Fingerprints) {
  1288. return errors.New("SFTPFs fingerprints mismatch")
  1289. }
  1290. }
  1291. return nil
  1292. }
  1293. func compareAzBlobConfig(expected *vfs.Filesystem, actual *vfs.Filesystem) error {
  1294. if expected.AzBlobConfig.Container != actual.AzBlobConfig.Container {
  1295. return errors.New("azure Blob container mismatch")
  1296. }
  1297. if expected.AzBlobConfig.AccountName != actual.AzBlobConfig.AccountName {
  1298. return errors.New("azure Blob account name mismatch")
  1299. }
  1300. if err := checkEncryptedSecret(expected.AzBlobConfig.AccountKey, actual.AzBlobConfig.AccountKey); err != nil {
  1301. return fmt.Errorf("azure Blob account key mismatch: %v", err)
  1302. }
  1303. if expected.AzBlobConfig.Endpoint != actual.AzBlobConfig.Endpoint {
  1304. return errors.New("azure Blob endpoint mismatch")
  1305. }
  1306. if err := checkEncryptedSecret(expected.AzBlobConfig.SASURL, actual.AzBlobConfig.SASURL); err != nil {
  1307. return fmt.Errorf("azure Blob SAS URL mismatch: %v", err)
  1308. }
  1309. if expected.AzBlobConfig.UploadPartSize != actual.AzBlobConfig.UploadPartSize {
  1310. return errors.New("azure Blob upload part size mismatch")
  1311. }
  1312. if expected.AzBlobConfig.UploadConcurrency != actual.AzBlobConfig.UploadConcurrency {
  1313. return errors.New("azure Blob upload concurrency mismatch")
  1314. }
  1315. if expected.AzBlobConfig.DownloadPartSize != actual.AzBlobConfig.DownloadPartSize {
  1316. return errors.New("azure Blob download part size mismatch")
  1317. }
  1318. if expected.AzBlobConfig.DownloadConcurrency != actual.AzBlobConfig.DownloadConcurrency {
  1319. return errors.New("azure Blob download concurrency mismatch")
  1320. }
  1321. if expected.AzBlobConfig.KeyPrefix != actual.AzBlobConfig.KeyPrefix &&
  1322. expected.AzBlobConfig.KeyPrefix+"/" != actual.AzBlobConfig.KeyPrefix {
  1323. return errors.New("azure Blob key prefix mismatch")
  1324. }
  1325. if expected.AzBlobConfig.UseEmulator != actual.AzBlobConfig.UseEmulator {
  1326. return errors.New("azure Blob use emulator mismatch")
  1327. }
  1328. if expected.AzBlobConfig.AccessTier != actual.AzBlobConfig.AccessTier {
  1329. return errors.New("azure Blob access tier mismatch")
  1330. }
  1331. return nil
  1332. }
  1333. func areSecretEquals(expected, actual *kms.Secret) bool {
  1334. if expected == nil && actual == nil {
  1335. return true
  1336. }
  1337. if expected != nil && expected.IsEmpty() && actual == nil {
  1338. return true
  1339. }
  1340. if actual != nil && actual.IsEmpty() && expected == nil {
  1341. return true
  1342. }
  1343. return false
  1344. }
  1345. func checkEncryptedSecret(expected, actual *kms.Secret) error {
  1346. if areSecretEquals(expected, actual) {
  1347. return nil
  1348. }
  1349. if expected == nil && actual != nil && !actual.IsEmpty() {
  1350. return errors.New("secret mismatch")
  1351. }
  1352. if actual == nil && expected != nil && !expected.IsEmpty() {
  1353. return errors.New("secret mismatch")
  1354. }
  1355. if expected.IsPlain() && actual.IsEncrypted() {
  1356. if actual.GetPayload() == "" {
  1357. return errors.New("invalid secret payload")
  1358. }
  1359. if actual.GetAdditionalData() != "" {
  1360. return errors.New("invalid secret additional data")
  1361. }
  1362. if actual.GetKey() != "" {
  1363. return errors.New("invalid secret key")
  1364. }
  1365. } else {
  1366. if expected.GetStatus() != actual.GetStatus() || expected.GetPayload() != actual.GetPayload() {
  1367. return errors.New("secret mismatch")
  1368. }
  1369. }
  1370. return nil
  1371. }
  1372. func compareUserFilterSubStructs(expected *dataprovider.User, actual *dataprovider.User) error {
  1373. for _, IPMask := range expected.Filters.AllowedIP {
  1374. if !util.IsStringInSlice(IPMask, actual.Filters.AllowedIP) {
  1375. return errors.New("allowed IP contents mismatch")
  1376. }
  1377. }
  1378. for _, IPMask := range expected.Filters.DeniedIP {
  1379. if !util.IsStringInSlice(IPMask, actual.Filters.DeniedIP) {
  1380. return errors.New("denied IP contents mismatch")
  1381. }
  1382. }
  1383. for _, method := range expected.Filters.DeniedLoginMethods {
  1384. if !util.IsStringInSlice(method, actual.Filters.DeniedLoginMethods) {
  1385. return errors.New("denied login methods contents mismatch")
  1386. }
  1387. }
  1388. for _, protocol := range expected.Filters.DeniedProtocols {
  1389. if !util.IsStringInSlice(protocol, actual.Filters.DeniedProtocols) {
  1390. return errors.New("denied protocols contents mismatch")
  1391. }
  1392. }
  1393. for _, options := range expected.Filters.WebClient {
  1394. if !util.IsStringInSlice(options, actual.Filters.WebClient) {
  1395. return errors.New("web client options contents mismatch")
  1396. }
  1397. }
  1398. if expected.Filters.Hooks.ExternalAuthDisabled != actual.Filters.Hooks.ExternalAuthDisabled {
  1399. return errors.New("external_auth_disabled hook mismatch")
  1400. }
  1401. if expected.Filters.Hooks.PreLoginDisabled != actual.Filters.Hooks.PreLoginDisabled {
  1402. return errors.New("pre_login_disabled hook mismatch")
  1403. }
  1404. if expected.Filters.Hooks.CheckPasswordDisabled != actual.Filters.Hooks.CheckPasswordDisabled {
  1405. return errors.New("check_password_disabled hook mismatch")
  1406. }
  1407. if expected.Filters.DisableFsChecks != actual.Filters.DisableFsChecks {
  1408. return errors.New("disable_fs_checks mismatch")
  1409. }
  1410. return nil
  1411. }
  1412. func compareUserFilters(expected *dataprovider.User, actual *dataprovider.User) error {
  1413. if len(expected.Filters.AllowedIP) != len(actual.Filters.AllowedIP) {
  1414. return errors.New("allowed IP mismatch")
  1415. }
  1416. if len(expected.Filters.DeniedIP) != len(actual.Filters.DeniedIP) {
  1417. return errors.New("denied IP mismatch")
  1418. }
  1419. if len(expected.Filters.DeniedLoginMethods) != len(actual.Filters.DeniedLoginMethods) {
  1420. return errors.New("denied login methods mismatch")
  1421. }
  1422. if len(expected.Filters.DeniedProtocols) != len(actual.Filters.DeniedProtocols) {
  1423. return errors.New("denied protocols mismatch")
  1424. }
  1425. if expected.Filters.MaxUploadFileSize != actual.Filters.MaxUploadFileSize {
  1426. return errors.New("max upload file size mismatch")
  1427. }
  1428. if expected.Filters.TLSUsername != actual.Filters.TLSUsername {
  1429. return errors.New("TLSUsername mismatch")
  1430. }
  1431. if len(expected.Filters.WebClient) != len(actual.Filters.WebClient) {
  1432. return errors.New("WebClient filter mismatch")
  1433. }
  1434. if expected.Filters.AllowAPIKeyAuth != actual.Filters.AllowAPIKeyAuth {
  1435. return errors.New("allow_api_key_auth mismatch")
  1436. }
  1437. if expected.Filters.ExternalAuthCacheTime != actual.Filters.ExternalAuthCacheTime {
  1438. return errors.New("external_auth_cache_time mismatch")
  1439. }
  1440. if err := compareUserFilterSubStructs(expected, actual); err != nil {
  1441. return err
  1442. }
  1443. if err := compareUserBandwidthLimitFilters(expected, actual); err != nil {
  1444. return err
  1445. }
  1446. if err := compareUserDataTransferLimitFilters(expected, actual); err != nil {
  1447. return err
  1448. }
  1449. return compareUserFilePatternsFilters(expected, actual)
  1450. }
  1451. func checkFilterMatch(expected []string, actual []string) bool {
  1452. if len(expected) != len(actual) {
  1453. return false
  1454. }
  1455. for _, e := range expected {
  1456. if !util.IsStringInSlice(strings.ToLower(e), actual) {
  1457. return false
  1458. }
  1459. }
  1460. return true
  1461. }
  1462. func compareUserDataTransferLimitFilters(expected *dataprovider.User, actual *dataprovider.User) error {
  1463. if len(expected.Filters.DataTransferLimits) != len(actual.Filters.DataTransferLimits) {
  1464. return errors.New("data transfer limits filters mismatch")
  1465. }
  1466. for idx, l := range expected.Filters.DataTransferLimits {
  1467. if actual.Filters.DataTransferLimits[idx].UploadDataTransfer != l.UploadDataTransfer {
  1468. return errors.New("data transfer limit upload_data_transfer mismatch")
  1469. }
  1470. if actual.Filters.DataTransferLimits[idx].DownloadDataTransfer != l.DownloadDataTransfer {
  1471. return errors.New("data transfer limit download_data_transfer mismatch")
  1472. }
  1473. if actual.Filters.DataTransferLimits[idx].TotalDataTransfer != l.TotalDataTransfer {
  1474. return errors.New("data transfer limit total_data_transfer mismatch")
  1475. }
  1476. for _, source := range actual.Filters.DataTransferLimits[idx].Sources {
  1477. if !util.IsStringInSlice(source, l.Sources) {
  1478. return errors.New("data transfer limit source mismatch")
  1479. }
  1480. }
  1481. }
  1482. return nil
  1483. }
  1484. func compareUserBandwidthLimitFilters(expected *dataprovider.User, actual *dataprovider.User) error {
  1485. if len(expected.Filters.BandwidthLimits) != len(actual.Filters.BandwidthLimits) {
  1486. return errors.New("bandwidth limits filters mismatch")
  1487. }
  1488. for idx, l := range expected.Filters.BandwidthLimits {
  1489. if actual.Filters.BandwidthLimits[idx].UploadBandwidth != l.UploadBandwidth {
  1490. return errors.New("bandwidth filters upload_bandwidth mismatch")
  1491. }
  1492. if actual.Filters.BandwidthLimits[idx].DownloadBandwidth != l.DownloadBandwidth {
  1493. return errors.New("bandwidth filters download_bandwidth mismatch")
  1494. }
  1495. if len(actual.Filters.BandwidthLimits[idx].Sources) != len(l.Sources) {
  1496. return errors.New("bandwidth filters sources mismatch")
  1497. }
  1498. for _, source := range actual.Filters.BandwidthLimits[idx].Sources {
  1499. if !util.IsStringInSlice(source, l.Sources) {
  1500. return errors.New("bandwidth filters source mismatch")
  1501. }
  1502. }
  1503. }
  1504. return nil
  1505. }
  1506. func compareUserFilePatternsFilters(expected *dataprovider.User, actual *dataprovider.User) error {
  1507. if len(expected.Filters.FilePatterns) != len(actual.Filters.FilePatterns) {
  1508. return errors.New("file patterns mismatch")
  1509. }
  1510. for _, f := range expected.Filters.FilePatterns {
  1511. found := false
  1512. for _, f1 := range actual.Filters.FilePatterns {
  1513. if path.Clean(f.Path) == path.Clean(f1.Path) && f.DenyPolicy == f1.DenyPolicy {
  1514. if !checkFilterMatch(f.AllowedPatterns, f1.AllowedPatterns) ||
  1515. !checkFilterMatch(f.DeniedPatterns, f1.DeniedPatterns) {
  1516. return errors.New("file patterns contents mismatch")
  1517. }
  1518. found = true
  1519. }
  1520. }
  1521. if !found {
  1522. return errors.New("file patterns contents mismatch")
  1523. }
  1524. }
  1525. return nil
  1526. }
  1527. func compareEqualsUserFields(expected *dataprovider.User, actual *dataprovider.User) error {
  1528. if dataprovider.ConvertName(expected.Username) != actual.Username {
  1529. return errors.New("username mismatch")
  1530. }
  1531. if expected.HomeDir != actual.HomeDir {
  1532. return errors.New("home dir mismatch")
  1533. }
  1534. if expected.UID != actual.UID {
  1535. return errors.New("UID mismatch")
  1536. }
  1537. if expected.GID != actual.GID {
  1538. return errors.New("GID mismatch")
  1539. }
  1540. if expected.MaxSessions != actual.MaxSessions {
  1541. return errors.New("MaxSessions mismatch")
  1542. }
  1543. if len(expected.Permissions) != len(actual.Permissions) {
  1544. return errors.New("permissions mismatch")
  1545. }
  1546. if expected.UploadBandwidth != actual.UploadBandwidth {
  1547. return errors.New("UploadBandwidth mismatch")
  1548. }
  1549. if expected.DownloadBandwidth != actual.DownloadBandwidth {
  1550. return errors.New("DownloadBandwidth mismatch")
  1551. }
  1552. if expected.Status != actual.Status {
  1553. return errors.New("status mismatch")
  1554. }
  1555. if expected.ExpirationDate != actual.ExpirationDate {
  1556. return errors.New("ExpirationDate mismatch")
  1557. }
  1558. if expected.AdditionalInfo != actual.AdditionalInfo {
  1559. return errors.New("AdditionalInfo mismatch")
  1560. }
  1561. if expected.Description != actual.Description {
  1562. return errors.New("description mismatch")
  1563. }
  1564. return compareQuotaUserFields(expected, actual)
  1565. }
  1566. func compareQuotaUserFields(expected *dataprovider.User, actual *dataprovider.User) error {
  1567. if expected.QuotaSize != actual.QuotaSize {
  1568. return errors.New("QuotaSize mismatch")
  1569. }
  1570. if expected.QuotaFiles != actual.QuotaFiles {
  1571. return errors.New("QuotaFiles mismatch")
  1572. }
  1573. if expected.UploadDataTransfer != actual.UploadDataTransfer {
  1574. return errors.New("upload_data_transfer mismatch")
  1575. }
  1576. if expected.DownloadDataTransfer != actual.DownloadDataTransfer {
  1577. return errors.New("download_data_transfer mismatch")
  1578. }
  1579. if expected.TotalDataTransfer != actual.TotalDataTransfer {
  1580. return errors.New("total_data_transfer mismatch")
  1581. }
  1582. return nil
  1583. }
  1584. func addLimitAndOffsetQueryParams(rawurl string, limit, offset int64) (*url.URL, error) {
  1585. url, err := url.Parse(rawurl)
  1586. if err != nil {
  1587. return nil, err
  1588. }
  1589. q := url.Query()
  1590. if limit > 0 {
  1591. q.Add("limit", strconv.FormatInt(limit, 10))
  1592. }
  1593. if offset > 0 {
  1594. q.Add("offset", strconv.FormatInt(offset, 10))
  1595. }
  1596. url.RawQuery = q.Encode()
  1597. return url, err
  1598. }
  1599. func addModeQueryParam(rawurl, mode string) (*url.URL, error) {
  1600. url, err := url.Parse(rawurl)
  1601. if err != nil {
  1602. return nil, err
  1603. }
  1604. q := url.Query()
  1605. if len(mode) > 0 {
  1606. q.Add("mode", mode)
  1607. }
  1608. url.RawQuery = q.Encode()
  1609. return url, err
  1610. }
  1611. func addDisconnectQueryParam(rawurl, disconnect string) (*url.URL, error) {
  1612. url, err := url.Parse(rawurl)
  1613. if err != nil {
  1614. return nil, err
  1615. }
  1616. q := url.Query()
  1617. if len(disconnect) > 0 {
  1618. q.Add("disconnect", disconnect)
  1619. }
  1620. url.RawQuery = q.Encode()
  1621. return url, err
  1622. }