| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953129541295512956129571295812959129601296112962129631296412965129661296712968129691297012971129721297312974129751297612977129781297912980129811298212983129841298512986129871298812989129901299112992129931299412995129961299712998129991300013001130021300313004130051300613007130081300913010130111301213013130141301513016130171301813019130201302113022130231302413025130261302713028130291303013031130321303313034130351303613037130381303913040130411304213043130441304513046130471304813049130501305113052130531305413055130561305713058130591306013061130621306313064130651306613067130681306913070130711307213073130741307513076130771307813079130801308113082130831308413085130861308713088130891309013091130921309313094130951309613097130981309913100131011310213103131041310513106131071310813109131101311113112131131311413115131161311713118131191312013121131221312313124131251312613127131281312913130131311313213133131341313513136131371313813139131401314113142131431314413145131461314713148131491315013151131521315313154131551315613157131581315913160131611316213163131641316513166131671316813169131701317113172131731317413175131761317713178131791318013181131821318313184131851318613187131881318913190131911319213193131941319513196131971319813199132001320113202132031320413205132061320713208132091321013211132121321313214132151321613217132181321913220132211322213223132241322513226132271322813229132301323113232132331323413235132361323713238132391324013241132421324313244132451324613247132481324913250132511325213253132541325513256132571325813259132601326113262132631326413265132661326713268132691327013271132721327313274132751327613277132781327913280132811328213283132841328513286132871328813289132901329113292132931329413295132961329713298132991330013301133021330313304133051330613307133081330913310133111331213313133141331513316133171331813319133201332113322133231332413325133261332713328133291333013331133321333313334133351333613337133381333913340133411334213343133441334513346133471334813349133501335113352133531335413355133561335713358133591336013361133621336313364133651336613367133681336913370133711337213373133741337513376133771337813379133801338113382133831338413385133861338713388133891339013391133921339313394133951339613397133981339913400134011340213403134041340513406134071340813409134101341113412134131341413415134161341713418134191342013421134221342313424134251342613427134281342913430134311343213433134341343513436134371343813439134401344113442134431344413445134461344713448134491345013451134521345313454134551345613457134581345913460134611346213463134641346513466134671346813469134701347113472134731347413475134761347713478134791348013481134821348313484134851348613487134881348913490134911349213493134941349513496134971349813499135001350113502135031350413505135061350713508135091351013511135121351313514135151351613517135181351913520135211352213523135241352513526135271352813529135301353113532135331353413535135361353713538135391354013541135421354313544135451354613547135481354913550135511355213553135541355513556135571355813559135601356113562135631356413565135661356713568135691357013571135721357313574135751357613577135781357913580135811358213583135841358513586135871358813589135901359113592135931359413595135961359713598135991360013601136021360313604136051360613607136081360913610136111361213613136141361513616136171361813619136201362113622136231362413625136261362713628136291363013631136321363313634136351363613637136381363913640136411364213643136441364513646136471364813649136501365113652136531365413655136561365713658136591366013661136621366313664136651366613667136681366913670136711367213673136741367513676136771367813679136801368113682136831368413685136861368713688136891369013691136921369313694136951369613697136981369913700137011370213703137041370513706137071370813709137101371113712137131371413715137161371713718137191372013721137221372313724137251372613727137281372913730137311373213733137341373513736137371373813739137401374113742137431374413745137461374713748137491375013751137521375313754137551375613757137581375913760137611376213763137641376513766137671376813769137701377113772137731377413775137761377713778137791378013781137821378313784137851378613787137881378913790137911379213793137941379513796137971379813799138001380113802138031380413805138061380713808138091381013811138121381313814138151381613817138181381913820138211382213823138241382513826138271382813829138301383113832138331383413835138361383713838138391384013841138421384313844138451384613847138481384913850138511385213853138541385513856138571385813859138601386113862138631386413865138661386713868138691387013871138721387313874138751387613877138781387913880138811388213883138841388513886138871388813889138901389113892138931389413895138961389713898138991390013901139021390313904139051390613907139081390913910139111391213913139141391513916139171391813919139201392113922139231392413925139261392713928139291393013931139321393313934139351393613937139381393913940139411394213943139441394513946139471394813949139501395113952139531395413955139561395713958139591396013961139621396313964139651396613967139681396913970139711397213973139741397513976139771397813979139801398113982139831398413985139861398713988139891399013991139921399313994139951399613997139981399914000140011400214003140041400514006140071400814009140101401114012140131401414015140161401714018140191402014021140221402314024140251402614027140281402914030140311403214033140341403514036140371403814039140401404114042140431404414045140461404714048140491405014051140521405314054140551405614057140581405914060140611406214063140641406514066140671406814069140701407114072140731407414075140761407714078140791408014081140821408314084140851408614087140881408914090140911409214093140941409514096140971409814099141001410114102141031410414105141061410714108141091411014111141121411314114141151411614117141181411914120141211412214123141241412514126141271412814129141301413114132141331413414135141361413714138141391414014141141421414314144141451414614147141481414914150141511415214153141541415514156141571415814159141601416114162141631416414165141661416714168141691417014171141721417314174141751417614177141781417914180141811418214183141841418514186141871418814189141901419114192141931419414195141961419714198141991420014201142021420314204142051420614207142081420914210142111421214213142141421514216142171421814219142201422114222142231422414225142261422714228142291423014231142321423314234142351423614237142381423914240142411424214243142441424514246142471424814249142501425114252142531425414255142561425714258142591426014261142621426314264142651426614267142681426914270142711427214273142741427514276142771427814279142801428114282142831428414285142861428714288142891429014291142921429314294142951429614297142981429914300143011430214303143041430514306143071430814309143101431114312143131431414315143161431714318143191432014321143221432314324143251432614327143281432914330143311433214333143341433514336143371433814339143401434114342143431434414345143461434714348143491435014351143521435314354143551435614357143581435914360143611436214363143641436514366143671436814369143701437114372143731437414375143761437714378143791438014381143821438314384143851438614387143881438914390143911439214393143941439514396143971439814399144001440114402144031440414405144061440714408144091441014411144121441314414144151441614417144181441914420144211442214423144241442514426144271442814429144301443114432144331443414435144361443714438144391444014441144421444314444144451444614447144481444914450144511445214453144541445514456144571445814459144601446114462144631446414465144661446714468144691447014471144721447314474144751447614477144781447914480144811448214483144841448514486144871448814489144901449114492144931449414495144961449714498144991450014501145021450314504145051450614507145081450914510145111451214513145141451514516145171451814519145201452114522145231452414525145261452714528145291453014531145321453314534145351453614537145381453914540145411454214543145441454514546145471454814549145501455114552145531455414555145561455714558145591456014561145621456314564145651456614567145681456914570145711457214573145741457514576145771457814579145801458114582145831458414585145861458714588145891459014591145921459314594145951459614597145981459914600146011460214603146041460514606146071460814609146101461114612146131461414615146161461714618146191462014621146221462314624146251462614627146281462914630146311463214633146341463514636146371463814639146401464114642146431464414645146461464714648146491465014651146521465314654146551465614657146581465914660146611466214663146641466514666146671466814669146701467114672146731467414675146761467714678146791468014681146821468314684146851468614687146881468914690146911469214693146941469514696146971469814699147001470114702147031470414705147061470714708147091471014711147121471314714147151471614717147181471914720147211472214723147241472514726147271472814729147301473114732147331473414735147361473714738147391474014741147421474314744147451474614747147481474914750147511475214753147541475514756147571475814759147601476114762147631476414765147661476714768147691477014771147721477314774147751477614777147781477914780147811478214783147841478514786147871478814789147901479114792147931479414795147961479714798147991480014801148021480314804148051480614807148081480914810148111481214813148141481514816148171481814819148201482114822148231482414825148261482714828148291483014831148321483314834148351483614837148381483914840148411484214843148441484514846148471484814849148501485114852148531485414855148561485714858148591486014861148621486314864148651486614867148681486914870148711487214873148741487514876148771487814879148801488114882148831488414885148861488714888148891489014891148921489314894148951489614897148981489914900149011490214903149041490514906149071490814909149101491114912149131491414915149161491714918149191492014921149221492314924149251492614927149281492914930149311493214933149341493514936149371493814939149401494114942149431494414945149461494714948149491495014951149521495314954149551495614957149581495914960149611496214963149641496514966149671496814969149701497114972149731497414975149761497714978149791498014981149821498314984149851498614987149881498914990149911499214993149941499514996149971499814999150001500115002150031500415005150061500715008150091501015011150121501315014150151501615017150181501915020150211502215023150241502515026150271502815029150301503115032150331503415035150361503715038150391504015041150421504315044150451504615047150481504915050150511505215053150541505515056150571505815059150601506115062150631506415065150661506715068150691507015071150721507315074150751507615077150781507915080150811508215083150841508515086150871508815089150901509115092150931509415095150961509715098150991510015101151021510315104151051510615107151081510915110151111511215113151141511515116151171511815119151201512115122151231512415125151261512715128151291513015131151321513315134151351513615137151381513915140151411514215143151441514515146151471514815149151501515115152151531515415155151561515715158151591516015161151621516315164151651516615167151681516915170151711517215173151741517515176151771517815179151801518115182151831518415185151861518715188151891519015191151921519315194151951519615197151981519915200152011520215203152041520515206152071520815209152101521115212152131521415215152161521715218152191522015221152221522315224152251522615227152281522915230152311523215233152341523515236152371523815239152401524115242152431524415245152461524715248152491525015251152521525315254152551525615257152581525915260152611526215263152641526515266152671526815269152701527115272152731527415275152761527715278152791528015281152821528315284152851528615287152881528915290152911529215293152941529515296152971529815299153001530115302153031530415305153061530715308153091531015311153121531315314153151531615317153181531915320153211532215323153241532515326153271532815329153301533115332153331533415335153361533715338153391534015341153421534315344153451534615347153481534915350153511535215353153541535515356153571535815359153601536115362153631536415365153661536715368153691537015371153721537315374153751537615377153781537915380153811538215383153841538515386153871538815389153901539115392153931539415395153961539715398153991540015401154021540315404154051540615407154081540915410154111541215413154141541515416154171541815419154201542115422154231542415425154261542715428154291543015431154321543315434154351543615437154381543915440154411544215443154441544515446154471544815449154501545115452154531545415455154561545715458154591546015461154621546315464154651546615467154681546915470154711547215473154741547515476154771547815479154801548115482154831548415485154861548715488154891549015491154921549315494154951549615497154981549915500155011550215503155041550515506155071550815509155101551115512155131551415515155161551715518155191552015521155221552315524155251552615527155281552915530155311553215533155341553515536155371553815539155401554115542155431554415545155461554715548155491555015551155521555315554155551555615557155581555915560155611556215563155641556515566155671556815569155701557115572155731557415575155761557715578155791558015581155821558315584155851558615587155881558915590155911559215593155941559515596155971559815599156001560115602156031560415605156061560715608156091561015611156121561315614156151561615617156181561915620156211562215623156241562515626156271562815629156301563115632156331563415635156361563715638156391564015641156421564315644156451564615647156481564915650156511565215653156541565515656156571565815659156601566115662156631566415665156661566715668156691567015671156721567315674156751567615677156781567915680156811568215683156841568515686156871568815689156901569115692156931569415695156961569715698156991570015701157021570315704157051570615707157081570915710157111571215713157141571515716157171571815719157201572115722157231572415725157261572715728157291573015731157321573315734157351573615737157381573915740157411574215743157441574515746157471574815749157501575115752157531575415755157561575715758157591576015761157621576315764157651576615767157681576915770157711577215773157741577515776157771577815779157801578115782157831578415785157861578715788157891579015791157921579315794157951579615797157981579915800158011580215803158041580515806158071580815809158101581115812158131581415815158161581715818158191582015821158221582315824158251582615827158281582915830158311583215833158341583515836158371583815839158401584115842158431584415845158461584715848158491585015851158521585315854158551585615857158581585915860158611586215863158641586515866158671586815869158701587115872158731587415875158761587715878158791588015881158821588315884158851588615887158881588915890158911589215893158941589515896158971589815899159001590115902159031590415905159061590715908159091591015911159121591315914159151591615917159181591915920159211592215923159241592515926159271592815929159301593115932159331593415935159361593715938159391594015941159421594315944159451594615947159481594915950159511595215953159541595515956159571595815959159601596115962159631596415965159661596715968159691597015971159721597315974159751597615977159781597915980159811598215983159841598515986159871598815989159901599115992159931599415995159961599715998159991600016001160021600316004160051600616007160081600916010160111601216013160141601516016160171601816019160201602116022160231602416025160261602716028160291603016031160321603316034160351603616037160381603916040160411604216043160441604516046160471604816049160501605116052160531605416055160561605716058160591606016061160621606316064160651606616067160681606916070160711607216073160741607516076160771607816079160801608116082160831608416085160861608716088160891609016091160921609316094160951609616097160981609916100161011610216103161041610516106161071610816109161101611116112161131611416115161161611716118161191612016121161221612316124161251612616127161281612916130161311613216133161341613516136161371613816139161401614116142161431614416145161461614716148161491615016151161521615316154161551615616157161581615916160161611616216163161641616516166161671616816169161701617116172161731617416175161761617716178161791618016181161821618316184161851618616187161881618916190161911619216193161941619516196161971619816199162001620116202162031620416205162061620716208162091621016211162121621316214162151621616217162181621916220162211622216223162241622516226162271622816229162301623116232162331623416235162361623716238162391624016241162421624316244162451624616247162481624916250162511625216253162541625516256162571625816259162601626116262162631626416265162661626716268162691627016271162721627316274162751627616277162781627916280162811628216283162841628516286162871628816289162901629116292162931629416295162961629716298162991630016301163021630316304163051630616307163081630916310163111631216313163141631516316163171631816319163201632116322163231632416325163261632716328163291633016331163321633316334163351633616337163381633916340163411634216343163441634516346163471634816349163501635116352163531635416355163561635716358163591636016361163621636316364163651636616367163681636916370163711637216373163741637516376163771637816379163801638116382163831638416385163861638716388163891639016391163921639316394163951639616397163981639916400164011640216403164041640516406164071640816409164101641116412164131641416415164161641716418164191642016421164221642316424164251642616427164281642916430164311643216433164341643516436164371643816439164401644116442164431644416445164461644716448164491645016451164521645316454164551645616457164581645916460164611646216463164641646516466164671646816469164701647116472164731647416475164761647716478164791648016481164821648316484164851648616487164881648916490164911649216493164941649516496164971649816499165001650116502165031650416505165061650716508165091651016511165121651316514165151651616517165181651916520165211652216523165241652516526165271652816529165301653116532165331653416535165361653716538165391654016541165421654316544165451654616547165481654916550165511655216553165541655516556165571655816559165601656116562165631656416565165661656716568165691657016571165721657316574165751657616577165781657916580165811658216583165841658516586165871658816589165901659116592165931659416595165961659716598165991660016601166021660316604166051660616607166081660916610166111661216613166141661516616166171661816619166201662116622166231662416625166261662716628166291663016631166321663316634166351663616637166381663916640166411664216643166441664516646166471664816649166501665116652166531665416655166561665716658166591666016661166621666316664166651666616667166681666916670166711667216673166741667516676166771667816679166801668116682166831668416685166861668716688166891669016691166921669316694166951669616697166981669916700167011670216703167041670516706167071670816709167101671116712167131671416715167161671716718167191672016721167221672316724167251672616727167281672916730167311673216733167341673516736167371673816739167401674116742167431674416745167461674716748167491675016751167521675316754167551675616757167581675916760167611676216763167641676516766167671676816769167701677116772167731677416775167761677716778167791678016781167821678316784167851678616787167881678916790167911679216793167941679516796167971679816799168001680116802168031680416805168061680716808168091681016811168121681316814168151681616817168181681916820168211682216823168241682516826168271682816829168301683116832168331683416835168361683716838168391684016841168421684316844168451684616847168481684916850168511685216853168541685516856168571685816859168601686116862168631686416865168661686716868168691687016871168721687316874168751687616877168781687916880168811688216883168841688516886168871688816889168901689116892168931689416895168961689716898168991690016901169021690316904169051690616907169081690916910169111691216913169141691516916169171691816919169201692116922169231692416925169261692716928169291693016931169321693316934169351693616937169381693916940169411694216943169441694516946169471694816949169501695116952169531695416955169561695716958169591696016961169621696316964169651696616967169681696916970169711697216973169741697516976169771697816979169801698116982169831698416985169861698716988169891699016991169921699316994169951699616997169981699917000170011700217003170041700517006170071700817009170101701117012170131701417015170161701717018170191702017021170221702317024170251702617027170281702917030170311703217033170341703517036170371703817039170401704117042170431704417045170461704717048170491705017051170521705317054170551705617057170581705917060170611706217063170641706517066170671706817069170701707117072170731707417075170761707717078170791708017081170821708317084170851708617087170881708917090170911709217093170941709517096170971709817099171001710117102171031710417105171061710717108171091711017111171121711317114171151711617117171181711917120171211712217123171241712517126171271712817129171301713117132171331713417135171361713717138171391714017141171421714317144171451714617147171481714917150171511715217153171541715517156171571715817159171601716117162171631716417165171661716717168171691717017171171721717317174171751717617177171781717917180171811718217183171841718517186171871718817189171901719117192171931719417195171961719717198171991720017201172021720317204172051720617207172081720917210172111721217213172141721517216172171721817219172201722117222172231722417225172261722717228172291723017231172321723317234172351723617237172381723917240172411724217243172441724517246172471724817249172501725117252172531725417255172561725717258172591726017261172621726317264 | 
							- package httpd_test
 
- import (
 
- 	"bytes"
 
- 	"crypto/rand"
 
- 	"encoding/json"
 
- 	"errors"
 
- 	"fmt"
 
- 	"io"
 
- 	"math"
 
- 	"mime/multipart"
 
- 	"net"
 
- 	"net/http"
 
- 	"net/http/httptest"
 
- 	"net/url"
 
- 	"os"
 
- 	"path"
 
- 	"path/filepath"
 
- 	"regexp"
 
- 	"runtime"
 
- 	"strconv"
 
- 	"strings"
 
- 	"sync"
 
- 	"testing"
 
- 	"time"
 
- 	"github.com/go-chi/render"
 
- 	_ "github.com/go-sql-driver/mysql"
 
- 	_ "github.com/lib/pq"
 
- 	"github.com/lithammer/shortuuid/v3"
 
- 	_ "github.com/mattn/go-sqlite3"
 
- 	"github.com/mhale/smtpd"
 
- 	"github.com/pquerna/otp"
 
- 	"github.com/pquerna/otp/totp"
 
- 	"github.com/rs/xid"
 
- 	"github.com/rs/zerolog"
 
- 	"github.com/sftpgo/sdk"
 
- 	sdkkms "github.com/sftpgo/sdk/kms"
 
- 	"github.com/stretchr/testify/assert"
 
- 	"github.com/stretchr/testify/require"
 
- 	"golang.org/x/crypto/bcrypt"
 
- 	"golang.org/x/net/html"
 
- 	"github.com/drakkan/sftpgo/v2/common"
 
- 	"github.com/drakkan/sftpgo/v2/config"
 
- 	"github.com/drakkan/sftpgo/v2/dataprovider"
 
- 	"github.com/drakkan/sftpgo/v2/httpclient"
 
- 	"github.com/drakkan/sftpgo/v2/httpd"
 
- 	"github.com/drakkan/sftpgo/v2/httpdtest"
 
- 	"github.com/drakkan/sftpgo/v2/kms"
 
- 	"github.com/drakkan/sftpgo/v2/logger"
 
- 	"github.com/drakkan/sftpgo/v2/mfa"
 
- 	"github.com/drakkan/sftpgo/v2/plugin"
 
- 	"github.com/drakkan/sftpgo/v2/sftpd"
 
- 	"github.com/drakkan/sftpgo/v2/smtp"
 
- 	"github.com/drakkan/sftpgo/v2/util"
 
- 	"github.com/drakkan/sftpgo/v2/vfs"
 
- )
 
- const (
 
- 	defaultUsername                 = "test_user"
 
- 	defaultPassword                 = "test_password"
 
- 	testPubKey                      = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC03jj0D+djk7pxIf/0OhrxrchJTRZklofJ1NoIu4752Sq02mdXmarMVsqJ1cAjV5LBVy3D1F5U6XW4rppkXeVtd04Pxb09ehtH0pRRPaoHHlALiJt8CoMpbKYMA8b3KXPPriGxgGomvtU2T2RMURSwOZbMtpsugfjYSWenyYX+VORYhylWnSXL961LTyC21ehd6d6QnW9G7E5hYMITMY9TuQZz3bROYzXiTsgN0+g6Hn7exFQp50p45StUMfV/SftCMdCxlxuyGny2CrN/vfjO7xxOo2uv7q1qm10Q46KPWJQv+pgZ/OfL+EDjy07n5QVSKHlbx+2nT4Q0EgOSQaCTYwn3YjtABfIxWwgAFdyj6YlPulCL22qU4MYhDcA6PSBwDdf8hvxBfvsiHdM+JcSHvv8/VeJhk6CmnZxGY0fxBupov27z3yEO8nAg8k+6PaUiW1MSUfuGMF/ktB8LOstXsEPXSszuyXiOv4DaryOXUiSn7bmRqKcEFlJusO6aZP0= nicola@p1"
 
- 	testPubKey1                     = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCd60+/j+y8f0tLftihWV1YN9RSahMI9btQMDIMqts/jeNbD8jgoogM3nhF7KxfcaMKURuD47KC4Ey6iAJUJ0sWkSNNxOcIYuvA+5MlspfZDsa8Ag76Fe1vyz72WeHMHMeh/hwFo2TeIeIXg480T1VI6mzfDrVp2GzUx0SS0dMsQBjftXkuVR8YOiOwMCAH2a//M1OrvV7d/NBk6kBN0WnuIBb2jKm15PAA7+jQQG7tzwk2HedNH3jeL5GH31xkSRwlBczRK0xsCQXehAlx6cT/e/s44iJcJTHfpPKoSk6UAhPJYe7Z1QnuoawY9P9jQaxpyeImBZxxUEowhjpj2avBxKdRGBVK8R7EL8tSOeLbhdyWe5Mwc1+foEbq9Zz5j5Kd+hn3Wm1UnsGCrXUUUoZp1jnlNl0NakCto+5KmqnT9cHxaY+ix2RLUWAZyVFlRq71OYux1UHJnEJPiEI1/tr4jFBSL46qhQZv/TfpkfVW8FLz0lErfqu0gQEZnNHr3Fc= nicola@p1"
 
- 	defaultTokenAuthUser            = "admin"
 
- 	defaultTokenAuthPass            = "password"
 
- 	altAdminUsername                = "newTestAdmin"
 
- 	altAdminPassword                = "password1"
 
- 	csrfFormToken                   = "_form_token"
 
- 	tokenPath                       = "/api/v2/token"
 
- 	userTokenPath                   = "/api/v2/user/token"
 
- 	userLogoutPath                  = "/api/v2/user/logout"
 
- 	userPath                        = "/api/v2/users"
 
- 	adminPath                       = "/api/v2/admins"
 
- 	adminPwdPath                    = "/api/v2/admin/changepwd"
 
- 	folderPath                      = "/api/v2/folders"
 
- 	activeConnectionsPath           = "/api/v2/connections"
 
- 	serverStatusPath                = "/api/v2/status"
 
- 	quotasBasePath                  = "/api/v2/quotas"
 
- 	quotaScanPath                   = "/api/v2/quotas/users/scans"
 
- 	quotaScanVFolderPath            = "/api/v2/quotas/folders/scans"
 
- 	quotaScanCompatPath             = "/api/v2/quota-scans"
 
- 	quotaScanVFolderCompatPath      = "/api/v2/folder-quota-scans"
 
- 	updateUsedQuotaCompatPath       = "/api/v2/quota-update"
 
- 	updateFolderUsedQuotaCompatPath = "/api/v2/folder-quota-update"
 
- 	defenderHosts                   = "/api/v2/defender/hosts"
 
- 	defenderBanTime                 = "/api/v2/defender/bantime"
 
- 	defenderUnban                   = "/api/v2/defender/unban"
 
- 	defenderScore                   = "/api/v2/defender/score"
 
- 	versionPath                     = "/api/v2/version"
 
- 	logoutPath                      = "/api/v2/logout"
 
- 	userPwdPath                     = "/api/v2/user/changepwd"
 
- 	userPublicKeysPath              = "/api/v2/user/publickeys"
 
- 	userDirsPath                    = "/api/v2/user/dirs"
 
- 	userFilesPath                   = "/api/v2/user/files"
 
- 	userStreamZipPath               = "/api/v2/user/streamzip"
 
- 	userUploadFilePath              = "/api/v2/user/files/upload"
 
- 	userFilesDirsMetadataPath       = "/api/v2/user/files/metadata"
 
- 	apiKeysPath                     = "/api/v2/apikeys"
 
- 	adminTOTPConfigsPath            = "/api/v2/admin/totp/configs"
 
- 	adminTOTPGeneratePath           = "/api/v2/admin/totp/generate"
 
- 	adminTOTPValidatePath           = "/api/v2/admin/totp/validate"
 
- 	adminTOTPSavePath               = "/api/v2/admin/totp/save"
 
- 	admin2FARecoveryCodesPath       = "/api/v2/admin/2fa/recoverycodes"
 
- 	adminProfilePath                = "/api/v2/admin/profile"
 
- 	userTOTPConfigsPath             = "/api/v2/user/totp/configs"
 
- 	userTOTPGeneratePath            = "/api/v2/user/totp/generate"
 
- 	userTOTPValidatePath            = "/api/v2/user/totp/validate"
 
- 	userTOTPSavePath                = "/api/v2/user/totp/save"
 
- 	user2FARecoveryCodesPath        = "/api/v2/user/2fa/recoverycodes"
 
- 	userProfilePath                 = "/api/v2/user/profile"
 
- 	userSharesPath                  = "/api/v2/user/shares"
 
- 	retentionBasePath               = "/api/v2/retention/users"
 
- 	metadataBasePath                = "/api/v2/metadata/users"
 
- 	fsEventsPath                    = "/api/v2/events/fs"
 
- 	providerEventsPath              = "/api/v2/events/provider"
 
- 	sharesPath                      = "/api/v2/shares"
 
- 	healthzPath                     = "/healthz"
 
- 	webBasePath                     = "/web"
 
- 	webBasePathAdmin                = "/web/admin"
 
- 	webAdminSetupPath               = "/web/admin/setup"
 
- 	webLoginPath                    = "/web/admin/login"
 
- 	webLogoutPath                   = "/web/admin/logout"
 
- 	webUsersPath                    = "/web/admin/users"
 
- 	webUserPath                     = "/web/admin/user"
 
- 	webFoldersPath                  = "/web/admin/folders"
 
- 	webFolderPath                   = "/web/admin/folder"
 
- 	webConnectionsPath              = "/web/admin/connections"
 
- 	webStatusPath                   = "/web/admin/status"
 
- 	webAdminsPath                   = "/web/admin/managers"
 
- 	webAdminPath                    = "/web/admin/manager"
 
- 	webMaintenancePath              = "/web/admin/maintenance"
 
- 	webRestorePath                  = "/web/admin/restore"
 
- 	webChangeAdminPwdPath           = "/web/admin/changepwd"
 
- 	webAdminProfilePath             = "/web/admin/profile"
 
- 	webTemplateUser                 = "/web/admin/template/user"
 
- 	webTemplateFolder               = "/web/admin/template/folder"
 
- 	webDefenderPath                 = "/web/admin/defender"
 
- 	webAdminTwoFactorPath           = "/web/admin/twofactor"
 
- 	webAdminTwoFactorRecoveryPath   = "/web/admin/twofactor-recovery"
 
- 	webAdminMFAPath                 = "/web/admin/mfa"
 
- 	webAdminTOTPSavePath            = "/web/admin/totp/save"
 
- 	webAdminForgotPwdPath           = "/web/admin/forgot-password"
 
- 	webAdminResetPwdPath            = "/web/admin/reset-password"
 
- 	webBasePathClient               = "/web/client"
 
- 	webClientLoginPath              = "/web/client/login"
 
- 	webClientFilesPath              = "/web/client/files"
 
- 	webClientEditFilePath           = "/web/client/editfile"
 
- 	webClientDirsPath               = "/web/client/dirs"
 
- 	webClientDownloadZipPath        = "/web/client/downloadzip"
 
- 	webChangeClientPwdPath          = "/web/client/changepwd"
 
- 	webClientProfilePath            = "/web/client/profile"
 
- 	webClientTwoFactorPath          = "/web/client/twofactor"
 
- 	webClientTwoFactorRecoveryPath  = "/web/client/twofactor-recovery"
 
- 	webClientLogoutPath             = "/web/client/logout"
 
- 	webClientMFAPath                = "/web/client/mfa"
 
- 	webClientTOTPSavePath           = "/web/client/totp/save"
 
- 	webClientSharesPath             = "/web/client/shares"
 
- 	webClientSharePath              = "/web/client/share"
 
- 	webClientPubSharesPath          = "/web/client/pubshares"
 
- 	webClientForgotPwdPath          = "/web/client/forgot-password"
 
- 	webClientResetPwdPath           = "/web/client/reset-password"
 
- 	webClientViewPDFPath            = "/web/client/viewpdf"
 
- 	httpBaseURL                     = "http://127.0.0.1:8081"
 
- 	sftpServerAddr                  = "127.0.0.1:8022"
 
- 	smtpServerAddr                  = "127.0.0.1:3525"
 
- 	configDir                       = ".."
 
- 	httpsCert                       = `-----BEGIN CERTIFICATE-----
 
- MIICHTCCAaKgAwIBAgIUHnqw7QnB1Bj9oUsNpdb+ZkFPOxMwCgYIKoZIzj0EAwIw
 
- RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
 
- dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDAyMDQwOTUzMDRaFw0zMDAyMDEw
 
- OTUzMDRaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYD
 
- VQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwdjAQBgcqhkjOPQIBBgUrgQQA
 
- IgNiAARCjRMqJ85rzMC998X5z761nJ+xL3bkmGVqWvrJ51t5OxV0v25NsOgR82CA
 
- NXUgvhVYs7vNFN+jxtb2aj6Xg+/2G/BNxkaFspIVCzgWkxiz7XE4lgUwX44FCXZM
 
- 3+JeUbKjUzBRMB0GA1UdDgQWBBRhLw+/o3+Z02MI/d4tmaMui9W16jAfBgNVHSME
 
- GDAWgBRhLw+/o3+Z02MI/d4tmaMui9W16jAPBgNVHRMBAf8EBTADAQH/MAoGCCqG
 
- SM49BAMCA2kAMGYCMQDqLt2lm8mE+tGgtjDmtFgdOcI72HSbRQ74D5rYTzgST1rY
 
- /8wTi5xl8TiFUyLMUsICMQC5ViVxdXbhuG7gX6yEqSkMKZICHpO8hqFwOD/uaFVI
 
- dV4vKmHUzwK/eIx+8Ay3neE=
 
- -----END CERTIFICATE-----`
 
- 	httpsKey = `-----BEGIN EC PARAMETERS-----
 
- BgUrgQQAIg==
 
- -----END EC PARAMETERS-----
 
- -----BEGIN EC PRIVATE KEY-----
 
- MIGkAgEBBDCfMNsN6miEE3rVyUPwElfiJSWaR5huPCzUenZOfJT04GAcQdWvEju3
 
- UM2lmBLIXpGgBwYFK4EEACKhZANiAARCjRMqJ85rzMC998X5z761nJ+xL3bkmGVq
 
- WvrJ51t5OxV0v25NsOgR82CANXUgvhVYs7vNFN+jxtb2aj6Xg+/2G/BNxkaFspIV
 
- CzgWkxiz7XE4lgUwX44FCXZM3+JeUbI=
 
- -----END EC PRIVATE KEY-----`
 
- 	sftpPrivateKey = `-----BEGIN OPENSSH PRIVATE KEY-----
 
- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
 
- QyNTUxOQAAACB+RB4yNTZz9mHOkawwUibNdemijVV3ErMeLxWUBlCN/gAAAJA7DjpfOw46
 
- XwAAAAtzc2gtZWQyNTUxOQAAACB+RB4yNTZz9mHOkawwUibNdemijVV3ErMeLxWUBlCN/g
 
- AAAEA0E24gi8ab/XRSvJ85TGZJMe6HVmwxSG4ExPfTMwwe2n5EHjI1NnP2Yc6RrDBSJs11
 
- 6aKNVXcSsx4vFZQGUI3+AAAACW5pY29sYUBwMQECAwQ=
 
- -----END OPENSSH PRIVATE KEY-----`
 
- 	sftpPkeyFingerprint = "SHA256:QVQ06XHZZbYZzqfrsZcf3Yozy2WTnqQPeLOkcJCdbP0"
 
- 	redactedSecret      = "[**redacted**]"
 
- 	osWindows           = "windows"
 
- 	oidcMockAddr        = "127.0.0.1:11111"
 
- )
 
- var (
 
- 	defaultPerms       = []string{dataprovider.PermAny}
 
- 	homeBasePath       string
 
- 	backupsPath        string
 
- 	credentialsPath    string
 
- 	testServer         *httptest.Server
 
- 	providerDriverName string
 
- 	postConnectPath    string
 
- 	preActionPath      string
 
- 	lastResetCode      string
 
- )
 
- type fakeConnection struct {
 
- 	*common.BaseConnection
 
- 	command string
 
- }
 
- func (c *fakeConnection) Disconnect() error {
 
- 	common.Connections.Remove(c.GetID())
 
- 	return nil
 
- }
 
- func (c *fakeConnection) GetClientVersion() string {
 
- 	return ""
 
- }
 
- func (c *fakeConnection) GetCommand() string {
 
- 	return c.command
 
- }
 
- func (c *fakeConnection) GetLocalAddress() string {
 
- 	return ""
 
- }
 
- func (c *fakeConnection) GetRemoteAddress() string {
 
- 	return ""
 
- }
 
- type generateTOTPRequest struct {
 
- 	ConfigName string `json:"config_name"`
 
- }
 
- type generateTOTPResponse struct {
 
- 	ConfigName string `json:"config_name"`
 
- 	Issuer     string `json:"issuer"`
 
- 	Secret     string `json:"secret"`
 
- 	QRCode     []byte `json:"qr_code"`
 
- }
 
- type validateTOTPRequest struct {
 
- 	ConfigName string `json:"config_name"`
 
- 	Passcode   string `json:"passcode"`
 
- 	Secret     string `json:"secret"`
 
- }
 
- type recoveryCode struct {
 
- 	Code string `json:"code"`
 
- 	Used bool   `json:"used"`
 
- }
 
- func TestMain(m *testing.M) {
 
- 	homeBasePath = os.TempDir()
 
- 	logfilePath := filepath.Join(configDir, "sftpgo_api_test.log")
 
- 	logger.InitLogger(logfilePath, 5, 1, 28, false, false, zerolog.DebugLevel)
 
- 	os.Setenv("SFTPGO_COMMON__UPLOAD_MODE", "2")
 
- 	os.Setenv("SFTPGO_DATA_PROVIDER__CREATE_DEFAULT_ADMIN", "1")
 
- 	os.Setenv("SFTPGO_DEFAULT_ADMIN_USERNAME", "admin")
 
- 	os.Setenv("SFTPGO_DEFAULT_ADMIN_PASSWORD", "password")
 
- 	os.Setenv("SFTPGO_HTTPD__BINDINGS__0__WEB_CLIENT_INTEGRATIONS__0__URL", "http://127.0.0.1/test.html")
 
- 	os.Setenv("SFTPGO_HTTPD__BINDINGS__0__WEB_CLIENT_INTEGRATIONS__0__FILE_EXTENSIONS", ".pdf,.txt")
 
- 	err := config.LoadConfig(configDir, "")
 
- 	if err != nil {
 
- 		logger.WarnToConsole("error loading configuration: %v", err)
 
- 		os.Exit(1)
 
- 	}
 
- 	wdPath, err := os.Getwd()
 
- 	if err != nil {
 
- 		logger.WarnToConsole("error getting exe path: %v", err)
 
- 		os.Exit(1)
 
- 	}
 
- 	pluginsConfig := []plugin.Config{
 
- 		{
 
- 			Type:     "eventsearcher",
 
- 			Cmd:      filepath.Join(wdPath, "..", "tests", "eventsearcher", "eventsearcher"),
 
- 			AutoMTLS: true,
 
- 		},
 
- 	}
 
- 	if runtime.GOOS == osWindows {
 
- 		pluginsConfig[0].Cmd += ".exe"
 
- 	}
 
- 	providerConf := config.GetProviderConf()
 
- 	credentialsPath = filepath.Join(os.TempDir(), "test_credentials")
 
- 	providerConf.CredentialsPath = credentialsPath
 
- 	providerDriverName = providerConf.Driver
 
- 	os.RemoveAll(credentialsPath) //nolint:errcheck
 
- 	logger.InfoToConsole("Starting HTTPD tests, provider: %v", providerConf.Driver)
 
- 	err = common.Initialize(config.GetCommonConfig(), 0)
 
- 	if err != nil {
 
- 		logger.WarnToConsole("error initializing common: %v", err)
 
- 		os.Exit(1)
 
- 	}
 
- 	err = dataprovider.Initialize(providerConf, configDir, true)
 
- 	if err != nil {
 
- 		logger.WarnToConsole("error initializing data provider: %v", err)
 
- 		os.Exit(1)
 
- 	}
 
- 	postConnectPath = filepath.Join(homeBasePath, "postconnect.sh")
 
- 	preActionPath = filepath.Join(homeBasePath, "preaction.sh")
 
- 	httpConfig := config.GetHTTPConfig()
 
- 	httpConfig.RetryMax = 1
 
- 	httpConfig.Timeout = 5
 
- 	httpConfig.Initialize(configDir) //nolint:errcheck
 
- 	kmsConfig := config.GetKMSConfig()
 
- 	err = kmsConfig.Initialize()
 
- 	if err != nil {
 
- 		logger.ErrorToConsole("error initializing kms: %v", err)
 
- 		os.Exit(1)
 
- 	}
 
- 	mfaConfig := config.GetMFAConfig()
 
- 	err = mfaConfig.Initialize()
 
- 	if err != nil {
 
- 		logger.ErrorToConsole("error initializing MFA: %v", err)
 
- 		os.Exit(1)
 
- 	}
 
- 	err = plugin.Initialize(pluginsConfig, true)
 
- 	if err != nil {
 
- 		logger.ErrorToConsole("error initializing plugin: %v", err)
 
- 		os.Exit(1)
 
- 	}
 
- 	httpdConf := config.GetHTTPDConfig()
 
- 	httpdConf.Bindings[0].Port = 8081
 
- 	httpdConf.Bindings[0].Security = httpd.SecurityConf{
 
- 		Enabled: true,
 
- 		HTTPSProxyHeaders: []httpd.HTTPSProxyHeader{
 
- 			{
 
- 				Key:   "X-Forwarded-Proto",
 
- 				Value: "https",
 
- 			},
 
- 		},
 
- 	}
 
- 	httpdtest.SetBaseURL(httpBaseURL)
 
- 	backupsPath = filepath.Join(os.TempDir(), "test_backups")
 
- 	httpdConf.BackupsPath = backupsPath
 
- 	err = os.MkdirAll(backupsPath, os.ModePerm)
 
- 	if err != nil {
 
- 		logger.ErrorToConsole("error creating backups path: %v", err)
 
- 		os.Exit(1)
 
- 	}
 
- 	// required to test sftpfs
 
- 	sftpdConf := config.GetSFTPDConfig()
 
- 	sftpdConf.Bindings = []sftpd.Binding{
 
- 		{
 
- 			Port: 8022,
 
- 		},
 
- 	}
 
- 	hostKeyPath := filepath.Join(os.TempDir(), "id_rsa")
 
- 	sftpdConf.HostKeys = []string{hostKeyPath}
 
- 	go func() {
 
- 		if err := httpdConf.Initialize(configDir); err != nil {
 
- 			logger.ErrorToConsole("could not start HTTP server: %v", err)
 
- 			os.Exit(1)
 
- 		}
 
- 	}()
 
- 	go func() {
 
- 		if err := sftpdConf.Initialize(configDir); err != nil {
 
- 			logger.ErrorToConsole("could not start SFTP server: %v", err)
 
- 			os.Exit(1)
 
- 		}
 
- 	}()
 
- 	startSMTPServer()
 
- 	startOIDCMockServer()
 
- 	waitTCPListening(httpdConf.Bindings[0].GetAddress())
 
- 	waitTCPListening(sftpdConf.Bindings[0].GetAddress())
 
- 	httpd.ReloadCertificateMgr() //nolint:errcheck
 
- 	// now start an https server
 
- 	certPath := filepath.Join(os.TempDir(), "test.crt")
 
- 	keyPath := filepath.Join(os.TempDir(), "test.key")
 
- 	err = os.WriteFile(certPath, []byte(httpsCert), os.ModePerm)
 
- 	if err != nil {
 
- 		logger.ErrorToConsole("error writing HTTPS certificate: %v", err)
 
- 		os.Exit(1)
 
- 	}
 
- 	err = os.WriteFile(keyPath, []byte(httpsKey), os.ModePerm)
 
- 	if err != nil {
 
- 		logger.ErrorToConsole("error writing HTTPS private key: %v", err)
 
- 		os.Exit(1)
 
- 	}
 
- 	httpdConf.Bindings[0].Port = 8443
 
- 	httpdConf.Bindings[0].EnableHTTPS = true
 
- 	httpdConf.CertificateFile = certPath
 
- 	httpdConf.CertificateKeyFile = keyPath
 
- 	httpdConf.Bindings = append(httpdConf.Bindings, httpd.Binding{})
 
- 	go func() {
 
- 		if err := httpdConf.Initialize(configDir); err != nil {
 
- 			logger.ErrorToConsole("could not start HTTPS server: %v", err)
 
- 			os.Exit(1)
 
- 		}
 
- 	}()
 
- 	waitTCPListening(httpdConf.Bindings[0].GetAddress())
 
- 	httpd.ReloadCertificateMgr() //nolint:errcheck
 
- 	testServer = httptest.NewServer(httpd.GetHTTPRouter(httpdConf.Bindings[0]))
 
- 	defer testServer.Close()
 
- 	exitCode := m.Run()
 
- 	os.Remove(logfilePath)
 
- 	os.RemoveAll(backupsPath)
 
- 	os.RemoveAll(credentialsPath)
 
- 	os.Remove(certPath)
 
- 	os.Remove(keyPath)
 
- 	os.Remove(hostKeyPath)
 
- 	os.Remove(hostKeyPath + ".pub")
 
- 	os.Remove(postConnectPath)
 
- 	os.Remove(preActionPath)
 
- 	os.Exit(exitCode)
 
- }
 
- func TestInitialization(t *testing.T) {
 
- 	err := config.LoadConfig(configDir, "")
 
- 	assert.NoError(t, err)
 
- 	invalidFile := "invalid file"
 
- 	httpdConf := config.GetHTTPDConfig()
 
- 	defaultTemplatesPath := httpdConf.TemplatesPath
 
- 	defaultStaticPath := httpdConf.StaticFilesPath
 
- 	httpdConf.BackupsPath = backupsPath
 
- 	httpdConf.CertificateFile = invalidFile
 
- 	httpdConf.CertificateKeyFile = invalidFile
 
- 	err = httpdConf.Initialize(configDir)
 
- 	assert.Error(t, err)
 
- 	httpdConf.CertificateFile = ""
 
- 	httpdConf.CertificateKeyFile = ""
 
- 	httpdConf.TemplatesPath = "."
 
- 	err = httpdConf.Initialize(configDir)
 
- 	assert.Error(t, err)
 
- 	httpdConf = config.GetHTTPDConfig()
 
- 	httpdConf.TemplatesPath = defaultTemplatesPath
 
- 	httpdConf.BackupsPath = ".."
 
- 	err = httpdConf.Initialize(configDir)
 
- 	assert.Error(t, err)
 
- 	httpdConf.BackupsPath = backupsPath
 
- 	httpdConf.CertificateFile = invalidFile
 
- 	httpdConf.CertificateKeyFile = invalidFile
 
- 	httpdConf.StaticFilesPath = ""
 
- 	httpdConf.TemplatesPath = ""
 
- 	err = httpdConf.Initialize(configDir)
 
- 	assert.Error(t, err)
 
- 	httpdConf.StaticFilesPath = defaultStaticPath
 
- 	httpdConf.TemplatesPath = defaultTemplatesPath
 
- 	httpdConf.CertificateFile = filepath.Join(os.TempDir(), "test.crt")
 
- 	httpdConf.CertificateKeyFile = filepath.Join(os.TempDir(), "test.key")
 
- 	httpdConf.CACertificates = append(httpdConf.CACertificates, invalidFile)
 
- 	err = httpdConf.Initialize(configDir)
 
- 	assert.Error(t, err)
 
- 	httpdConf.CACertificates = nil
 
- 	httpdConf.CARevocationLists = append(httpdConf.CARevocationLists, invalidFile)
 
- 	err = httpdConf.Initialize(configDir)
 
- 	assert.Error(t, err)
 
- 	httpdConf.CARevocationLists = nil
 
- 	httpdConf.Bindings[0].ProxyAllowed = []string{"invalid ip/network"}
 
- 	err = httpdConf.Initialize(configDir)
 
- 	if assert.Error(t, err) {
 
- 		assert.Contains(t, err.Error(), "is not a valid IP range")
 
- 	}
 
- 	httpdConf.Bindings[0].ProxyAllowed = nil
 
- 	httpdConf.Bindings[0].EnableWebAdmin = false
 
- 	httpdConf.Bindings[0].EnableWebClient = false
 
- 	httpdConf.Bindings[0].Port = 8081
 
- 	httpdConf.Bindings[0].EnableHTTPS = true
 
- 	httpdConf.Bindings[0].ClientAuthType = 1
 
- 	err = httpdConf.Initialize(configDir)
 
- 	assert.Error(t, err)
 
- 	httpdConf.Bindings[0].OIDC = httpd.OIDC{
 
- 		ClientID:     "123",
 
- 		ClientSecret: "secret",
 
- 		ConfigURL:    "http://127.0.0.1:11111",
 
- 	}
 
- 	err = httpdConf.Initialize(configDir)
 
- 	if assert.Error(t, err) {
 
- 		assert.Contains(t, err.Error(), "oidc")
 
- 	}
 
- 	httpdConf.Bindings[0].OIDC.UsernameField = "preferred_username"
 
- 	err = httpdConf.Initialize(configDir)
 
- 	if assert.Error(t, err) {
 
- 		assert.Contains(t, err.Error(), "oidc")
 
- 	}
 
- }
 
- func TestBasicUserHandling(t *testing.T) {
 
- 	u := getTestUser()
 
- 	u.Email = "[email protected]"
 
- 	user, resp, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err, string(resp))
 
- 	user.MaxSessions = 10
 
- 	user.QuotaSize = 4096
 
- 	user.QuotaFiles = 2
 
- 	user.UploadBandwidth = 128
 
- 	user.DownloadBandwidth = 64
 
- 	user.ExpirationDate = util.GetTimeAsMsSinceEpoch(time.Now())
 
- 	user.AdditionalInfo = "some free text"
 
- 	user.Filters.TLSUsername = sdk.TLSUsernameCN
 
- 	user.Email = "[email protected]"
 
- 	user.Filters.WebClient = append(user.Filters.WebClient, sdk.WebClientPubKeyChangeDisabled,
 
- 		sdk.WebClientWriteDisabled)
 
- 	originalUser := user
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, originalUser.ID, user.ID)
 
- 	user, _, err = httpdtest.GetUserByUsername(defaultUsername, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	user.Email = "invalid@email"
 
- 	_, body, err := httpdtest.UpdateUser(user, http.StatusBadRequest, "")
 
- 	assert.NoError(t, err)
 
- 	assert.Contains(t, string(body), "Validation error: email")
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUserTransferLimits(t *testing.T) {
 
- 	u := getTestUser()
 
- 	u.TotalDataTransfer = 100
 
- 	u.Filters.DataTransferLimits = []sdk.DataTransferLimit{
 
- 		{
 
- 			Sources: nil,
 
- 		},
 
- 	}
 
- 	_, resp, err := httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err, string(resp))
 
- 	assert.Contains(t, string(resp), "Validation error: no data transfer limit source specified")
 
- 	u.Filters.DataTransferLimits = []sdk.DataTransferLimit{
 
- 		{
 
- 			Sources: []string{"a"},
 
- 		},
 
- 	}
 
- 	_, resp, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err, string(resp))
 
- 	assert.Contains(t, string(resp), "Validation error: could not parse data transfer limit source")
 
- 	u.Filters.DataTransferLimits = []sdk.DataTransferLimit{
 
- 		{
 
- 			Sources:              []string{"127.0.0.1/32"},
 
- 			UploadDataTransfer:   120,
 
- 			DownloadDataTransfer: 140,
 
- 		},
 
- 		{
 
- 			Sources:           []string{"192.168.0.0/24", "192.168.1.0/24"},
 
- 			TotalDataTransfer: 400,
 
- 		},
 
- 		{
 
- 			Sources: []string{"10.0.0.0/8"},
 
- 		},
 
- 	}
 
- 	user, resp, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err, string(resp))
 
- 	assert.Len(t, user.Filters.DataTransferLimits, 3)
 
- 	assert.Equal(t, u.Filters.DataTransferLimits, user.Filters.DataTransferLimits)
 
- 	up, down, total := user.GetDataTransferLimits("1.1.1.1")
 
- 	assert.Equal(t, user.TotalDataTransfer*1024*1024, total)
 
- 	assert.Equal(t, user.UploadDataTransfer*1024*1024, up)
 
- 	assert.Equal(t, user.DownloadDataTransfer*1024*1024, down)
 
- 	up, down, total = user.GetDataTransferLimits("127.0.0.1")
 
- 	assert.Equal(t, user.Filters.DataTransferLimits[0].TotalDataTransfer*1024*1024, total)
 
- 	assert.Equal(t, user.Filters.DataTransferLimits[0].UploadDataTransfer*1024*1024, up)
 
- 	assert.Equal(t, user.Filters.DataTransferLimits[0].DownloadDataTransfer*1024*1024, down)
 
- 	up, down, total = user.GetDataTransferLimits("192.168.1.6")
 
- 	assert.Equal(t, user.Filters.DataTransferLimits[1].TotalDataTransfer*1024*1024, total)
 
- 	assert.Equal(t, user.Filters.DataTransferLimits[1].UploadDataTransfer*1024*1024, up)
 
- 	assert.Equal(t, user.Filters.DataTransferLimits[1].DownloadDataTransfer*1024*1024, down)
 
- 	up, down, total = user.GetDataTransferLimits("10.1.2.3")
 
- 	assert.Equal(t, user.Filters.DataTransferLimits[2].TotalDataTransfer*1024*1024, total)
 
- 	assert.Equal(t, user.Filters.DataTransferLimits[2].UploadDataTransfer*1024*1024, up)
 
- 	assert.Equal(t, user.Filters.DataTransferLimits[2].DownloadDataTransfer*1024*1024, down)
 
- 	connID := xid.New().String()
 
- 	localAddr := "::1"
 
- 	conn := common.NewBaseConnection(connID, common.ProtocolHTTP, localAddr, "1.1.1.2", user)
 
- 	transferQuota := conn.GetTransferQuota()
 
- 	assert.Equal(t, user.TotalDataTransfer*1024*1024, transferQuota.AllowedTotalSize)
 
- 	assert.Equal(t, user.UploadDataTransfer*1024*1024, transferQuota.AllowedULSize)
 
- 	assert.Equal(t, user.DownloadDataTransfer*1024*1024, transferQuota.AllowedDLSize)
 
- 	conn = common.NewBaseConnection(connID, common.ProtocolHTTP, localAddr, "127.0.0.1", user)
 
- 	transferQuota = conn.GetTransferQuota()
 
- 	assert.Equal(t, user.Filters.DataTransferLimits[0].TotalDataTransfer*1024*1024, transferQuota.AllowedTotalSize)
 
- 	assert.Equal(t, user.Filters.DataTransferLimits[0].UploadDataTransfer*1024*1024, transferQuota.AllowedULSize)
 
- 	assert.Equal(t, user.Filters.DataTransferLimits[0].DownloadDataTransfer*1024*1024, transferQuota.AllowedDLSize)
 
- 	conn = common.NewBaseConnection(connID, common.ProtocolHTTP, localAddr, "192.168.1.5", user)
 
- 	transferQuota = conn.GetTransferQuota()
 
- 	assert.Equal(t, user.Filters.DataTransferLimits[1].TotalDataTransfer*1024*1024, transferQuota.AllowedTotalSize)
 
- 	assert.Equal(t, user.Filters.DataTransferLimits[1].UploadDataTransfer*1024*1024, transferQuota.AllowedULSize)
 
- 	assert.Equal(t, user.Filters.DataTransferLimits[1].DownloadDataTransfer*1024*1024, transferQuota.AllowedDLSize)
 
- 	u.UsedDownloadDataTransfer = 10 * 1024 * 1024
 
- 	u.UsedUploadDataTransfer = 5 * 1024 * 1024
 
- 	_, err = httpdtest.UpdateTransferQuotaUsage(u, "", http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	conn = common.NewBaseConnection(connID, common.ProtocolHTTP, localAddr, "192.168.1.6", user)
 
- 	transferQuota = conn.GetTransferQuota()
 
- 	assert.Equal(t, (user.Filters.DataTransferLimits[1].TotalDataTransfer-15)*1024*1024, transferQuota.AllowedTotalSize)
 
- 	assert.Equal(t, user.Filters.DataTransferLimits[1].UploadDataTransfer*1024*1024, transferQuota.AllowedULSize)
 
- 	assert.Equal(t, user.Filters.DataTransferLimits[1].DownloadDataTransfer*1024*1024, transferQuota.AllowedDLSize)
 
- 	conn = common.NewBaseConnection(connID, common.ProtocolHTTP, localAddr, "10.8.3.4", user)
 
- 	transferQuota = conn.GetTransferQuota()
 
- 	assert.Equal(t, int64(0), transferQuota.AllowedTotalSize)
 
- 	assert.Equal(t, int64(0), transferQuota.AllowedULSize)
 
- 	assert.Equal(t, int64(0), transferQuota.AllowedDLSize)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUserBandwidthLimits(t *testing.T) {
 
- 	u := getTestUser()
 
- 	u.UploadBandwidth = 128
 
- 	u.DownloadBandwidth = 96
 
- 	u.Filters.BandwidthLimits = []sdk.BandwidthLimit{
 
- 		{
 
- 			Sources: []string{"1"},
 
- 		},
 
- 	}
 
- 	_, resp, err := httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err, string(resp))
 
- 	assert.Contains(t, string(resp), "Validation error: could not parse bandwidth limit source")
 
- 	u.Filters.BandwidthLimits = []sdk.BandwidthLimit{
 
- 		{
 
- 			Sources: nil,
 
- 		},
 
- 	}
 
- 	_, resp, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err, string(resp))
 
- 	assert.Contains(t, string(resp), "Validation error: no bandwidth limit source specified")
 
- 	u.Filters.BandwidthLimits = []sdk.BandwidthLimit{
 
- 		{
 
- 			Sources:         []string{"127.0.0.0/8", "::1/128"},
 
- 			UploadBandwidth: 256,
 
- 		},
 
- 		{
 
- 			Sources:           []string{"10.0.0.0/8"},
 
- 			UploadBandwidth:   512,
 
- 			DownloadBandwidth: 256,
 
- 		},
 
- 	}
 
- 	user, resp, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err, string(resp))
 
- 	assert.Len(t, user.Filters.BandwidthLimits, 2)
 
- 	assert.Equal(t, u.Filters.BandwidthLimits, user.Filters.BandwidthLimits)
 
- 	connID := xid.New().String()
 
- 	localAddr := "127.0.0.1"
 
- 	up, down := user.GetBandwidthForIP("127.0.1.1", connID)
 
- 	assert.Equal(t, int64(256), up)
 
- 	assert.Equal(t, int64(0), down)
 
- 	conn := common.NewBaseConnection(connID, common.ProtocolHTTP, localAddr, "127.0.1.1", user)
 
- 	assert.Equal(t, int64(256), conn.User.UploadBandwidth)
 
- 	assert.Equal(t, int64(0), conn.User.DownloadBandwidth)
 
- 	up, down = user.GetBandwidthForIP("10.1.2.3", connID)
 
- 	assert.Equal(t, int64(512), up)
 
- 	assert.Equal(t, int64(256), down)
 
- 	conn = common.NewBaseConnection(connID, common.ProtocolHTTP, localAddr, "10.2.1.4:1234", user)
 
- 	assert.Equal(t, int64(512), conn.User.UploadBandwidth)
 
- 	assert.Equal(t, int64(256), conn.User.DownloadBandwidth)
 
- 	up, down = user.GetBandwidthForIP("192.168.1.2", connID)
 
- 	assert.Equal(t, int64(128), up)
 
- 	assert.Equal(t, int64(96), down)
 
- 	conn = common.NewBaseConnection(connID, common.ProtocolHTTP, localAddr, "172.16.0.1", user)
 
- 	assert.Equal(t, int64(128), conn.User.UploadBandwidth)
 
- 	assert.Equal(t, int64(96), conn.User.DownloadBandwidth)
 
- 	up, down = user.GetBandwidthForIP("invalid", connID)
 
- 	assert.Equal(t, int64(128), up)
 
- 	assert.Equal(t, int64(96), down)
 
- 	conn = common.NewBaseConnection(connID, common.ProtocolHTTP, localAddr, "172.16.0", user)
 
- 	assert.Equal(t, int64(128), conn.User.UploadBandwidth)
 
- 	assert.Equal(t, int64(96), conn.User.DownloadBandwidth)
 
- 	user.Filters.BandwidthLimits = []sdk.BandwidthLimit{
 
- 		{
 
- 			Sources:           []string{"10.0.0.0/24"},
 
- 			UploadBandwidth:   256,
 
- 			DownloadBandwidth: 512,
 
- 		},
 
- 	}
 
- 	user, resp, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err, string(resp))
 
- 	if assert.Len(t, user.Filters.BandwidthLimits, 1) {
 
- 		bwLimit := user.Filters.BandwidthLimits[0]
 
- 		assert.Equal(t, []string{"10.0.0.0/24"}, bwLimit.Sources)
 
- 		assert.Equal(t, int64(256), bwLimit.UploadBandwidth)
 
- 		assert.Equal(t, int64(512), bwLimit.DownloadBandwidth)
 
- 	}
 
- 	up, down = user.GetBandwidthForIP("10.1.2.3", connID)
 
- 	assert.Equal(t, int64(128), up)
 
- 	assert.Equal(t, int64(96), down)
 
- 	conn = common.NewBaseConnection(connID, common.ProtocolHTTP, localAddr, "172.16.0.2", user)
 
- 	assert.Equal(t, int64(128), conn.User.UploadBandwidth)
 
- 	assert.Equal(t, int64(96), conn.User.DownloadBandwidth)
 
- 	up, down = user.GetBandwidthForIP("10.0.0.26", connID)
 
- 	assert.Equal(t, int64(256), up)
 
- 	assert.Equal(t, int64(512), down)
 
- 	conn = common.NewBaseConnection(connID, common.ProtocolHTTP, localAddr, "10.0.0.28", user)
 
- 	assert.Equal(t, int64(256), conn.User.UploadBandwidth)
 
- 	assert.Equal(t, int64(512), conn.User.DownloadBandwidth)
 
- 	// this works if we remove the omitempty tag from BandwidthLimits
 
- 	/*user.Filters.BandwidthLimits = nil
 
- 	user, resp, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err, string(resp))
 
- 	assert.Len(t, user.Filters.BandwidthLimits, 0)*/
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUserTimestamps(t *testing.T) {
 
- 	user, resp, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err, string(resp))
 
- 	createdAt := user.CreatedAt
 
- 	updatedAt := user.UpdatedAt
 
- 	assert.Equal(t, int64(0), user.LastLogin)
 
- 	assert.Greater(t, createdAt, int64(0))
 
- 	assert.Greater(t, updatedAt, int64(0))
 
- 	mappedPath := filepath.Join(os.TempDir(), "mapped_dir")
 
- 	folderName := filepath.Base(mappedPath)
 
- 	user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{
 
- 		BaseVirtualFolder: vfs.BaseVirtualFolder{
 
- 			Name:       folderName,
 
- 			MappedPath: mappedPath,
 
- 		},
 
- 		VirtualPath: "/vdir",
 
- 	})
 
- 	time.Sleep(10 * time.Millisecond)
 
- 	user, resp, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err, string(resp))
 
- 	assert.Equal(t, int64(0), user.LastLogin)
 
- 	assert.Equal(t, createdAt, user.CreatedAt)
 
- 	assert.Greater(t, user.UpdatedAt, updatedAt)
 
- 	updatedAt = user.UpdatedAt
 
- 	// after a folder update or delete the user updated_at field should change
 
- 	folder, _, err := httpdtest.GetFolderByName(folderName, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, folder.Users, 1)
 
- 	time.Sleep(10 * time.Millisecond)
 
- 	_, _, err = httpdtest.UpdateFolder(folder, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, int64(0), user.LastLogin)
 
- 	assert.Equal(t, createdAt, user.CreatedAt)
 
- 	assert.Greater(t, user.UpdatedAt, updatedAt)
 
- 	updatedAt = user.UpdatedAt
 
- 	time.Sleep(10 * time.Millisecond)
 
- 	_, err = httpdtest.RemoveFolder(folder, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, int64(0), user.LastLogin)
 
- 	assert.Equal(t, createdAt, user.CreatedAt)
 
- 	assert.Greater(t, user.UpdatedAt, updatedAt)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestAdminTimestamps(t *testing.T) {
 
- 	admin := getTestAdmin()
 
- 	admin.Username = altAdminUsername
 
- 	admin, _, err := httpdtest.AddAdmin(admin, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	createdAt := admin.CreatedAt
 
- 	updatedAt := admin.UpdatedAt
 
- 	assert.Equal(t, int64(0), admin.LastLogin)
 
- 	assert.Greater(t, createdAt, int64(0))
 
- 	assert.Greater(t, updatedAt, int64(0))
 
- 	time.Sleep(10 * time.Millisecond)
 
- 	admin, _, err = httpdtest.UpdateAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, int64(0), admin.LastLogin)
 
- 	assert.Equal(t, createdAt, admin.CreatedAt)
 
- 	assert.Greater(t, admin.UpdatedAt, updatedAt)
 
- 	_, err = httpdtest.RemoveAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestHTTPUserAuthentication(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, userTokenPath), nil)
 
- 	assert.NoError(t, err)
 
- 	req.SetBasicAuth(defaultUsername, defaultPassword)
 
- 	c := httpclient.GetHTTPClient()
 
- 	resp, err := c.Do(req)
 
- 	c.CloseIdleConnections()
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, http.StatusOK, resp.StatusCode)
 
- 	responseHolder := make(map[string]interface{})
 
- 	err = render.DecodeJSON(resp.Body, &responseHolder)
 
- 	assert.NoError(t, err)
 
- 	userToken := responseHolder["access_token"].(string)
 
- 	assert.NotEmpty(t, userToken)
 
- 	err = resp.Body.Close()
 
- 	assert.NoError(t, err)
 
- 	// login with wrong credentials
 
- 	req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, userTokenPath), nil)
 
- 	assert.NoError(t, err)
 
- 	req.SetBasicAuth(defaultUsername, "")
 
- 	resp, err = httpclient.GetHTTPClient().Do(req)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, http.StatusUnauthorized, resp.StatusCode)
 
- 	err = resp.Body.Close()
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, userTokenPath), nil)
 
- 	assert.NoError(t, err)
 
- 	resp, err = httpclient.GetHTTPClient().Do(req)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, http.StatusUnauthorized, resp.StatusCode)
 
- 	err = resp.Body.Close()
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, userTokenPath), nil)
 
- 	assert.NoError(t, err)
 
- 	req.SetBasicAuth(defaultUsername, "wrong pwd")
 
- 	resp, err = httpclient.GetHTTPClient().Do(req)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, http.StatusUnauthorized, resp.StatusCode)
 
- 	respBody, err := io.ReadAll(resp.Body)
 
- 	assert.NoError(t, err)
 
- 	assert.Contains(t, string(respBody), "invalid credentials")
 
- 	err = resp.Body.Close()
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, userTokenPath), nil)
 
- 	assert.NoError(t, err)
 
- 	req.SetBasicAuth("wrong username", defaultPassword)
 
- 	resp, err = httpclient.GetHTTPClient().Do(req)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, http.StatusUnauthorized, resp.StatusCode)
 
- 	respBody, err = io.ReadAll(resp.Body)
 
- 	assert.NoError(t, err)
 
- 	assert.Contains(t, string(respBody), "invalid credentials")
 
- 	err = resp.Body.Close()
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, tokenPath), nil)
 
- 	assert.NoError(t, err)
 
- 	req.SetBasicAuth(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	resp, err = httpclient.GetHTTPClient().Do(req)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, http.StatusOK, resp.StatusCode)
 
- 	responseHolder = make(map[string]interface{})
 
- 	err = render.DecodeJSON(resp.Body, &responseHolder)
 
- 	assert.NoError(t, err)
 
- 	adminToken := responseHolder["access_token"].(string)
 
- 	assert.NotEmpty(t, adminToken)
 
- 	err = resp.Body.Close()
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, versionPath), nil)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Authorization", fmt.Sprintf("Bearer %v", adminToken))
 
- 	resp, err = httpclient.GetHTTPClient().Do(req)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, http.StatusOK, resp.StatusCode)
 
- 	err = resp.Body.Close()
 
- 	assert.NoError(t, err)
 
- 	// using the user token should not work
 
- 	req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, versionPath), nil)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Authorization", fmt.Sprintf("Bearer %v", userToken))
 
- 	resp, err = httpclient.GetHTTPClient().Do(req)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, http.StatusUnauthorized, resp.StatusCode)
 
- 	err = resp.Body.Close()
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, userPublicKeysPath), nil)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Authorization", fmt.Sprintf("Bearer %v", userToken))
 
- 	resp, err = httpclient.GetHTTPClient().Do(req)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, http.StatusOK, resp.StatusCode)
 
- 	err = resp.Body.Close()
 
- 	assert.NoError(t, err)
 
- 	// using the admin token should not work
 
- 	req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, userPublicKeysPath), nil)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Authorization", fmt.Sprintf("Bearer %v", adminToken))
 
- 	resp, err = httpclient.GetHTTPClient().Do(req)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, http.StatusUnauthorized, resp.StatusCode)
 
- 	err = resp.Body.Close()
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, userLogoutPath), nil)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Authorization", fmt.Sprintf("Bearer %v", adminToken))
 
- 	resp, err = httpclient.GetHTTPClient().Do(req)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, http.StatusUnauthorized, resp.StatusCode)
 
- 	err = resp.Body.Close()
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, userLogoutPath), nil)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Authorization", fmt.Sprintf("Bearer %v", userToken))
 
- 	resp, err = httpclient.GetHTTPClient().Do(req)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, http.StatusOK, resp.StatusCode)
 
- 	err = resp.Body.Close()
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, userPublicKeysPath), nil)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Authorization", fmt.Sprintf("Bearer %v", userToken))
 
- 	resp, err = httpclient.GetHTTPClient().Do(req)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, http.StatusUnauthorized, resp.StatusCode)
 
- 	err = resp.Body.Close()
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- }
 
- func TestPermMFADisabled(t *testing.T) {
 
- 	u := getTestUser()
 
- 	u.Filters.WebClient = []string{sdk.WebClientMFADisabled}
 
- 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	configName, _, secret, _, err := mfa.GenerateTOTPSecret(mfa.GetAvailableTOTPConfigNames()[0], user.Username)
 
- 	assert.NoError(t, err)
 
- 	token, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	userTOTPConfig := dataprovider.UserTOTPConfig{
 
- 		Enabled:    true,
 
- 		ConfigName: configName,
 
- 		Secret:     kms.NewPlainSecret(secret),
 
- 		Protocols:  []string{common.ProtocolSSH},
 
- 	}
 
- 	asJSON, err := json.Marshal(userTOTPConfig)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodPost, userTOTPSavePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr) // MFA is disabled for this user
 
- 	user.Filters.WebClient = []string{sdk.WebClientWriteDisabled}
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	token, err = getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userTOTPSavePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// now we cannot disable MFA for this user
 
- 	user.Filters.WebClient = []string{sdk.WebClientMFADisabled}
 
- 	_, resp, err := httpdtest.UpdateUser(user, http.StatusBadRequest, "")
 
- 	assert.NoError(t, err)
 
- 	assert.Contains(t, string(resp), "multi-factor authentication cannot be disabled for a user with an active configuration")
 
- 	saveReq := make(map[string]bool)
 
- 	saveReq["enabled"] = false
 
- 	asJSON, err = json.Marshal(saveReq)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userTOTPSavePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	user.Filters.RecoveryCodes = []dataprovider.RecoveryCode{
 
- 		{
 
- 			Secret: kms.NewPlainSecret(util.GenerateUniqueID()),
 
- 		},
 
- 	}
 
- 	user, resp, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err, string(resp))
 
- 	assert.Contains(t, user.Filters.WebClient, sdk.WebClientMFADisabled)
 
- 	assert.Len(t, user.Filters.RecoveryCodes, 12)
 
- 	req, err = http.NewRequest(http.MethodGet, user2FARecoveryCodesPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var recCodes []recoveryCode
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &recCodes)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, recCodes, 12)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- }
 
- func TestLoginUserAPITOTP(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	configName, _, secret, _, err := mfa.GenerateTOTPSecret(mfa.GetAvailableTOTPConfigNames()[0], user.Username)
 
- 	assert.NoError(t, err)
 
- 	token, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	userTOTPConfig := dataprovider.UserTOTPConfig{
 
- 		Enabled:    true,
 
- 		ConfigName: configName,
 
- 		Secret:     kms.NewPlainSecret(secret),
 
- 		Protocols:  []string{common.ProtocolHTTP},
 
- 	}
 
- 	asJSON, err := json.Marshal(userTOTPConfig)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodPost, userTOTPSavePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, userTokenPath), nil)
 
- 	assert.NoError(t, err)
 
- 	req.SetBasicAuth(defaultUsername, defaultPassword)
 
- 	resp, err := httpclient.GetHTTPClient().Do(req)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, http.StatusUnauthorized, resp.StatusCode)
 
- 	err = resp.Body.Close()
 
- 	assert.NoError(t, err)
 
- 	passcode, err := generateTOTPPasscode(secret)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, userTokenPath), nil)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("X-SFTPGO-OTP", passcode)
 
- 	req.SetBasicAuth(defaultUsername, defaultPassword)
 
- 	resp, err = httpclient.GetHTTPClient().Do(req)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, http.StatusOK, resp.StatusCode)
 
- 	responseHolder := make(map[string]interface{})
 
- 	err = render.DecodeJSON(resp.Body, &responseHolder)
 
- 	assert.NoError(t, err)
 
- 	adminToken := responseHolder["access_token"].(string)
 
- 	assert.NotEmpty(t, adminToken)
 
- 	err = resp.Body.Close()
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, userTokenPath), nil)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("X-SFTPGO-OTP", passcode)
 
- 	req.SetBasicAuth(defaultUsername, defaultPassword)
 
- 	resp, err = httpclient.GetHTTPClient().Do(req)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, http.StatusUnauthorized, resp.StatusCode)
 
- 	err = resp.Body.Close()
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- }
 
- func TestLoginAdminAPITOTP(t *testing.T) {
 
- 	admin := getTestAdmin()
 
- 	admin.Username = altAdminUsername
 
- 	admin.Password = altAdminPassword
 
- 	admin, _, err := httpdtest.AddAdmin(admin, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	configName, _, secret, _, err := mfa.GenerateTOTPSecret(mfa.GetAvailableTOTPConfigNames()[0], admin.Username)
 
- 	assert.NoError(t, err)
 
- 	altToken, err := getJWTAPITokenFromTestServer(altAdminUsername, altAdminPassword)
 
- 	assert.NoError(t, err)
 
- 	adminTOTPConfig := dataprovider.AdminTOTPConfig{
 
- 		Enabled:    true,
 
- 		ConfigName: configName,
 
- 		Secret:     kms.NewPlainSecret(secret),
 
- 	}
 
- 	asJSON, err := json.Marshal(adminTOTPConfig)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodPost, adminTOTPSavePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, altToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, tokenPath), nil)
 
- 	assert.NoError(t, err)
 
- 	req.SetBasicAuth(altAdminUsername, altAdminPassword)
 
- 	resp, err := httpclient.GetHTTPClient().Do(req)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, http.StatusUnauthorized, resp.StatusCode)
 
- 	err = resp.Body.Close()
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, tokenPath), nil)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("X-SFTPGO-OTP", "passcode")
 
- 	req.SetBasicAuth(altAdminUsername, altAdminPassword)
 
- 	resp, err = httpclient.GetHTTPClient().Do(req)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, http.StatusUnauthorized, resp.StatusCode)
 
- 	err = resp.Body.Close()
 
- 	assert.NoError(t, err)
 
- 	passcode, err := generateTOTPPasscode(secret)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, tokenPath), nil)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("X-SFTPGO-OTP", passcode)
 
- 	req.SetBasicAuth(altAdminUsername, altAdminPassword)
 
- 	resp, err = httpclient.GetHTTPClient().Do(req)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, http.StatusOK, resp.StatusCode)
 
- 	responseHolder := make(map[string]interface{})
 
- 	err = render.DecodeJSON(resp.Body, &responseHolder)
 
- 	assert.NoError(t, err)
 
- 	adminToken := responseHolder["access_token"].(string)
 
- 	assert.NotEmpty(t, adminToken)
 
- 	err = resp.Body.Close()
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, versionPath), nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, adminToken)
 
- 	resp, err = httpclient.GetHTTPClient().Do(req)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, http.StatusOK, resp.StatusCode)
 
- 	err = resp.Body.Close()
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestHTTPStreamZipError(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, userTokenPath), nil)
 
- 	assert.NoError(t, err)
 
- 	req.SetBasicAuth(defaultUsername, defaultPassword)
 
- 	resp, err := httpclient.GetHTTPClient().Do(req)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, http.StatusOK, resp.StatusCode)
 
- 	responseHolder := make(map[string]interface{})
 
- 	err = render.DecodeJSON(resp.Body, &responseHolder)
 
- 	assert.NoError(t, err)
 
- 	userToken := responseHolder["access_token"].(string)
 
- 	assert.NotEmpty(t, userToken)
 
- 	err = resp.Body.Close()
 
- 	assert.NoError(t, err)
 
- 	filesList := []string{"missing"}
 
- 	asJSON, err := json.Marshal(filesList)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, fmt.Sprintf("%v%v", httpBaseURL, userStreamZipPath), bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Authorization", fmt.Sprintf("Bearer %v", userToken))
 
- 	resp, err = httpclient.GetHTTPClient().Do(req)
 
- 	if !assert.Error(t, err) { // the connection will be closed
 
- 		err = resp.Body.Close()
 
- 		assert.NoError(t, err)
 
- 	}
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- }
 
- func TestBasicAdminHandling(t *testing.T) {
 
- 	// we have one admin by default
 
- 	admins, _, err := httpdtest.GetAdmins(0, 0, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.GreaterOrEqual(t, len(admins), 1)
 
- 	admin := getTestAdmin()
 
- 	// the default admin already exists
 
- 	_, _, err = httpdtest.AddAdmin(admin, http.StatusInternalServerError)
 
- 	assert.NoError(t, err)
 
- 	admin.Username = altAdminUsername
 
- 	admin, _, err = httpdtest.AddAdmin(admin, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	admin, _, err = httpdtest.GetAdminByUsername(admin.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	admin.AdditionalInfo = "test info"
 
- 	admin, _, err = httpdtest.UpdateAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, "test info", admin.AdditionalInfo)
 
- 	admins, _, err = httpdtest.GetAdmins(1, 0, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, admins, 1)
 
- 	assert.NotEqual(t, admin.Username, admins[0].Username)
 
- 	admins, _, err = httpdtest.GetAdmins(1, 1, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, admins, 1)
 
- 	assert.Equal(t, admin.Username, admins[0].Username)
 
- 	_, err = httpdtest.RemoveAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveAdmin(admin, http.StatusNotFound)
 
- 	assert.NoError(t, err)
 
- 	admin, _, err = httpdtest.GetAdminByUsername(admin.Username+"123", http.StatusNotFound)
 
- 	assert.NoError(t, err)
 
- 	admin.Username = defaultTokenAuthUser
 
- 	_, err = httpdtest.RemoveAdmin(admin, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestChangeAdminPassword(t *testing.T) {
 
- 	_, err := httpdtest.ChangeAdminPassword("wrong", defaultTokenAuthPass, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.ChangeAdminPassword(defaultTokenAuthPass, defaultTokenAuthPass, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.ChangeAdminPassword(defaultTokenAuthPass, defaultTokenAuthPass+"1", http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.ChangeAdminPassword(defaultTokenAuthPass+"1", defaultTokenAuthPass, http.StatusUnauthorized)
 
- 	assert.NoError(t, err)
 
- 	admin, err := dataprovider.AdminExists(defaultTokenAuthUser)
 
- 	assert.NoError(t, err)
 
- 	admin.Password = defaultTokenAuthPass
 
- 	err = dataprovider.UpdateAdmin(&admin, "", "")
 
- 	assert.NoError(t, err)
 
- }
 
- func TestPasswordValidations(t *testing.T) {
 
- 	if config.GetProviderConf().Driver == dataprovider.MemoryDataProviderName {
 
- 		t.Skip("this test is not supported with the memory provider")
 
- 	}
 
- 	err := dataprovider.Close()
 
- 	assert.NoError(t, err)
 
- 	err = config.LoadConfig(configDir, "")
 
- 	providerConf := config.GetProviderConf()
 
- 	assert.NoError(t, err)
 
- 	providerConf.PasswordValidation.Admins.MinEntropy = 50
 
- 	providerConf.PasswordValidation.Users.MinEntropy = 70
 
- 	err = dataprovider.Initialize(providerConf, configDir, true)
 
- 	assert.NoError(t, err)
 
- 	a := getTestAdmin()
 
- 	a.Username = altAdminUsername
 
- 	a.Password = altAdminPassword
 
- 	_, resp, err := httpdtest.AddAdmin(a, http.StatusBadRequest)
 
- 	assert.NoError(t, err, string(resp))
 
- 	assert.Contains(t, string(resp), "insecure password")
 
- 	_, resp, err = httpdtest.AddUser(getTestUser(), http.StatusBadRequest)
 
- 	assert.NoError(t, err, string(resp))
 
- 	assert.Contains(t, string(resp), "insecure password")
 
- 	err = dataprovider.Close()
 
- 	assert.NoError(t, err)
 
- 	err = config.LoadConfig(configDir, "")
 
- 	assert.NoError(t, err)
 
- 	providerConf = config.GetProviderConf()
 
- 	providerConf.CredentialsPath = credentialsPath
 
- 	err = os.RemoveAll(credentialsPath)
 
- 	assert.NoError(t, err)
 
- 	err = dataprovider.Initialize(providerConf, configDir, true)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestAdminPasswordHashing(t *testing.T) {
 
- 	if config.GetProviderConf().Driver == dataprovider.MemoryDataProviderName {
 
- 		t.Skip("this test is not supported with the memory provider")
 
- 	}
 
- 	err := dataprovider.Close()
 
- 	assert.NoError(t, err)
 
- 	err = config.LoadConfig(configDir, "")
 
- 	providerConf := config.GetProviderConf()
 
- 	assert.NoError(t, err)
 
- 	providerConf.PasswordHashing.Algo = dataprovider.HashingAlgoArgon2ID
 
- 	err = dataprovider.Initialize(providerConf, configDir, true)
 
- 	assert.NoError(t, err)
 
- 	currentAdmin, err := dataprovider.AdminExists(defaultTokenAuthUser)
 
- 	assert.NoError(t, err)
 
- 	assert.True(t, strings.HasPrefix(currentAdmin.Password, "$2a$"))
 
- 	a := getTestAdmin()
 
- 	a.Username = altAdminUsername
 
- 	a.Password = altAdminPassword
 
- 	admin, _, err := httpdtest.AddAdmin(a, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	newAdmin, err := dataprovider.AdminExists(altAdminUsername)
 
- 	assert.NoError(t, err)
 
- 	assert.True(t, strings.HasPrefix(newAdmin.Password, "$argon2id$"))
 
- 	token, _, err := httpdtest.GetToken(altAdminUsername, altAdminPassword)
 
- 	assert.NoError(t, err)
 
- 	httpdtest.SetJWTToken(token)
 
- 	_, _, err = httpdtest.GetStatus(http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	httpdtest.SetJWTToken("")
 
- 	_, _, err = httpdtest.GetStatus(http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = dataprovider.Close()
 
- 	assert.NoError(t, err)
 
- 	err = config.LoadConfig(configDir, "")
 
- 	assert.NoError(t, err)
 
- 	providerConf = config.GetProviderConf()
 
- 	providerConf.CredentialsPath = credentialsPath
 
- 	err = os.RemoveAll(credentialsPath)
 
- 	assert.NoError(t, err)
 
- 	err = dataprovider.Initialize(providerConf, configDir, true)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestAdminInvalidCredentials(t *testing.T) {
 
- 	req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, tokenPath), nil)
 
- 	assert.NoError(t, err)
 
- 	req.SetBasicAuth(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	resp, err := httpclient.GetHTTPClient().Do(req)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, http.StatusOK, resp.StatusCode)
 
- 	err = resp.Body.Close()
 
- 	assert.NoError(t, err)
 
- 	// wrong password
 
- 	req.SetBasicAuth(defaultTokenAuthUser, "wrong pwd")
 
- 	resp, err = httpclient.GetHTTPClient().Do(req)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, http.StatusUnauthorized, resp.StatusCode)
 
- 	responseHolder := make(map[string]interface{})
 
- 	err = render.DecodeJSON(resp.Body, &responseHolder)
 
- 	assert.NoError(t, err)
 
- 	err = resp.Body.Close()
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, dataprovider.ErrInvalidCredentials.Error(), responseHolder["error"].(string))
 
- 	// wrong username
 
- 	req.SetBasicAuth("wrong username", defaultTokenAuthPass)
 
- 	resp, err = httpclient.GetHTTPClient().Do(req)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, http.StatusUnauthorized, resp.StatusCode)
 
- 	responseHolder = make(map[string]interface{})
 
- 	err = render.DecodeJSON(resp.Body, &responseHolder)
 
- 	assert.NoError(t, err)
 
- 	err = resp.Body.Close()
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, dataprovider.ErrInvalidCredentials.Error(), responseHolder["error"].(string))
 
- }
 
- func TestAdminLastLogin(t *testing.T) {
 
- 	a := getTestAdmin()
 
- 	a.Username = altAdminUsername
 
- 	a.Password = altAdminPassword
 
- 	admin, _, err := httpdtest.AddAdmin(a, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, int64(0), admin.LastLogin)
 
- 	_, _, err = httpdtest.GetToken(altAdminUsername, altAdminPassword)
 
- 	assert.NoError(t, err)
 
- 	admin, _, err = httpdtest.GetAdminByUsername(altAdminUsername, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Greater(t, admin.LastLogin, int64(0))
 
- 	_, err = httpdtest.RemoveAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestAdminAllowList(t *testing.T) {
 
- 	a := getTestAdmin()
 
- 	a.Username = altAdminUsername
 
- 	a.Password = altAdminPassword
 
- 	admin, _, err := httpdtest.AddAdmin(a, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	token, _, err := httpdtest.GetToken(altAdminUsername, altAdminPassword)
 
- 	assert.NoError(t, err)
 
- 	httpdtest.SetJWTToken(token)
 
- 	_, _, err = httpdtest.GetStatus(http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	httpdtest.SetJWTToken("")
 
- 	admin.Password = altAdminPassword
 
- 	admin.Filters.AllowList = []string{"10.6.6.0/32"}
 
- 	admin, _, err = httpdtest.UpdateAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.GetToken(altAdminUsername, altAdminPassword)
 
- 	assert.EqualError(t, err, "wrong status code: got 401 want 200")
 
- 	_, err = httpdtest.RemoveAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUserStatus(t *testing.T) {
 
- 	u := getTestUser()
 
- 	u.Status = 3
 
- 	_, _, err := httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.Status = 0
 
- 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	user.Status = 2
 
- 	_, _, err = httpdtest.UpdateUser(user, http.StatusBadRequest, "")
 
- 	assert.NoError(t, err)
 
- 	user.Status = 1
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUidGidLimits(t *testing.T) {
 
- 	u := getTestUser()
 
- 	u.UID = math.MaxInt32
 
- 	u.GID = math.MaxInt32
 
- 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, math.MaxInt32, user.GetUID())
 
- 	assert.Equal(t, math.MaxInt32, user.GetGID())
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestAddUserNoCredentials(t *testing.T) {
 
- 	u := getTestUser()
 
- 	u.Password = ""
 
- 	u.PublicKeys = []string{}
 
- 	_, _, err := httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestAddUserNoUsername(t *testing.T) {
 
- 	u := getTestUser()
 
- 	u.Username = ""
 
- 	_, _, err := httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestAddUserNoHomeDir(t *testing.T) {
 
- 	u := getTestUser()
 
- 	u.HomeDir = ""
 
- 	_, _, err := httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestAddUserInvalidHomeDir(t *testing.T) {
 
- 	u := getTestUser()
 
- 	u.HomeDir = "relative_path" //nolint:goconst
 
- 	_, _, err := httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestAddUserNoPerms(t *testing.T) {
 
- 	u := getTestUser()
 
- 	u.Permissions = make(map[string][]string)
 
- 	_, _, err := httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.Permissions["/"] = []string{}
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestAddUserInvalidEmail(t *testing.T) {
 
- 	u := getTestUser()
 
- 	u.Email = "invalid_email"
 
- 	_, body, err := httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	assert.Contains(t, string(body), "Validation error: email")
 
- }
 
- func TestAddUserInvalidPerms(t *testing.T) {
 
- 	u := getTestUser()
 
- 	u.Permissions["/"] = []string{"invalidPerm"}
 
- 	_, _, err := httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	// permissions for root dir are mandatory
 
- 	u.Permissions["/"] = []string{}
 
- 	u.Permissions["/somedir"] = []string{dataprovider.PermAny}
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.Permissions["/"] = []string{dataprovider.PermAny}
 
- 	u.Permissions["/subdir/.."] = []string{dataprovider.PermAny}
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestAddUserInvalidFilters(t *testing.T) {
 
- 	u := getTestUser()
 
- 	u.Filters.AllowedIP = []string{"192.168.1.0/24", "192.168.2.0"}
 
- 	_, _, err := httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.Filters.AllowedIP = []string{}
 
- 	u.Filters.DeniedIP = []string{"192.168.3.0/16", "invalid"}
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.Filters.DeniedIP = []string{}
 
- 	u.Filters.DeniedLoginMethods = []string{"invalid"}
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.Filters.DeniedLoginMethods = dataprovider.ValidLoginMethods
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.Filters.DeniedLoginMethods = []string{}
 
- 	u.Filters.FilePatterns = []sdk.PatternsFilter{
 
- 		{
 
- 			Path:            "relative",
 
- 			AllowedPatterns: []string{},
 
- 			DeniedPatterns:  []string{},
 
- 		},
 
- 	}
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.Filters.FilePatterns = []sdk.PatternsFilter{
 
- 		{
 
- 			Path:            "/",
 
- 			AllowedPatterns: []string{},
 
- 			DeniedPatterns:  []string{},
 
- 		},
 
- 	}
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.Filters.FilePatterns = []sdk.PatternsFilter{
 
- 		{
 
- 			Path:            "/subdir",
 
- 			AllowedPatterns: []string{"*.zip"},
 
- 			DeniedPatterns:  []string{},
 
- 		},
 
- 		{
 
- 			Path:            "/subdir",
 
- 			AllowedPatterns: []string{"*.rar"},
 
- 			DeniedPatterns:  []string{"*.jpg"},
 
- 		},
 
- 	}
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.Filters.FilePatterns = []sdk.PatternsFilter{
 
- 		{
 
- 			Path:            "relative",
 
- 			AllowedPatterns: []string{},
 
- 			DeniedPatterns:  []string{},
 
- 		},
 
- 	}
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.Filters.FilePatterns = []sdk.PatternsFilter{
 
- 		{
 
- 			Path:            "/",
 
- 			AllowedPatterns: []string{},
 
- 			DeniedPatterns:  []string{},
 
- 		},
 
- 	}
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.Filters.FilePatterns = []sdk.PatternsFilter{
 
- 		{
 
- 			Path:            "/subdir",
 
- 			AllowedPatterns: []string{"*.zip"},
 
- 		},
 
- 		{
 
- 			Path:            "/subdir",
 
- 			AllowedPatterns: []string{"*.rar"},
 
- 			DeniedPatterns:  []string{"*.jpg"},
 
- 		},
 
- 	}
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.Filters.FilePatterns = []sdk.PatternsFilter{
 
- 		{
 
- 			Path:            "/subdir",
 
- 			AllowedPatterns: []string{"a\\"},
 
- 		},
 
- 	}
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.Filters.FilePatterns = []sdk.PatternsFilter{
 
- 		{
 
- 			Path:            "/subdir",
 
- 			AllowedPatterns: []string{"*.*"},
 
- 			DenyPolicy:      100,
 
- 		},
 
- 	}
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.Filters.DeniedProtocols = []string{"invalid"}
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.Filters.DeniedProtocols = dataprovider.ValidProtocols
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.Filters.DeniedProtocols = nil
 
- 	u.Filters.TLSUsername = "not a supported attribute"
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.Filters.TLSUsername = ""
 
- 	u.Filters.WebClient = []string{"not a valid web client options"}
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestAddUserInvalidFsConfig(t *testing.T) {
 
- 	u := getTestUser()
 
- 	u.FsConfig.Provider = sdk.S3FilesystemProvider
 
- 	u.FsConfig.S3Config.Bucket = ""
 
- 	_, _, err := httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(credentialsPath)
 
- 	assert.NoError(t, err)
 
- 	err = os.MkdirAll(credentialsPath, 0700)
 
- 	assert.NoError(t, err)
 
- 	u.FsConfig.S3Config.Bucket = "testbucket"
 
- 	u.FsConfig.S3Config.Region = "eu-west-1"     //nolint:goconst
 
- 	u.FsConfig.S3Config.AccessKey = "access-key" //nolint:goconst
 
- 	u.FsConfig.S3Config.AccessSecret = kms.NewSecret(sdkkms.SecretStatusRedacted, "access-secret", "", "")
 
- 	u.FsConfig.S3Config.Endpoint = "http://127.0.0.1:9000/path?a=b"
 
- 	u.FsConfig.S3Config.StorageClass = "Standard" //nolint:goconst
 
- 	u.FsConfig.S3Config.KeyPrefix = "/adir/subdir/"
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.FsConfig.S3Config.AccessSecret.SetStatus(sdkkms.SecretStatusPlain)
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.FsConfig.S3Config.KeyPrefix = ""
 
- 	u.FsConfig.S3Config.UploadPartSize = 3
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.FsConfig.S3Config.UploadPartSize = 5001
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.FsConfig.S3Config.UploadPartSize = 0
 
- 	u.FsConfig.S3Config.UploadConcurrency = -1
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.FsConfig.S3Config.UploadConcurrency = 0
 
- 	u.FsConfig.S3Config.DownloadPartSize = -1
 
- 	_, resp, err := httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	if assert.NoError(t, err) {
 
- 		assert.Contains(t, string(resp), "download_part_size cannot be")
 
- 	}
 
- 	u.FsConfig.S3Config.DownloadPartSize = 5001
 
- 	_, resp, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	if assert.NoError(t, err) {
 
- 		assert.Contains(t, string(resp), "download_part_size cannot be")
 
- 	}
 
- 	u.FsConfig.S3Config.DownloadPartSize = 0
 
- 	u.FsConfig.S3Config.DownloadConcurrency = 100
 
- 	_, resp, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	if assert.NoError(t, err) {
 
- 		assert.Contains(t, string(resp), "invalid download concurrency")
 
- 	}
 
- 	u.FsConfig.S3Config.DownloadConcurrency = -1
 
- 	_, resp, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	if assert.NoError(t, err) {
 
- 		assert.Contains(t, string(resp), "invalid download concurrency")
 
- 	}
 
- 	u = getTestUser()
 
- 	u.FsConfig.Provider = sdk.GCSFilesystemProvider
 
- 	u.FsConfig.GCSConfig.Bucket = ""
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.FsConfig.GCSConfig.Bucket = "abucket"
 
- 	u.FsConfig.GCSConfig.StorageClass = "Standard"
 
- 	u.FsConfig.GCSConfig.KeyPrefix = "/somedir/subdir/"
 
- 	u.FsConfig.GCSConfig.Credentials = kms.NewSecret(sdkkms.SecretStatusRedacted, "test", "", "") //nolint:goconst
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.FsConfig.GCSConfig.Credentials.SetStatus(sdkkms.SecretStatusPlain)
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.FsConfig.GCSConfig.KeyPrefix = "somedir/subdir/" //nolint:goconst
 
- 	u.FsConfig.GCSConfig.Credentials = kms.NewEmptySecret()
 
- 	u.FsConfig.GCSConfig.AutomaticCredentials = 0
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.FsConfig.GCSConfig.Credentials = kms.NewSecret(sdkkms.SecretStatusSecretBox, "invalid", "", "")
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u = getTestUser()
 
- 	u.FsConfig.Provider = sdk.AzureBlobFilesystemProvider
 
- 	u.FsConfig.AzBlobConfig.SASURL = kms.NewPlainSecret("http://foo\x7f.com/")
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.FsConfig.AzBlobConfig.SASURL = kms.NewSecret(sdkkms.SecretStatusRedacted, "key", "", "")
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.FsConfig.AzBlobConfig.SASURL = kms.NewEmptySecret()
 
- 	u.FsConfig.AzBlobConfig.AccountName = "name"
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.FsConfig.AzBlobConfig.Container = "container"
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.FsConfig.AzBlobConfig.AccountKey = kms.NewSecret(sdkkms.SecretStatusRedacted, "key", "", "")
 
- 	u.FsConfig.AzBlobConfig.KeyPrefix = "/amedir/subdir/"
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.FsConfig.AzBlobConfig.AccountKey.SetStatus(sdkkms.SecretStatusPlain)
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.FsConfig.AzBlobConfig.KeyPrefix = "amedir/subdir/"
 
- 	u.FsConfig.AzBlobConfig.UploadPartSize = -1
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.FsConfig.AzBlobConfig.UploadPartSize = 101
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u = getTestUser()
 
- 	u.FsConfig.Provider = sdk.CryptedFilesystemProvider
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.FsConfig.CryptConfig.Passphrase = kms.NewSecret(sdkkms.SecretStatusRedacted, "akey", "", "")
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u = getTestUser()
 
- 	u.FsConfig.Provider = sdk.SFTPFilesystemProvider
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.FsConfig.SFTPConfig.Password = kms.NewSecret(sdkkms.SecretStatusRedacted, "randompkey", "", "")
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.FsConfig.SFTPConfig.Password = kms.NewEmptySecret()
 
- 	u.FsConfig.SFTPConfig.PrivateKey = kms.NewSecret(sdkkms.SecretStatusRedacted, "keyforpkey", "", "")
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.FsConfig.SFTPConfig.PrivateKey = kms.NewPlainSecret("pk")
 
- 	u.FsConfig.SFTPConfig.Endpoint = "127.1.1.1:22"
 
- 	u.FsConfig.SFTPConfig.Username = defaultUsername
 
- 	u.FsConfig.SFTPConfig.BufferSize = -1
 
- 	_, resp, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	if assert.NoError(t, err) {
 
- 		assert.Contains(t, string(resp), "invalid buffer_size")
 
- 	}
 
- 	u.FsConfig.SFTPConfig.BufferSize = 1000
 
- 	_, resp, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	if assert.NoError(t, err) {
 
- 		assert.Contains(t, string(resp), "invalid buffer_size")
 
- 	}
 
- }
 
- func TestUserRedactedPassword(t *testing.T) {
 
- 	u := getTestUser()
 
- 	u.FsConfig.Provider = sdk.S3FilesystemProvider
 
- 	u.FsConfig.S3Config.Bucket = "b"
 
- 	u.FsConfig.S3Config.Region = "eu-west-1"
 
- 	u.FsConfig.S3Config.AccessKey = "access-key"
 
- 	u.FsConfig.S3Config.SessionToken = "session token"
 
- 	u.FsConfig.S3Config.RoleARN = "myRoleARN"
 
- 	u.FsConfig.S3Config.AccessSecret = kms.NewSecret(sdkkms.SecretStatusRedacted, "access-secret", "", "")
 
- 	u.FsConfig.S3Config.Endpoint = "http://127.0.0.1:9000/path?k=m"
 
- 	u.FsConfig.S3Config.StorageClass = "Standard"
 
- 	u.FsConfig.S3Config.ACL = "bucket-owner-full-control"
 
- 	_, resp, err := httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err, string(resp))
 
- 	assert.Contains(t, string(resp), "cannot save a user with a redacted secret")
 
- 	err = dataprovider.AddUser(&u, "", "")
 
- 	if assert.Error(t, err) {
 
- 		assert.Contains(t, err.Error(), "cannot save a user with a redacted secret")
 
- 	}
 
- 	u.FsConfig.S3Config.AccessSecret = kms.NewPlainSecret("secret")
 
- 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	folderName := "folderName"
 
- 	vfolder := vfs.VirtualFolder{
 
- 		BaseVirtualFolder: vfs.BaseVirtualFolder{
 
- 			Name:       folderName,
 
- 			MappedPath: filepath.Join(os.TempDir(), "crypted"),
 
- 			FsConfig: vfs.Filesystem{
 
- 				Provider: sdk.CryptedFilesystemProvider,
 
- 				CryptConfig: vfs.CryptFsConfig{
 
- 					Passphrase: kms.NewSecret(sdkkms.SecretStatusRedacted, "crypted-secret", "", ""),
 
- 				},
 
- 			},
 
- 		},
 
- 		VirtualPath: "/avpath",
 
- 	}
 
- 	user.Password = defaultPassword
 
- 	user.VirtualFolders = append(user.VirtualFolders, vfolder)
 
- 	err = dataprovider.UpdateUser(&user, "", "")
 
- 	if assert.Error(t, err) {
 
- 		assert.Contains(t, err.Error(), "cannot save a user with a redacted secret")
 
- 	}
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUserType(t *testing.T) {
 
- 	u := getTestUser()
 
- 	u.Filters.UserType = string(sdk.UserTypeLDAP)
 
- 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, string(sdk.UserTypeLDAP), user.Filters.UserType)
 
- 	user.Filters.UserType = string(sdk.UserTypeOS)
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, string(sdk.UserTypeOS), user.Filters.UserType)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestMetadataAPI(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodGet, path.Join(metadataBasePath, "/checks"), nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var resp []interface{}
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &resp)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, resp, 0)
 
- 	req, err = http.NewRequest(http.MethodPost, path.Join(metadataBasePath, user.Username, "/check"), nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusAccepted, rr)
 
- 	assert.Eventually(t, func() bool {
 
- 		req, err := http.NewRequest(http.MethodGet, path.Join(metadataBasePath, "/checks"), nil)
 
- 		assert.NoError(t, err)
 
- 		setBearerForReq(req, token)
 
- 		rr := executeRequest(req)
 
- 		checkResponseCode(t, http.StatusOK, rr)
 
- 		var resp []interface{}
 
- 		err = json.Unmarshal(rr.Body.Bytes(), &resp)
 
- 		assert.NoError(t, err)
 
- 		return len(resp) == 0
 
- 	}, 1000*time.Millisecond, 50*time.Millisecond)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, path.Join(metadataBasePath, user.Username, "/check"), nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- }
 
- func TestRetentionAPI(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	checks, _, err := httpdtest.GetRetentionChecks(http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, checks, 0)
 
- 	localFilePath := filepath.Join(user.HomeDir, "testdir", "testfile")
 
- 	err = os.MkdirAll(filepath.Dir(localFilePath), os.ModePerm)
 
- 	assert.NoError(t, err)
 
- 	err = os.WriteFile(localFilePath, []byte("test data"), os.ModePerm)
 
- 	assert.NoError(t, err)
 
- 	folderRetention := []common.FolderRetention{
 
- 		{
 
- 			Path:            "/",
 
- 			Retention:       0,
 
- 			DeleteEmptyDirs: true,
 
- 		},
 
- 	}
 
- 	_, err = httpdtest.StartRetentionCheck(altAdminUsername, folderRetention, http.StatusNotFound)
 
- 	assert.NoError(t, err)
 
- 	resp, err := httpdtest.StartRetentionCheck(user.Username, folderRetention, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	assert.Contains(t, string(resp), "Invalid retention check")
 
- 	folderRetention[0].Retention = 24
 
- 	_, err = httpdtest.StartRetentionCheck(user.Username, folderRetention, http.StatusAccepted)
 
- 	assert.NoError(t, err)
 
- 	assert.Eventually(t, func() bool {
 
- 		return len(common.RetentionChecks.Get()) == 0
 
- 	}, 1000*time.Millisecond, 50*time.Millisecond)
 
- 	assert.FileExists(t, localFilePath)
 
- 	err = os.Chtimes(localFilePath, time.Now().Add(-48*time.Hour), time.Now().Add(-48*time.Hour))
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.StartRetentionCheck(user.Username, folderRetention, http.StatusAccepted)
 
- 	assert.NoError(t, err)
 
- 	assert.Eventually(t, func() bool {
 
- 		return len(common.RetentionChecks.Get()) == 0
 
- 	}, 1000*time.Millisecond, 50*time.Millisecond)
 
- 	assert.NoFileExists(t, localFilePath)
 
- 	assert.NoDirExists(t, filepath.Dir(localFilePath))
 
- 	check := common.RetentionCheck{
 
- 		Folders: folderRetention,
 
- 	}
 
- 	c := common.RetentionChecks.Add(check, &user)
 
- 	assert.NotNil(t, c)
 
- 	_, err = httpdtest.StartRetentionCheck(user.Username, folderRetention, http.StatusConflict)
 
- 	assert.NoError(t, err)
 
- 	c.Start()
 
- 	assert.Len(t, common.RetentionChecks.Get(), 0)
 
- 	admin := getTestAdmin()
 
- 	admin.Username = altAdminUsername
 
- 	admin.Password = altAdminPassword
 
- 	admin, _, err = httpdtest.AddAdmin(admin, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	token, err := getJWTAPITokenFromTestServer(altAdminUsername, altAdminPassword)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodPost, retentionBasePath+"/"+user.Username+"/check",
 
- 		bytes.NewBuffer([]byte("invalid json")))
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	asJSON, err := json.Marshal(folderRetention)
 
- 	assert.NoError(t, err)
 
- 	req, _ = http.NewRequest(http.MethodPost, retentionBasePath+"/"+user.Username+"/check?notifications=Email,",
 
- 		bytes.NewBuffer(asJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "to notify results via email")
 
- 	_, err = httpdtest.RemoveAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	req, _ = http.NewRequest(http.MethodPost, retentionBasePath+"/"+user.Username+"/check?notifications=Email",
 
- 		bytes.NewBuffer(asJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- }
 
- func TestAddUserInvalidVirtualFolders(t *testing.T) {
 
- 	u := getTestUser()
 
- 	folderName := "fname"
 
- 	u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
 
- 		BaseVirtualFolder: vfs.BaseVirtualFolder{
 
- 			MappedPath: filepath.Join(os.TempDir(), "mapped_dir"),
 
- 			Name:       folderName,
 
- 		},
 
- 		VirtualPath: "vdir", // invalid
 
- 	})
 
- 	_, _, err := httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.VirtualFolders = nil
 
- 	u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
 
- 		BaseVirtualFolder: vfs.BaseVirtualFolder{
 
- 			MappedPath: filepath.Join(os.TempDir(), "mapped_dir"),
 
- 			Name:       folderName,
 
- 		},
 
- 		VirtualPath: "/", // invalid
 
- 	})
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.VirtualFolders = nil
 
- 	u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
 
- 		BaseVirtualFolder: vfs.BaseVirtualFolder{
 
- 			MappedPath: filepath.Join(u.GetHomeDir(), "mapped_dir"), // invalid, inside home dir
 
- 			Name:       folderName,
 
- 		},
 
- 		VirtualPath: "/vdir",
 
- 	})
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.VirtualFolders = nil
 
- 	u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
 
- 		BaseVirtualFolder: vfs.BaseVirtualFolder{
 
- 			MappedPath: u.GetHomeDir(), // invalid
 
- 			Name:       folderName,
 
- 		},
 
- 		VirtualPath: "/vdir",
 
- 	})
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.VirtualFolders = nil
 
- 	u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
 
- 		BaseVirtualFolder: vfs.BaseVirtualFolder{
 
- 			MappedPath: filepath.Join(u.GetHomeDir(), ".."), // invalid, contains home dir
 
- 			Name:       "tmp",
 
- 		},
 
- 		VirtualPath: "/vdir",
 
- 	})
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.VirtualFolders = nil
 
- 	u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
 
- 		BaseVirtualFolder: vfs.BaseVirtualFolder{
 
- 			MappedPath: filepath.Join(os.TempDir(), "mapped_dir"),
 
- 			Name:       folderName,
 
- 		},
 
- 		VirtualPath: "/vdir",
 
- 	})
 
- 	u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
 
- 		BaseVirtualFolder: vfs.BaseVirtualFolder{
 
- 			MappedPath: filepath.Join(os.TempDir(), "mapped_dir1"),
 
- 			Name:       folderName + "1",
 
- 		},
 
- 		VirtualPath: "/vdir", // invalid, already defined
 
- 	})
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.VirtualFolders = nil
 
- 	u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
 
- 		BaseVirtualFolder: vfs.BaseVirtualFolder{
 
- 			MappedPath: filepath.Join(os.TempDir(), "mapped_dir"),
 
- 			Name:       folderName,
 
- 		},
 
- 		VirtualPath: "/vdir1",
 
- 	})
 
- 	u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
 
- 		BaseVirtualFolder: vfs.BaseVirtualFolder{
 
- 			MappedPath: filepath.Join(os.TempDir(), "mapped_dir"), // invalid, already defined
 
- 			Name:       folderName,
 
- 		},
 
- 		VirtualPath: "/vdir2",
 
- 	})
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.VirtualFolders = nil
 
- 	u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
 
- 		BaseVirtualFolder: vfs.BaseVirtualFolder{
 
- 			MappedPath: filepath.Join(os.TempDir(), "mapped_dir1"),
 
- 			Name:       folderName + "1",
 
- 		},
 
- 		VirtualPath: "/vdir1/",
 
- 		QuotaSize:   -1,
 
- 		QuotaFiles:  1, // invvalid, we cannot have -1 and > 0
 
- 	})
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.VirtualFolders = nil
 
- 	u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
 
- 		BaseVirtualFolder: vfs.BaseVirtualFolder{
 
- 			MappedPath: filepath.Join(os.TempDir(), "mapped_dir1"),
 
- 			Name:       folderName + "1",
 
- 		},
 
- 		VirtualPath: "/vdir1/",
 
- 		QuotaSize:   1,
 
- 		QuotaFiles:  -1,
 
- 	})
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.VirtualFolders = nil
 
- 	u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
 
- 		BaseVirtualFolder: vfs.BaseVirtualFolder{
 
- 			MappedPath: filepath.Join(os.TempDir(), "mapped_dir1"),
 
- 			Name:       folderName + "1",
 
- 		},
 
- 		VirtualPath: "/vdir1/",
 
- 		QuotaSize:   -2, // invalid
 
- 		QuotaFiles:  0,
 
- 	})
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.VirtualFolders = nil
 
- 	u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
 
- 		BaseVirtualFolder: vfs.BaseVirtualFolder{
 
- 			MappedPath: filepath.Join(os.TempDir(), "mapped_dir1"),
 
- 			Name:       folderName + "1",
 
- 		},
 
- 		VirtualPath: "/vdir1/",
 
- 		QuotaSize:   0,
 
- 		QuotaFiles:  -2, // invalid
 
- 	})
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.VirtualFolders = nil
 
- 	u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
 
- 		BaseVirtualFolder: vfs.BaseVirtualFolder{
 
- 			MappedPath: filepath.Join(os.TempDir(), "mapped_dir"),
 
- 		},
 
- 		VirtualPath: "/vdir1",
 
- 	})
 
- 	// folder name is mandatory
 
- 	_, _, err = httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUserPublicKey(t *testing.T) {
 
- 	u := getTestUser()
 
- 	u.Password = ""
 
- 	invalidPubKey := "invalid"
 
- 	u.PublicKeys = []string{invalidPubKey}
 
- 	_, _, err := httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.PublicKeys = []string{testPubKey}
 
- 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	dbUser, err := dataprovider.UserExists(u.Username)
 
- 	assert.NoError(t, err)
 
- 	assert.Empty(t, dbUser.Password)
 
- 	assert.False(t, dbUser.IsPasswordHashed())
 
- 	user.PublicKeys = []string{testPubKey, invalidPubKey}
 
- 	_, _, err = httpdtest.UpdateUser(user, http.StatusBadRequest, "")
 
- 	assert.NoError(t, err)
 
- 	user.PublicKeys = []string{testPubKey, testPubKey, testPubKey}
 
- 	user.Password = defaultPassword
 
- 	_, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	dbUser, err = dataprovider.UserExists(u.Username)
 
- 	assert.NoError(t, err)
 
- 	assert.NotEmpty(t, dbUser.Password)
 
- 	assert.True(t, dbUser.IsPasswordHashed())
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUpdateUserEmptyPassword(t *testing.T) {
 
- 	u := getTestUser()
 
- 	u.PublicKeys = []string{testPubKey}
 
- 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	// the password is not empty
 
- 	dbUser, err := dataprovider.UserExists(u.Username)
 
- 	assert.NoError(t, err)
 
- 	assert.NotEmpty(t, dbUser.Password)
 
- 	assert.True(t, dbUser.IsPasswordHashed())
 
- 	// now update the user and set an empty password
 
- 	customUser := make(map[string]interface{})
 
- 	customUser["password"] = ""
 
- 	asJSON, err := json.Marshal(customUser)
 
- 	assert.NoError(t, err)
 
- 	userNoPwd, _, err := httpdtest.UpdateUserWithJSON(user, http.StatusOK, "", asJSON)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, user.Password, userNoPwd.Password) // the password is hidden
 
- 	// check the password within the data provider
 
- 	dbUser, err = dataprovider.UserExists(u.Username)
 
- 	assert.NoError(t, err)
 
- 	assert.Empty(t, dbUser.Password)
 
- 	assert.False(t, dbUser.IsPasswordHashed())
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUpdateUser(t *testing.T) {
 
- 	u := getTestUser()
 
- 	u.UsedQuotaFiles = 1
 
- 	u.UsedQuotaSize = 2
 
- 	u.Filters.TLSUsername = sdk.TLSUsernameCN
 
- 	u.Filters.Hooks.CheckPasswordDisabled = true
 
- 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, 0, user.UsedQuotaFiles)
 
- 	assert.Equal(t, int64(0), user.UsedQuotaSize)
 
- 	user.HomeDir = filepath.Join(homeBasePath, "testmod")
 
- 	user.UID = 33
 
- 	user.GID = 101
 
- 	user.MaxSessions = 10
 
- 	user.QuotaSize = 4096
 
- 	user.QuotaFiles = 2
 
- 	user.Permissions["/"] = []string{dataprovider.PermCreateDirs, dataprovider.PermDelete, dataprovider.PermDownload}
 
- 	user.Permissions["/subdir"] = []string{dataprovider.PermListItems, dataprovider.PermUpload}
 
- 	user.Filters.AllowedIP = []string{"192.168.1.0/24", "192.168.2.0/24"}
 
- 	user.Filters.DeniedIP = []string{"192.168.3.0/24", "192.168.4.0/24"}
 
- 	user.Filters.DeniedLoginMethods = []string{dataprovider.LoginMethodPassword}
 
- 	user.Filters.DeniedProtocols = []string{common.ProtocolWebDAV}
 
- 	user.Filters.TLSUsername = sdk.TLSUsernameNone
 
- 	user.Filters.Hooks.ExternalAuthDisabled = true
 
- 	user.Filters.Hooks.PreLoginDisabled = true
 
- 	user.Filters.Hooks.CheckPasswordDisabled = false
 
- 	user.Filters.DisableFsChecks = true
 
- 	user.Filters.FilePatterns = append(user.Filters.FilePatterns, sdk.PatternsFilter{
 
- 		Path:            "/subdir",
 
- 		AllowedPatterns: []string{"*.zip", "*.rar"},
 
- 		DeniedPatterns:  []string{"*.jpg", "*.png"},
 
- 		DenyPolicy:      sdk.DenyPolicyHide,
 
- 	})
 
- 	user.Filters.MaxUploadFileSize = 4096
 
- 	user.UploadBandwidth = 1024
 
- 	user.DownloadBandwidth = 512
 
- 	user.VirtualFolders = nil
 
- 	mappedPath1 := filepath.Join(os.TempDir(), "mapped_dir1")
 
- 	mappedPath2 := filepath.Join(os.TempDir(), "mapped_dir2")
 
- 	folderName1 := filepath.Base(mappedPath1)
 
- 	folderName2 := filepath.Base(mappedPath2)
 
- 	user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{
 
- 		BaseVirtualFolder: vfs.BaseVirtualFolder{
 
- 			Name:       folderName1,
 
- 			MappedPath: mappedPath1,
 
- 		},
 
- 		VirtualPath: "/vdir1",
 
- 	})
 
- 	user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{
 
- 		BaseVirtualFolder: vfs.BaseVirtualFolder{
 
- 			Name:       folderName2,
 
- 			MappedPath: mappedPath2,
 
- 		},
 
- 		VirtualPath: "/vdir12/subdir",
 
- 		QuotaSize:   123,
 
- 		QuotaFiles:  2,
 
- 	})
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.UpdateUser(user, http.StatusBadRequest, "invalid")
 
- 	assert.NoError(t, err)
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "0")
 
- 	assert.NoError(t, err)
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "1")
 
- 	assert.NoError(t, err)
 
- 	user.Permissions["/subdir"] = []string{}
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, user.Permissions["/subdir"], 0)
 
- 	assert.Len(t, user.VirtualFolders, 2)
 
- 	for _, folder := range user.VirtualFolders {
 
- 		assert.Greater(t, folder.ID, int64(0))
 
- 		if folder.VirtualPath == "/vdir12/subdir" {
 
- 			assert.Equal(t, int64(123), folder.QuotaSize)
 
- 			assert.Equal(t, 2, folder.QuotaFiles)
 
- 		}
 
- 	}
 
- 	folder, _, err := httpdtest.GetFolderByName(folderName1, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, folder.Users, 1)
 
- 	assert.Contains(t, folder.Users, user.Username)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	// removing the user must remove folder mapping
 
- 	folder, _, err = httpdtest.GetFolderByName(folderName1, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, folder.Users, 0)
 
- 	_, err = httpdtest.RemoveFolder(folder, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	folder, _, err = httpdtest.GetFolderByName(folderName2, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, folder.Users, 0)
 
- 	_, err = httpdtest.RemoveFolder(folder, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUpdateUserTransferQuotaUsage(t *testing.T) {
 
- 	u := getTestUser()
 
- 	usedDownloadDataTransfer := int64(2 * 1024 * 1024)
 
- 	usedUploadDataTransfer := int64(1024 * 1024)
 
- 	u.UsedDownloadDataTransfer = usedDownloadDataTransfer
 
- 	u.UsedUploadDataTransfer = usedUploadDataTransfer
 
- 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, int64(0), user.UsedUploadDataTransfer)
 
- 	assert.Equal(t, int64(0), user.UsedDownloadDataTransfer)
 
- 	_, err = httpdtest.UpdateTransferQuotaUsage(u, "invalid_mode", http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.UpdateTransferQuotaUsage(u, "", http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, usedUploadDataTransfer, user.UsedUploadDataTransfer)
 
- 	assert.Equal(t, usedDownloadDataTransfer, user.UsedDownloadDataTransfer)
 
- 	_, err = httpdtest.UpdateTransferQuotaUsage(u, "add", http.StatusBadRequest)
 
- 	assert.NoError(t, err, "user has no transfer quota restrictions add mode should fail")
 
- 	user.TotalDataTransfer = 100
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.UpdateTransferQuotaUsage(u, "add", http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, 2*usedUploadDataTransfer, user.UsedUploadDataTransfer)
 
- 	assert.Equal(t, 2*usedDownloadDataTransfer, user.UsedDownloadDataTransfer)
 
- 	u.UsedDownloadDataTransfer = -1
 
- 	_, err = httpdtest.UpdateTransferQuotaUsage(u, "add", http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.UsedDownloadDataTransfer = usedDownloadDataTransfer
 
- 	u.Username += "1"
 
- 	_, err = httpdtest.UpdateTransferQuotaUsage(u, "", http.StatusNotFound)
 
- 	assert.NoError(t, err)
 
- 	u.Username = defaultUsername
 
- 	_, err = httpdtest.UpdateTransferQuotaUsage(u, "", http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, usedUploadDataTransfer, user.UsedUploadDataTransfer)
 
- 	assert.Equal(t, usedDownloadDataTransfer, user.UsedDownloadDataTransfer)
 
- 	u.UsedDownloadDataTransfer = 0
 
- 	u.UsedUploadDataTransfer = 1
 
- 	_, err = httpdtest.UpdateTransferQuotaUsage(u, "add", http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, usedUploadDataTransfer+1, user.UsedUploadDataTransfer)
 
- 	assert.Equal(t, usedDownloadDataTransfer, user.UsedDownloadDataTransfer)
 
- 	u.UsedDownloadDataTransfer = 1
 
- 	u.UsedUploadDataTransfer = 0
 
- 	_, err = httpdtest.UpdateTransferQuotaUsage(u, "add", http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, usedUploadDataTransfer+1, user.UsedUploadDataTransfer)
 
- 	assert.Equal(t, usedDownloadDataTransfer+1, user.UsedDownloadDataTransfer)
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodPut, path.Join(quotasBasePath, "users", u.Username, "transfer-usage"),
 
- 		bytes.NewBuffer([]byte(`not a json`)))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUpdateUserQuotaUsage(t *testing.T) {
 
- 	u := getTestUser()
 
- 	usedQuotaFiles := 1
 
- 	usedQuotaSize := int64(65535)
 
- 	u.UsedQuotaFiles = usedQuotaFiles
 
- 	u.UsedQuotaSize = usedQuotaSize
 
- 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, 0, user.UsedQuotaFiles)
 
- 	assert.Equal(t, int64(0), user.UsedQuotaSize)
 
- 	_, err = httpdtest.UpdateQuotaUsage(u, "invalid_mode", http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.UpdateQuotaUsage(u, "", http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, usedQuotaFiles, user.UsedQuotaFiles)
 
- 	assert.Equal(t, usedQuotaSize, user.UsedQuotaSize)
 
- 	_, err = httpdtest.UpdateQuotaUsage(u, "add", http.StatusBadRequest)
 
- 	assert.NoError(t, err, "user has no quota restrictions add mode should fail")
 
- 	user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, usedQuotaFiles, user.UsedQuotaFiles)
 
- 	assert.Equal(t, usedQuotaSize, user.UsedQuotaSize)
 
- 	user.QuotaFiles = 100
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.UpdateQuotaUsage(u, "add", http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, 2*usedQuotaFiles, user.UsedQuotaFiles)
 
- 	assert.Equal(t, 2*usedQuotaSize, user.UsedQuotaSize)
 
- 	u.UsedQuotaFiles = -1
 
- 	_, err = httpdtest.UpdateQuotaUsage(u, "", http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.UsedQuotaFiles = usedQuotaFiles
 
- 	u.Username = u.Username + "1"
 
- 	_, err = httpdtest.UpdateQuotaUsage(u, "", http.StatusNotFound)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUserFolderMapping(t *testing.T) {
 
- 	mappedPath1 := filepath.Join(os.TempDir(), "mapped_dir1")
 
- 	mappedPath2 := filepath.Join(os.TempDir(), "mapped_dir2")
 
- 	folderName1 := filepath.Base(mappedPath1)
 
- 	folderName2 := filepath.Base(mappedPath2)
 
- 	u1 := getTestUser()
 
- 	u1.VirtualFolders = append(u1.VirtualFolders, vfs.VirtualFolder{
 
- 		BaseVirtualFolder: vfs.BaseVirtualFolder{
 
- 			Name:            folderName1,
 
- 			MappedPath:      mappedPath1,
 
- 			UsedQuotaFiles:  2,
 
- 			UsedQuotaSize:   123,
 
- 			LastQuotaUpdate: 456,
 
- 		},
 
- 		VirtualPath: "/vdir",
 
- 		QuotaSize:   -1,
 
- 		QuotaFiles:  -1,
 
- 	})
 
- 	user1, _, err := httpdtest.AddUser(u1, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	// virtual folder must be auto created
 
- 	folder, _, err := httpdtest.GetFolderByName(folderName1, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, folder.Users, 1)
 
- 	assert.Contains(t, folder.Users, user1.Username)
 
- 	assert.Equal(t, 0, folder.UsedQuotaFiles)
 
- 	assert.Equal(t, int64(0), folder.UsedQuotaSize)
 
- 	assert.Equal(t, int64(0), folder.LastQuotaUpdate)
 
- 	assert.Equal(t, 0, user1.VirtualFolders[0].UsedQuotaFiles)
 
- 	assert.Equal(t, int64(0), user1.VirtualFolders[0].UsedQuotaSize)
 
- 	assert.Equal(t, int64(0), user1.VirtualFolders[0].LastQuotaUpdate)
 
- 	u2 := getTestUser()
 
- 	u2.Username = defaultUsername + "2"
 
- 	u2.VirtualFolders = append(u2.VirtualFolders, vfs.VirtualFolder{
 
- 		BaseVirtualFolder: vfs.BaseVirtualFolder{
 
- 			Name:       folderName1,
 
- 			MappedPath: mappedPath1,
 
- 		},
 
- 		VirtualPath: "/vdir1",
 
- 		QuotaSize:   0,
 
- 		QuotaFiles:  0,
 
- 	})
 
- 	u2.VirtualFolders = append(u2.VirtualFolders, vfs.VirtualFolder{
 
- 		BaseVirtualFolder: vfs.BaseVirtualFolder{
 
- 			Name:       folderName2,
 
- 			MappedPath: mappedPath2,
 
- 		},
 
- 		VirtualPath: "/vdir2",
 
- 		QuotaSize:   -1,
 
- 		QuotaFiles:  -1,
 
- 	})
 
- 	user2, _, err := httpdtest.AddUser(u2, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	folder, _, err = httpdtest.GetFolderByName(folderName2, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, folder.Users, 1)
 
- 	assert.Contains(t, folder.Users, user2.Username)
 
- 	folder, _, err = httpdtest.GetFolderByName(folderName1, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, folder.Users, 2)
 
- 	assert.Contains(t, folder.Users, user1.Username)
 
- 	assert.Contains(t, folder.Users, user2.Username)
 
- 	// now update user2 removing mappedPath1
 
- 	user2.VirtualFolders = nil
 
- 	user2.VirtualFolders = append(user2.VirtualFolders, vfs.VirtualFolder{
 
- 		BaseVirtualFolder: vfs.BaseVirtualFolder{
 
- 			Name:           folderName2,
 
- 			MappedPath:     mappedPath2,
 
- 			UsedQuotaFiles: 2,
 
- 			UsedQuotaSize:  123,
 
- 		},
 
- 		VirtualPath: "/vdir",
 
- 		QuotaSize:   0,
 
- 		QuotaFiles:  0,
 
- 	})
 
- 	user2, _, err = httpdtest.UpdateUser(user2, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	folder, _, err = httpdtest.GetFolderByName(folderName2, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, folder.Users, 1)
 
- 	assert.Contains(t, folder.Users, user2.Username)
 
- 	assert.Equal(t, 0, folder.UsedQuotaFiles)
 
- 	assert.Equal(t, int64(0), folder.UsedQuotaSize)
 
- 	folder, _, err = httpdtest.GetFolderByName(folderName1, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, folder.Users, 1)
 
- 	assert.Contains(t, folder.Users, user1.Username)
 
- 	// add mappedPath1 again to user2
 
- 	user2.VirtualFolders = append(user2.VirtualFolders, vfs.VirtualFolder{
 
- 		BaseVirtualFolder: vfs.BaseVirtualFolder{
 
- 			Name:       folderName1,
 
- 			MappedPath: mappedPath1,
 
- 		},
 
- 		VirtualPath: "/vdir1",
 
- 	})
 
- 	user2, _, err = httpdtest.UpdateUser(user2, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	folder, _, err = httpdtest.GetFolderByName(folderName2, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, folder.Users, 1)
 
- 	assert.Contains(t, folder.Users, user2.Username)
 
- 	// removing virtual folders should clear relations on both side
 
- 	_, err = httpdtest.RemoveFolder(vfs.BaseVirtualFolder{Name: folderName2}, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	user2, _, err = httpdtest.GetUserByUsername(user2.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	if assert.Len(t, user2.VirtualFolders, 1) {
 
- 		folder := user2.VirtualFolders[0]
 
- 		assert.Equal(t, mappedPath1, folder.MappedPath)
 
- 		assert.Equal(t, folderName1, folder.Name)
 
- 	}
 
- 	user1, _, err = httpdtest.GetUserByUsername(user1.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	if assert.Len(t, user2.VirtualFolders, 1) {
 
- 		folder := user2.VirtualFolders[0]
 
- 		assert.Equal(t, mappedPath1, folder.MappedPath)
 
- 	}
 
- 	folder, _, err = httpdtest.GetFolderByName(folderName1, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, folder.Users, 2)
 
- 	// removing a user should clear virtual folder mapping
 
- 	_, err = httpdtest.RemoveUser(user1, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	folder, _, err = httpdtest.GetFolderByName(folderName1, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, folder.Users, 1)
 
- 	assert.Contains(t, folder.Users, user2.Username)
 
- 	// removing a folder should clear mapping on the user side too
 
- 	_, err = httpdtest.RemoveFolder(vfs.BaseVirtualFolder{Name: folderName1}, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	user2, _, err = httpdtest.GetUserByUsername(user2.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, user2.VirtualFolders, 0)
 
- 	_, err = httpdtest.RemoveUser(user2, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUserS3Config(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	user.FsConfig.Provider = sdk.S3FilesystemProvider
 
- 	user.FsConfig.S3Config.Bucket = "test"      //nolint:goconst
 
- 	user.FsConfig.S3Config.Region = "us-east-1" //nolint:goconst
 
- 	user.FsConfig.S3Config.AccessKey = "Server-Access-Key"
 
- 	user.FsConfig.S3Config.AccessSecret = kms.NewPlainSecret("Server-Access-Secret")
 
- 	user.FsConfig.S3Config.SessionToken = "Session token"
 
- 	user.FsConfig.S3Config.RoleARN = "myRoleARN"
 
- 	user.FsConfig.S3Config.Endpoint = "http://127.0.0.1:9000"
 
- 	user.FsConfig.S3Config.UploadPartSize = 8
 
- 	user.FsConfig.S3Config.DownloadPartMaxTime = 60
 
- 	user.FsConfig.S3Config.UploadPartMaxTime = 40
 
- 	user.FsConfig.S3Config.ForcePathStyle = true
 
- 	user.FsConfig.S3Config.DownloadPartSize = 6
 
- 	folderName := "vfolderName"
 
- 	user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{
 
- 		BaseVirtualFolder: vfs.BaseVirtualFolder{
 
- 			Name:       folderName,
 
- 			MappedPath: filepath.Join(os.TempDir(), "folderName"),
 
- 			FsConfig: vfs.Filesystem{
 
- 				Provider: sdk.CryptedFilesystemProvider,
 
- 				CryptConfig: vfs.CryptFsConfig{
 
- 					Passphrase: kms.NewPlainSecret("Crypted-Secret"),
 
- 				},
 
- 			},
 
- 		},
 
- 		VirtualPath: "/folderPath",
 
- 	})
 
- 	user, body, err := httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err, string(body))
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.S3Config.AccessSecret.GetStatus())
 
- 	assert.NotEmpty(t, user.FsConfig.S3Config.AccessSecret.GetPayload())
 
- 	assert.Empty(t, user.FsConfig.S3Config.AccessSecret.GetAdditionalData())
 
- 	assert.Empty(t, user.FsConfig.S3Config.AccessSecret.GetKey())
 
- 	assert.Equal(t, 60, user.FsConfig.S3Config.DownloadPartMaxTime)
 
- 	assert.Equal(t, 40, user.FsConfig.S3Config.UploadPartMaxTime)
 
- 	if assert.Len(t, user.VirtualFolders, 1) {
 
- 		folder := user.VirtualFolders[0]
 
- 		assert.Equal(t, sdkkms.SecretStatusSecretBox, folder.FsConfig.CryptConfig.Passphrase.GetStatus())
 
- 		assert.NotEmpty(t, folder.FsConfig.CryptConfig.Passphrase.GetPayload())
 
- 		assert.Empty(t, folder.FsConfig.CryptConfig.Passphrase.GetAdditionalData())
 
- 		assert.Empty(t, folder.FsConfig.CryptConfig.Passphrase.GetKey())
 
- 	}
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	folder, _, err := httpdtest.GetFolderByName(folderName, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, folder.FsConfig.CryptConfig.Passphrase.GetStatus())
 
- 	assert.NotEmpty(t, folder.FsConfig.CryptConfig.Passphrase.GetPayload())
 
- 	assert.Empty(t, folder.FsConfig.CryptConfig.Passphrase.GetAdditionalData())
 
- 	assert.Empty(t, folder.FsConfig.CryptConfig.Passphrase.GetKey())
 
- 	_, err = httpdtest.RemoveFolder(folder, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	user.Password = defaultPassword
 
- 	user.ID = 0
 
- 	user.CreatedAt = 0
 
- 	user.VirtualFolders = nil
 
- 	secret := kms.NewSecret(sdkkms.SecretStatusSecretBox, "Server-Access-Secret", "", "")
 
- 	user.FsConfig.S3Config.AccessSecret = secret
 
- 	_, _, err = httpdtest.AddUser(user, http.StatusCreated)
 
- 	assert.Error(t, err)
 
- 	user.FsConfig.S3Config.AccessSecret.SetStatus(sdkkms.SecretStatusPlain)
 
- 	user, _, err = httpdtest.AddUser(user, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	initialSecretPayload := user.FsConfig.S3Config.AccessSecret.GetPayload()
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.S3Config.AccessSecret.GetStatus())
 
- 	assert.NotEmpty(t, initialSecretPayload)
 
- 	assert.Empty(t, user.FsConfig.S3Config.AccessSecret.GetAdditionalData())
 
- 	assert.Empty(t, user.FsConfig.S3Config.AccessSecret.GetKey())
 
- 	user.FsConfig.Provider = sdk.S3FilesystemProvider
 
- 	user.FsConfig.S3Config.Bucket = "test-bucket"
 
- 	user.FsConfig.S3Config.Region = "us-east-1" //nolint:goconst
 
- 	user.FsConfig.S3Config.AccessKey = "Server-Access-Key1"
 
- 	user.FsConfig.S3Config.Endpoint = "http://localhost:9000"
 
- 	user.FsConfig.S3Config.KeyPrefix = "somedir/subdir" //nolint:goconst
 
- 	user.FsConfig.S3Config.UploadConcurrency = 5
 
- 	user.FsConfig.S3Config.DownloadConcurrency = 4
 
- 	user, bb, err := httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err, string(bb))
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.S3Config.AccessSecret.GetStatus())
 
- 	assert.Equal(t, initialSecretPayload, user.FsConfig.S3Config.AccessSecret.GetPayload())
 
- 	assert.Empty(t, user.FsConfig.S3Config.AccessSecret.GetAdditionalData())
 
- 	assert.Empty(t, user.FsConfig.S3Config.AccessSecret.GetKey())
 
- 	// test user without access key and access secret (shared config state)
 
- 	user.FsConfig.Provider = sdk.S3FilesystemProvider
 
- 	user.FsConfig.S3Config.Bucket = "testbucket"
 
- 	user.FsConfig.S3Config.Region = "us-east-1"
 
- 	user.FsConfig.S3Config.AccessKey = ""
 
- 	user.FsConfig.S3Config.AccessSecret = kms.NewEmptySecret()
 
- 	user.FsConfig.S3Config.Endpoint = ""
 
- 	user.FsConfig.S3Config.KeyPrefix = "somedir/subdir"
 
- 	user.FsConfig.S3Config.UploadPartSize = 6
 
- 	user.FsConfig.S3Config.UploadConcurrency = 4
 
- 	user, body, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err, string(body))
 
- 	assert.Nil(t, user.FsConfig.S3Config.AccessSecret)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	user.Password = defaultPassword
 
- 	user.ID = 0
 
- 	user.CreatedAt = 0
 
- 	// shared credential test for add instead of update
 
- 	user, _, err = httpdtest.AddUser(user, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	assert.Nil(t, user.FsConfig.S3Config.AccessSecret)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUserGCSConfig(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(credentialsPath)
 
- 	assert.NoError(t, err)
 
- 	err = os.MkdirAll(credentialsPath, 0700)
 
- 	assert.NoError(t, err)
 
- 	user.FsConfig.Provider = sdk.GCSFilesystemProvider
 
- 	user.FsConfig.GCSConfig.Bucket = "test"
 
- 	user.FsConfig.GCSConfig.Credentials = kms.NewPlainSecret("fake credentials") //nolint:goconst
 
- 	user, bb, err := httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err, string(bb))
 
- 	credentialFile := filepath.Join(credentialsPath, fmt.Sprintf("%v_gcs_credentials.json", user.Username))
 
- 	assert.FileExists(t, credentialFile)
 
- 	creds, err := os.ReadFile(credentialFile)
 
- 	assert.NoError(t, err)
 
- 	secret := kms.NewEmptySecret()
 
- 	err = json.Unmarshal(creds, secret)
 
- 	assert.NoError(t, err)
 
- 	err = secret.Decrypt()
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, "fake credentials", secret.GetPayload())
 
- 	user.FsConfig.GCSConfig.Credentials = kms.NewSecret(sdkkms.SecretStatusSecretBox, "fake encrypted credentials", "", "")
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	assert.FileExists(t, credentialFile)
 
- 	creds, err = os.ReadFile(credentialFile)
 
- 	assert.NoError(t, err)
 
- 	secret = kms.NewEmptySecret()
 
- 	err = json.Unmarshal(creds, secret)
 
- 	assert.NoError(t, err)
 
- 	err = secret.Decrypt()
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, "fake credentials", secret.GetPayload())
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	user.Password = defaultPassword
 
- 	user.ID = 0
 
- 	user.CreatedAt = 0
 
- 	user.FsConfig.GCSConfig.Credentials = kms.NewSecret(sdkkms.SecretStatusSecretBox, "fake credentials", "", "")
 
- 	_, _, err = httpdtest.AddUser(user, http.StatusCreated)
 
- 	assert.Error(t, err)
 
- 	user.FsConfig.GCSConfig.Credentials.SetStatus(sdkkms.SecretStatusPlain)
 
- 	user, body, err := httpdtest.AddUser(user, http.StatusCreated)
 
- 	assert.NoError(t, err, string(body))
 
- 	err = os.RemoveAll(credentialsPath)
 
- 	assert.NoError(t, err)
 
- 	err = os.MkdirAll(credentialsPath, 0700)
 
- 	assert.NoError(t, err)
 
- 	user.FsConfig.GCSConfig.Credentials = kms.NewEmptySecret()
 
- 	user.FsConfig.GCSConfig.AutomaticCredentials = 1
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	assert.NoFileExists(t, credentialFile)
 
- 	user.FsConfig.GCSConfig = vfs.GCSFsConfig{}
 
- 	user.FsConfig.Provider = sdk.S3FilesystemProvider
 
- 	user.FsConfig.S3Config.Bucket = "test1"
 
- 	user.FsConfig.S3Config.Region = "us-east-1"
 
- 	user.FsConfig.S3Config.AccessKey = "Server-Access-Key1"
 
- 	user.FsConfig.S3Config.AccessSecret = kms.NewPlainSecret("secret")
 
- 	user.FsConfig.S3Config.Endpoint = "http://localhost:9000"
 
- 	user.FsConfig.S3Config.KeyPrefix = "somedir/subdir"
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	user.FsConfig.S3Config = vfs.S3FsConfig{}
 
- 	user.FsConfig.Provider = sdk.GCSFilesystemProvider
 
- 	user.FsConfig.GCSConfig.Bucket = "test1"
 
- 	user.FsConfig.GCSConfig.Credentials = kms.NewPlainSecret("fake credentials")
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUserAzureBlobConfig(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	user.FsConfig.Provider = sdk.AzureBlobFilesystemProvider
 
- 	user.FsConfig.AzBlobConfig.Container = "test"
 
- 	user.FsConfig.AzBlobConfig.AccountName = "Server-Account-Name"
 
- 	user.FsConfig.AzBlobConfig.AccountKey = kms.NewPlainSecret("Server-Account-Key")
 
- 	user.FsConfig.AzBlobConfig.Endpoint = "http://127.0.0.1:9000"
 
- 	user.FsConfig.AzBlobConfig.UploadPartSize = 8
 
- 	user.FsConfig.AzBlobConfig.DownloadPartSize = 6
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	initialPayload := user.FsConfig.AzBlobConfig.AccountKey.GetPayload()
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.AzBlobConfig.AccountKey.GetStatus())
 
- 	assert.NotEmpty(t, initialPayload)
 
- 	assert.Empty(t, user.FsConfig.AzBlobConfig.AccountKey.GetAdditionalData())
 
- 	assert.Empty(t, user.FsConfig.AzBlobConfig.AccountKey.GetKey())
 
- 	user.FsConfig.AzBlobConfig.AccountKey.SetStatus(sdkkms.SecretStatusSecretBox)
 
- 	user.FsConfig.AzBlobConfig.AccountKey.SetAdditionalData("data")
 
- 	user.FsConfig.AzBlobConfig.AccountKey.SetKey("fake key")
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.AzBlobConfig.AccountKey.GetStatus())
 
- 	assert.Equal(t, initialPayload, user.FsConfig.AzBlobConfig.AccountKey.GetPayload())
 
- 	assert.Empty(t, user.FsConfig.AzBlobConfig.AccountKey.GetAdditionalData())
 
- 	assert.Empty(t, user.FsConfig.AzBlobConfig.AccountKey.GetKey())
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	user.Password = defaultPassword
 
- 	user.ID = 0
 
- 	user.CreatedAt = 0
 
- 	secret := kms.NewSecret(sdkkms.SecretStatusSecretBox, "Server-Account-Key", "", "")
 
- 	user.FsConfig.AzBlobConfig.AccountKey = secret
 
- 	_, _, err = httpdtest.AddUser(user, http.StatusCreated)
 
- 	assert.Error(t, err)
 
- 	user.FsConfig.AzBlobConfig.AccountKey = kms.NewPlainSecret("Server-Account-Key-Test")
 
- 	user, _, err = httpdtest.AddUser(user, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	initialPayload = user.FsConfig.AzBlobConfig.AccountKey.GetPayload()
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.AzBlobConfig.AccountKey.GetStatus())
 
- 	assert.NotEmpty(t, initialPayload)
 
- 	assert.Empty(t, user.FsConfig.AzBlobConfig.AccountKey.GetAdditionalData())
 
- 	assert.Empty(t, user.FsConfig.AzBlobConfig.AccountKey.GetKey())
 
- 	user.FsConfig.Provider = sdk.AzureBlobFilesystemProvider
 
- 	user.FsConfig.AzBlobConfig.Container = "test-container"
 
- 	user.FsConfig.AzBlobConfig.Endpoint = "http://localhost:9001"
 
- 	user.FsConfig.AzBlobConfig.KeyPrefix = "somedir/subdir"
 
- 	user.FsConfig.AzBlobConfig.UploadConcurrency = 5
 
- 	user.FsConfig.AzBlobConfig.DownloadConcurrency = 4
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.AzBlobConfig.AccountKey.GetStatus())
 
- 	assert.NotEmpty(t, initialPayload)
 
- 	assert.Equal(t, initialPayload, user.FsConfig.AzBlobConfig.AccountKey.GetPayload())
 
- 	assert.Empty(t, user.FsConfig.AzBlobConfig.AccountKey.GetAdditionalData())
 
- 	assert.Empty(t, user.FsConfig.AzBlobConfig.AccountKey.GetKey())
 
- 	// test user without access key and access secret (SAS)
 
- 	user.FsConfig.Provider = sdk.AzureBlobFilesystemProvider
 
- 	user.FsConfig.AzBlobConfig.SASURL = kms.NewPlainSecret("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")
 
- 	user.FsConfig.AzBlobConfig.KeyPrefix = "somedir/subdir"
 
- 	user.FsConfig.AzBlobConfig.AccountName = ""
 
- 	user.FsConfig.AzBlobConfig.AccountKey = kms.NewEmptySecret()
 
- 	user.FsConfig.AzBlobConfig.UploadPartSize = 6
 
- 	user.FsConfig.AzBlobConfig.UploadConcurrency = 4
 
- 	user.FsConfig.AzBlobConfig.DownloadPartSize = 3
 
- 	user.FsConfig.AzBlobConfig.DownloadConcurrency = 5
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	assert.Nil(t, user.FsConfig.AzBlobConfig.AccountKey)
 
- 	assert.NotNil(t, user.FsConfig.AzBlobConfig.SASURL)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	user.Password = defaultPassword
 
- 	user.ID = 0
 
- 	user.CreatedAt = 0
 
- 	// sas test for add instead of update
 
- 	user.FsConfig.AzBlobConfig = vfs.AzBlobFsConfig{
 
- 		BaseAzBlobFsConfig: sdk.BaseAzBlobFsConfig{
 
- 			Container: user.FsConfig.AzBlobConfig.Container,
 
- 		},
 
- 		SASURL: kms.NewPlainSecret("http://127.0.0.1/fake/sass/url"),
 
- 	}
 
- 	user, _, err = httpdtest.AddUser(user, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	assert.Nil(t, user.FsConfig.AzBlobConfig.AccountKey)
 
- 	initialPayload = user.FsConfig.AzBlobConfig.SASURL.GetPayload()
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.AzBlobConfig.SASURL.GetStatus())
 
- 	assert.NotEmpty(t, initialPayload)
 
- 	assert.Empty(t, user.FsConfig.AzBlobConfig.SASURL.GetAdditionalData())
 
- 	assert.Empty(t, user.FsConfig.AzBlobConfig.SASURL.GetKey())
 
- 	user.FsConfig.AzBlobConfig.SASURL.SetStatus(sdkkms.SecretStatusSecretBox)
 
- 	user.FsConfig.AzBlobConfig.SASURL.SetAdditionalData("data")
 
- 	user.FsConfig.AzBlobConfig.SASURL.SetKey("fake key")
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.AzBlobConfig.SASURL.GetStatus())
 
- 	assert.Equal(t, initialPayload, user.FsConfig.AzBlobConfig.SASURL.GetPayload())
 
- 	assert.Empty(t, user.FsConfig.AzBlobConfig.SASURL.GetAdditionalData())
 
- 	assert.Empty(t, user.FsConfig.AzBlobConfig.SASURL.GetKey())
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUserCryptFs(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	user.FsConfig.Provider = sdk.CryptedFilesystemProvider
 
- 	user.FsConfig.CryptConfig.Passphrase = kms.NewPlainSecret("crypt passphrase")
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	initialPayload := user.FsConfig.CryptConfig.Passphrase.GetPayload()
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.CryptConfig.Passphrase.GetStatus())
 
- 	assert.NotEmpty(t, initialPayload)
 
- 	assert.Empty(t, user.FsConfig.CryptConfig.Passphrase.GetAdditionalData())
 
- 	assert.Empty(t, user.FsConfig.CryptConfig.Passphrase.GetKey())
 
- 	user.FsConfig.CryptConfig.Passphrase.SetStatus(sdkkms.SecretStatusSecretBox)
 
- 	user.FsConfig.CryptConfig.Passphrase.SetAdditionalData("data")
 
- 	user.FsConfig.CryptConfig.Passphrase.SetKey("fake pass key")
 
- 	user, bb, err := httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err, string(bb))
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.CryptConfig.Passphrase.GetStatus())
 
- 	assert.Equal(t, initialPayload, user.FsConfig.CryptConfig.Passphrase.GetPayload())
 
- 	assert.Empty(t, user.FsConfig.CryptConfig.Passphrase.GetAdditionalData())
 
- 	assert.Empty(t, user.FsConfig.CryptConfig.Passphrase.GetKey())
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	user.Password = defaultPassword
 
- 	user.ID = 0
 
- 	user.CreatedAt = 0
 
- 	secret := kms.NewSecret(sdkkms.SecretStatusSecretBox, "invalid encrypted payload", "", "")
 
- 	user.FsConfig.CryptConfig.Passphrase = secret
 
- 	_, _, err = httpdtest.AddUser(user, http.StatusCreated)
 
- 	assert.Error(t, err)
 
- 	user.FsConfig.CryptConfig.Passphrase = kms.NewPlainSecret("passphrase test")
 
- 	user, _, err = httpdtest.AddUser(user, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	initialPayload = user.FsConfig.CryptConfig.Passphrase.GetPayload()
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.CryptConfig.Passphrase.GetStatus())
 
- 	assert.NotEmpty(t, initialPayload)
 
- 	assert.Empty(t, user.FsConfig.CryptConfig.Passphrase.GetAdditionalData())
 
- 	assert.Empty(t, user.FsConfig.CryptConfig.Passphrase.GetKey())
 
- 	user.FsConfig.Provider = sdk.CryptedFilesystemProvider
 
- 	user.FsConfig.CryptConfig.Passphrase.SetKey("pass")
 
- 	user, bb, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err, string(bb))
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.CryptConfig.Passphrase.GetStatus())
 
- 	assert.NotEmpty(t, initialPayload)
 
- 	assert.Equal(t, initialPayload, user.FsConfig.CryptConfig.Passphrase.GetPayload())
 
- 	assert.Empty(t, user.FsConfig.CryptConfig.Passphrase.GetAdditionalData())
 
- 	assert.Empty(t, user.FsConfig.CryptConfig.Passphrase.GetKey())
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUserSFTPFs(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	user.FsConfig.Provider = sdk.SFTPFilesystemProvider
 
- 	user.FsConfig.SFTPConfig.Endpoint = "127.0.0.1" // missing port
 
- 	user.FsConfig.SFTPConfig.Username = "sftp_user"
 
- 	user.FsConfig.SFTPConfig.Password = kms.NewPlainSecret("sftp_pwd")
 
- 	user.FsConfig.SFTPConfig.PrivateKey = kms.NewPlainSecret(sftpPrivateKey)
 
- 	user.FsConfig.SFTPConfig.Fingerprints = []string{sftpPkeyFingerprint}
 
- 	user.FsConfig.SFTPConfig.BufferSize = 2
 
- 	_, resp, err := httpdtest.UpdateUser(user, http.StatusBadRequest, "")
 
- 	assert.NoError(t, err)
 
- 	assert.Contains(t, string(resp), "invalid endpoint")
 
- 	user.FsConfig.SFTPConfig.Endpoint = "127.0.0.1:2022"
 
- 	user.FsConfig.SFTPConfig.DisableCouncurrentReads = true
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, "/", user.FsConfig.SFTPConfig.Prefix)
 
- 	assert.True(t, user.FsConfig.SFTPConfig.DisableCouncurrentReads)
 
- 	assert.Equal(t, int64(2), user.FsConfig.SFTPConfig.BufferSize)
 
- 	initialPwdPayload := user.FsConfig.SFTPConfig.Password.GetPayload()
 
- 	initialPkeyPayload := user.FsConfig.SFTPConfig.PrivateKey.GetPayload()
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.SFTPConfig.Password.GetStatus())
 
- 	assert.NotEmpty(t, initialPwdPayload)
 
- 	assert.Empty(t, user.FsConfig.SFTPConfig.Password.GetAdditionalData())
 
- 	assert.Empty(t, user.FsConfig.SFTPConfig.Password.GetKey())
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.SFTPConfig.PrivateKey.GetStatus())
 
- 	assert.NotEmpty(t, initialPkeyPayload)
 
- 	assert.Empty(t, user.FsConfig.SFTPConfig.PrivateKey.GetAdditionalData())
 
- 	assert.Empty(t, user.FsConfig.SFTPConfig.PrivateKey.GetKey())
 
- 	user.FsConfig.SFTPConfig.Password.SetStatus(sdkkms.SecretStatusSecretBox)
 
- 	user.FsConfig.SFTPConfig.Password.SetAdditionalData("adata")
 
- 	user.FsConfig.SFTPConfig.Password.SetKey("fake pwd key")
 
- 	user.FsConfig.SFTPConfig.PrivateKey.SetStatus(sdkkms.SecretStatusSecretBox)
 
- 	user.FsConfig.SFTPConfig.PrivateKey.SetAdditionalData("adata")
 
- 	user.FsConfig.SFTPConfig.PrivateKey.SetKey("fake key")
 
- 	user.FsConfig.SFTPConfig.DisableCouncurrentReads = false
 
- 	user, bb, err := httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err, string(bb))
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.SFTPConfig.Password.GetStatus())
 
- 	assert.Equal(t, initialPwdPayload, user.FsConfig.SFTPConfig.Password.GetPayload())
 
- 	assert.Empty(t, user.FsConfig.SFTPConfig.Password.GetAdditionalData())
 
- 	assert.Empty(t, user.FsConfig.SFTPConfig.Password.GetKey())
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.SFTPConfig.PrivateKey.GetStatus())
 
- 	assert.Equal(t, initialPkeyPayload, user.FsConfig.SFTPConfig.PrivateKey.GetPayload())
 
- 	assert.Empty(t, user.FsConfig.SFTPConfig.PrivateKey.GetAdditionalData())
 
- 	assert.Empty(t, user.FsConfig.SFTPConfig.PrivateKey.GetKey())
 
- 	assert.False(t, user.FsConfig.SFTPConfig.DisableCouncurrentReads)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	user.Password = defaultPassword
 
- 	user.ID = 0
 
- 	user.CreatedAt = 0
 
- 	secret := kms.NewSecret(sdkkms.SecretStatusSecretBox, "invalid encrypted payload", "", "")
 
- 	user.FsConfig.SFTPConfig.Password = secret
 
- 	_, _, err = httpdtest.AddUser(user, http.StatusCreated)
 
- 	assert.Error(t, err)
 
- 	user.FsConfig.SFTPConfig.Password = kms.NewEmptySecret()
 
- 	user.FsConfig.SFTPConfig.PrivateKey = secret
 
- 	_, _, err = httpdtest.AddUser(user, http.StatusCreated)
 
- 	assert.Error(t, err)
 
- 	user.FsConfig.SFTPConfig.PrivateKey = kms.NewPlainSecret(sftpPrivateKey)
 
- 	user, _, err = httpdtest.AddUser(user, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	initialPkeyPayload = user.FsConfig.SFTPConfig.PrivateKey.GetPayload()
 
- 	assert.Nil(t, user.FsConfig.SFTPConfig.Password)
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.SFTPConfig.PrivateKey.GetStatus())
 
- 	assert.NotEmpty(t, initialPkeyPayload)
 
- 	assert.Empty(t, user.FsConfig.SFTPConfig.PrivateKey.GetAdditionalData())
 
- 	assert.Empty(t, user.FsConfig.SFTPConfig.PrivateKey.GetKey())
 
- 	user.FsConfig.Provider = sdk.SFTPFilesystemProvider
 
- 	user.FsConfig.SFTPConfig.PrivateKey.SetKey("k")
 
- 	user, bb, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err, string(bb))
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.SFTPConfig.PrivateKey.GetStatus())
 
- 	assert.NotEmpty(t, initialPkeyPayload)
 
- 	assert.Equal(t, initialPkeyPayload, user.FsConfig.SFTPConfig.PrivateKey.GetPayload())
 
- 	assert.Empty(t, user.FsConfig.SFTPConfig.PrivateKey.GetAdditionalData())
 
- 	assert.Empty(t, user.FsConfig.SFTPConfig.PrivateKey.GetKey())
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUserHiddenFields(t *testing.T) {
 
- 	err := dataprovider.Close()
 
- 	assert.NoError(t, err)
 
- 	err = config.LoadConfig(configDir, "")
 
- 	assert.NoError(t, err)
 
- 	providerConf := config.GetProviderConf()
 
- 	providerConf.PreferDatabaseCredentials = true
 
- 	err = dataprovider.Initialize(providerConf, configDir, true)
 
- 	assert.NoError(t, err)
 
- 	// sensitive data must be hidden but not deleted from the dataprovider
 
- 	usernames := []string{"user1", "user2", "user3", "user4", "user5"}
 
- 	u1 := getTestUser()
 
- 	u1.Username = usernames[0]
 
- 	u1.FsConfig.Provider = sdk.S3FilesystemProvider
 
- 	u1.FsConfig.S3Config.Bucket = "test"
 
- 	u1.FsConfig.S3Config.Region = "us-east-1"
 
- 	u1.FsConfig.S3Config.AccessKey = "S3-Access-Key"
 
- 	u1.FsConfig.S3Config.AccessSecret = kms.NewPlainSecret("S3-Access-Secret")
 
- 	user1, _, err := httpdtest.AddUser(u1, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	u2 := getTestUser()
 
- 	u2.Username = usernames[1]
 
- 	u2.FsConfig.Provider = sdk.GCSFilesystemProvider
 
- 	u2.FsConfig.GCSConfig.Bucket = "test"
 
- 	u2.FsConfig.GCSConfig.Credentials = kms.NewPlainSecret("fake credentials")
 
- 	u2.FsConfig.GCSConfig.ACL = "bucketOwnerRead"
 
- 	user2, _, err := httpdtest.AddUser(u2, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	u3 := getTestUser()
 
- 	u3.Username = usernames[2]
 
- 	u3.FsConfig.Provider = sdk.AzureBlobFilesystemProvider
 
- 	u3.FsConfig.AzBlobConfig.Container = "test"
 
- 	u3.FsConfig.AzBlobConfig.AccountName = "Server-Account-Name"
 
- 	u3.FsConfig.AzBlobConfig.AccountKey = kms.NewPlainSecret("Server-Account-Key")
 
- 	user3, _, err := httpdtest.AddUser(u3, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	u4 := getTestUser()
 
- 	u4.Username = usernames[3]
 
- 	u4.FsConfig.Provider = sdk.CryptedFilesystemProvider
 
- 	u4.FsConfig.CryptConfig.Passphrase = kms.NewPlainSecret("test passphrase")
 
- 	user4, _, err := httpdtest.AddUser(u4, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	u5 := getTestUser()
 
- 	u5.Username = usernames[4]
 
- 	u5.FsConfig.Provider = sdk.SFTPFilesystemProvider
 
- 	u5.FsConfig.SFTPConfig.Endpoint = "127.0.0.1:2022"
 
- 	u5.FsConfig.SFTPConfig.Username = "sftp_user"
 
- 	u5.FsConfig.SFTPConfig.Password = kms.NewPlainSecret("apassword")
 
- 	u5.FsConfig.SFTPConfig.PrivateKey = kms.NewPlainSecret(sftpPrivateKey)
 
- 	u5.FsConfig.SFTPConfig.Fingerprints = []string{sftpPkeyFingerprint}
 
- 	u5.FsConfig.SFTPConfig.Prefix = "/prefix"
 
- 	user5, _, err := httpdtest.AddUser(u5, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	users, _, err := httpdtest.GetUsers(0, 0, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.GreaterOrEqual(t, len(users), 5)
 
- 	for _, username := range usernames {
 
- 		user, _, err := httpdtest.GetUserByUsername(username, http.StatusOK)
 
- 		assert.NoError(t, err)
 
- 		assert.Empty(t, user.Password)
 
- 	}
 
- 	user1, _, err = httpdtest.GetUserByUsername(user1.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Empty(t, user1.Password)
 
- 	assert.Empty(t, user1.FsConfig.S3Config.AccessSecret.GetKey())
 
- 	assert.Empty(t, user1.FsConfig.S3Config.AccessSecret.GetAdditionalData())
 
- 	assert.NotEmpty(t, user1.FsConfig.S3Config.AccessSecret.GetStatus())
 
- 	assert.NotEmpty(t, user1.FsConfig.S3Config.AccessSecret.GetPayload())
 
- 	user2, _, err = httpdtest.GetUserByUsername(user2.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Empty(t, user2.Password)
 
- 	assert.Empty(t, user2.FsConfig.GCSConfig.Credentials.GetKey())
 
- 	assert.Empty(t, user2.FsConfig.GCSConfig.Credentials.GetAdditionalData())
 
- 	assert.NotEmpty(t, user2.FsConfig.GCSConfig.Credentials.GetStatus())
 
- 	assert.NotEmpty(t, user2.FsConfig.GCSConfig.Credentials.GetPayload())
 
- 	user3, _, err = httpdtest.GetUserByUsername(user3.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Empty(t, user3.Password)
 
- 	assert.Empty(t, user3.FsConfig.AzBlobConfig.AccountKey.GetKey())
 
- 	assert.Empty(t, user3.FsConfig.AzBlobConfig.AccountKey.GetAdditionalData())
 
- 	assert.NotEmpty(t, user3.FsConfig.AzBlobConfig.AccountKey.GetStatus())
 
- 	assert.NotEmpty(t, user3.FsConfig.AzBlobConfig.AccountKey.GetPayload())
 
- 	user4, _, err = httpdtest.GetUserByUsername(user4.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Empty(t, user4.Password)
 
- 	assert.Empty(t, user4.FsConfig.CryptConfig.Passphrase.GetKey())
 
- 	assert.Empty(t, user4.FsConfig.CryptConfig.Passphrase.GetAdditionalData())
 
- 	assert.NotEmpty(t, user4.FsConfig.CryptConfig.Passphrase.GetStatus())
 
- 	assert.NotEmpty(t, user4.FsConfig.CryptConfig.Passphrase.GetPayload())
 
- 	user5, _, err = httpdtest.GetUserByUsername(user5.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Empty(t, user5.Password)
 
- 	assert.Empty(t, user5.FsConfig.SFTPConfig.Password.GetKey())
 
- 	assert.Empty(t, user5.FsConfig.SFTPConfig.Password.GetAdditionalData())
 
- 	assert.NotEmpty(t, user5.FsConfig.SFTPConfig.Password.GetStatus())
 
- 	assert.NotEmpty(t, user5.FsConfig.SFTPConfig.Password.GetPayload())
 
- 	assert.Empty(t, user5.FsConfig.SFTPConfig.PrivateKey.GetKey())
 
- 	assert.Empty(t, user5.FsConfig.SFTPConfig.PrivateKey.GetAdditionalData())
 
- 	assert.NotEmpty(t, user5.FsConfig.SFTPConfig.PrivateKey.GetStatus())
 
- 	assert.NotEmpty(t, user5.FsConfig.SFTPConfig.PrivateKey.GetPayload())
 
- 	assert.Equal(t, "/prefix", user5.FsConfig.SFTPConfig.Prefix)
 
- 	// finally check that we have all the data inside the data provider
 
- 	user1, err = dataprovider.UserExists(user1.Username)
 
- 	assert.NoError(t, err)
 
- 	assert.NotEmpty(t, user1.Password)
 
- 	assert.NotEmpty(t, user1.FsConfig.S3Config.AccessSecret.GetKey())
 
- 	assert.NotEmpty(t, user1.FsConfig.S3Config.AccessSecret.GetAdditionalData())
 
- 	assert.NotEmpty(t, user1.FsConfig.S3Config.AccessSecret.GetStatus())
 
- 	assert.NotEmpty(t, user1.FsConfig.S3Config.AccessSecret.GetPayload())
 
- 	err = user1.FsConfig.S3Config.AccessSecret.Decrypt()
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, sdkkms.SecretStatusPlain, user1.FsConfig.S3Config.AccessSecret.GetStatus())
 
- 	assert.Equal(t, u1.FsConfig.S3Config.AccessSecret.GetPayload(), user1.FsConfig.S3Config.AccessSecret.GetPayload())
 
- 	assert.Empty(t, user1.FsConfig.S3Config.AccessSecret.GetKey())
 
- 	assert.Empty(t, user1.FsConfig.S3Config.AccessSecret.GetAdditionalData())
 
- 	user2, err = dataprovider.UserExists(user2.Username)
 
- 	assert.NoError(t, err)
 
- 	assert.NotEmpty(t, user2.Password)
 
- 	assert.NotEmpty(t, user2.FsConfig.GCSConfig.Credentials.GetKey())
 
- 	assert.NotEmpty(t, user2.FsConfig.GCSConfig.Credentials.GetAdditionalData())
 
- 	assert.NotEmpty(t, user2.FsConfig.GCSConfig.Credentials.GetStatus())
 
- 	assert.NotEmpty(t, user2.FsConfig.GCSConfig.Credentials.GetPayload())
 
- 	err = user2.FsConfig.GCSConfig.Credentials.Decrypt()
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, sdkkms.SecretStatusPlain, user2.FsConfig.GCSConfig.Credentials.GetStatus())
 
- 	assert.Equal(t, u2.FsConfig.GCSConfig.Credentials.GetPayload(), user2.FsConfig.GCSConfig.Credentials.GetPayload())
 
- 	assert.Empty(t, user2.FsConfig.GCSConfig.Credentials.GetKey())
 
- 	assert.Empty(t, user2.FsConfig.GCSConfig.Credentials.GetAdditionalData())
 
- 	user3, err = dataprovider.UserExists(user3.Username)
 
- 	assert.NoError(t, err)
 
- 	assert.NotEmpty(t, user3.Password)
 
- 	assert.NotEmpty(t, user3.FsConfig.AzBlobConfig.AccountKey.GetKey())
 
- 	assert.NotEmpty(t, user3.FsConfig.AzBlobConfig.AccountKey.GetAdditionalData())
 
- 	assert.NotEmpty(t, user3.FsConfig.AzBlobConfig.AccountKey.GetStatus())
 
- 	assert.NotEmpty(t, user3.FsConfig.AzBlobConfig.AccountKey.GetPayload())
 
- 	err = user3.FsConfig.AzBlobConfig.AccountKey.Decrypt()
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, sdkkms.SecretStatusPlain, user3.FsConfig.AzBlobConfig.AccountKey.GetStatus())
 
- 	assert.Equal(t, u3.FsConfig.AzBlobConfig.AccountKey.GetPayload(), user3.FsConfig.AzBlobConfig.AccountKey.GetPayload())
 
- 	assert.Empty(t, user3.FsConfig.AzBlobConfig.AccountKey.GetKey())
 
- 	assert.Empty(t, user3.FsConfig.AzBlobConfig.AccountKey.GetAdditionalData())
 
- 	user4, err = dataprovider.UserExists(user4.Username)
 
- 	assert.NoError(t, err)
 
- 	assert.NotEmpty(t, user4.Password)
 
- 	assert.NotEmpty(t, user4.FsConfig.CryptConfig.Passphrase.GetKey())
 
- 	assert.NotEmpty(t, user4.FsConfig.CryptConfig.Passphrase.GetAdditionalData())
 
- 	assert.NotEmpty(t, user4.FsConfig.CryptConfig.Passphrase.GetStatus())
 
- 	assert.NotEmpty(t, user4.FsConfig.CryptConfig.Passphrase.GetPayload())
 
- 	err = user4.FsConfig.CryptConfig.Passphrase.Decrypt()
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, sdkkms.SecretStatusPlain, user4.FsConfig.CryptConfig.Passphrase.GetStatus())
 
- 	assert.Equal(t, u4.FsConfig.CryptConfig.Passphrase.GetPayload(), user4.FsConfig.CryptConfig.Passphrase.GetPayload())
 
- 	assert.Empty(t, user4.FsConfig.CryptConfig.Passphrase.GetKey())
 
- 	assert.Empty(t, user4.FsConfig.CryptConfig.Passphrase.GetAdditionalData())
 
- 	user5, err = dataprovider.UserExists(user5.Username)
 
- 	assert.NoError(t, err)
 
- 	assert.NotEmpty(t, user5.Password)
 
- 	assert.NotEmpty(t, user5.FsConfig.SFTPConfig.Password.GetKey())
 
- 	assert.NotEmpty(t, user5.FsConfig.SFTPConfig.Password.GetAdditionalData())
 
- 	assert.NotEmpty(t, user5.FsConfig.SFTPConfig.Password.GetStatus())
 
- 	assert.NotEmpty(t, user5.FsConfig.SFTPConfig.Password.GetPayload())
 
- 	err = user5.FsConfig.SFTPConfig.Password.Decrypt()
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, sdkkms.SecretStatusPlain, user5.FsConfig.SFTPConfig.Password.GetStatus())
 
- 	assert.Equal(t, u5.FsConfig.SFTPConfig.Password.GetPayload(), user5.FsConfig.SFTPConfig.Password.GetPayload())
 
- 	assert.Empty(t, user5.FsConfig.SFTPConfig.Password.GetKey())
 
- 	assert.Empty(t, user5.FsConfig.SFTPConfig.Password.GetAdditionalData())
 
- 	assert.NotEmpty(t, user5.FsConfig.SFTPConfig.PrivateKey.GetKey())
 
- 	assert.NotEmpty(t, user5.FsConfig.SFTPConfig.PrivateKey.GetAdditionalData())
 
- 	assert.NotEmpty(t, user5.FsConfig.SFTPConfig.PrivateKey.GetStatus())
 
- 	assert.NotEmpty(t, user5.FsConfig.SFTPConfig.PrivateKey.GetPayload())
 
- 	err = user5.FsConfig.SFTPConfig.PrivateKey.Decrypt()
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, sdkkms.SecretStatusPlain, user5.FsConfig.SFTPConfig.PrivateKey.GetStatus())
 
- 	assert.Equal(t, u5.FsConfig.SFTPConfig.PrivateKey.GetPayload(), user5.FsConfig.SFTPConfig.PrivateKey.GetPayload())
 
- 	assert.Empty(t, user5.FsConfig.SFTPConfig.PrivateKey.GetKey())
 
- 	assert.Empty(t, user5.FsConfig.SFTPConfig.PrivateKey.GetAdditionalData())
 
- 	// update the GCS user and check that the credentials are preserved
 
- 	user2.FsConfig.GCSConfig.Credentials = kms.NewEmptySecret()
 
- 	user2.FsConfig.GCSConfig.ACL = "private"
 
- 	_, _, err = httpdtest.UpdateUser(user2, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	user2, _, err = httpdtest.GetUserByUsername(user2.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Empty(t, user2.Password)
 
- 	assert.Empty(t, user2.FsConfig.GCSConfig.Credentials.GetKey())
 
- 	assert.Empty(t, user2.FsConfig.GCSConfig.Credentials.GetAdditionalData())
 
- 	assert.NotEmpty(t, user2.FsConfig.GCSConfig.Credentials.GetStatus())
 
- 	assert.NotEmpty(t, user2.FsConfig.GCSConfig.Credentials.GetPayload())
 
- 	_, err = httpdtest.RemoveUser(user1, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(user2, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(user3, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(user4, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(user5, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = dataprovider.Close()
 
- 	assert.NoError(t, err)
 
- 	err = config.LoadConfig(configDir, "")
 
- 	assert.NoError(t, err)
 
- 	providerConf = config.GetProviderConf()
 
- 	providerConf.CredentialsPath = credentialsPath
 
- 	err = os.RemoveAll(credentialsPath)
 
- 	assert.NoError(t, err)
 
- 	err = dataprovider.Initialize(providerConf, configDir, true)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestSecretObject(t *testing.T) {
 
- 	s := kms.NewPlainSecret("test data")
 
- 	s.SetAdditionalData("username")
 
- 	require.True(t, s.IsValid())
 
- 	err := s.Encrypt()
 
- 	require.NoError(t, err)
 
- 	require.Equal(t, sdkkms.SecretStatusSecretBox, s.GetStatus())
 
- 	require.NotEmpty(t, s.GetPayload())
 
- 	require.NotEmpty(t, s.GetKey())
 
- 	require.True(t, s.IsValid())
 
- 	err = s.Decrypt()
 
- 	require.NoError(t, err)
 
- 	require.Equal(t, sdkkms.SecretStatusPlain, s.GetStatus())
 
- 	require.Equal(t, "test data", s.GetPayload())
 
- 	require.Empty(t, s.GetKey())
 
- }
 
- func TestSecretObjectCompatibility(t *testing.T) {
 
- 	// this is manually tested against vault too
 
- 	testPayload := "test payload"
 
- 	s := kms.NewPlainSecret(testPayload)
 
- 	require.True(t, s.IsValid())
 
- 	err := s.Encrypt()
 
- 	require.NoError(t, err)
 
- 	localAsJSON, err := json.Marshal(s)
 
- 	assert.NoError(t, err)
 
- 	for _, secretStatus := range []string{sdkkms.SecretStatusSecretBox} {
 
- 		kmsConfig := config.GetKMSConfig()
 
- 		assert.Empty(t, kmsConfig.Secrets.MasterKeyPath)
 
- 		if secretStatus == sdkkms.SecretStatusVaultTransit {
 
- 			os.Setenv("VAULT_SERVER_URL", "http://127.0.0.1:8200")
 
- 			os.Setenv("VAULT_SERVER_TOKEN", "s.9lYGq83MbgG5KR5kfebXVyhJ")
 
- 			kmsConfig.Secrets.URL = "hashivault://mykey"
 
- 		}
 
- 		err := kmsConfig.Initialize()
 
- 		assert.NoError(t, err)
 
- 		// encrypt without a master key
 
- 		secret := kms.NewPlainSecret(testPayload)
 
- 		secret.SetAdditionalData("add data")
 
- 		err = secret.Encrypt()
 
- 		assert.NoError(t, err)
 
- 		assert.Equal(t, 0, secret.GetMode())
 
- 		secretClone := secret.Clone()
 
- 		err = secretClone.Decrypt()
 
- 		assert.NoError(t, err)
 
- 		assert.Equal(t, testPayload, secretClone.GetPayload())
 
- 		if secretStatus == sdkkms.SecretStatusVaultTransit {
 
- 			// decrypt the local secret now that the provider is vault
 
- 			secretLocal := kms.NewEmptySecret()
 
- 			err = json.Unmarshal(localAsJSON, secretLocal)
 
- 			assert.NoError(t, err)
 
- 			assert.Equal(t, sdkkms.SecretStatusSecretBox, secretLocal.GetStatus())
 
- 			assert.Equal(t, 0, secretLocal.GetMode())
 
- 			err = secretLocal.Decrypt()
 
- 			assert.NoError(t, err)
 
- 			assert.Equal(t, testPayload, secretLocal.GetPayload())
 
- 			assert.Equal(t, sdkkms.SecretStatusPlain, secretLocal.GetStatus())
 
- 			err = secretLocal.Encrypt()
 
- 			assert.NoError(t, err)
 
- 			assert.Equal(t, sdkkms.SecretStatusSecretBox, secretLocal.GetStatus())
 
- 			assert.Equal(t, 0, secretLocal.GetMode())
 
- 		}
 
- 		asJSON, err := json.Marshal(secret)
 
- 		assert.NoError(t, err)
 
- 		masterKeyPath := filepath.Join(os.TempDir(), "mkey")
 
- 		err = os.WriteFile(masterKeyPath, []byte("test key"), os.ModePerm)
 
- 		assert.NoError(t, err)
 
- 		config := kms.Configuration{
 
- 			Secrets: kms.Secrets{
 
- 				MasterKeyPath: masterKeyPath,
 
- 			},
 
- 		}
 
- 		if secretStatus == sdkkms.SecretStatusVaultTransit {
 
- 			config.Secrets.URL = "hashivault://mykey"
 
- 		}
 
- 		err = config.Initialize()
 
- 		assert.NoError(t, err)
 
- 		// now build the secret from JSON
 
- 		secret = kms.NewEmptySecret()
 
- 		err = json.Unmarshal(asJSON, secret)
 
- 		assert.NoError(t, err)
 
- 		assert.Equal(t, 0, secret.GetMode())
 
- 		err = secret.Decrypt()
 
- 		assert.NoError(t, err)
 
- 		assert.Equal(t, testPayload, secret.GetPayload())
 
- 		err = secret.Encrypt()
 
- 		assert.NoError(t, err)
 
- 		assert.Equal(t, 1, secret.GetMode())
 
- 		err = secret.Decrypt()
 
- 		assert.NoError(t, err)
 
- 		assert.Equal(t, testPayload, secret.GetPayload())
 
- 		if secretStatus == sdkkms.SecretStatusVaultTransit {
 
- 			// decrypt the local secret encryped without a master key now that
 
- 			// the provider is vault and a master key is set.
 
- 			// The provider will not change, the master key will be used
 
- 			secretLocal := kms.NewEmptySecret()
 
- 			err = json.Unmarshal(localAsJSON, secretLocal)
 
- 			assert.NoError(t, err)
 
- 			assert.Equal(t, sdkkms.SecretStatusSecretBox, secretLocal.GetStatus())
 
- 			assert.Equal(t, 0, secretLocal.GetMode())
 
- 			err = secretLocal.Decrypt()
 
- 			assert.NoError(t, err)
 
- 			assert.Equal(t, testPayload, secretLocal.GetPayload())
 
- 			assert.Equal(t, sdkkms.SecretStatusPlain, secretLocal.GetStatus())
 
- 			err = secretLocal.Encrypt()
 
- 			assert.NoError(t, err)
 
- 			assert.Equal(t, sdkkms.SecretStatusSecretBox, secretLocal.GetStatus())
 
- 			assert.Equal(t, 1, secretLocal.GetMode())
 
- 		}
 
- 		err = kmsConfig.Initialize()
 
- 		assert.NoError(t, err)
 
- 		err = os.Remove(masterKeyPath)
 
- 		assert.NoError(t, err)
 
- 		if secretStatus == sdkkms.SecretStatusVaultTransit {
 
- 			os.Unsetenv("VAULT_SERVER_URL")
 
- 			os.Unsetenv("VAULT_SERVER_TOKEN")
 
- 		}
 
- 	}
 
- }
 
- func TestUpdateUserNoCredentials(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	user.Password = ""
 
- 	user.PublicKeys = []string{}
 
- 	// password and public key will be omitted from json serialization if empty and so they will remain unchanged
 
- 	// and no validation error will be raised
 
- 	_, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUpdateUserEmptyHomeDir(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	user.HomeDir = ""
 
- 	_, _, err = httpdtest.UpdateUser(user, http.StatusBadRequest, "")
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUpdateUserInvalidHomeDir(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	user.HomeDir = "relative_path"
 
- 	_, _, err = httpdtest.UpdateUser(user, http.StatusBadRequest, "")
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUpdateNonExistentUser(t *testing.T) {
 
- 	_, _, err := httpdtest.UpdateUser(getTestUser(), http.StatusNotFound, "")
 
- 	assert.NoError(t, err)
 
- }
 
- func TestGetNonExistentUser(t *testing.T) {
 
- 	_, _, err := httpdtest.GetUserByUsername("na", http.StatusNotFound)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestDeleteNonExistentUser(t *testing.T) {
 
- 	_, err := httpdtest.RemoveUser(getTestUser(), http.StatusNotFound)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestAddDuplicateUser(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.AddUser(getTestUser(), http.StatusInternalServerError)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.Error(t, err, "adding a duplicate user must fail")
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestGetUsers(t *testing.T) {
 
- 	user1, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	u := getTestUser()
 
- 	u.Username = defaultUsername + "1"
 
- 	user2, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	users, _, err := httpdtest.GetUsers(0, 0, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.GreaterOrEqual(t, len(users), 2)
 
- 	users, _, err = httpdtest.GetUsers(1, 0, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, 1, len(users))
 
- 	users, _, err = httpdtest.GetUsers(1, 1, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, 1, len(users))
 
- 	_, _, err = httpdtest.GetUsers(1, 1, http.StatusInternalServerError)
 
- 	assert.Error(t, err)
 
- 	_, err = httpdtest.RemoveUser(user1, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(user2, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestGetQuotaScans(t *testing.T) {
 
- 	_, _, err := httpdtest.GetQuotaScans(http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.GetQuotaScans(http.StatusInternalServerError)
 
- 	assert.Error(t, err)
 
- 	_, _, err = httpdtest.GetFoldersQuotaScans(http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.GetFoldersQuotaScans(http.StatusInternalServerError)
 
- 	assert.Error(t, err)
 
- }
 
- func TestStartQuotaScan(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.StartQuotaScan(user, http.StatusAccepted)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	folder := vfs.BaseVirtualFolder{
 
- 		Name:        "vfolder",
 
- 		MappedPath:  filepath.Join(os.TempDir(), "folder"),
 
- 		Description: "virtual folder",
 
- 	}
 
- 	_, _, err = httpdtest.AddFolder(folder, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.StartFolderQuotaScan(folder, http.StatusAccepted)
 
- 	assert.NoError(t, err)
 
- 	for {
 
- 		quotaScan, _, err := httpdtest.GetFoldersQuotaScans(http.StatusOK)
 
- 		if !assert.NoError(t, err, "Error getting active scans") {
 
- 			break
 
- 		}
 
- 		if len(quotaScan) == 0 {
 
- 			break
 
- 		}
 
- 		time.Sleep(100 * time.Millisecond)
 
- 	}
 
- 	_, err = httpdtest.RemoveFolder(folder, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestEmbeddedFolders(t *testing.T) {
 
- 	u := getTestUser()
 
- 	mappedPath := filepath.Join(os.TempDir(), "mapped_path")
 
- 	name := filepath.Base(mappedPath)
 
- 	u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
 
- 		BaseVirtualFolder: vfs.BaseVirtualFolder{
 
- 			Name:            name,
 
- 			UsedQuotaFiles:  1000,
 
- 			UsedQuotaSize:   8192,
 
- 			LastQuotaUpdate: 123,
 
- 		},
 
- 		VirtualPath: "/vdir",
 
- 		QuotaSize:   4096,
 
- 		QuotaFiles:  1,
 
- 	})
 
- 	_, _, err := httpdtest.AddUser(u, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	u.VirtualFolders[0].MappedPath = mappedPath
 
- 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	// check that the folder was created
 
- 	folder, _, err := httpdtest.GetFolderByName(name, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, mappedPath, folder.MappedPath)
 
- 	assert.Equal(t, 0, folder.UsedQuotaFiles)
 
- 	assert.Equal(t, int64(0), folder.UsedQuotaSize)
 
- 	assert.Equal(t, int64(0), folder.LastQuotaUpdate)
 
- 	if assert.Len(t, user.VirtualFolders, 1) {
 
- 		assert.Equal(t, mappedPath, user.VirtualFolders[0].MappedPath)
 
- 		assert.Equal(t, u.VirtualFolders[0].VirtualPath, user.VirtualFolders[0].VirtualPath)
 
- 		assert.Equal(t, u.VirtualFolders[0].QuotaFiles, user.VirtualFolders[0].QuotaFiles)
 
- 		assert.Equal(t, u.VirtualFolders[0].QuotaSize, user.VirtualFolders[0].QuotaSize)
 
- 	}
 
- 	// if the folder already exists we can just reference it by name while adding/updating a user
 
- 	u.Username = u.Username + "1"
 
- 	u.VirtualFolders[0].MappedPath = ""
 
- 	user1, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.EqualError(t, err, "mapped path mismatch")
 
- 	if assert.Len(t, user1.VirtualFolders, 1) {
 
- 		assert.Equal(t, mappedPath, user1.VirtualFolders[0].MappedPath)
 
- 		assert.Equal(t, u.VirtualFolders[0].VirtualPath, user1.VirtualFolders[0].VirtualPath)
 
- 		assert.Equal(t, u.VirtualFolders[0].QuotaFiles, user1.VirtualFolders[0].QuotaFiles)
 
- 		assert.Equal(t, u.VirtualFolders[0].QuotaSize, user1.VirtualFolders[0].QuotaSize)
 
- 	}
 
- 	user1.VirtualFolders = u.VirtualFolders
 
- 	user1, _, err = httpdtest.UpdateUser(user1, http.StatusOK, "")
 
- 	assert.EqualError(t, err, "mapped path mismatch")
 
- 	if assert.Len(t, user1.VirtualFolders, 1) {
 
- 		assert.Equal(t, mappedPath, user1.VirtualFolders[0].MappedPath)
 
- 		assert.Equal(t, u.VirtualFolders[0].VirtualPath, user1.VirtualFolders[0].VirtualPath)
 
- 		assert.Equal(t, u.VirtualFolders[0].QuotaFiles, user1.VirtualFolders[0].QuotaFiles)
 
- 		assert.Equal(t, u.VirtualFolders[0].QuotaSize, user1.VirtualFolders[0].QuotaSize)
 
- 	}
 
- 	// now the virtual folder contains all the required paths
 
- 	user1, _, err = httpdtest.UpdateUser(user1, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	if assert.Len(t, user1.VirtualFolders, 1) {
 
- 		assert.Equal(t, mappedPath, user1.VirtualFolders[0].MappedPath)
 
- 		assert.Equal(t, u.VirtualFolders[0].VirtualPath, user1.VirtualFolders[0].VirtualPath)
 
- 		assert.Equal(t, u.VirtualFolders[0].QuotaFiles, user1.VirtualFolders[0].QuotaFiles)
 
- 		assert.Equal(t, u.VirtualFolders[0].QuotaSize, user1.VirtualFolders[0].QuotaSize)
 
- 	}
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(user1, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveFolder(vfs.BaseVirtualFolder{Name: name}, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestEmbeddedFoldersUpdate(t *testing.T) {
 
- 	u := getTestUser()
 
- 	mappedPath := filepath.Join(os.TempDir(), "mapped_path")
 
- 	name := filepath.Base(mappedPath)
 
- 	u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
 
- 		BaseVirtualFolder: vfs.BaseVirtualFolder{
 
- 			Name:            name,
 
- 			MappedPath:      mappedPath,
 
- 			UsedQuotaFiles:  1000,
 
- 			UsedQuotaSize:   8192,
 
- 			LastQuotaUpdate: 123,
 
- 		},
 
- 		VirtualPath: "/vdir",
 
- 		QuotaSize:   4096,
 
- 		QuotaFiles:  1,
 
- 	})
 
- 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	folder, _, err := httpdtest.GetFolderByName(name, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, mappedPath, folder.MappedPath)
 
- 	assert.Equal(t, 0, folder.UsedQuotaFiles)
 
- 	assert.Equal(t, int64(0), folder.UsedQuotaSize)
 
- 	assert.Equal(t, int64(0), folder.LastQuotaUpdate)
 
- 	assert.Empty(t, folder.Description)
 
- 	assert.Equal(t, sdk.LocalFilesystemProvider, folder.FsConfig.Provider)
 
- 	assert.Len(t, folder.Users, 1)
 
- 	assert.Contains(t, folder.Users, user.Username)
 
- 	// update a field on the folder
 
- 	description := "updatedDesc"
 
- 	folder.MappedPath = mappedPath + "_update"
 
- 	folder.Description = description
 
- 	folder, _, err = httpdtest.UpdateFolder(folder, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, mappedPath+"_update", folder.MappedPath)
 
- 	assert.Equal(t, 0, folder.UsedQuotaFiles)
 
- 	assert.Equal(t, int64(0), folder.UsedQuotaSize)
 
- 	assert.Equal(t, int64(0), folder.LastQuotaUpdate)
 
- 	assert.Equal(t, description, folder.Description)
 
- 	assert.Equal(t, sdk.LocalFilesystemProvider, folder.FsConfig.Provider)
 
- 	// check that the user gets the changes
 
- 	user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	userFolder := user.VirtualFolders[0].BaseVirtualFolder
 
- 	assert.Equal(t, mappedPath+"_update", folder.MappedPath)
 
- 	assert.Equal(t, 0, userFolder.UsedQuotaFiles)
 
- 	assert.Equal(t, int64(0), userFolder.UsedQuotaSize)
 
- 	assert.Equal(t, int64(0), userFolder.LastQuotaUpdate)
 
- 	assert.Equal(t, description, userFolder.Description)
 
- 	assert.Equal(t, sdk.LocalFilesystemProvider, userFolder.FsConfig.Provider)
 
- 	// now update the folder embedding it inside the user
 
- 	user.VirtualFolders = []vfs.VirtualFolder{
 
- 		{
 
- 			BaseVirtualFolder: vfs.BaseVirtualFolder{
 
- 				Name:            name,
 
- 				MappedPath:      "",
 
- 				UsedQuotaFiles:  1000,
 
- 				UsedQuotaSize:   8192,
 
- 				LastQuotaUpdate: 123,
 
- 				FsConfig: vfs.Filesystem{
 
- 					Provider: sdk.S3FilesystemProvider,
 
- 					S3Config: vfs.S3FsConfig{
 
- 						BaseS3FsConfig: sdk.BaseS3FsConfig{
 
- 							Bucket:    "test",
 
- 							Region:    "us-east-1",
 
- 							AccessKey: "akey",
 
- 							Endpoint:  "http://127.0.1.1:9090",
 
- 						},
 
- 						AccessSecret: kms.NewPlainSecret("asecret"),
 
- 					},
 
- 				},
 
- 			},
 
- 			VirtualPath: "/vdir1",
 
- 			QuotaSize:   4096,
 
- 			QuotaFiles:  1,
 
- 		},
 
- 	}
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	userFolder = user.VirtualFolders[0].BaseVirtualFolder
 
- 	assert.Equal(t, 0, userFolder.UsedQuotaFiles)
 
- 	assert.Equal(t, int64(0), userFolder.UsedQuotaSize)
 
- 	assert.Equal(t, int64(0), userFolder.LastQuotaUpdate)
 
- 	assert.Empty(t, userFolder.Description)
 
- 	assert.Equal(t, sdk.S3FilesystemProvider, userFolder.FsConfig.Provider)
 
- 	assert.Equal(t, "test", userFolder.FsConfig.S3Config.Bucket)
 
- 	assert.Equal(t, "us-east-1", userFolder.FsConfig.S3Config.Region)
 
- 	assert.Equal(t, "http://127.0.1.1:9090", userFolder.FsConfig.S3Config.Endpoint)
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, userFolder.FsConfig.S3Config.AccessSecret.GetStatus())
 
- 	assert.NotEmpty(t, userFolder.FsConfig.S3Config.AccessSecret.GetPayload())
 
- 	assert.Empty(t, userFolder.FsConfig.S3Config.AccessSecret.GetKey())
 
- 	assert.Empty(t, userFolder.FsConfig.S3Config.AccessSecret.GetAdditionalData())
 
- 	// confirm the changes
 
- 	folder, _, err = httpdtest.GetFolderByName(name, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, 0, folder.UsedQuotaFiles)
 
- 	assert.Equal(t, int64(0), folder.UsedQuotaSize)
 
- 	assert.Equal(t, int64(0), folder.LastQuotaUpdate)
 
- 	assert.Empty(t, folder.Description)
 
- 	assert.Equal(t, sdk.S3FilesystemProvider, folder.FsConfig.Provider)
 
- 	assert.Equal(t, "test", folder.FsConfig.S3Config.Bucket)
 
- 	assert.Equal(t, "us-east-1", folder.FsConfig.S3Config.Region)
 
- 	assert.Equal(t, "http://127.0.1.1:9090", folder.FsConfig.S3Config.Endpoint)
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, folder.FsConfig.S3Config.AccessSecret.GetStatus())
 
- 	assert.NotEmpty(t, folder.FsConfig.S3Config.AccessSecret.GetPayload())
 
- 	assert.Empty(t, folder.FsConfig.S3Config.AccessSecret.GetKey())
 
- 	assert.Empty(t, folder.FsConfig.S3Config.AccessSecret.GetAdditionalData())
 
- 	// now update folder usage limits and check that a folder update will not change them
 
- 	folder.UsedQuotaFiles = 100
 
- 	folder.UsedQuotaSize = 32768
 
- 	_, err = httpdtest.UpdateFolderQuotaUsage(folder, "reset", http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	folder, _, err = httpdtest.GetFolderByName(name, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, 100, folder.UsedQuotaFiles)
 
- 	assert.Equal(t, int64(32768), folder.UsedQuotaSize)
 
- 	assert.Greater(t, folder.LastQuotaUpdate, int64(0))
 
- 	assert.Equal(t, sdk.S3FilesystemProvider, folder.FsConfig.Provider)
 
- 	assert.Equal(t, "test", folder.FsConfig.S3Config.Bucket)
 
- 	assert.Equal(t, "us-east-1", folder.FsConfig.S3Config.Region)
 
- 	assert.Equal(t, "http://127.0.1.1:9090", folder.FsConfig.S3Config.Endpoint)
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, folder.FsConfig.S3Config.AccessSecret.GetStatus())
 
- 	assert.NotEmpty(t, folder.FsConfig.S3Config.AccessSecret.GetPayload())
 
- 	assert.Empty(t, folder.FsConfig.S3Config.AccessSecret.GetKey())
 
- 	assert.Empty(t, folder.FsConfig.S3Config.AccessSecret.GetAdditionalData())
 
- 	user.VirtualFolders[0].FsConfig.S3Config.AccessSecret = kms.NewPlainSecret("updated secret")
 
- 	user, resp, err := httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err, string(resp))
 
- 	userFolder = user.VirtualFolders[0].BaseVirtualFolder
 
- 	assert.Equal(t, 100, userFolder.UsedQuotaFiles)
 
- 	assert.Equal(t, int64(32768), userFolder.UsedQuotaSize)
 
- 	assert.Greater(t, userFolder.LastQuotaUpdate, int64(0))
 
- 	assert.Empty(t, userFolder.Description)
 
- 	assert.Equal(t, sdk.S3FilesystemProvider, userFolder.FsConfig.Provider)
 
- 	assert.Equal(t, "test", userFolder.FsConfig.S3Config.Bucket)
 
- 	assert.Equal(t, "us-east-1", userFolder.FsConfig.S3Config.Region)
 
- 	assert.Equal(t, "http://127.0.1.1:9090", userFolder.FsConfig.S3Config.Endpoint)
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, userFolder.FsConfig.S3Config.AccessSecret.GetStatus())
 
- 	assert.NotEmpty(t, userFolder.FsConfig.S3Config.AccessSecret.GetPayload())
 
- 	assert.Empty(t, userFolder.FsConfig.S3Config.AccessSecret.GetKey())
 
- 	assert.Empty(t, userFolder.FsConfig.S3Config.AccessSecret.GetAdditionalData())
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveFolder(vfs.BaseVirtualFolder{Name: name}, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUpdateFolderQuotaUsage(t *testing.T) {
 
- 	f := vfs.BaseVirtualFolder{
 
- 		Name:       "vdir",
 
- 		MappedPath: filepath.Join(os.TempDir(), "folder"),
 
- 	}
 
- 	usedQuotaFiles := 1
 
- 	usedQuotaSize := int64(65535)
 
- 	f.UsedQuotaFiles = usedQuotaFiles
 
- 	f.UsedQuotaSize = usedQuotaSize
 
- 	folder, _, err := httpdtest.AddFolder(f, http.StatusCreated)
 
- 	if assert.NoError(t, err) {
 
- 		assert.Equal(t, usedQuotaFiles, folder.UsedQuotaFiles)
 
- 		assert.Equal(t, usedQuotaSize, folder.UsedQuotaSize)
 
- 	}
 
- 	_, err = httpdtest.UpdateFolderQuotaUsage(folder, "invalid mode", http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.UpdateFolderQuotaUsage(f, "reset", http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	folder, _, err = httpdtest.GetFolderByName(f.Name, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, usedQuotaFiles, folder.UsedQuotaFiles)
 
- 	assert.Equal(t, usedQuotaSize, folder.UsedQuotaSize)
 
- 	_, err = httpdtest.UpdateFolderQuotaUsage(f, "add", http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	folder, _, err = httpdtest.GetFolderByName(f.Name, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, 2*usedQuotaFiles, folder.UsedQuotaFiles)
 
- 	assert.Equal(t, 2*usedQuotaSize, folder.UsedQuotaSize)
 
- 	f.UsedQuotaSize = -1
 
- 	_, err = httpdtest.UpdateFolderQuotaUsage(f, "", http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	f.UsedQuotaSize = usedQuotaSize
 
- 	f.Name = f.Name + "1"
 
- 	_, err = httpdtest.UpdateFolderQuotaUsage(f, "", http.StatusNotFound)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveFolder(folder, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestGetVersion(t *testing.T) {
 
- 	_, _, err := httpdtest.GetVersion(http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.GetVersion(http.StatusInternalServerError)
 
- 	assert.Error(t, err, "get version request must succeed, we requested to check a wrong status code")
 
- }
 
- func TestGetStatus(t *testing.T) {
 
- 	_, _, err := httpdtest.GetStatus(http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.GetStatus(http.StatusBadRequest)
 
- 	assert.Error(t, err, "get provider status request must succeed, we requested to check a wrong status code")
 
- }
 
- func TestGetConnections(t *testing.T) {
 
- 	_, _, err := httpdtest.GetConnections(http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.GetConnections(http.StatusInternalServerError)
 
- 	assert.Error(t, err, "get sftp connections request must succeed, we requested to check a wrong status code")
 
- }
 
- func TestCloseActiveConnection(t *testing.T) {
 
- 	_, err := httpdtest.CloseConnection("non_existent_id", http.StatusNotFound)
 
- 	assert.NoError(t, err)
 
- 	user := getTestUser()
 
- 	c := common.NewBaseConnection("connID", common.ProtocolSFTP, "", "", user)
 
- 	fakeConn := &fakeConnection{
 
- 		BaseConnection: c,
 
- 	}
 
- 	common.Connections.Add(fakeConn)
 
- 	_, err = httpdtest.CloseConnection(c.GetID(), http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, common.Connections.GetStats(), 0)
 
- }
 
- func TestCloseConnectionAfterUserUpdateDelete(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	c := common.NewBaseConnection("connID", common.ProtocolFTP, "", "", user)
 
- 	fakeConn := &fakeConnection{
 
- 		BaseConnection: c,
 
- 	}
 
- 	common.Connections.Add(fakeConn)
 
- 	c1 := common.NewBaseConnection("connID1", common.ProtocolSFTP, "", "", user)
 
- 	fakeConn1 := &fakeConnection{
 
- 		BaseConnection: c1,
 
- 	}
 
- 	common.Connections.Add(fakeConn1)
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "0")
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, common.Connections.GetStats(), 2)
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "1")
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, common.Connections.GetStats(), 0)
 
- 	common.Connections.Add(fakeConn)
 
- 	common.Connections.Add(fakeConn1)
 
- 	assert.Len(t, common.Connections.GetStats(), 2)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, common.Connections.GetStats(), 0)
 
- }
 
- func TestNamingRules(t *testing.T) {
 
- 	smtpCfg := smtp.Config{
 
- 		Host:          "127.0.0.1",
 
- 		Port:          3525,
 
- 		TemplatesPath: "templates",
 
- 	}
 
- 	err := smtpCfg.Initialize("..")
 
- 	require.NoError(t, err)
 
- 	err = dataprovider.Close()
 
- 	assert.NoError(t, err)
 
- 	err = config.LoadConfig(configDir, "")
 
- 	assert.NoError(t, err)
 
- 	providerConf := config.GetProviderConf()
 
- 	providerConf.NamingRules = 7
 
- 	err = dataprovider.Initialize(providerConf, configDir, true)
 
- 	assert.NoError(t, err)
 
- 	u := getTestUser()
 
- 	u.Username = " [email protected] "
 
- 	u.Email = dataprovider.ConvertName(u.Username)
 
- 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, "[email protected]", user.Username)
 
- 	user.Username = u.Username
 
- 	user.AdditionalInfo = "info"
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	user, _, err = httpdtest.GetUserByUsername(u.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	a := getTestAdmin()
 
- 	a.Username = "[email protected] "
 
- 	admin, _, err := httpdtest.AddAdmin(a, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, "[email protected]", admin.Username)
 
- 	admin.Email = dataprovider.ConvertName(a.Username)
 
- 	admin.Username = a.Username
 
- 	admin, _, err = httpdtest.UpdateAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	admin, _, err = httpdtest.GetAdminByUsername(a.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	f := vfs.BaseVirtualFolder{
 
- 		Name:       "文件夹AB",
 
- 		MappedPath: filepath.Clean(os.TempDir()),
 
- 	}
 
- 	folder, resp, err := httpdtest.AddFolder(f, http.StatusCreated)
 
- 	assert.NoError(t, err, string(resp))
 
- 	assert.Equal(t, "文件夹ab", folder.Name)
 
- 	folder.Name = f.Name
 
- 	folder.Description = folder.Name
 
- 	folder, resp, err = httpdtest.UpdateFolder(folder, http.StatusOK)
 
- 	assert.NoError(t, err, string(resp))
 
- 	folder, resp, err = httpdtest.GetFolderByName(f.Name, http.StatusOK)
 
- 	assert.NoError(t, err, string(resp))
 
- 	_, err = httpdtest.RemoveFolder(f, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	token, err := getJWTWebClientTokenFromTestServer(u.Username, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	assert.NotEmpty(t, token)
 
- 	adminAPIToken, err := getJWTAPITokenFromTestServer(a.Username, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	assert.NotEmpty(t, adminAPIToken)
 
- 	err = dataprovider.Close()
 
- 	assert.NoError(t, err)
 
- 	err = config.LoadConfig(configDir, "")
 
- 	assert.NoError(t, err)
 
- 	providerConf = config.GetProviderConf()
 
- 	providerConf.CredentialsPath = credentialsPath
 
- 	err = os.RemoveAll(credentialsPath)
 
- 	assert.NoError(t, err)
 
- 	err = dataprovider.Initialize(providerConf, configDir, true)
 
- 	assert.NoError(t, err)
 
- 	if config.GetProviderConf().Driver == dataprovider.MemoryDataProviderName {
 
- 		return
 
- 	}
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webClientLoginPath)
 
- 	assert.NoError(t, err)
 
- 	token, err = getJWTWebClientTokenFromTestServer(user.Username, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	form := make(url.Values)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	req, err := http.NewRequest(http.MethodPost, webClientProfilePath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "the following characters are allowed")
 
- 	// test user reset password
 
- 	form = make(url.Values)
 
- 	form.Set("username", user.Username)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	lastResetCode = ""
 
- 	req, err = http.NewRequest(http.MethodPost, webClientForgotPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusFound, rr.Code)
 
- 	assert.GreaterOrEqual(t, len(lastResetCode), 20)
 
- 	form = make(url.Values)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	form.Set("code", lastResetCode)
 
- 	form.Set("password", defaultPassword)
 
- 	req, err = http.NewRequest(http.MethodPost, webClientResetPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "Unable to set the new password")
 
- 	adminAPIToken, err = getJWTAPITokenFromTestServer(admin.Username, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	userAPIToken, err := getJWTAPIUserTokenFromTestServer(user.Username, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPut, userPath+"/"+user.Username+"/2fa/disable", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, adminAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "the following characters are allowed")
 
- 	req, err = http.NewRequest(http.MethodPost, user2FARecoveryCodesPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, userAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "the following characters are allowed")
 
- 	apiKeyAuthReq := make(map[string]bool)
 
- 	apiKeyAuthReq["allow_api_key_auth"] = true
 
- 	asJSON, err := json.Marshal(apiKeyAuthReq)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPut, userProfilePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, userAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "the following characters are allowed")
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- 	token, err = getJWTWebTokenFromTestServer(admin.Username, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	csrfToken, err = getCSRFToken(httpBaseURL + webLoginPath)
 
- 	assert.NoError(t, err)
 
- 	form = make(url.Values)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	req, _ = http.NewRequest(http.MethodPost, webAdminProfilePath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "the following characters are allowed")
 
- 	apiKeyAuthReq = make(map[string]bool)
 
- 	apiKeyAuthReq["allow_api_key_auth"] = true
 
- 	asJSON, err = json.Marshal(apiKeyAuthReq)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPut, adminProfilePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, adminAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "the following characters are allowed")
 
- 	req, err = http.NewRequest(http.MethodPut, adminPath+"/"+admin.Username+"/2fa/disable", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, adminAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "the following characters are allowed")
 
- 	req, err = http.NewRequest(http.MethodPost, admin2FARecoveryCodesPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, adminAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "the following characters are allowed")
 
- 	// test admin reset password
 
- 	form = make(url.Values)
 
- 	form.Set("username", admin.Username)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	lastResetCode = ""
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminForgotPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusFound, rr.Code)
 
- 	assert.GreaterOrEqual(t, len(lastResetCode), 20)
 
- 	form = make(url.Values)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	form.Set("code", lastResetCode)
 
- 	form.Set("password", defaultPassword)
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminResetPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "Unable to set the new password")
 
- 	_, err = httpdtest.RemoveAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	smtpCfg = smtp.Config{}
 
- 	err = smtpCfg.Initialize("..")
 
- 	require.NoError(t, err)
 
- }
 
- func TestSaveErrors(t *testing.T) {
 
- 	err := dataprovider.Close()
 
- 	assert.NoError(t, err)
 
- 	err = config.LoadConfig(configDir, "")
 
- 	assert.NoError(t, err)
 
- 	providerConf := config.GetProviderConf()
 
- 	providerConf.NamingRules = 1
 
- 	err = dataprovider.Initialize(providerConf, configDir, true)
 
- 	assert.NoError(t, err)
 
- 	recCode := "recovery code"
 
- 	recoveryCodes := []dataprovider.RecoveryCode{
 
- 		{
 
- 			Secret: kms.NewPlainSecret(recCode),
 
- 			Used:   false,
 
- 		},
 
- 	}
 
- 	u := getTestUser()
 
- 	u.Username = "[email protected]"
 
- 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	configName, _, secret, _, err := mfa.GenerateTOTPSecret(mfa.GetAvailableTOTPConfigNames()[0], user.Username)
 
- 	assert.NoError(t, err)
 
- 	user.Password = u.Password
 
- 	user.Filters.TOTPConfig = dataprovider.UserTOTPConfig{
 
- 		Enabled:    true,
 
- 		ConfigName: configName,
 
- 		Secret:     kms.NewPlainSecret(secret),
 
- 		Protocols:  []string{common.ProtocolSSH, common.ProtocolHTTP},
 
- 	}
 
- 	user.Filters.RecoveryCodes = recoveryCodes
 
- 	err = dataprovider.UpdateUser(&user, "", "")
 
- 	assert.NoError(t, err)
 
- 	user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.True(t, user.Filters.TOTPConfig.Enabled)
 
- 	assert.Len(t, user.Filters.RecoveryCodes, 1)
 
- 	a := getTestAdmin()
 
- 	a.Username = "[email protected]"
 
- 	admin, _, err := httpdtest.AddAdmin(a, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	admin.Email = admin.Username
 
- 	admin, _, err = httpdtest.UpdateAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	admin.Password = a.Password
 
- 	admin.Filters.TOTPConfig = dataprovider.AdminTOTPConfig{
 
- 		Enabled:    true,
 
- 		ConfigName: configName,
 
- 		Secret:     kms.NewPlainSecret(secret),
 
- 	}
 
- 	admin.Filters.RecoveryCodes = recoveryCodes
 
- 	err = dataprovider.UpdateAdmin(&admin, "", "")
 
- 	assert.NoError(t, err)
 
- 	admin, _, err = httpdtest.GetAdminByUsername(admin.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.True(t, admin.Filters.TOTPConfig.Enabled)
 
- 	assert.Len(t, admin.Filters.RecoveryCodes, 1)
 
- 	err = dataprovider.Close()
 
- 	assert.NoError(t, err)
 
- 	err = config.LoadConfig(configDir, "")
 
- 	assert.NoError(t, err)
 
- 	providerConf = config.GetProviderConf()
 
- 	providerConf.CredentialsPath = credentialsPath
 
- 	err = os.RemoveAll(credentialsPath)
 
- 	assert.NoError(t, err)
 
- 	err = dataprovider.Initialize(providerConf, configDir, true)
 
- 	assert.NoError(t, err)
 
- 	if config.GetProviderConf().Driver == dataprovider.MemoryDataProviderName {
 
- 		return
 
- 	}
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath)
 
- 	assert.NoError(t, err)
 
- 	form := getLoginForm(a.Username, a.Password, csrfToken)
 
- 	req, err := http.NewRequest(http.MethodPost, webLoginPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr := executeRequest(req)
 
- 	assert.Equal(t, http.StatusFound, rr.Code)
 
- 	assert.Equal(t, webAdminTwoFactorPath, rr.Header().Get("Location"))
 
- 	cookie, err := getCookieFromResponse(rr)
 
- 	assert.NoError(t, err)
 
- 	form = make(url.Values)
 
- 	form.Set("recovery_code", recCode)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusInternalServerError, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "unable to set the recovery code as used")
 
- 	csrfToken, err = getCSRFToken(httpBaseURL + webClientLoginPath)
 
- 	assert.NoError(t, err)
 
- 	form = getLoginForm(u.Username, u.Password, csrfToken)
 
- 	req, err = http.NewRequest(http.MethodPost, webClientLoginPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusFound, rr.Code)
 
- 	assert.Equal(t, webClientTwoFactorPath, rr.Header().Get("Location"))
 
- 	cookie, err = getCookieFromResponse(rr)
 
- 	assert.NoError(t, err)
 
- 	form = make(url.Values)
 
- 	form.Set("recovery_code", recCode)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	req, err = http.NewRequest(http.MethodPost, webClientTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusInternalServerError, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "unable to set the recovery code as used")
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUserBaseDir(t *testing.T) {
 
- 	err := dataprovider.Close()
 
- 	assert.NoError(t, err)
 
- 	err = config.LoadConfig(configDir, "")
 
- 	assert.NoError(t, err)
 
- 	providerConf := config.GetProviderConf()
 
- 	providerConf.UsersBaseDir = homeBasePath
 
- 	err = dataprovider.Initialize(providerConf, configDir, true)
 
- 	assert.NoError(t, err)
 
- 	u := getTestUser()
 
- 	u.HomeDir = ""
 
- 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	if assert.Error(t, err) {
 
- 		assert.EqualError(t, err, "home dir mismatch")
 
- 	}
 
- 	assert.Equal(t, filepath.Join(providerConf.UsersBaseDir, u.Username), user.HomeDir)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = dataprovider.Close()
 
- 	assert.NoError(t, err)
 
- 	err = config.LoadConfig(configDir, "")
 
- 	assert.NoError(t, err)
 
- 	providerConf = config.GetProviderConf()
 
- 	providerConf.CredentialsPath = credentialsPath
 
- 	err = os.RemoveAll(credentialsPath)
 
- 	assert.NoError(t, err)
 
- 	err = dataprovider.Initialize(providerConf, configDir, true)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestQuotaTrackingDisabled(t *testing.T) {
 
- 	err := dataprovider.Close()
 
- 	assert.NoError(t, err)
 
- 	err = config.LoadConfig(configDir, "")
 
- 	assert.NoError(t, err)
 
- 	providerConf := config.GetProviderConf()
 
- 	providerConf.TrackQuota = 0
 
- 	err = dataprovider.Initialize(providerConf, configDir, true)
 
- 	assert.NoError(t, err)
 
- 	// user quota scan must fail
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.StartQuotaScan(user, http.StatusForbidden)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.UpdateQuotaUsage(user, "", http.StatusForbidden)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.UpdateTransferQuotaUsage(user, "", http.StatusForbidden)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	// folder quota scan must fail
 
- 	folder := vfs.BaseVirtualFolder{
 
- 		Name:       "folder_quota_test",
 
- 		MappedPath: filepath.Clean(os.TempDir()),
 
- 	}
 
- 	folder, resp, err := httpdtest.AddFolder(folder, http.StatusCreated)
 
- 	assert.NoError(t, err, string(resp))
 
- 	_, err = httpdtest.StartFolderQuotaScan(folder, http.StatusForbidden)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.UpdateFolderQuotaUsage(folder, "", http.StatusForbidden)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveFolder(folder, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = dataprovider.Close()
 
- 	assert.NoError(t, err)
 
- 	err = config.LoadConfig(configDir, "")
 
- 	assert.NoError(t, err)
 
- 	providerConf = config.GetProviderConf()
 
- 	providerConf.CredentialsPath = credentialsPath
 
- 	err = os.RemoveAll(credentialsPath)
 
- 	assert.NoError(t, err)
 
- 	err = dataprovider.Initialize(providerConf, configDir, true)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestProviderErrors(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	userAPIToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	userWebToken, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	token, _, err := httpdtest.GetToken(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	testServerToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	httpdtest.SetJWTToken(token)
 
- 	err = dataprovider.Close()
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.GetUserByUsername("na", http.StatusInternalServerError)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.GetUsers(1, 0, http.StatusInternalServerError)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.GetAdmins(1, 0, http.StatusInternalServerError)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.GetAPIKeys(1, 0, http.StatusInternalServerError)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodGet, userSharesPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, userAPIToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusInternalServerError, rr)
 
- 	// password reset errors
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath)
 
- 	assert.NoError(t, err)
 
- 	form := make(url.Values)
 
- 	form.Set("username", "username")
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	req, err = http.NewRequest(http.MethodPost, webClientForgotPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "Error retrieving your account, please try again later")
 
- 	req, err = http.NewRequest(http.MethodGet, webClientSharesPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, userWebToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusInternalServerError, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, webClientSharePath+"/shareID", nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, userWebToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusInternalServerError, rr)
 
- 	req, err = http.NewRequest(http.MethodPost, webClientSharePath+"/shareID", nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, userWebToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusInternalServerError, rr)
 
- 	_, _, err = httpdtest.UpdateUser(dataprovider.User{BaseUser: sdk.BaseUser{Username: "auser"}}, http.StatusInternalServerError, "")
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(dataprovider.User{BaseUser: sdk.BaseUser{Username: "auser"}}, http.StatusInternalServerError)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveFolder(vfs.BaseVirtualFolder{Name: "aname"}, http.StatusInternalServerError)
 
- 	assert.NoError(t, err)
 
- 	status, _, err := httpdtest.GetStatus(http.StatusOK)
 
- 	if assert.NoError(t, err) {
 
- 		assert.False(t, status.DataProvider.IsActive)
 
- 	}
 
- 	_, _, err = httpdtest.Dumpdata("backup.json", "", "", http.StatusInternalServerError)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.GetFolders(0, 0, http.StatusInternalServerError)
 
- 	assert.NoError(t, err)
 
- 	user = getTestUser()
 
- 	user.ID = 1
 
- 	backupData := dataprovider.BackupData{}
 
- 	backupData.Users = append(backupData.Users, user)
 
- 	backupContent, err := json.Marshal(backupData)
 
- 	assert.NoError(t, err)
 
- 	backupFilePath := filepath.Join(backupsPath, "backup.json")
 
- 	err = os.WriteFile(backupFilePath, backupContent, os.ModePerm)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.Loaddata(backupFilePath, "", "", http.StatusInternalServerError)
 
- 	assert.NoError(t, err)
 
- 	backupData.Folders = append(backupData.Folders, vfs.BaseVirtualFolder{Name: "testFolder", MappedPath: filepath.Clean(os.TempDir())})
 
- 	backupContent, err = json.Marshal(backupData)
 
- 	assert.NoError(t, err)
 
- 	err = os.WriteFile(backupFilePath, backupContent, os.ModePerm)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.Loaddata(backupFilePath, "", "", http.StatusInternalServerError)
 
- 	assert.NoError(t, err)
 
- 	backupData.Users = nil
 
- 	backupData.Folders = nil
 
- 	backupData.Admins = append(backupData.Admins, getTestAdmin())
 
- 	backupContent, err = json.Marshal(backupData)
 
- 	assert.NoError(t, err)
 
- 	err = os.WriteFile(backupFilePath, backupContent, os.ModePerm)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.Loaddata(backupFilePath, "", "", http.StatusInternalServerError)
 
- 	assert.NoError(t, err)
 
- 	backupData.Users = nil
 
- 	backupData.Folders = nil
 
- 	backupData.Admins = nil
 
- 	backupData.APIKeys = append(backupData.APIKeys, dataprovider.APIKey{
 
- 		Name:  "name",
 
- 		KeyID: util.GenerateUniqueID(),
 
- 		Key:   fmt.Sprintf("%v.%v", util.GenerateUniqueID(), util.GenerateUniqueID()),
 
- 		Scope: dataprovider.APIKeyScopeUser,
 
- 	})
 
- 	backupContent, err = json.Marshal(backupData)
 
- 	assert.NoError(t, err)
 
- 	err = os.WriteFile(backupFilePath, backupContent, os.ModePerm)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.Loaddata(backupFilePath, "", "", http.StatusInternalServerError)
 
- 	assert.NoError(t, err)
 
- 	backupData.APIKeys = nil
 
- 	backupData.Shares = append(backupData.Shares, dataprovider.Share{
 
- 		Name:     util.GenerateUniqueID(),
 
- 		ShareID:  util.GenerateUniqueID(),
 
- 		Scope:    dataprovider.ShareScopeRead,
 
- 		Paths:    []string{"/"},
 
- 		Username: defaultUsername,
 
- 	})
 
- 	backupContent, err = json.Marshal(backupData)
 
- 	assert.NoError(t, err)
 
- 	err = os.WriteFile(backupFilePath, backupContent, os.ModePerm)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.Loaddata(backupFilePath, "", "", http.StatusInternalServerError)
 
- 	assert.NoError(t, err)
 
- 	err = os.Remove(backupFilePath)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, webUserPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, testServerToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusInternalServerError, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, webTemplateUser+"?from=auser", nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, testServerToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusInternalServerError, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, webTemplateFolder+"?from=afolder", nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, testServerToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusInternalServerError, rr)
 
- 	err = config.LoadConfig(configDir, "")
 
- 	assert.NoError(t, err)
 
- 	providerConf := config.GetProviderConf()
 
- 	providerConf.CredentialsPath = credentialsPath
 
- 	err = os.RemoveAll(credentialsPath)
 
- 	assert.NoError(t, err)
 
- 	err = dataprovider.Initialize(providerConf, configDir, true)
 
- 	assert.NoError(t, err)
 
- 	httpdtest.SetJWTToken("")
 
- }
 
- func TestFolders(t *testing.T) {
 
- 	folder := vfs.BaseVirtualFolder{
 
- 		Name:       "name",
 
- 		MappedPath: "relative path",
 
- 		Users:      []string{"1", "2", "3"},
 
- 		FsConfig: vfs.Filesystem{
 
- 			Provider: sdk.CryptedFilesystemProvider,
 
- 			CryptConfig: vfs.CryptFsConfig{
 
- 				Passphrase: kms.NewPlainSecret("asecret"),
 
- 			},
 
- 		},
 
- 	}
 
- 	_, _, err := httpdtest.AddFolder(folder, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	folder.MappedPath = filepath.Clean(os.TempDir())
 
- 	folder1, resp, err := httpdtest.AddFolder(folder, http.StatusCreated)
 
- 	assert.NoError(t, err, string(resp))
 
- 	assert.Equal(t, folder.Name, folder1.Name)
 
- 	assert.Equal(t, folder.MappedPath, folder1.MappedPath)
 
- 	assert.Equal(t, 0, folder1.UsedQuotaFiles)
 
- 	assert.Equal(t, int64(0), folder1.UsedQuotaSize)
 
- 	assert.Equal(t, int64(0), folder1.LastQuotaUpdate)
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, folder1.FsConfig.CryptConfig.Passphrase.GetStatus())
 
- 	assert.NotEmpty(t, folder1.FsConfig.CryptConfig.Passphrase.GetPayload())
 
- 	assert.Empty(t, folder1.FsConfig.CryptConfig.Passphrase.GetAdditionalData())
 
- 	assert.Empty(t, folder1.FsConfig.CryptConfig.Passphrase.GetKey())
 
- 	assert.Len(t, folder1.Users, 0)
 
- 	// adding a duplicate folder must fail
 
- 	_, _, err = httpdtest.AddFolder(folder, http.StatusCreated)
 
- 	assert.Error(t, err)
 
- 	folder.MappedPath = filepath.Join(os.TempDir(), "vfolder")
 
- 	folder.Name = filepath.Base(folder.MappedPath)
 
- 	folder.UsedQuotaFiles = 1
 
- 	folder.UsedQuotaSize = 345
 
- 	folder.LastQuotaUpdate = 10
 
- 	folder2, _, err := httpdtest.AddFolder(folder, http.StatusCreated)
 
- 	assert.NoError(t, err, string(resp))
 
- 	assert.Equal(t, 1, folder2.UsedQuotaFiles)
 
- 	assert.Equal(t, int64(345), folder2.UsedQuotaSize)
 
- 	assert.Equal(t, int64(10), folder2.LastQuotaUpdate)
 
- 	assert.Len(t, folder2.Users, 0)
 
- 	folders, _, err := httpdtest.GetFolders(0, 0, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	numResults := len(folders)
 
- 	assert.GreaterOrEqual(t, numResults, 2)
 
- 	found := false
 
- 	for _, f := range folders {
 
- 		if f.Name == folder1.Name {
 
- 			found = true
 
- 			assert.Equal(t, folder1.MappedPath, f.MappedPath)
 
- 			assert.Equal(t, sdkkms.SecretStatusSecretBox, f.FsConfig.CryptConfig.Passphrase.GetStatus())
 
- 			assert.NotEmpty(t, f.FsConfig.CryptConfig.Passphrase.GetPayload())
 
- 			assert.Empty(t, f.FsConfig.CryptConfig.Passphrase.GetAdditionalData())
 
- 			assert.Empty(t, f.FsConfig.CryptConfig.Passphrase.GetKey())
 
- 			assert.Len(t, f.Users, 0)
 
- 		}
 
- 	}
 
- 	assert.True(t, found)
 
- 	folders, _, err = httpdtest.GetFolders(0, 1, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, folders, numResults-1)
 
- 	folders, _, err = httpdtest.GetFolders(1, 0, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, folders, 1)
 
- 	f, _, err := httpdtest.GetFolderByName(folder1.Name, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, folder1.Name, f.Name)
 
- 	assert.Equal(t, folder1.MappedPath, f.MappedPath)
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, f.FsConfig.CryptConfig.Passphrase.GetStatus())
 
- 	assert.NotEmpty(t, f.FsConfig.CryptConfig.Passphrase.GetPayload())
 
- 	assert.Empty(t, f.FsConfig.CryptConfig.Passphrase.GetAdditionalData())
 
- 	assert.Empty(t, f.FsConfig.CryptConfig.Passphrase.GetKey())
 
- 	assert.Len(t, f.Users, 0)
 
- 	f, _, err = httpdtest.GetFolderByName(folder2.Name, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, folder2.Name, f.Name)
 
- 	assert.Equal(t, folder2.MappedPath, f.MappedPath)
 
- 	_, err = httpdtest.RemoveFolder(vfs.BaseVirtualFolder{
 
- 		Name: "invalid",
 
- 	}, http.StatusNotFound)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.UpdateFolder(vfs.BaseVirtualFolder{Name: "notfound"}, http.StatusNotFound)
 
- 	assert.NoError(t, err)
 
- 	folder1.MappedPath = "a/relative/path"
 
- 	_, _, err = httpdtest.UpdateFolder(folder1, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	folder1.MappedPath = filepath.Join(os.TempDir(), "updated")
 
- 	folder1.Description = "updated folder description"
 
- 	f, resp, err = httpdtest.UpdateFolder(folder1, http.StatusOK)
 
- 	assert.NoError(t, err, string(resp))
 
- 	assert.Equal(t, folder1.MappedPath, f.MappedPath)
 
- 	assert.Equal(t, folder1.Description, f.Description)
 
- 	_, err = httpdtest.RemoveFolder(folder1, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveFolder(folder2, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestDumpdata(t *testing.T) {
 
- 	err := dataprovider.Close()
 
- 	assert.NoError(t, err)
 
- 	err = config.LoadConfig(configDir, "")
 
- 	assert.NoError(t, err)
 
- 	providerConf := config.GetProviderConf()
 
- 	err = dataprovider.Initialize(providerConf, configDir, true)
 
- 	assert.NoError(t, err)
 
- 	_, rawResp, err := httpdtest.Dumpdata("", "", "", http.StatusBadRequest)
 
- 	assert.NoError(t, err, string(rawResp))
 
- 	_, _, err = httpdtest.Dumpdata(filepath.Join(backupsPath, "backup.json"), "", "", http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	_, rawResp, err = httpdtest.Dumpdata("../backup.json", "", "", http.StatusBadRequest)
 
- 	assert.NoError(t, err, string(rawResp))
 
- 	_, rawResp, err = httpdtest.Dumpdata("backup.json", "", "0", http.StatusOK)
 
- 	assert.NoError(t, err, string(rawResp))
 
- 	response, _, err := httpdtest.Dumpdata("", "1", "0", http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, ok := response["admins"]
 
- 	assert.True(t, ok)
 
- 	_, ok = response["users"]
 
- 	assert.True(t, ok)
 
- 	_, ok = response["folders"]
 
- 	assert.True(t, ok)
 
- 	_, ok = response["api_keys"]
 
- 	assert.True(t, ok)
 
- 	_, ok = response["shares"]
 
- 	assert.True(t, ok)
 
- 	_, ok = response["version"]
 
- 	assert.True(t, ok)
 
- 	_, rawResp, err = httpdtest.Dumpdata("backup.json", "", "1", http.StatusOK)
 
- 	assert.NoError(t, err, string(rawResp))
 
- 	err = os.Remove(filepath.Join(backupsPath, "backup.json"))
 
- 	assert.NoError(t, err)
 
- 	if runtime.GOOS != osWindows {
 
- 		err = os.Chmod(backupsPath, 0001)
 
- 		assert.NoError(t, err)
 
- 		_, _, err = httpdtest.Dumpdata("bck.json", "", "", http.StatusForbidden)
 
- 		assert.NoError(t, err)
 
- 		// subdir cannot be created
 
- 		_, _, err = httpdtest.Dumpdata(filepath.Join("subdir", "bck.json"), "", "", http.StatusForbidden)
 
- 		assert.NoError(t, err)
 
- 		err = os.Chmod(backupsPath, 0755)
 
- 		assert.NoError(t, err)
 
- 	}
 
- 	err = dataprovider.Close()
 
- 	assert.NoError(t, err)
 
- 	err = config.LoadConfig(configDir, "")
 
- 	assert.NoError(t, err)
 
- 	providerConf = config.GetProviderConf()
 
- 	providerConf.CredentialsPath = credentialsPath
 
- 	err = os.RemoveAll(credentialsPath)
 
- 	assert.NoError(t, err)
 
- 	err = dataprovider.Initialize(providerConf, configDir, true)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestDefenderAPI(t *testing.T) {
 
- 	oldConfig := config.GetCommonConfig()
 
- 	drivers := []string{common.DefenderDriverMemory}
 
- 	if isDbDefenderSupported() {
 
- 		drivers = append(drivers, common.DefenderDriverProvider)
 
- 	}
 
- 	for _, driver := range drivers {
 
- 		cfg := config.GetCommonConfig()
 
- 		cfg.DefenderConfig.Enabled = true
 
- 		cfg.DefenderConfig.Driver = driver
 
- 		cfg.DefenderConfig.Threshold = 3
 
- 		cfg.DefenderConfig.ScoreLimitExceeded = 2
 
- 		err := common.Initialize(cfg, 0)
 
- 		assert.NoError(t, err)
 
- 		ip := "::1"
 
- 		response, _, err := httpdtest.GetBanTime(ip, http.StatusOK)
 
- 		assert.NoError(t, err)
 
- 		banTime, ok := response["date_time"]
 
- 		assert.True(t, ok)
 
- 		assert.Nil(t, banTime)
 
- 		hosts, _, err := httpdtest.GetDefenderHosts(http.StatusOK)
 
- 		assert.NoError(t, err)
 
- 		assert.Len(t, hosts, 0)
 
- 		response, _, err = httpdtest.GetScore(ip, http.StatusOK)
 
- 		assert.NoError(t, err)
 
- 		score, ok := response["score"]
 
- 		assert.True(t, ok)
 
- 		assert.Equal(t, float64(0), score)
 
- 		err = httpdtest.UnbanIP(ip, http.StatusNotFound)
 
- 		assert.NoError(t, err)
 
- 		_, err = httpdtest.RemoveDefenderHostByIP(ip, http.StatusNotFound)
 
- 		assert.NoError(t, err)
 
- 		common.AddDefenderEvent(ip, common.HostEventNoLoginTried)
 
- 		response, _, err = httpdtest.GetScore(ip, http.StatusOK)
 
- 		assert.NoError(t, err)
 
- 		score, ok = response["score"]
 
- 		assert.True(t, ok)
 
- 		assert.Equal(t, float64(2), score)
 
- 		hosts, _, err = httpdtest.GetDefenderHosts(http.StatusOK)
 
- 		assert.NoError(t, err)
 
- 		if assert.Len(t, hosts, 1) {
 
- 			host := hosts[0]
 
- 			assert.Empty(t, host.GetBanTime())
 
- 			assert.Equal(t, 2, host.Score)
 
- 			assert.Equal(t, ip, host.IP)
 
- 		}
 
- 		host, _, err := httpdtest.GetDefenderHostByIP(ip, http.StatusOK)
 
- 		assert.NoError(t, err)
 
- 		assert.Empty(t, host.GetBanTime())
 
- 		assert.Equal(t, 2, host.Score)
 
- 		common.AddDefenderEvent(ip, common.HostEventNoLoginTried)
 
- 		response, _, err = httpdtest.GetBanTime(ip, http.StatusOK)
 
- 		assert.NoError(t, err)
 
- 		banTime, ok = response["date_time"]
 
- 		assert.True(t, ok)
 
- 		assert.NotNil(t, banTime)
 
- 		hosts, _, err = httpdtest.GetDefenderHosts(http.StatusOK)
 
- 		assert.NoError(t, err)
 
- 		if assert.Len(t, hosts, 1) {
 
- 			host := hosts[0]
 
- 			assert.NotEmpty(t, host.GetBanTime())
 
- 			assert.Equal(t, 0, host.Score)
 
- 			assert.Equal(t, ip, host.IP)
 
- 		}
 
- 		host, _, err = httpdtest.GetDefenderHostByIP(ip, http.StatusOK)
 
- 		assert.NoError(t, err)
 
- 		assert.NotEmpty(t, host.GetBanTime())
 
- 		assert.Equal(t, 0, host.Score)
 
- 		err = httpdtest.UnbanIP(ip, http.StatusOK)
 
- 		assert.NoError(t, err)
 
- 		err = httpdtest.UnbanIP(ip, http.StatusNotFound)
 
- 		assert.NoError(t, err)
 
- 		host, _, err = httpdtest.GetDefenderHostByIP(ip, http.StatusNotFound)
 
- 		assert.NoError(t, err)
 
- 		common.AddDefenderEvent(ip, common.HostEventNoLoginTried)
 
- 		common.AddDefenderEvent(ip, common.HostEventNoLoginTried)
 
- 		hosts, _, err = httpdtest.GetDefenderHosts(http.StatusOK)
 
- 		assert.NoError(t, err)
 
- 		assert.Len(t, hosts, 1)
 
- 		_, err = httpdtest.RemoveDefenderHostByIP(ip, http.StatusOK)
 
- 		assert.NoError(t, err)
 
- 		host, _, err = httpdtest.GetDefenderHostByIP(ip, http.StatusNotFound)
 
- 		assert.NoError(t, err)
 
- 		_, err = httpdtest.RemoveDefenderHostByIP(ip, http.StatusNotFound)
 
- 		assert.NoError(t, err)
 
- 		host, _, err = httpdtest.GetDefenderHostByIP("invalid_ip", http.StatusBadRequest)
 
- 		assert.NoError(t, err)
 
- 		_, err = httpdtest.RemoveDefenderHostByIP("invalid_ip", http.StatusBadRequest)
 
- 		assert.NoError(t, err)
 
- 		if driver == common.DefenderDriverProvider {
 
- 			err = dataprovider.CleanupDefender(util.GetTimeAsMsSinceEpoch(time.Now().Add(1 * time.Hour)))
 
- 			assert.NoError(t, err)
 
- 		}
 
- 	}
 
- 	err := common.Initialize(oldConfig, 0)
 
- 	require.NoError(t, err)
 
- }
 
- func TestDefenderAPIErrors(t *testing.T) {
 
- 	_, _, err := httpdtest.GetBanTime("", http.StatusBadRequest)
 
- 	require.NoError(t, err)
 
- 	_, _, err = httpdtest.GetBanTime("invalid", http.StatusBadRequest)
 
- 	require.NoError(t, err)
 
- 	_, _, err = httpdtest.GetScore("", http.StatusBadRequest)
 
- 	require.NoError(t, err)
 
- 	err = httpdtest.UnbanIP("", http.StatusBadRequest)
 
- 	require.NoError(t, err)
 
- 	if isDbDefenderSupported() {
 
- 		oldConfig := config.GetCommonConfig()
 
- 		cfg := config.GetCommonConfig()
 
- 		cfg.DefenderConfig.Enabled = true
 
- 		cfg.DefenderConfig.Driver = common.DefenderDriverProvider
 
- 		err := common.Initialize(cfg, 0)
 
- 		require.NoError(t, err)
 
- 		token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 		assert.NoError(t, err)
 
- 		err = dataprovider.Close()
 
- 		assert.NoError(t, err)
 
- 		ip := "127.1.1.2"
 
- 		req, err := http.NewRequest(http.MethodGet, defenderHosts, nil)
 
- 		assert.NoError(t, err)
 
- 		setBearerForReq(req, token)
 
- 		rr := executeRequest(req)
 
- 		checkResponseCode(t, http.StatusInternalServerError, rr)
 
- 		req, err = http.NewRequest(http.MethodGet, defenderBanTime+"?ip="+ip, nil)
 
- 		assert.NoError(t, err)
 
- 		setBearerForReq(req, token)
 
- 		rr = executeRequest(req)
 
- 		checkResponseCode(t, http.StatusInternalServerError, rr)
 
- 		req, err = http.NewRequest(http.MethodGet, defenderScore+"?ip="+ip, nil)
 
- 		assert.NoError(t, err)
 
- 		setBearerForReq(req, token)
 
- 		rr = executeRequest(req)
 
- 		checkResponseCode(t, http.StatusInternalServerError, rr)
 
- 		err = config.LoadConfig(configDir, "")
 
- 		assert.NoError(t, err)
 
- 		providerConf := config.GetProviderConf()
 
- 		providerConf.CredentialsPath = credentialsPath
 
- 		err = os.RemoveAll(credentialsPath)
 
- 		assert.NoError(t, err)
 
- 		err = dataprovider.Initialize(providerConf, configDir, true)
 
- 		assert.NoError(t, err)
 
- 		err = common.Initialize(oldConfig, 0)
 
- 		require.NoError(t, err)
 
- 	}
 
- }
 
- func TestRestoreShares(t *testing.T) {
 
- 	// shares should be restored preserving the UsedTokens, CreatedAt, LastUseAt, UpdatedAt,
 
- 	// and ExpiresAt, so an expired share can be restored while we cannot create an already
 
- 	// expired share
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	share := dataprovider.Share{
 
- 		ShareID:     shortuuid.New(),
 
- 		Name:        "share name",
 
- 		Description: "share description",
 
- 		Scope:       dataprovider.ShareScopeRead,
 
- 		Paths:       []string{"/"},
 
- 		Username:    user.Username,
 
- 		CreatedAt:   util.GetTimeAsMsSinceEpoch(time.Now().Add(-144 * time.Hour)),
 
- 		UpdatedAt:   util.GetTimeAsMsSinceEpoch(time.Now().Add(-96 * time.Hour)),
 
- 		LastUseAt:   util.GetTimeAsMsSinceEpoch(time.Now().Add(-64 * time.Hour)),
 
- 		ExpiresAt:   util.GetTimeAsMsSinceEpoch(time.Now().Add(-48 * time.Hour)),
 
- 		MaxTokens:   10,
 
- 		UsedTokens:  8,
 
- 		AllowFrom:   []string{"127.0.0.0/8"},
 
- 	}
 
- 	backupData := dataprovider.BackupData{}
 
- 	backupData.Shares = append(backupData.Shares, share)
 
- 	backupContent, err := json.Marshal(backupData)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.LoaddataFromPostBody(backupContent, "0", "0", http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	shareGet, err := dataprovider.ShareExists(share.ShareID, user.Username)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, share, shareGet)
 
- 	share.CreatedAt = util.GetTimeAsMsSinceEpoch(time.Now().Add(-142 * time.Hour))
 
- 	share.UpdatedAt = util.GetTimeAsMsSinceEpoch(time.Now().Add(-92 * time.Hour))
 
- 	share.LastUseAt = util.GetTimeAsMsSinceEpoch(time.Now().Add(-62 * time.Hour))
 
- 	share.UsedTokens = 6
 
- 	backupData.Shares = []dataprovider.Share{share}
 
- 	backupContent, err = json.Marshal(backupData)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.LoaddataFromPostBody(backupContent, "0", "0", http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	shareGet, err = dataprovider.ShareExists(share.ShareID, user.Username)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, share, shareGet)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestLoaddataFromPostBody(t *testing.T) {
 
- 	mappedPath := filepath.Join(os.TempDir(), "restored_folder")
 
- 	folderName := filepath.Base(mappedPath)
 
- 	user := getTestUser()
 
- 	user.ID = 1
 
- 	user.Username = "test_user_restored"
 
- 	admin := getTestAdmin()
 
- 	admin.ID = 1
 
- 	admin.Username = "test_admin_restored"
 
- 	backupData := dataprovider.BackupData{}
 
- 	backupData.Users = append(backupData.Users, user)
 
- 	backupData.Admins = append(backupData.Admins, admin)
 
- 	backupData.Folders = []vfs.BaseVirtualFolder{
 
- 		{
 
- 			Name:            folderName,
 
- 			MappedPath:      mappedPath,
 
- 			UsedQuotaSize:   123,
 
- 			UsedQuotaFiles:  456,
 
- 			LastQuotaUpdate: 789,
 
- 			Users:           []string{"user"},
 
- 		},
 
- 		{
 
- 			Name:       folderName,
 
- 			MappedPath: mappedPath + "1",
 
- 		},
 
- 	}
 
- 	backupData.APIKeys = append(backupData.APIKeys, dataprovider.APIKey{})
 
- 	backupData.Shares = append(backupData.Shares, dataprovider.Share{})
 
- 	backupContent, err := json.Marshal(backupData)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.LoaddataFromPostBody(nil, "0", "0", http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.LoaddataFromPostBody(backupContent, "a", "0", http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.LoaddataFromPostBody([]byte("invalid content"), "0", "0", http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.LoaddataFromPostBody(backupContent, "0", "0", http.StatusInternalServerError)
 
- 	assert.NoError(t, err)
 
- 	keyID := util.GenerateUniqueID()
 
- 	backupData.APIKeys = []dataprovider.APIKey{
 
- 		{
 
- 			Name:  "test key",
 
- 			Scope: dataprovider.APIKeyScopeAdmin,
 
- 			KeyID: keyID,
 
- 			Key:   fmt.Sprintf("%v.%v", util.GenerateUniqueID(), util.GenerateUniqueID()),
 
- 		},
 
- 	}
 
- 	backupData.Shares = []dataprovider.Share{
 
- 		{
 
- 			ShareID:  keyID,
 
- 			Name:     keyID,
 
- 			Scope:    dataprovider.ShareScopeWrite,
 
- 			Paths:    []string{"/"},
 
- 			Username: user.Username,
 
- 		},
 
- 	}
 
- 	backupContent, err = json.Marshal(backupData)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.LoaddataFromPostBody(backupContent, "0", "0", http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, err = dataprovider.ShareExists(keyID, user.Username)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	admin, _, err = httpdtest.GetAdminByUsername(admin.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	apiKey, _, err := httpdtest.GetAPIKeyByID(keyID, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveAPIKey(apiKey, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	folder, _, err := httpdtest.GetFolderByName(folderName, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, mappedPath+"1", folder.MappedPath)
 
- 	assert.Equal(t, int64(123), folder.UsedQuotaSize)
 
- 	assert.Equal(t, 456, folder.UsedQuotaFiles)
 
- 	assert.Equal(t, int64(789), folder.LastQuotaUpdate)
 
- 	assert.Len(t, folder.Users, 0)
 
- 	_, err = httpdtest.RemoveFolder(folder, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestLoaddata(t *testing.T) {
 
- 	mappedPath := filepath.Join(os.TempDir(), "restored_folder")
 
- 	folderName := filepath.Base(mappedPath)
 
- 	foldeDesc := "restored folder desc"
 
- 	user := getTestUser()
 
- 	user.ID = 1
 
- 	user.Username = "test_user_restore"
 
- 	admin := getTestAdmin()
 
- 	admin.ID = 1
 
- 	admin.Username = "test_admin_restore"
 
- 	apiKey := dataprovider.APIKey{
 
- 		Name:  util.GenerateUniqueID(),
 
- 		Scope: dataprovider.APIKeyScopeAdmin,
 
- 		KeyID: util.GenerateUniqueID(),
 
- 		Key:   fmt.Sprintf("%v.%v", util.GenerateUniqueID(), util.GenerateUniqueID()),
 
- 	}
 
- 	share := dataprovider.Share{
 
- 		ShareID:  util.GenerateUniqueID(),
 
- 		Name:     util.GenerateUniqueID(),
 
- 		Scope:    dataprovider.ShareScopeRead,
 
- 		Paths:    []string{"/"},
 
- 		Username: user.Username,
 
- 	}
 
- 	backupData := dataprovider.BackupData{}
 
- 	backupData.Users = append(backupData.Users, user)
 
- 	backupData.Admins = append(backupData.Admins, admin)
 
- 	backupData.Folders = []vfs.BaseVirtualFolder{
 
- 		{
 
- 			Name:            folderName,
 
- 			MappedPath:      mappedPath + "1",
 
- 			UsedQuotaSize:   123,
 
- 			UsedQuotaFiles:  456,
 
- 			LastQuotaUpdate: 789,
 
- 			Users:           []string{"user"},
 
- 		},
 
- 		{
 
- 			MappedPath:  mappedPath,
 
- 			Name:        folderName,
 
- 			Description: foldeDesc,
 
- 		},
 
- 	}
 
- 	backupData.APIKeys = append(backupData.APIKeys, apiKey)
 
- 	backupData.Shares = append(backupData.Shares, share)
 
- 	backupContent, err := json.Marshal(backupData)
 
- 	assert.NoError(t, err)
 
- 	backupFilePath := filepath.Join(backupsPath, "backup.json")
 
- 	err = os.WriteFile(backupFilePath, backupContent, os.ModePerm)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.Loaddata(backupFilePath, "a", "", http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.Loaddata(backupFilePath, "", "a", http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.Loaddata("backup.json", "1", "", http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.Loaddata(backupFilePath+"a", "1", "", http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	if runtime.GOOS != osWindows {
 
- 		err = os.Chmod(backupFilePath, 0111)
 
- 		assert.NoError(t, err)
 
- 		_, _, err = httpdtest.Loaddata(backupFilePath, "1", "", http.StatusForbidden)
 
- 		assert.NoError(t, err)
 
- 		err = os.Chmod(backupFilePath, 0644)
 
- 		assert.NoError(t, err)
 
- 	}
 
- 	// add user, folder, admin, API key, share from backup
 
- 	_, _, err = httpdtest.Loaddata(backupFilePath, "1", "", http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	// update from backup
 
- 	_, _, err = httpdtest.Loaddata(backupFilePath, "2", "", http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, err = dataprovider.ShareExists(share.ShareID, user.Username)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	admin, _, err = httpdtest.GetAdminByUsername(admin.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	apiKey, _, err = httpdtest.GetAPIKeyByID(apiKey.KeyID, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveAPIKey(apiKey, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	folder, _, err := httpdtest.GetFolderByName(folderName, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, mappedPath, folder.MappedPath)
 
- 	assert.Equal(t, int64(123), folder.UsedQuotaSize)
 
- 	assert.Equal(t, 456, folder.UsedQuotaFiles)
 
- 	assert.Equal(t, int64(789), folder.LastQuotaUpdate)
 
- 	assert.Equal(t, foldeDesc, folder.Description)
 
- 	assert.Len(t, folder.Users, 0)
 
- 	_, err = httpdtest.RemoveFolder(folder, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.Remove(backupFilePath)
 
- 	assert.NoError(t, err)
 
- 	err = createTestFile(backupFilePath, 10485761)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.Loaddata(backupFilePath, "1", "0", http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	err = os.Remove(backupFilePath)
 
- 	assert.NoError(t, err)
 
- 	err = createTestFile(backupFilePath, 65535)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.Loaddata(backupFilePath, "1", "0", http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	err = os.Remove(backupFilePath)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestLoaddataMode(t *testing.T) {
 
- 	mappedPath := filepath.Join(os.TempDir(), "restored_fold")
 
- 	folderName := filepath.Base(mappedPath)
 
- 	user := getTestUser()
 
- 	user.ID = 1
 
- 	user.Username = "test_user_restore"
 
- 	admin := getTestAdmin()
 
- 	admin.ID = 1
 
- 	admin.Username = "test_admin_restore"
 
- 	apiKey := dataprovider.APIKey{
 
- 		Name:        util.GenerateUniqueID(),
 
- 		Scope:       dataprovider.APIKeyScopeAdmin,
 
- 		KeyID:       util.GenerateUniqueID(),
 
- 		Key:         fmt.Sprintf("%v.%v", util.GenerateUniqueID(), util.GenerateUniqueID()),
 
- 		Description: "desc",
 
- 	}
 
- 	share := dataprovider.Share{
 
- 		ShareID:  util.GenerateUniqueID(),
 
- 		Name:     util.GenerateUniqueID(),
 
- 		Scope:    dataprovider.ShareScopeRead,
 
- 		Paths:    []string{"/"},
 
- 		Username: user.Username,
 
- 	}
 
- 	backupData := dataprovider.BackupData{}
 
- 	backupData.Users = append(backupData.Users, user)
 
- 	backupData.Admins = append(backupData.Admins, admin)
 
- 	backupData.Folders = []vfs.BaseVirtualFolder{
 
- 		{
 
- 			Name:            folderName,
 
- 			MappedPath:      mappedPath,
 
- 			UsedQuotaSize:   123,
 
- 			UsedQuotaFiles:  456,
 
- 			LastQuotaUpdate: 789,
 
- 			Users:           []string{"user"},
 
- 		},
 
- 		{
 
- 			MappedPath: mappedPath + "1",
 
- 			Name:       folderName,
 
- 		},
 
- 	}
 
- 	backupData.APIKeys = append(backupData.APIKeys, apiKey)
 
- 	backupData.Shares = append(backupData.Shares, share)
 
- 	backupContent, _ := json.Marshal(backupData)
 
- 	backupFilePath := filepath.Join(backupsPath, "backup.json")
 
- 	err := os.WriteFile(backupFilePath, backupContent, os.ModePerm)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.Loaddata(backupFilePath, "0", "0", http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	folder, _, err := httpdtest.GetFolderByName(folderName, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, mappedPath+"1", folder.MappedPath)
 
- 	assert.Equal(t, int64(123), folder.UsedQuotaSize)
 
- 	assert.Equal(t, 456, folder.UsedQuotaFiles)
 
- 	assert.Equal(t, int64(789), folder.LastQuotaUpdate)
 
- 	assert.Len(t, folder.Users, 0)
 
- 	user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	oldUploadBandwidth := user.UploadBandwidth
 
- 	user.UploadBandwidth = oldUploadBandwidth + 128
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	admin, _, err = httpdtest.GetAdminByUsername(admin.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	oldInfo := admin.AdditionalInfo
 
- 	oldDesc := admin.Description
 
- 	admin.AdditionalInfo = "newInfo"
 
- 	admin.Description = "newDesc"
 
- 	admin, _, err = httpdtest.UpdateAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	apiKey, _, err = httpdtest.GetAPIKeyByID(apiKey.KeyID, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	oldAPIKeyDesc := apiKey.Description
 
- 	apiKey.ExpiresAt = util.GetTimeAsMsSinceEpoch(time.Now())
 
- 	apiKey.Description = "new desc"
 
- 	apiKey, _, err = httpdtest.UpdateAPIKey(apiKey, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	share.Description = "test desc"
 
- 	err = dataprovider.UpdateShare(&share, "", "")
 
- 	assert.NoError(t, err)
 
- 	backupData.Folders = []vfs.BaseVirtualFolder{
 
- 		{
 
- 			MappedPath: mappedPath,
 
- 			Name:       folderName,
 
- 		},
 
- 	}
 
- 	_, _, err = httpdtest.Loaddata(backupFilePath, "0", "1", http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	folder, _, err = httpdtest.GetFolderByName(folderName, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, mappedPath+"1", folder.MappedPath)
 
- 	assert.Equal(t, int64(123), folder.UsedQuotaSize)
 
- 	assert.Equal(t, 456, folder.UsedQuotaFiles)
 
- 	assert.Equal(t, int64(789), folder.LastQuotaUpdate)
 
- 	assert.Len(t, folder.Users, 0)
 
- 	c := common.NewBaseConnection("connID", common.ProtocolFTP, "", "", user)
 
- 	fakeConn := &fakeConnection{
 
- 		BaseConnection: c,
 
- 	}
 
- 	common.Connections.Add(fakeConn)
 
- 	assert.Len(t, common.Connections.GetStats(), 1)
 
- 	user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.NotEqual(t, oldUploadBandwidth, user.UploadBandwidth)
 
- 	admin, _, err = httpdtest.GetAdminByUsername(admin.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.NotEqual(t, oldInfo, admin.AdditionalInfo)
 
- 	assert.NotEqual(t, oldDesc, admin.Description)
 
- 	apiKey, _, err = httpdtest.GetAPIKeyByID(apiKey.KeyID, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.NotEqual(t, int64(0), apiKey.ExpiresAt)
 
- 	assert.NotEqual(t, oldAPIKeyDesc, apiKey.Description)
 
- 	share, err = dataprovider.ShareExists(share.ShareID, user.Username)
 
- 	assert.NoError(t, err)
 
- 	assert.NotEmpty(t, share.Description)
 
- 	_, _, err = httpdtest.Loaddata(backupFilePath, "0", "2", http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	// mode 2 will update the user and close the previous connection
 
- 	assert.Len(t, common.Connections.GetStats(), 0)
 
- 	user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, oldUploadBandwidth, user.UploadBandwidth)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveFolder(folder, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveAPIKey(apiKey, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.Remove(backupFilePath)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestRateLimiter(t *testing.T) {
 
- 	oldConfig := config.GetCommonConfig()
 
- 	cfg := config.GetCommonConfig()
 
- 	cfg.RateLimitersConfig = []common.RateLimiterConfig{
 
- 		{
 
- 			Average:   1,
 
- 			Period:    1000,
 
- 			Burst:     1,
 
- 			Type:      1,
 
- 			Protocols: []string{common.ProtocolHTTP},
 
- 		},
 
- 	}
 
- 	err := common.Initialize(cfg, 0)
 
- 	assert.NoError(t, err)
 
- 	client := &http.Client{
 
- 		Timeout: 5 * time.Second,
 
- 	}
 
- 	resp, err := client.Get(httpBaseURL + healthzPath)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, http.StatusOK, resp.StatusCode)
 
- 	err = resp.Body.Close()
 
- 	assert.NoError(t, err)
 
- 	resp, err = client.Get(httpBaseURL + healthzPath)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, http.StatusTooManyRequests, resp.StatusCode)
 
- 	assert.Equal(t, "1", resp.Header.Get("Retry-After"))
 
- 	assert.NotEmpty(t, resp.Header.Get("X-Retry-In"))
 
- 	err = resp.Body.Close()
 
- 	assert.NoError(t, err)
 
- 	resp, err = client.Get(httpBaseURL + webLoginPath)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, http.StatusTooManyRequests, resp.StatusCode)
 
- 	assert.Equal(t, "1", resp.Header.Get("Retry-After"))
 
- 	assert.NotEmpty(t, resp.Header.Get("X-Retry-In"))
 
- 	err = resp.Body.Close()
 
- 	assert.NoError(t, err)
 
- 	resp, err = client.Get(httpBaseURL + webClientLoginPath)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, http.StatusTooManyRequests, resp.StatusCode)
 
- 	assert.Equal(t, "1", resp.Header.Get("Retry-After"))
 
- 	assert.NotEmpty(t, resp.Header.Get("X-Retry-In"))
 
- 	err = resp.Body.Close()
 
- 	assert.NoError(t, err)
 
- 	err = common.Initialize(oldConfig, 0)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestHTTPSConnection(t *testing.T) {
 
- 	client := &http.Client{
 
- 		Timeout: 5 * time.Second,
 
- 	}
 
- 	resp, err := client.Get("https://localhost:8443" + healthzPath)
 
- 	if assert.Error(t, err) {
 
- 		if !strings.Contains(err.Error(), "certificate is not valid") &&
 
- 			!strings.Contains(err.Error(), "certificate signed by unknown authority") {
 
- 			assert.Fail(t, err.Error())
 
- 		}
 
- 	} else {
 
- 		resp.Body.Close()
 
- 	}
 
- }
 
- // test using mock http server
 
- func TestBasicUserHandlingMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	user := getTestUser()
 
- 	userAsJSON := getUserAsJSON(t, user)
 
- 	req, err := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	err = render.DecodeJSON(rr.Body, &user)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusInternalServerError, rr)
 
- 	user.MaxSessions = 10
 
- 	user.UploadBandwidth = 128
 
- 	user.Permissions["/"] = []string{dataprovider.PermAny, dataprovider.PermDelete, dataprovider.PermDownload}
 
- 	userAsJSON = getUserAsJSON(t, user)
 
- 	req, _ = http.NewRequest(http.MethodPut, userPath+"/"+user.Username, bytes.NewBuffer(userAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, userPath+"/"+user.Username, nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var updatedUser dataprovider.User
 
- 	err = render.DecodeJSON(rr.Body, &updatedUser)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, user.MaxSessions, updatedUser.MaxSessions)
 
- 	assert.Equal(t, user.UploadBandwidth, updatedUser.UploadBandwidth)
 
- 	assert.Equal(t, 1, len(updatedUser.Permissions["/"]))
 
- 	assert.True(t, util.IsStringInSlice(dataprovider.PermAny, updatedUser.Permissions["/"]))
 
- 	req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+user.Username, nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- }
 
- func TestAddUserNoUsernameMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	user := getTestUser()
 
- 	user.Username = ""
 
- 	userAsJSON := getUserAsJSON(t, user)
 
- 	req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- }
 
- func TestAddUserInvalidHomeDirMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	user := getTestUser()
 
- 	user.HomeDir = "relative_path"
 
- 	userAsJSON := getUserAsJSON(t, user)
 
- 	req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- }
 
- func TestAddUserInvalidPermsMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	user := getTestUser()
 
- 	user.Permissions["/"] = []string{}
 
- 	userAsJSON := getUserAsJSON(t, user)
 
- 	req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- }
 
- func TestAddFolderInvalidJsonMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodPost, folderPath, bytes.NewBuffer([]byte("invalid json")))
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- }
 
- func TestUpdateFolderInvalidJsonMock(t *testing.T) {
 
- 	folder := vfs.BaseVirtualFolder{
 
- 		Name:       "name",
 
- 		MappedPath: filepath.Clean(os.TempDir()),
 
- 	}
 
- 	folder, resp, err := httpdtest.AddFolder(folder, http.StatusCreated)
 
- 	assert.NoError(t, err, string(resp))
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodPut, path.Join(folderPath, folder.Name), bytes.NewBuffer([]byte("not a json")))
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	_, err = httpdtest.RemoveFolder(folder, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUnbanInvalidJsonMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodPost, defenderUnban, bytes.NewBuffer([]byte("invalid json")))
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- }
 
- func TestAddUserInvalidJsonMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer([]byte("invalid json")))
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- }
 
- func TestAddAdminInvalidJsonMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodPost, adminPath, bytes.NewBuffer([]byte("...")))
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- }
 
- func TestAddAdminNoPasswordMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	admin := getTestAdmin()
 
- 	admin.Password = ""
 
- 	asJSON, err := json.Marshal(admin)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodPost, adminPath, bytes.NewBuffer(asJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "please set a password")
 
- }
 
- func TestAdminTwoFactorLogin(t *testing.T) {
 
- 	admin := getTestAdmin()
 
- 	admin.Username = altAdminUsername
 
- 	admin.Password = altAdminPassword
 
- 	admin, _, err := httpdtest.AddAdmin(admin, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	// enable two factor authentication
 
- 	configName, _, secret, _, err := mfa.GenerateTOTPSecret(mfa.GetAvailableTOTPConfigNames()[0], admin.Username)
 
- 	assert.NoError(t, err)
 
- 	altToken, err := getJWTAPITokenFromTestServer(altAdminUsername, altAdminPassword)
 
- 	assert.NoError(t, err)
 
- 	adminTOTPConfig := dataprovider.AdminTOTPConfig{
 
- 		Enabled:    true,
 
- 		ConfigName: configName,
 
- 		Secret:     kms.NewPlainSecret(secret),
 
- 	}
 
- 	asJSON, err := json.Marshal(adminTOTPConfig)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodPost, adminTOTPSavePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, altToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	admin, _, err = httpdtest.GetAdminByUsername(admin.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.True(t, admin.Filters.TOTPConfig.Enabled)
 
- 	req, err = http.NewRequest(http.MethodGet, admin2FARecoveryCodesPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, altToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var recCodes []recoveryCode
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &recCodes)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, recCodes, 12)
 
- 	admin, _, err = httpdtest.GetAdminByUsername(altAdminUsername, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, admin.Filters.RecoveryCodes, 12)
 
- 	for _, c := range admin.Filters.RecoveryCodes {
 
- 		assert.Empty(t, c.Secret.GetAdditionalData())
 
- 		assert.Empty(t, c.Secret.GetKey())
 
- 		assert.Equal(t, sdkkms.SecretStatusSecretBox, c.Secret.GetStatus())
 
- 		assert.NotEmpty(t, c.Secret.GetPayload())
 
- 	}
 
- 	webToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, webAdminTwoFactorPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, webAdminTwoFactorRecoveryPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorRecoveryPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath)
 
- 	assert.NoError(t, err)
 
- 	form := getLoginForm(altAdminUsername, altAdminPassword, csrfToken)
 
- 	req, err = http.NewRequest(http.MethodPost, webLoginPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusFound, rr.Code)
 
- 	assert.Equal(t, webAdminTwoFactorPath, rr.Header().Get("Location"))
 
- 	cookie, err := getCookieFromResponse(rr)
 
- 	assert.NoError(t, err)
 
- 	// without a cookie
 
- 	req, err = http.NewRequest(http.MethodGet, webAdminTwoFactorRecoveryPath, nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, webAdminTwoFactorPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, webAdminTwoFactorRecoveryPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// any other page will be redirected to the two factor auth page
 
- 	req, err = http.NewRequest(http.MethodGet, webUsersPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusFound, rr)
 
- 	assert.Equal(t, webAdminTwoFactorPath, rr.Header().Get("Location"))
 
- 	// a partial token cannot be used for user pages
 
- 	req, err = http.NewRequest(http.MethodGet, webClientFilesPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusFound, rr)
 
- 	assert.Equal(t, webClientLoginPath, rr.Header().Get("Location"))
 
- 	passcode, err := generateTOTPPasscode(secret)
 
- 	assert.NoError(t, err)
 
- 	form = make(url.Values)
 
- 	form.Set("passcode", passcode)
 
- 	// no csrf
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "unable to verify form token")
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	form.Set("passcode", "invalid_passcode")
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "Invalid authentication code")
 
- 	form.Set("passcode", "")
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "Invalid credentials")
 
- 	form.Set("passcode", passcode)
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusFound, rr.Code)
 
- 	assert.Equal(t, webUsersPath, rr.Header().Get("Location"))
 
- 	// the same cookie cannot be reused
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusNotFound, rr.Code)
 
- 	// get a new cookie and login using a recovery code
 
- 	form = getLoginForm(altAdminUsername, altAdminPassword, csrfToken)
 
- 	req, err = http.NewRequest(http.MethodPost, webLoginPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusFound, rr.Code)
 
- 	assert.Equal(t, webAdminTwoFactorPath, rr.Header().Get("Location"))
 
- 	cookie, err = getCookieFromResponse(rr)
 
- 	assert.NoError(t, err)
 
- 	form = make(url.Values)
 
- 	recoveryCode := recCodes[0].Code
 
- 	form.Set("recovery_code", recoveryCode)
 
- 	// no csrf
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "unable to verify form token")
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	form.Set("recovery_code", "")
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "Invalid credentials")
 
- 	form.Set("recovery_code", recoveryCode)
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusFound, rr.Code)
 
- 	assert.Equal(t, webUsersPath, rr.Header().Get("Location"))
 
- 	authenticatedCookie, err := getCookieFromResponse(rr)
 
- 	assert.NoError(t, err)
 
- 	//render MFA page
 
- 	req, err = http.NewRequest(http.MethodGet, webAdminMFAPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, authenticatedCookie)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// check that the recovery code was marked as used
 
- 	req, err = http.NewRequest(http.MethodGet, admin2FARecoveryCodesPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, altToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	recCodes = nil
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &recCodes)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, recCodes, 12)
 
- 	found := false
 
- 	for _, rc := range recCodes {
 
- 		if rc.Code == recoveryCode {
 
- 			found = true
 
- 			assert.True(t, rc.Used)
 
- 		} else {
 
- 			assert.False(t, rc.Used)
 
- 		}
 
- 	}
 
- 	assert.True(t, found)
 
- 	// the same recovery code cannot be reused
 
- 	form = getLoginForm(altAdminUsername, altAdminPassword, csrfToken)
 
- 	req, err = http.NewRequest(http.MethodPost, webLoginPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusFound, rr.Code)
 
- 	assert.Equal(t, webAdminTwoFactorPath, rr.Header().Get("Location"))
 
- 	cookie, err = getCookieFromResponse(rr)
 
- 	assert.NoError(t, err)
 
- 	form = make(url.Values)
 
- 	form.Set("recovery_code", recoveryCode)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "This recovery code was already used")
 
- 	form.Set("recovery_code", "invalid_recovery_code")
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "Invalid recovery code")
 
- 	form = getLoginForm(altAdminUsername, altAdminPassword, csrfToken)
 
- 	req, err = http.NewRequest(http.MethodPost, webLoginPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusFound, rr.Code)
 
- 	assert.Equal(t, webAdminTwoFactorPath, rr.Header().Get("Location"))
 
- 	cookie, err = getCookieFromResponse(rr)
 
- 	assert.NoError(t, err)
 
- 	// disable TOTP
 
- 	req, err = http.NewRequest(http.MethodPut, adminPath+"/"+altAdminUsername+"/2fa/disable", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, altToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	form = make(url.Values)
 
- 	form.Set("recovery_code", recoveryCode)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "Two factory authentication is not enabled")
 
- 	form.Set("passcode", passcode)
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "Two factory authentication is not enabled")
 
- 	_, err = httpdtest.RemoveAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "Invalid credentials")
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "Invalid credentials")
 
- 	req, err = http.NewRequest(http.MethodGet, webAdminMFAPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, authenticatedCookie)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusInternalServerError, rr)
 
- }
 
- func TestAdminTOTP(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	admin := getTestAdmin()
 
- 	admin.Username = altAdminUsername
 
- 	admin.Password = altAdminPassword
 
- 	// TOTPConfig will be ignored on add
 
- 	admin.Filters.TOTPConfig = dataprovider.AdminTOTPConfig{
 
- 		Enabled:    true,
 
- 		ConfigName: "config",
 
- 		Secret:     kms.NewEmptySecret(),
 
- 	}
 
- 	asJSON, err := json.Marshal(admin)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodPost, adminPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	admin, _, err = httpdtest.GetAdminByUsername(altAdminUsername, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.False(t, admin.Filters.TOTPConfig.Enabled)
 
- 	assert.Len(t, admin.Filters.RecoveryCodes, 0)
 
- 	altToken, err := getJWTAPITokenFromTestServer(altAdminUsername, altAdminPassword)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, adminTOTPConfigsPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, altToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var configs []mfa.TOTPConfig
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &configs)
 
- 	assert.NoError(t, err, rr.Body.String())
 
- 	assert.Len(t, configs, len(mfa.GetAvailableTOTPConfigs()))
 
- 	totpConfig := configs[0]
 
- 	totpReq := generateTOTPRequest{
 
- 		ConfigName: totpConfig.Name,
 
- 	}
 
- 	asJSON, err = json.Marshal(totpReq)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, adminTOTPGeneratePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, altToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var totpGenResp generateTOTPResponse
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &totpGenResp)
 
- 	assert.NoError(t, err)
 
- 	assert.NotEmpty(t, totpGenResp.Secret)
 
- 	assert.NotEmpty(t, totpGenResp.QRCode)
 
- 	passcode, err := generateTOTPPasscode(totpGenResp.Secret)
 
- 	assert.NoError(t, err)
 
- 	validateReq := validateTOTPRequest{
 
- 		ConfigName: totpGenResp.ConfigName,
 
- 		Passcode:   passcode,
 
- 		Secret:     totpGenResp.Secret,
 
- 	}
 
- 	asJSON, err = json.Marshal(validateReq)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, adminTOTPValidatePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, altToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// the same passcode cannot be reused
 
- 	req, err = http.NewRequest(http.MethodPost, adminTOTPValidatePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, altToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "this passcode was already used")
 
- 	adminTOTPConfig := dataprovider.AdminTOTPConfig{
 
- 		Enabled:    true,
 
- 		ConfigName: totpGenResp.ConfigName,
 
- 		Secret:     kms.NewPlainSecret(totpGenResp.Secret),
 
- 	}
 
- 	asJSON, err = json.Marshal(adminTOTPConfig)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, adminTOTPSavePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, altToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	admin, _, err = httpdtest.GetAdminByUsername(altAdminUsername, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.True(t, admin.Filters.TOTPConfig.Enabled)
 
- 	assert.Equal(t, totpGenResp.ConfigName, admin.Filters.TOTPConfig.ConfigName)
 
- 	assert.Empty(t, admin.Filters.TOTPConfig.Secret.GetKey())
 
- 	assert.Empty(t, admin.Filters.TOTPConfig.Secret.GetAdditionalData())
 
- 	assert.NotEmpty(t, admin.Filters.TOTPConfig.Secret.GetPayload())
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, admin.Filters.TOTPConfig.Secret.GetStatus())
 
- 	admin.Filters.TOTPConfig = dataprovider.AdminTOTPConfig{
 
- 		Enabled:    false,
 
- 		ConfigName: util.GenerateUniqueID(),
 
- 		Secret:     kms.NewEmptySecret(),
 
- 	}
 
- 	admin.Filters.RecoveryCodes = []dataprovider.RecoveryCode{
 
- 		{
 
- 			Secret: kms.NewEmptySecret(),
 
- 		},
 
- 	}
 
- 	admin, resp, err := httpdtest.UpdateAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err, string(resp))
 
- 	assert.True(t, admin.Filters.TOTPConfig.Enabled)
 
- 	assert.Len(t, admin.Filters.RecoveryCodes, 12)
 
- 	// if we use token we should get no recovery codes
 
- 	req, err = http.NewRequest(http.MethodGet, admin2FARecoveryCodesPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var recCodes []recoveryCode
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &recCodes)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, recCodes, 0)
 
- 	// now the same but with altToken
 
- 	req, err = http.NewRequest(http.MethodGet, admin2FARecoveryCodesPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, altToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	recCodes = nil
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &recCodes)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, recCodes, 12)
 
- 	// regenerate recovery codes
 
- 	req, err = http.NewRequest(http.MethodPost, admin2FARecoveryCodesPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, altToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// check that recovery codes are different
 
- 	req, err = http.NewRequest(http.MethodGet, admin2FARecoveryCodesPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, altToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var newRecCodes []recoveryCode
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &newRecCodes)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, newRecCodes, 12)
 
- 	assert.NotEqual(t, recCodes, newRecCodes)
 
- 	// disable 2FA, the update admin API should not work
 
- 	admin.Filters.TOTPConfig.Enabled = false
 
- 	admin.Filters.RecoveryCodes = nil
 
- 	admin, _, err = httpdtest.UpdateAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, altAdminUsername, admin.Username)
 
- 	assert.True(t, admin.Filters.TOTPConfig.Enabled)
 
- 	assert.Len(t, admin.Filters.RecoveryCodes, 12)
 
- 	// use the dedicated API
 
- 	req, err = http.NewRequest(http.MethodPut, adminPath+"/"+altAdminUsername+"/2fa/disable", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	admin, _, err = httpdtest.GetAdminByUsername(altAdminUsername, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.False(t, admin.Filters.TOTPConfig.Enabled)
 
- 	assert.Len(t, admin.Filters.RecoveryCodes, 0)
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(adminPath, altAdminUsername), nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, err = http.NewRequest(http.MethodPut, adminPath+"/"+altAdminUsername+"/2fa/disable", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, admin2FARecoveryCodesPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, altToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodPost, admin2FARecoveryCodesPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, altToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodPost, adminTOTPSavePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, altToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- }
 
- func TestChangeAdminPwdInvalidJsonMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodPut, adminPwdPath, bytes.NewBuffer([]byte("{")))
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- }
 
- func TestMFAPermission(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	webToken, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodGet, webClientMFAPath, nil)
 
- 	assert.NoError(t, err)
 
- 	req.RequestURI = webClientMFAPath
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	user.Filters.WebClient = []string{sdk.WebClientMFADisabled}
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	webToken, err = getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, webClientMFAPath, nil)
 
- 	assert.NoError(t, err)
 
- 	req.RequestURI = webClientMFAPath
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- }
 
- func TestWebUserTwoFactorLogin(t *testing.T) {
 
- 	u := getTestUser()
 
- 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	// enable two factor authentication
 
- 	configName, _, secret, _, err := mfa.GenerateTOTPSecret(mfa.GetAvailableTOTPConfigNames()[0], user.Username)
 
- 	assert.NoError(t, err)
 
- 	token, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	adminToken, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	webToken, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	userTOTPConfig := dataprovider.UserTOTPConfig{
 
- 		Enabled:    true,
 
- 		ConfigName: configName,
 
- 		Secret:     kms.NewPlainSecret(secret),
 
- 		Protocols:  []string{common.ProtocolHTTP},
 
- 	}
 
- 	asJSON, err := json.Marshal(userTOTPConfig)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodPost, userTOTPSavePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, user2FARecoveryCodesPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var recCodes []recoveryCode
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &recCodes)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, recCodes, 12)
 
- 	user, _, err = httpdtest.GetUserByUsername(defaultUsername, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, user.Filters.RecoveryCodes, 12)
 
- 	for _, c := range user.Filters.RecoveryCodes {
 
- 		assert.Empty(t, c.Secret.GetAdditionalData())
 
- 		assert.Empty(t, c.Secret.GetKey())
 
- 		assert.Equal(t, sdkkms.SecretStatusSecretBox, c.Secret.GetStatus())
 
- 		assert.NotEmpty(t, c.Secret.GetPayload())
 
- 	}
 
- 	req, err = http.NewRequest(http.MethodGet, webClientTwoFactorPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, webClientTwoFactorRecoveryPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodPost, webClientTwoFactorPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodPost, webClientTwoFactorRecoveryPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webClientLoginPath)
 
- 	assert.NoError(t, err)
 
- 	form := getLoginForm(defaultUsername, defaultPassword, csrfToken)
 
- 	req, err = http.NewRequest(http.MethodPost, webClientLoginPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusFound, rr.Code)
 
- 	assert.Equal(t, webClientTwoFactorPath, rr.Header().Get("Location"))
 
- 	cookie, err := getCookieFromResponse(rr)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, webClientTwoFactorPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// without a cookie
 
- 	req, err = http.NewRequest(http.MethodGet, webClientTwoFactorPath, nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, webClientTwoFactorRecoveryPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// any other page will be redirected to the two factor auth page
 
- 	req, err = http.NewRequest(http.MethodGet, webClientFilesPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusFound, rr)
 
- 	assert.Equal(t, webClientTwoFactorPath, rr.Header().Get("Location"))
 
- 	// a partial token cannot be used for admin pages
 
- 	req, err = http.NewRequest(http.MethodGet, webUsersPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusFound, rr)
 
- 	assert.Equal(t, webLoginPath, rr.Header().Get("Location"))
 
- 	passcode, err := generateTOTPPasscode(secret)
 
- 	assert.NoError(t, err)
 
- 	form = make(url.Values)
 
- 	form.Set("passcode", passcode)
 
- 	req, err = http.NewRequest(http.MethodPost, webClientTwoFactorPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "unable to verify form token")
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	form.Set("passcode", "invalid_user_passcode")
 
- 	req, err = http.NewRequest(http.MethodPost, webClientTwoFactorPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "Invalid authentication code")
 
- 	form.Set("passcode", "")
 
- 	req, err = http.NewRequest(http.MethodPost, webClientTwoFactorPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "Invalid credentials")
 
- 	form.Set("passcode", passcode)
 
- 	req, err = http.NewRequest(http.MethodPost, webClientTwoFactorPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusFound, rr.Code)
 
- 	assert.Equal(t, webClientFilesPath, rr.Header().Get("Location"))
 
- 	// the same cookie cannot be reused
 
- 	req, err = http.NewRequest(http.MethodPost, webClientTwoFactorPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusNotFound, rr.Code)
 
- 	// get a new cookie and login using a recovery code
 
- 	form = getLoginForm(defaultUsername, defaultPassword, csrfToken)
 
- 	req, err = http.NewRequest(http.MethodPost, webClientLoginPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusFound, rr.Code)
 
- 	assert.Equal(t, webClientTwoFactorPath, rr.Header().Get("Location"))
 
- 	cookie, err = getCookieFromResponse(rr)
 
- 	assert.NoError(t, err)
 
- 	form = make(url.Values)
 
- 	recoveryCode := recCodes[0].Code
 
- 	form.Set("recovery_code", recoveryCode)
 
- 	// no csrf
 
- 	req, err = http.NewRequest(http.MethodPost, webClientTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "unable to verify form token")
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	form.Set("recovery_code", "")
 
- 	req, err = http.NewRequest(http.MethodPost, webClientTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "Invalid credentials")
 
- 	form.Set("recovery_code", recoveryCode)
 
- 	req, err = http.NewRequest(http.MethodPost, webClientTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusFound, rr.Code)
 
- 	assert.Equal(t, webClientFilesPath, rr.Header().Get("Location"))
 
- 	authenticatedCookie, err := getCookieFromResponse(rr)
 
- 	assert.NoError(t, err)
 
- 	//render MFA page
 
- 	req, err = http.NewRequest(http.MethodGet, webClientMFAPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, authenticatedCookie)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// check that the recovery code was marked as used
 
- 	req, err = http.NewRequest(http.MethodGet, user2FARecoveryCodesPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	recCodes = nil
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &recCodes)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, recCodes, 12)
 
- 	found := false
 
- 	for _, rc := range recCodes {
 
- 		if rc.Code == recoveryCode {
 
- 			found = true
 
- 			assert.True(t, rc.Used)
 
- 		} else {
 
- 			assert.False(t, rc.Used)
 
- 		}
 
- 	}
 
- 	assert.True(t, found)
 
- 	// the same recovery code cannot be reused
 
- 	form = getLoginForm(defaultUsername, defaultPassword, csrfToken)
 
- 	req, err = http.NewRequest(http.MethodPost, webClientLoginPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusFound, rr.Code)
 
- 	assert.Equal(t, webClientTwoFactorPath, rr.Header().Get("Location"))
 
- 	cookie, err = getCookieFromResponse(rr)
 
- 	assert.NoError(t, err)
 
- 	form = make(url.Values)
 
- 	form.Set("recovery_code", recoveryCode)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	req, err = http.NewRequest(http.MethodPost, webClientTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "This recovery code was already used")
 
- 	form.Set("recovery_code", "invalid_user_recovery_code")
 
- 	req, err = http.NewRequest(http.MethodPost, webClientTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "Invalid recovery code")
 
- 	form = getLoginForm(defaultUsername, defaultPassword, csrfToken)
 
- 	req, err = http.NewRequest(http.MethodPost, webClientLoginPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusFound, rr.Code)
 
- 	assert.Equal(t, webClientTwoFactorPath, rr.Header().Get("Location"))
 
- 	cookie, err = getCookieFromResponse(rr)
 
- 	assert.NoError(t, err)
 
- 	// disable TOTP
 
- 	req, err = http.NewRequest(http.MethodPut, userPath+"/"+user.Username+"/2fa/disable", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, adminToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	form = make(url.Values)
 
- 	form.Set("recovery_code", recoveryCode)
 
- 	form.Set("passcode", passcode)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	req, err = http.NewRequest(http.MethodPost, webClientTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "Two factory authentication is not enabled")
 
- 	req, err = http.NewRequest(http.MethodPost, webClientTwoFactorPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "Two factory authentication is not enabled")
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, webClientTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "Invalid credentials")
 
- 	req, err = http.NewRequest(http.MethodPost, webClientTwoFactorPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "Invalid credentials")
 
- 	req, err = http.NewRequest(http.MethodGet, webClientMFAPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, authenticatedCookie)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusInternalServerError, rr)
 
- }
 
- func TestSearchEvents(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodGet, fsEventsPath+"?limit=10&order=ASC&fs_provider=0", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	events := make([]map[string]interface{}, 0)
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &events)
 
- 	assert.NoError(t, err)
 
- 	if assert.Len(t, events, 1) {
 
- 		ev := events[0]
 
- 		for _, field := range []string{"id", "timestamp", "action", "username", "fs_path", "status", "protocol",
 
- 			"ip", "session_id", "fs_provider", "bucket", "endpoint", "open_flags", "instance_id"} {
 
- 			_, ok := ev[field]
 
- 			assert.True(t, ok, field)
 
- 		}
 
- 	}
 
- 	// the test eventsearcher plugin returns error if start_timestamp < 0
 
- 	req, err = http.NewRequest(http.MethodGet, fsEventsPath+"?start_timestamp=-1&end_timestamp=123456&statuses=1,2", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusInternalServerError, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, fsEventsPath+"?limit=a", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, providerEventsPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	events = make([]map[string]interface{}, 0)
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &events)
 
- 	assert.NoError(t, err)
 
- 	if assert.Len(t, events, 1) {
 
- 		ev := events[0]
 
- 		for _, field := range []string{"id", "timestamp", "action", "username", "object_type", "object_name",
 
- 			"object_data", "instance_id"} {
 
- 			_, ok := ev[field]
 
- 			assert.True(t, ok, field)
 
- 		}
 
- 	}
 
- 	// the test eventsearcher plugin returns error if start_timestamp < 0
 
- 	req, err = http.NewRequest(http.MethodGet, providerEventsPath+"?start_timestamp=-1", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusInternalServerError, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, providerEventsPath+"?limit=2000", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, fsEventsPath+"?start_timestamp=a", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, fsEventsPath+"?end_timestamp=a", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, fsEventsPath+"?order=ASSC", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, fsEventsPath+"?statuses=a,b", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, fsEventsPath+"?fs_provider=a", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- }
 
- func TestMFAErrors(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	assert.False(t, user.Filters.TOTPConfig.Enabled)
 
- 	userToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	adminToken, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	// invalid config name
 
- 	totpReq := generateTOTPRequest{
 
- 		ConfigName: "invalid config name",
 
- 	}
 
- 	asJSON, err := json.Marshal(totpReq)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodPost, userTOTPGeneratePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, userToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	// invalid JSON
 
- 	invalidJSON := []byte("not a JSON")
 
- 	req, err = http.NewRequest(http.MethodPost, userTOTPGeneratePath, bytes.NewBuffer(invalidJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, userToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	req, err = http.NewRequest(http.MethodPost, userTOTPSavePath, bytes.NewBuffer(invalidJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, userToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	req, err = http.NewRequest(http.MethodPost, adminTOTPSavePath, bytes.NewBuffer(invalidJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, adminToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	req, err = http.NewRequest(http.MethodPost, adminTOTPValidatePath, bytes.NewBuffer(invalidJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, adminToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	// invalid TOTP config name
 
- 	userTOTPConfig := dataprovider.UserTOTPConfig{
 
- 		Enabled:    true,
 
- 		ConfigName: "missing name",
 
- 		Secret:     kms.NewPlainSecret(xid.New().String()),
 
- 		Protocols:  []string{common.ProtocolSSH},
 
- 	}
 
- 	asJSON, err = json.Marshal(userTOTPConfig)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userTOTPSavePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, userToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "totp: config name")
 
- 	// invalid TOTP secret
 
- 	userTOTPConfig = dataprovider.UserTOTPConfig{
 
- 		Enabled:    true,
 
- 		ConfigName: mfa.GetAvailableTOTPConfigNames()[0],
 
- 		Secret:     nil,
 
- 		Protocols:  []string{common.ProtocolSSH},
 
- 	}
 
- 	asJSON, err = json.Marshal(userTOTPConfig)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userTOTPSavePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, userToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "totp: secret is mandatory")
 
- 	// no protocol
 
- 	userTOTPConfig = dataprovider.UserTOTPConfig{
 
- 		Enabled:    true,
 
- 		ConfigName: mfa.GetAvailableTOTPConfigNames()[0],
 
- 		Secret:     kms.NewPlainSecret(xid.New().String()),
 
- 		Protocols:  nil,
 
- 	}
 
- 	asJSON, err = json.Marshal(userTOTPConfig)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userTOTPSavePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, userToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "totp: specify at least one protocol")
 
- 	// invalid protocol
 
- 	userTOTPConfig = dataprovider.UserTOTPConfig{
 
- 		Enabled:    true,
 
- 		ConfigName: mfa.GetAvailableTOTPConfigNames()[0],
 
- 		Secret:     kms.NewPlainSecret(xid.New().String()),
 
- 		Protocols:  []string{common.ProtocolWebDAV},
 
- 	}
 
- 	asJSON, err = json.Marshal(userTOTPConfig)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userTOTPSavePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, userToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "totp: invalid protocol")
 
- 	adminTOTPConfig := dataprovider.AdminTOTPConfig{
 
- 		Enabled:    true,
 
- 		ConfigName: "",
 
- 		Secret:     kms.NewPlainSecret("secret"),
 
- 	}
 
- 	asJSON, err = json.Marshal(adminTOTPConfig)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, adminTOTPSavePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, adminToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "totp: config name is mandatory")
 
- 	adminTOTPConfig = dataprovider.AdminTOTPConfig{
 
- 		Enabled:    true,
 
- 		ConfigName: mfa.GetAvailableTOTPConfigNames()[0],
 
- 		Secret:     nil,
 
- 	}
 
- 	asJSON, err = json.Marshal(adminTOTPConfig)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, adminTOTPSavePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, adminToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "totp: secret is mandatory")
 
- 	// invalid TOTP secret status
 
- 	userTOTPConfig = dataprovider.UserTOTPConfig{
 
- 		Enabled:    true,
 
- 		ConfigName: mfa.GetAvailableTOTPConfigNames()[0],
 
- 		Secret:     kms.NewSecret(sdkkms.SecretStatusRedacted, "", "", ""),
 
- 		Protocols:  []string{common.ProtocolSSH},
 
- 	}
 
- 	asJSON, err = json.Marshal(userTOTPConfig)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userTOTPSavePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, userToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	// previous secret will be preserved and we have no secret saved
 
- 	assert.Contains(t, rr.Body.String(), "totp: secret is mandatory")
 
- 	req, err = http.NewRequest(http.MethodPost, adminTOTPSavePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, adminToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "totp: secret is mandatory")
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- }
 
- func TestMFAInvalidSecret(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	userToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	user.Password = defaultPassword
 
- 	user.Filters.TOTPConfig = dataprovider.UserTOTPConfig{
 
- 		Enabled:    true,
 
- 		ConfigName: mfa.GetAvailableTOTPConfigNames()[0],
 
- 		Secret:     kms.NewSecret(sdkkms.SecretStatusSecretBox, "payload", "key", user.Username),
 
- 		Protocols:  []string{common.ProtocolSSH, common.ProtocolHTTP},
 
- 	}
 
- 	user.Filters.RecoveryCodes = append(user.Filters.RecoveryCodes, dataprovider.RecoveryCode{
 
- 		Used:   false,
 
- 		Secret: kms.NewSecret(sdkkms.SecretStatusSecretBox, "payload", "key", user.Username),
 
- 	})
 
- 	err = dataprovider.UpdateUser(&user, "", "")
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodGet, user2FARecoveryCodesPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, userToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusInternalServerError, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Unable to decrypt recovery codes")
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webClientLoginPath)
 
- 	assert.NoError(t, err)
 
- 	form := getLoginForm(defaultUsername, defaultPassword, csrfToken)
 
- 	req, err = http.NewRequest(http.MethodPost, webClientLoginPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusFound, rr.Code)
 
- 	assert.Equal(t, webClientTwoFactorPath, rr.Header().Get("Location"))
 
- 	cookie, err := getCookieFromResponse(rr)
 
- 	assert.NoError(t, err)
 
- 	form = make(url.Values)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	form.Set("passcode", "123456")
 
- 	req, err = http.NewRequest(http.MethodPost, webClientTwoFactorPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusInternalServerError, rr.Code)
 
- 	form = make(url.Values)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	form.Set("recovery_code", "RC-123456")
 
- 	req, err = http.NewRequest(http.MethodPost, webClientTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusInternalServerError, rr.Code)
 
- 	req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, userTokenPath), nil)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("X-SFTPGO-OTP", "authcode")
 
- 	req.SetBasicAuth(defaultUsername, defaultPassword)
 
- 	resp, err := httpclient.GetHTTPClient().Do(req)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, http.StatusInternalServerError, resp.StatusCode)
 
- 	err = resp.Body.Close()
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- 	admin := getTestAdmin()
 
- 	admin.Username = altAdminUsername
 
- 	admin.Password = altAdminPassword
 
- 	admin, _, err = httpdtest.AddAdmin(admin, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	admin.Password = altAdminPassword
 
- 	admin.Filters.TOTPConfig = dataprovider.AdminTOTPConfig{
 
- 		Enabled:    true,
 
- 		ConfigName: mfa.GetAvailableTOTPConfigNames()[0],
 
- 		Secret:     kms.NewSecret(sdkkms.SecretStatusSecretBox, "payload", "key", user.Username),
 
- 	}
 
- 	admin.Filters.RecoveryCodes = append(user.Filters.RecoveryCodes, dataprovider.RecoveryCode{
 
- 		Used:   false,
 
- 		Secret: kms.NewSecret(sdkkms.SecretStatusSecretBox, "payload", "key", user.Username),
 
- 	})
 
- 	err = dataprovider.UpdateAdmin(&admin, "", "")
 
- 	assert.NoError(t, err)
 
- 	csrfToken, err = getCSRFToken(httpBaseURL + webLoginPath)
 
- 	assert.NoError(t, err)
 
- 	form = getLoginForm(altAdminUsername, altAdminPassword, csrfToken)
 
- 	req, err = http.NewRequest(http.MethodPost, webLoginPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusFound, rr.Code)
 
- 	assert.Equal(t, webAdminTwoFactorPath, rr.Header().Get("Location"))
 
- 	cookie, err = getCookieFromResponse(rr)
 
- 	assert.NoError(t, err)
 
- 	form = make(url.Values)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	form.Set("passcode", "123456")
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusInternalServerError, rr.Code)
 
- 	form = make(url.Values)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	form.Set("recovery_code", "RC-123456")
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminTwoFactorRecoveryPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, cookie)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusInternalServerError, rr.Code)
 
- 	req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v%v", httpBaseURL, tokenPath), nil)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("X-SFTPGO-OTP", "auth-code")
 
- 	req.SetBasicAuth(altAdminUsername, altAdminPassword)
 
- 	resp, err = httpclient.GetHTTPClient().Do(req)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, http.StatusInternalServerError, resp.StatusCode)
 
- 	err = resp.Body.Close()
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestWebUserTOTP(t *testing.T) {
 
- 	u := getTestUser()
 
- 	// TOTPConfig will be ignored on add
 
- 	u.Filters.TOTPConfig = dataprovider.UserTOTPConfig{
 
- 		Enabled:    true,
 
- 		ConfigName: "",
 
- 		Secret:     kms.NewEmptySecret(),
 
- 		Protocols:  []string{common.ProtocolSSH},
 
- 	}
 
- 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	assert.False(t, user.Filters.TOTPConfig.Enabled)
 
- 	token, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodGet, userTOTPConfigsPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var configs []mfa.TOTPConfig
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &configs)
 
- 	assert.NoError(t, err, rr.Body.String())
 
- 	assert.Len(t, configs, len(mfa.GetAvailableTOTPConfigs()))
 
- 	totpConfig := configs[0]
 
- 	totpReq := generateTOTPRequest{
 
- 		ConfigName: totpConfig.Name,
 
- 	}
 
- 	asJSON, err := json.Marshal(totpReq)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userTOTPGeneratePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var totpGenResp generateTOTPResponse
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &totpGenResp)
 
- 	assert.NoError(t, err)
 
- 	assert.NotEmpty(t, totpGenResp.Secret)
 
- 	assert.NotEmpty(t, totpGenResp.QRCode)
 
- 	passcode, err := generateTOTPPasscode(totpGenResp.Secret)
 
- 	assert.NoError(t, err)
 
- 	validateReq := validateTOTPRequest{
 
- 		ConfigName: totpGenResp.ConfigName,
 
- 		Passcode:   passcode,
 
- 		Secret:     totpGenResp.Secret,
 
- 	}
 
- 	asJSON, err = json.Marshal(validateReq)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userTOTPValidatePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// the same passcode cannot be reused
 
- 	req, err = http.NewRequest(http.MethodPost, userTOTPValidatePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "this passcode was already used")
 
- 	userTOTPConfig := dataprovider.UserTOTPConfig{
 
- 		Enabled:    true,
 
- 		ConfigName: totpGenResp.ConfigName,
 
- 		Secret:     kms.NewPlainSecret(totpGenResp.Secret),
 
- 		Protocols:  []string{common.ProtocolSSH},
 
- 	}
 
- 	asJSON, err = json.Marshal(userTOTPConfig)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userTOTPSavePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	totpCfg := user.Filters.TOTPConfig
 
- 	assert.True(t, totpCfg.Enabled)
 
- 	secretPayload := totpCfg.Secret.GetPayload()
 
- 	assert.Equal(t, totpGenResp.ConfigName, totpCfg.ConfigName)
 
- 	assert.Empty(t, totpCfg.Secret.GetKey())
 
- 	assert.Empty(t, totpCfg.Secret.GetAdditionalData())
 
- 	assert.NotEmpty(t, secretPayload)
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, totpCfg.Secret.GetStatus())
 
- 	assert.Len(t, totpCfg.Protocols, 1)
 
- 	assert.Contains(t, totpCfg.Protocols, common.ProtocolSSH)
 
- 	// update protocols only
 
- 	userTOTPConfig = dataprovider.UserTOTPConfig{
 
- 		Protocols: []string{common.ProtocolSSH, common.ProtocolFTP},
 
- 		Secret:    kms.NewEmptySecret(),
 
- 	}
 
- 	asJSON, err = json.Marshal(userTOTPConfig)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userTOTPSavePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// update the user, TOTP should not be affected
 
- 	user.Filters.TOTPConfig = dataprovider.UserTOTPConfig{
 
- 		Enabled: false,
 
- 		Secret:  kms.NewEmptySecret(),
 
- 	}
 
- 	_, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.True(t, user.Filters.TOTPConfig.Enabled)
 
- 	assert.Equal(t, totpCfg.ConfigName, user.Filters.TOTPConfig.ConfigName)
 
- 	assert.Empty(t, user.Filters.TOTPConfig.Secret.GetKey())
 
- 	assert.Empty(t, user.Filters.TOTPConfig.Secret.GetAdditionalData())
 
- 	assert.Equal(t, secretPayload, user.Filters.TOTPConfig.Secret.GetPayload())
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, user.Filters.TOTPConfig.Secret.GetStatus())
 
- 	assert.Len(t, user.Filters.TOTPConfig.Protocols, 2)
 
- 	assert.Contains(t, user.Filters.TOTPConfig.Protocols, common.ProtocolSSH)
 
- 	assert.Contains(t, user.Filters.TOTPConfig.Protocols, common.ProtocolFTP)
 
- 	req, err = http.NewRequest(http.MethodGet, user2FARecoveryCodesPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var recCodes []recoveryCode
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &recCodes)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, recCodes, 12)
 
- 	// regenerate recovery codes
 
- 	req, err = http.NewRequest(http.MethodPost, user2FARecoveryCodesPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// check that recovery codes are different
 
- 	req, err = http.NewRequest(http.MethodGet, user2FARecoveryCodesPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var newRecCodes []recoveryCode
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &newRecCodes)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, newRecCodes, 12)
 
- 	assert.NotEqual(t, recCodes, newRecCodes)
 
- 	// disable 2FA, the update user API should not work
 
- 	adminToken, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	user.Filters.TOTPConfig.Enabled = false
 
- 	user.Filters.RecoveryCodes = nil
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, defaultUsername, user.Username)
 
- 	assert.True(t, user.Filters.TOTPConfig.Enabled)
 
- 	assert.Len(t, user.Filters.RecoveryCodes, 12)
 
- 	// use the dedicated API
 
- 	req, err = http.NewRequest(http.MethodPut, userPath+"/"+defaultUsername+"/2fa/disable", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, adminToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	user, _, err = httpdtest.GetUserByUsername(defaultUsername, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.False(t, user.Filters.TOTPConfig.Enabled)
 
- 	assert.Len(t, user.Filters.RecoveryCodes, 0)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPut, userPath+"/"+defaultUsername+"/2fa/disable", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, adminToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, user2FARecoveryCodesPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodPost, user2FARecoveryCodesPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodPost, userTOTPSavePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- }
 
- func TestWebAPIChangeUserProfileMock(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	assert.False(t, user.Filters.AllowAPIKeyAuth)
 
- 	token, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	// invalid json
 
- 	req, err := http.NewRequest(http.MethodPut, userProfilePath, bytes.NewBuffer([]byte("{")))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	email := "[email protected]"
 
- 	description := "user API description"
 
- 	profileReq := make(map[string]interface{})
 
- 	profileReq["allow_api_key_auth"] = true
 
- 	profileReq["email"] = email
 
- 	profileReq["description"] = description
 
- 	profileReq["public_keys"] = []string{testPubKey, testPubKey1}
 
- 	asJSON, err := json.Marshal(profileReq)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPut, userProfilePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	profileReq = make(map[string]interface{})
 
- 	req, err = http.NewRequest(http.MethodGet, userProfilePath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &profileReq)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, email, profileReq["email"].(string))
 
- 	assert.Equal(t, description, profileReq["description"].(string))
 
- 	assert.True(t, profileReq["allow_api_key_auth"].(bool))
 
- 	assert.Len(t, profileReq["public_keys"].([]interface{}), 2)
 
- 	// set an invalid email
 
- 	profileReq = make(map[string]interface{})
 
- 	profileReq["email"] = "notavalidemail"
 
- 	asJSON, err = json.Marshal(profileReq)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPut, userProfilePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Validation error: email")
 
- 	// set an invalid public key
 
- 	profileReq = make(map[string]interface{})
 
- 	profileReq["public_keys"] = []string{"not a public key"}
 
- 	asJSON, err = json.Marshal(profileReq)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPut, userProfilePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Validation error: could not parse key")
 
- 	user.Filters.WebClient = []string{sdk.WebClientAPIKeyAuthChangeDisabled, sdk.WebClientPubKeyChangeDisabled}
 
- 	user.Email = email
 
- 	user.Description = description
 
- 	user.Filters.AllowAPIKeyAuth = true
 
- 	_, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	token, err = getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	profileReq = make(map[string]interface{})
 
- 	profileReq["allow_api_key_auth"] = false
 
- 	profileReq["email"] = email
 
- 	profileReq["description"] = description + "_mod"
 
- 	profileReq["public_keys"] = []string{testPubKey}
 
- 	asJSON, err = json.Marshal(profileReq)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPut, userProfilePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Profile updated")
 
- 	// check that api key auth and public keys were not changed
 
- 	profileReq = make(map[string]interface{})
 
- 	req, err = http.NewRequest(http.MethodGet, userProfilePath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &profileReq)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, email, profileReq["email"].(string))
 
- 	assert.Equal(t, description+"_mod", profileReq["description"].(string))
 
- 	assert.True(t, profileReq["allow_api_key_auth"].(bool))
 
- 	assert.Len(t, profileReq["public_keys"].([]interface{}), 2)
 
- 	user.Filters.WebClient = []string{sdk.WebClientAPIKeyAuthChangeDisabled, sdk.WebClientInfoChangeDisabled}
 
- 	user.Description = description + "_mod"
 
- 	_, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	token, err = getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	profileReq = make(map[string]interface{})
 
- 	profileReq["allow_api_key_auth"] = false
 
- 	profileReq["email"] = "[email protected]"
 
- 	profileReq["description"] = description
 
- 	profileReq["public_keys"] = []string{testPubKey}
 
- 	asJSON, err = json.Marshal(profileReq)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPut, userProfilePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	profileReq = make(map[string]interface{})
 
- 	req, err = http.NewRequest(http.MethodGet, userProfilePath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &profileReq)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, email, profileReq["email"].(string))
 
- 	assert.Equal(t, description+"_mod", profileReq["description"].(string))
 
- 	assert.True(t, profileReq["allow_api_key_auth"].(bool))
 
- 	assert.Len(t, profileReq["public_keys"].([]interface{}), 1)
 
- 	// finally disable all profile permissions
 
- 	user.Filters.WebClient = []string{sdk.WebClientAPIKeyAuthChangeDisabled, sdk.WebClientInfoChangeDisabled,
 
- 		sdk.WebClientPubKeyChangeDisabled}
 
- 	_, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPut, userProfilePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "You are not allowed to change anything")
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, userProfilePath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodPut, userProfilePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- }
 
- func TestWebAPIChangeUserPwdMock(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	token, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	// invalid json
 
- 	req, err := http.NewRequest(http.MethodPut, userPwdPath, bytes.NewBuffer([]byte("{")))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	pwd := make(map[string]string)
 
- 	pwd["current_password"] = defaultPassword
 
- 	pwd["new_password"] = defaultPassword
 
- 	asJSON, err := json.Marshal(pwd)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPut, userPwdPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "the new password must be different from the current one")
 
- 	pwd["new_password"] = altAdminPassword
 
- 	asJSON, err = json.Marshal(pwd)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPut, userPwdPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	_, err = getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.Error(t, err)
 
- 	token, err = getJWTAPIUserTokenFromTestServer(defaultUsername, altAdminPassword)
 
- 	assert.NoError(t, err)
 
- 	assert.NotEmpty(t, token)
 
- 	// remove the change password permission
 
- 	user.Filters.WebClient = []string{sdk.WebClientPasswordChangeDisabled}
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, user.Filters.WebClient, 1)
 
- 	assert.Contains(t, user.Filters.WebClient, sdk.WebClientPasswordChangeDisabled)
 
- 	token, err = getJWTAPIUserTokenFromTestServer(defaultUsername, altAdminPassword)
 
- 	assert.NoError(t, err)
 
- 	assert.NotEmpty(t, token)
 
- 	pwd["current_password"] = altAdminPassword
 
- 	pwd["new_password"] = defaultPassword
 
- 	asJSON, err = json.Marshal(pwd)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPut, userPwdPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- }
 
- func TestLoginInvalidPasswordMock(t *testing.T) {
 
- 	_, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass+"1")
 
- 	assert.Error(t, err)
 
- 	// now a login with no credentials
 
- 	req, _ := http.NewRequest(http.MethodGet, "/api/v2/token", nil)
 
- 	rr := executeRequest(req)
 
- 	assert.Equal(t, http.StatusUnauthorized, rr.Code)
 
- }
 
- func TestWebAPIChangeAdminProfileMock(t *testing.T) {
 
- 	admin := getTestAdmin()
 
- 	admin.Username = altAdminUsername
 
- 	admin.Password = altAdminPassword
 
- 	admin, _, err := httpdtest.AddAdmin(admin, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	assert.False(t, admin.Filters.AllowAPIKeyAuth)
 
- 	token, err := getJWTAPITokenFromTestServer(altAdminUsername, altAdminPassword)
 
- 	assert.NoError(t, err)
 
- 	// invalid json
 
- 	req, err := http.NewRequest(http.MethodPut, adminProfilePath, bytes.NewBuffer([]byte("{")))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	email := "[email protected]"
 
- 	description := "admin API description"
 
- 	profileReq := make(map[string]interface{})
 
- 	profileReq["allow_api_key_auth"] = true
 
- 	profileReq["email"] = email
 
- 	profileReq["description"] = description
 
- 	asJSON, err := json.Marshal(profileReq)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPut, adminProfilePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Profile updated")
 
- 	profileReq = make(map[string]interface{})
 
- 	req, err = http.NewRequest(http.MethodGet, adminProfilePath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &profileReq)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, email, profileReq["email"].(string))
 
- 	assert.Equal(t, description, profileReq["description"].(string))
 
- 	assert.True(t, profileReq["allow_api_key_auth"].(bool))
 
- 	// set an invalid email
 
- 	profileReq["email"] = "admin_invalid_email"
 
- 	asJSON, err = json.Marshal(profileReq)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPut, adminProfilePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Validation error: email")
 
- 	_, err = httpdtest.RemoveAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, adminProfilePath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodPut, adminProfilePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- }
 
- func TestChangeAdminPwdMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	admin := getTestAdmin()
 
- 	admin.Username = altAdminUsername
 
- 	admin.Password = altAdminPassword
 
- 	admin.Permissions = []string{dataprovider.PermAdminAddUsers, dataprovider.PermAdminDeleteUsers}
 
- 	asJSON, err := json.Marshal(admin)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodPost, adminPath, bytes.NewBuffer(asJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	altToken, err := getJWTAPITokenFromTestServer(altAdminUsername, altAdminPassword)
 
- 	assert.NoError(t, err)
 
- 	user := getTestUser()
 
- 	userAsJSON := getUserAsJSON(t, user)
 
- 	req, _ = http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
 
- 	setBearerForReq(req, altToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	req, _ = http.NewRequest(http.MethodPut, path.Join(userPath, user.Username), bytes.NewBuffer(userAsJSON))
 
- 	setBearerForReq(req, altToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	pwd := make(map[string]string)
 
- 	pwd["current_password"] = altAdminPassword
 
- 	pwd["new_password"] = defaultTokenAuthPass
 
- 	asJSON, err = json.Marshal(pwd)
 
- 	assert.NoError(t, err)
 
- 	req, _ = http.NewRequest(http.MethodPut, adminPwdPath, bytes.NewBuffer(asJSON))
 
- 	setBearerForReq(req, altToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	_, err = getJWTAPITokenFromTestServer(altAdminUsername, altAdminPassword)
 
- 	assert.Error(t, err)
 
- 	altToken, err = getJWTAPITokenFromTestServer(altAdminUsername, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	req, _ = http.NewRequest(http.MethodPut, adminPwdPath, bytes.NewBuffer(asJSON))
 
- 	setBearerForReq(req, altToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr) // current password does not match
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(userPath, user.Username), nil)
 
- 	setBearerForReq(req, altToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(adminPath, altAdminUsername), nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- }
 
- func TestUpdateAdminMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	_, err = getJWTAPITokenFromTestServer(altAdminUsername, defaultTokenAuthPass)
 
- 	assert.Error(t, err)
 
- 	admin := getTestAdmin()
 
- 	admin.Username = altAdminUsername
 
- 	admin.Permissions = []string{dataprovider.PermAdminManageAdmins}
 
- 	asJSON, err := json.Marshal(admin)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodPost, adminPath, bytes.NewBuffer(asJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	_, err = getJWTAPITokenFromTestServer(altAdminUsername, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	req, _ = http.NewRequest(http.MethodPut, path.Join(adminPath, "abc"), bytes.NewBuffer(asJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, _ = http.NewRequest(http.MethodPut, path.Join(adminPath, altAdminUsername), bytes.NewBuffer([]byte("no json")))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	admin.Permissions = nil
 
- 	asJSON, err = json.Marshal(admin)
 
- 	assert.NoError(t, err)
 
- 	req, _ = http.NewRequest(http.MethodPut, path.Join(adminPath, altAdminUsername), bytes.NewBuffer(asJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	admin = getTestAdmin()
 
- 	admin.Status = 0
 
- 	asJSON, err = json.Marshal(admin)
 
- 	assert.NoError(t, err)
 
- 	req, _ = http.NewRequest(http.MethodPut, path.Join(adminPath, defaultTokenAuthUser), bytes.NewBuffer(asJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	admin.Status = 1
 
- 	admin.Permissions = []string{dataprovider.PermAdminAddUsers}
 
- 	asJSON, err = json.Marshal(admin)
 
- 	assert.NoError(t, err)
 
- 	req, _ = http.NewRequest(http.MethodPut, path.Join(adminPath, defaultTokenAuthUser), bytes.NewBuffer(asJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	altToken, err := getJWTAPITokenFromTestServer(altAdminUsername, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	admin.Password = "" // it must remain unchanged
 
- 	admin.Permissions = []string{dataprovider.PermAdminManageAdmins, dataprovider.PermAdminCloseConnections}
 
- 	asJSON, err = json.Marshal(admin)
 
- 	assert.NoError(t, err)
 
- 	req, _ = http.NewRequest(http.MethodPut, path.Join(adminPath, altAdminUsername), bytes.NewBuffer(asJSON))
 
- 	setBearerForReq(req, altToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	_, err = getJWTAPITokenFromTestServer(altAdminUsername, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(adminPath, altAdminUsername), nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- }
 
- func TestAdminLastLoginWithAPIKey(t *testing.T) {
 
- 	admin := getTestAdmin()
 
- 	admin.Username = altAdminUsername
 
- 	admin.Filters.AllowAPIKeyAuth = true
 
- 	admin, resp, err := httpdtest.AddAdmin(admin, http.StatusCreated)
 
- 	assert.NoError(t, err, string(resp))
 
- 	assert.Equal(t, int64(0), admin.LastLogin)
 
- 	apiKey := dataprovider.APIKey{
 
- 		Name:      "admin API key",
 
- 		Scope:     dataprovider.APIKeyScopeAdmin,
 
- 		Admin:     altAdminUsername,
 
- 		LastUseAt: 123,
 
- 	}
 
- 	apiKey, resp, err = httpdtest.AddAPIKey(apiKey, http.StatusCreated)
 
- 	assert.NoError(t, err, string(resp))
 
- 	assert.Equal(t, int64(0), apiKey.LastUseAt)
 
- 	req, err := http.NewRequest(http.MethodGet, versionPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, apiKey.Key, admin.Username)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	admin, _, err = httpdtest.GetAdminByUsername(altAdminUsername, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Greater(t, admin.LastLogin, int64(0))
 
- 	_, err = httpdtest.RemoveAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUserLastLoginWithAPIKey(t *testing.T) {
 
- 	user := getTestUser()
 
- 	user.Filters.AllowAPIKeyAuth = true
 
- 	user, resp, err := httpdtest.AddUser(user, http.StatusCreated)
 
- 	assert.NoError(t, err, string(resp))
 
- 	assert.Equal(t, int64(0), user.LastLogin)
 
- 	apiKey := dataprovider.APIKey{
 
- 		Name:  "user API key",
 
- 		Scope: dataprovider.APIKeyScopeUser,
 
- 		User:  user.Username,
 
- 	}
 
- 	apiKey, resp, err = httpdtest.AddAPIKey(apiKey, http.StatusCreated)
 
- 	assert.NoError(t, err, string(resp))
 
- 	req, err := http.NewRequest(http.MethodGet, userDirsPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, apiKey.Key, "")
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Greater(t, user.LastLogin, int64(0))
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- }
 
- func TestAdminHandlingWithAPIKeys(t *testing.T) {
 
- 	sysAdmin, _, err := httpdtest.GetAdminByUsername(defaultTokenAuthUser, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	sysAdmin.Filters.AllowAPIKeyAuth = true
 
- 	sysAdmin, _, err = httpdtest.UpdateAdmin(sysAdmin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	apiKey := dataprovider.APIKey{
 
- 		Name:  "test admin API key",
 
- 		Scope: dataprovider.APIKeyScopeAdmin,
 
- 		Admin: defaultTokenAuthUser,
 
- 	}
 
- 	apiKey, resp, err := httpdtest.AddAPIKey(apiKey, http.StatusCreated)
 
- 	assert.NoError(t, err, string(resp))
 
- 	admin := getTestAdmin()
 
- 	admin.Username = altAdminUsername
 
- 	asJSON, err := json.Marshal(admin)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodPost, adminPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, apiKey.Key, "")
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	_, err = getJWTAPITokenFromTestServer(altAdminUsername, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	admin.Filters.AllowAPIKeyAuth = true
 
- 	asJSON, err = json.Marshal(admin)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPut, path.Join(adminPath, altAdminUsername), bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, apiKey.Key, "")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(adminPath, altAdminUsername), nil)
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, apiKey.Key, "")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var adminGet dataprovider.Admin
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &adminGet)
 
- 	assert.NoError(t, err)
 
- 	assert.True(t, adminGet.Filters.AllowAPIKeyAuth)
 
- 	req, err = http.NewRequest(http.MethodPut, path.Join(adminPath, defaultTokenAuthUser), bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, apiKey.Key, "")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "updating the admin impersonated with an API key is not allowed")
 
- 	// changing the password for the impersonated admin is not allowed
 
- 	pwd := make(map[string]string)
 
- 	pwd["current_password"] = defaultTokenAuthPass
 
- 	pwd["new_password"] = altAdminPassword
 
- 	asJSON, err = json.Marshal(pwd)
 
- 	assert.NoError(t, err)
 
- 	req, _ = http.NewRequest(http.MethodPut, adminPwdPath, bytes.NewBuffer(asJSON))
 
- 	setAPIKeyForReq(req, apiKey.Key, "")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "API key authentication is not allowed")
 
- 	req, err = http.NewRequest(http.MethodDelete, path.Join(adminPath, defaultTokenAuthUser), nil)
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, apiKey.Key, "")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "you cannot delete yourself")
 
- 	req, err = http.NewRequest(http.MethodDelete, path.Join(adminPath, altAdminUsername), nil)
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, apiKey.Key, "")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	_, err = httpdtest.RemoveAPIKey(apiKey, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	dbAdmin, err := dataprovider.AdminExists(defaultTokenAuthUser)
 
- 	assert.NoError(t, err)
 
- 	dbAdmin.Filters.AllowAPIKeyAuth = false
 
- 	err = dataprovider.UpdateAdmin(&dbAdmin, "", "")
 
- 	assert.NoError(t, err)
 
- 	sysAdmin, _, err = httpdtest.GetAdminByUsername(defaultTokenAuthUser, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.False(t, sysAdmin.Filters.AllowAPIKeyAuth)
 
- }
 
- func TestUserHandlingWithAPIKey(t *testing.T) {
 
- 	admin := getTestAdmin()
 
- 	admin.Username = altAdminUsername
 
- 	admin.Filters.AllowAPIKeyAuth = true
 
- 	admin, _, err := httpdtest.AddAdmin(admin, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	apiKey := dataprovider.APIKey{
 
- 		Name:  "test admin API key",
 
- 		Scope: dataprovider.APIKeyScopeAdmin,
 
- 		Admin: admin.Username,
 
- 	}
 
- 	apiKey, _, err = httpdtest.AddAPIKey(apiKey, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	user := getTestUser()
 
- 	userAsJSON := getUserAsJSON(t, user)
 
- 	req, err := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, apiKey.Key, "")
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	user.Filters.DisableFsChecks = true
 
- 	user.Description = "desc"
 
- 	userAsJSON = getUserAsJSON(t, user)
 
- 	req, err = http.NewRequest(http.MethodPut, path.Join(userPath, user.Username), bytes.NewBuffer(userAsJSON))
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, apiKey.Key, "")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil)
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, apiKey.Key, "")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var updatedUser dataprovider.User
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &updatedUser)
 
- 	assert.NoError(t, err)
 
- 	assert.True(t, updatedUser.Filters.DisableFsChecks)
 
- 	assert.Equal(t, user.Description, updatedUser.Description)
 
- 	req, err = http.NewRequest(http.MethodDelete, path.Join(userPath, user.Username), nil)
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, apiKey.Key, "")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.GetAPIKeyByID(apiKey.KeyID, http.StatusNotFound)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUpdateUserMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	user := getTestUser()
 
- 	userAsJSON := getUserAsJSON(t, user)
 
- 	req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	err = render.DecodeJSON(rr.Body, &user)
 
- 	assert.NoError(t, err)
 
- 	// permissions should not change if empty or nil
 
- 	permissions := user.Permissions
 
- 	user.Permissions = make(map[string][]string)
 
- 	userAsJSON = getUserAsJSON(t, user)
 
- 	req, _ = http.NewRequest(http.MethodPut, userPath+"/"+user.Username, bytes.NewBuffer(userAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, userPath+"/"+user.Username, nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var updatedUser dataprovider.User
 
- 	err = render.DecodeJSON(rr.Body, &updatedUser)
 
- 	assert.NoError(t, err)
 
- 	for dir, perms := range permissions {
 
- 		if actualPerms, ok := updatedUser.Permissions[dir]; ok {
 
- 			for _, v := range actualPerms {
 
- 				assert.True(t, util.IsStringInSlice(v, perms))
 
- 			}
 
- 		} else {
 
- 			assert.Fail(t, "Permissions directories mismatch")
 
- 		}
 
- 	}
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(userPath, user.Username), nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- }
 
- func TestUpdateUserQuotaUsageMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	var user dataprovider.User
 
- 	u := getTestUser()
 
- 	usedQuotaFiles := 1
 
- 	usedQuotaSize := int64(65535)
 
- 	u.UsedQuotaFiles = usedQuotaFiles
 
- 	u.UsedQuotaSize = usedQuotaSize
 
- 	u.QuotaFiles = 100
 
- 	userAsJSON := getUserAsJSON(t, u)
 
- 	req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	err = render.DecodeJSON(rr.Body, &user)
 
- 	assert.NoError(t, err)
 
- 	req, _ = http.NewRequest(http.MethodPut, path.Join(quotasBasePath, "users", u.Username, "usage"), bytes.NewBuffer(userAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodPut, updateUsedQuotaCompatPath, bytes.NewBuffer(userAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	err = render.DecodeJSON(rr.Body, &user)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, usedQuotaFiles, user.UsedQuotaFiles)
 
- 	assert.Equal(t, usedQuotaSize, user.UsedQuotaSize)
 
- 	// now update only quota size
 
- 	u.UsedQuotaFiles = 0
 
- 	userAsJSON = getUserAsJSON(t, u)
 
- 	req, _ = http.NewRequest(http.MethodPut, path.Join(quotasBasePath, "users", u.Username, "usage")+"?mode=add", bytes.NewBuffer(userAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	err = render.DecodeJSON(rr.Body, &user)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, usedQuotaFiles, user.UsedQuotaFiles)
 
- 	assert.Equal(t, usedQuotaSize*2, user.UsedQuotaSize)
 
- 	// only quota files
 
- 	u.UsedQuotaFiles = usedQuotaFiles
 
- 	u.UsedQuotaSize = 0
 
- 	userAsJSON = getUserAsJSON(t, u)
 
- 	req, _ = http.NewRequest(http.MethodPut, path.Join(quotasBasePath, "users", u.Username, "usage")+"?mode=add", bytes.NewBuffer(userAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	err = render.DecodeJSON(rr.Body, &user)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, usedQuotaFiles*2, user.UsedQuotaFiles)
 
- 	assert.Equal(t, usedQuotaSize*2, user.UsedQuotaSize)
 
- 	req, _ = http.NewRequest(http.MethodPut, updateUsedQuotaCompatPath, bytes.NewBuffer([]byte("string")))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	req, _ = http.NewRequest(http.MethodPut, path.Join(quotasBasePath, "users", u.Username, "usage"), bytes.NewBuffer([]byte("string")))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.True(t, common.QuotaScans.AddUserQuotaScan(user.Username))
 
- 	req, _ = http.NewRequest(http.MethodPut, path.Join(quotasBasePath, "users", u.Username, "usage"), bytes.NewBuffer(userAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusConflict, rr)
 
- 	assert.True(t, common.QuotaScans.RemoveUserQuotaScan(user.Username))
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(userPath, user.Username), nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- }
 
- func TestUserPermissionsMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	user := getTestUser()
 
- 	user.Permissions = make(map[string][]string)
 
- 	user.Permissions["/somedir"] = []string{dataprovider.PermAny}
 
- 	userAsJSON := getUserAsJSON(t, user)
 
- 	req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	user.Permissions = make(map[string][]string)
 
- 	user.Permissions["/"] = []string{dataprovider.PermAny}
 
- 	user.Permissions[".."] = []string{dataprovider.PermAny}
 
- 	userAsJSON = getUserAsJSON(t, user)
 
- 	req, _ = http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	user.Permissions = make(map[string][]string)
 
- 	user.Permissions["/"] = []string{dataprovider.PermAny}
 
- 	userAsJSON = getUserAsJSON(t, user)
 
- 	req, _ = http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	err = render.DecodeJSON(rr.Body, &user)
 
- 	assert.NoError(t, err)
 
- 	user.Permissions["/somedir"] = []string{"invalid"}
 
- 	userAsJSON = getUserAsJSON(t, user)
 
- 	req, _ = http.NewRequest(http.MethodPut, path.Join(userPath, user.Username), bytes.NewBuffer(userAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	delete(user.Permissions, "/somedir")
 
- 	user.Permissions["/somedir/.."] = []string{dataprovider.PermAny}
 
- 	userAsJSON = getUserAsJSON(t, user)
 
- 	req, _ = http.NewRequest(http.MethodPut, path.Join(userPath, user.Username), bytes.NewBuffer(userAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	delete(user.Permissions, "/somedir/..")
 
- 	user.Permissions["not_abs_path"] = []string{dataprovider.PermAny}
 
- 	userAsJSON = getUserAsJSON(t, user)
 
- 	req, _ = http.NewRequest(http.MethodPut, path.Join(userPath, user.Username), bytes.NewBuffer(userAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	delete(user.Permissions, "not_abs_path")
 
- 	user.Permissions["/somedir/../otherdir/"] = []string{dataprovider.PermListItems}
 
- 	userAsJSON = getUserAsJSON(t, user)
 
- 	req, _ = http.NewRequest(http.MethodPut, path.Join(userPath, user.Username), bytes.NewBuffer(userAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var updatedUser dataprovider.User
 
- 	err = render.DecodeJSON(rr.Body, &updatedUser)
 
- 	assert.NoError(t, err)
 
- 	if val, ok := updatedUser.Permissions["/otherdir"]; ok {
 
- 		assert.True(t, util.IsStringInSlice(dataprovider.PermListItems, val))
 
- 		assert.Equal(t, 1, len(val))
 
- 	} else {
 
- 		assert.Fail(t, "expected dir not found in permissions")
 
- 	}
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(userPath, user.Username), nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- }
 
- func TestUpdateUserInvalidJsonMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	user := getTestUser()
 
- 	userAsJSON := getUserAsJSON(t, user)
 
- 	req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	err = render.DecodeJSON(rr.Body, &user)
 
- 	assert.NoError(t, err)
 
- 	req, _ = http.NewRequest(http.MethodPut, path.Join(userPath, user.Username), bytes.NewBuffer([]byte("Invalid json")))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(userPath, user.Username), nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- }
 
- func TestUpdateUserInvalidParamsMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	user := getTestUser()
 
- 	userAsJSON := getUserAsJSON(t, user)
 
- 	req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	err = render.DecodeJSON(rr.Body, &user)
 
- 	assert.NoError(t, err)
 
- 	user.HomeDir = ""
 
- 	userAsJSON = getUserAsJSON(t, user)
 
- 	req, _ = http.NewRequest(http.MethodPut, path.Join(userPath, user.Username), bytes.NewBuffer(userAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	userID := user.ID
 
- 	user.ID = 0
 
- 	user.CreatedAt = 0
 
- 	userAsJSON = getUserAsJSON(t, user)
 
- 	req, _ = http.NewRequest(http.MethodPut, path.Join(userPath, user.Username), bytes.NewBuffer(userAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	user.ID = userID
 
- 	req, _ = http.NewRequest(http.MethodPut, userPath+"/0", bytes.NewBuffer(userAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(userPath, user.Username), nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- }
 
- func TestGetAdminsMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	admin := getTestAdmin()
 
- 	admin.Username = altAdminUsername
 
- 	asJSON, err := json.Marshal(admin)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodPost, adminPath, bytes.NewBuffer(asJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, adminPath+"?limit=510&offset=0&order=ASC", nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var admins []dataprovider.Admin
 
- 	err = render.DecodeJSON(rr.Body, &admins)
 
- 	assert.NoError(t, err)
 
- 	assert.GreaterOrEqual(t, len(admins), 1)
 
- 	firtAdmin := admins[0].Username
 
- 	req, _ = http.NewRequest(http.MethodGet, adminPath+"?limit=510&offset=0&order=DESC", nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	admins = nil
 
- 	err = render.DecodeJSON(rr.Body, &admins)
 
- 	assert.NoError(t, err)
 
- 	assert.GreaterOrEqual(t, len(admins), 1)
 
- 	assert.NotEqual(t, firtAdmin, admins[0].Username)
 
- 	req, _ = http.NewRequest(http.MethodGet, adminPath+"?limit=510&offset=1&order=ASC", nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	admins = nil
 
- 	err = render.DecodeJSON(rr.Body, &admins)
 
- 	assert.NoError(t, err)
 
- 	assert.GreaterOrEqual(t, len(admins), 1)
 
- 	assert.NotEqual(t, firtAdmin, admins[0].Username)
 
- 	req, _ = http.NewRequest(http.MethodGet, adminPath+"?limit=a&offset=0&order=ASC", nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, adminPath+"?limit=1&offset=a&order=ASC", nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, adminPath+"?limit=1&offset=0&order=ASCa", nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(adminPath, admin.Username), nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- }
 
- func TestGetUsersMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	user := getTestUser()
 
- 	userAsJSON := getUserAsJSON(t, user)
 
- 	req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	err = render.DecodeJSON(rr.Body, &user)
 
- 	assert.NoError(t, err)
 
- 	req, _ = http.NewRequest(http.MethodGet, userPath+"?limit=510&offset=0&order=ASC", nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var users []dataprovider.User
 
- 	err = render.DecodeJSON(rr.Body, &users)
 
- 	assert.NoError(t, err)
 
- 	assert.GreaterOrEqual(t, len(users), 1)
 
- 	req, _ = http.NewRequest(http.MethodGet, userPath+"?limit=a&offset=0&order=ASC", nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, userPath+"?limit=1&offset=a&order=ASC", nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, userPath+"?limit=1&offset=0&order=ASCa", nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(userPath, user.Username), nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- }
 
- func TestDeleteUserInvalidParamsMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodDelete, userPath+"/0", nil)
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- }
 
- func TestGetQuotaScansMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodGet, quotaScanPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- }
 
- func TestStartQuotaScanMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	user := getTestUser()
 
- 	userAsJSON := getUserAsJSON(t, user)
 
- 	req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	err = render.DecodeJSON(rr.Body, &user)
 
- 	assert.NoError(t, err)
 
- 	_, err = os.Stat(user.HomeDir)
 
- 	if err == nil {
 
- 		err = os.Remove(user.HomeDir)
 
- 		assert.NoError(t, err)
 
- 	}
 
- 	// simulate a duplicate quota scan
 
- 	common.QuotaScans.AddUserQuotaScan(user.Username)
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(quotasBasePath, "users", user.Username, "scan"), nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusConflict, rr)
 
- 	assert.True(t, common.QuotaScans.RemoveUserQuotaScan(user.Username))
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(quotasBasePath, "users", user.Username, "scan"), nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusAccepted, rr)
 
- 	waitForUsersQuotaScan(t, token)
 
- 	_, err = os.Stat(user.HomeDir)
 
- 	if err != nil && os.IsNotExist(err) {
 
- 		err = os.MkdirAll(user.HomeDir, os.ModePerm)
 
- 		assert.NoError(t, err)
 
- 	}
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(quotasBasePath, "users", user.Username, "scan"), nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusAccepted, rr)
 
- 	waitForUsersQuotaScan(t, token)
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(quotasBasePath, "users", user.Username, "scan"), nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusAccepted, rr)
 
- 	waitForUsersQuotaScan(t, token)
 
- 	asJSON, err := json.Marshal(user)
 
- 	assert.NoError(t, err)
 
- 	req, _ = http.NewRequest(http.MethodPost, quotaScanCompatPath, bytes.NewBuffer(asJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusAccepted, rr)
 
- 	waitForUsersQuotaScan(t, token)
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(userPath, user.Username), nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUpdateFolderQuotaUsageMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	mappedPath := filepath.Join(os.TempDir(), "vfolder")
 
- 	folderName := filepath.Base(mappedPath)
 
- 	f := vfs.BaseVirtualFolder{
 
- 		MappedPath: mappedPath,
 
- 		Name:       folderName,
 
- 	}
 
- 	usedQuotaFiles := 1
 
- 	usedQuotaSize := int64(65535)
 
- 	f.UsedQuotaFiles = usedQuotaFiles
 
- 	f.UsedQuotaSize = usedQuotaSize
 
- 	var folder vfs.BaseVirtualFolder
 
- 	folderAsJSON, err := json.Marshal(f)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodPost, folderPath, bytes.NewBuffer(folderAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	err = render.DecodeJSON(rr.Body, &folder)
 
- 	assert.NoError(t, err)
 
- 	req, _ = http.NewRequest(http.MethodPut, path.Join(quotasBasePath, "folders", folder.Name, "usage"), bytes.NewBuffer(folderAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodPut, updateFolderUsedQuotaCompatPath, bytes.NewBuffer(folderAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var folderGet vfs.BaseVirtualFolder
 
- 	req, _ = http.NewRequest(http.MethodGet, path.Join(folderPath, folderName), nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	err = render.DecodeJSON(rr.Body, &folderGet)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, usedQuotaFiles, folderGet.UsedQuotaFiles)
 
- 	assert.Equal(t, usedQuotaSize, folderGet.UsedQuotaSize)
 
- 	// now update only quota size
 
- 	f.UsedQuotaFiles = 0
 
- 	folderAsJSON, err = json.Marshal(f)
 
- 	assert.NoError(t, err)
 
- 	req, _ = http.NewRequest(http.MethodPut, path.Join(quotasBasePath, "folders", folder.Name, "usage")+"?mode=add",
 
- 		bytes.NewBuffer(folderAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	folderGet = vfs.BaseVirtualFolder{}
 
- 	req, _ = http.NewRequest(http.MethodGet, path.Join(folderPath, folderName), nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	err = render.DecodeJSON(rr.Body, &folderGet)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, usedQuotaFiles, folderGet.UsedQuotaFiles)
 
- 	assert.Equal(t, usedQuotaSize*2, folderGet.UsedQuotaSize)
 
- 	// now update only quota files
 
- 	f.UsedQuotaSize = 0
 
- 	f.UsedQuotaFiles = 1
 
- 	folderAsJSON, err = json.Marshal(f)
 
- 	assert.NoError(t, err)
 
- 	req, _ = http.NewRequest(http.MethodPut, path.Join(quotasBasePath, "folders", folder.Name, "usage")+"?mode=add",
 
- 		bytes.NewBuffer(folderAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	folderGet = vfs.BaseVirtualFolder{}
 
- 	req, _ = http.NewRequest(http.MethodGet, path.Join(folderPath, folderName), nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	err = render.DecodeJSON(rr.Body, &folderGet)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, usedQuotaFiles*2, folderGet.UsedQuotaFiles)
 
- 	assert.Equal(t, usedQuotaSize*2, folderGet.UsedQuotaSize)
 
- 	req, _ = http.NewRequest(http.MethodPut, updateFolderUsedQuotaCompatPath, bytes.NewBuffer([]byte("string")))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	req, _ = http.NewRequest(http.MethodPut, path.Join(quotasBasePath, "folders", folder.Name, "usage"),
 
- 		bytes.NewBuffer([]byte("not a json")))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.True(t, common.QuotaScans.AddVFolderQuotaScan(folderName))
 
- 	req, _ = http.NewRequest(http.MethodPut, path.Join(quotasBasePath, "folders", folder.Name, "usage"),
 
- 		bytes.NewBuffer(folderAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusConflict, rr)
 
- 	assert.True(t, common.QuotaScans.RemoveVFolderQuotaScan(folderName))
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(folderPath, folderName), nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- }
 
- func TestStartFolderQuotaScanMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	mappedPath := filepath.Join(os.TempDir(), "vfolder")
 
- 	folderName := filepath.Base(mappedPath)
 
- 	folder := vfs.BaseVirtualFolder{
 
- 		Name:       folderName,
 
- 		MappedPath: mappedPath,
 
- 	}
 
- 	folderAsJSON, err := json.Marshal(folder)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodPost, folderPath, bytes.NewBuffer(folderAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	_, err = os.Stat(mappedPath)
 
- 	if err == nil {
 
- 		err = os.Remove(mappedPath)
 
- 		assert.NoError(t, err)
 
- 	}
 
- 	// simulate a duplicate quota scan
 
- 	common.QuotaScans.AddVFolderQuotaScan(folderName)
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(quotasBasePath, "folders", folder.Name, "scan"), nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusConflict, rr)
 
- 	assert.True(t, common.QuotaScans.RemoveVFolderQuotaScan(folderName))
 
- 	// and now a real quota scan
 
- 	_, err = os.Stat(mappedPath)
 
- 	if err != nil && os.IsNotExist(err) {
 
- 		err = os.MkdirAll(mappedPath, os.ModePerm)
 
- 		assert.NoError(t, err)
 
- 	}
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(quotasBasePath, "folders", folder.Name, "scan"), nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusAccepted, rr)
 
- 	waitForFoldersQuotaScanPath(t, token)
 
- 	asJSON, err := json.Marshal(folder)
 
- 	assert.NoError(t, err)
 
- 	req, _ = http.NewRequest(http.MethodPost, quotaScanVFolderCompatPath, bytes.NewBuffer(asJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusAccepted, rr)
 
- 	waitForFoldersQuotaScanPath(t, token)
 
- 	// cleanup
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(folderPath, folderName), nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	err = os.RemoveAll(folderPath)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(mappedPath)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestStartQuotaScanNonExistentUserMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	user := getTestUser()
 
- 	req, _ := http.NewRequest(http.MethodPost, path.Join(quotasBasePath, "users", user.Username, "scan"), nil)
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- }
 
- func TestStartQuotaScanBadUserMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodPost, quotaScanCompatPath, bytes.NewBuffer([]byte("invalid json")))
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- }
 
- func TestStartQuotaScanBadFolderMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodPost, quotaScanVFolderCompatPath, bytes.NewBuffer([]byte("invalid json")))
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- }
 
- func TestStartQuotaScanNonExistentFolderMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	folder := vfs.BaseVirtualFolder{
 
- 		MappedPath: os.TempDir(),
 
- 		Name:       "afolder",
 
- 	}
 
- 	req, _ := http.NewRequest(http.MethodPost, path.Join(quotasBasePath, "folders", folder.Name, "scan"), nil)
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- }
 
- func TestGetFoldersMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	mappedPath := filepath.Join(os.TempDir(), "vfolder")
 
- 	folderName := filepath.Base(mappedPath)
 
- 	folder := vfs.BaseVirtualFolder{
 
- 		Name:       folderName,
 
- 		MappedPath: mappedPath,
 
- 	}
 
- 	folderAsJSON, err := json.Marshal(folder)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodPost, folderPath, bytes.NewBuffer(folderAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	err = render.DecodeJSON(rr.Body, &folder)
 
- 	assert.NoError(t, err)
 
- 	var folders []vfs.BaseVirtualFolder
 
- 	url, err := url.Parse(folderPath + "?limit=510&offset=0&order=DESC")
 
- 	assert.NoError(t, err)
 
- 	req, _ = http.NewRequest(http.MethodGet, url.String(), nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	err = render.DecodeJSON(rr.Body, &folders)
 
- 	assert.NoError(t, err)
 
- 	assert.GreaterOrEqual(t, len(folders), 1)
 
- 	req, _ = http.NewRequest(http.MethodGet, folderPath+"?limit=a&offset=0&order=ASC", nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, folderPath+"?limit=1&offset=a&order=ASC", nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, folderPath+"?limit=1&offset=0&order=ASCa", nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(folderPath, folderName), nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- }
 
- func TestGetVersionMock(t *testing.T) {
 
- 	req, _ := http.NewRequest(http.MethodGet, versionPath, nil)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusUnauthorized, rr)
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	req, _ = http.NewRequest(http.MethodGet, versionPath, nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, versionPath, nil)
 
- 	setBearerForReq(req, "abcde")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusUnauthorized, rr)
 
- }
 
- func TestGetConnectionsMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodGet, activeConnectionsPath, nil)
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- }
 
- func TestGetStatusMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodGet, serverStatusPath, nil)
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- }
 
- func TestDeleteActiveConnectionMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodDelete, activeConnectionsPath+"/connectionID", nil)
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- }
 
- func TestNotFoundMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodGet, "/non/existing/path", nil)
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- }
 
- func TestMethodNotAllowedMock(t *testing.T) {
 
- 	req, _ := http.NewRequest(http.MethodPost, activeConnectionsPath, nil)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusMethodNotAllowed, rr)
 
- }
 
- func TestHealthCheck(t *testing.T) {
 
- 	req, _ := http.NewRequest(http.MethodGet, "/healthz", nil)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Equal(t, "ok", rr.Body.String())
 
- }
 
- func TestGetWebRootMock(t *testing.T) {
 
- 	req, _ := http.NewRequest(http.MethodGet, "/", nil)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusFound, rr)
 
- 	assert.Equal(t, webClientLoginPath, rr.Header().Get("Location"))
 
- 	req, _ = http.NewRequest(http.MethodGet, webBasePath, nil)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusFound, rr)
 
- 	assert.Equal(t, webClientLoginPath, rr.Header().Get("Location"))
 
- 	req, _ = http.NewRequest(http.MethodGet, webBasePathAdmin, nil)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusFound, rr)
 
- 	assert.Equal(t, webLoginPath, rr.Header().Get("Location"))
 
- 	req, _ = http.NewRequest(http.MethodGet, webBasePathClient, nil)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusFound, rr)
 
- 	assert.Equal(t, webClientLoginPath, rr.Header().Get("Location"))
 
- }
 
- func TestWebNotFoundURI(t *testing.T) {
 
- 	urlString := httpBaseURL + webBasePath + "/a"
 
- 	req, err := http.NewRequest(http.MethodGet, urlString, nil)
 
- 	assert.NoError(t, err)
 
- 	resp, err := httpclient.GetHTTPClient().Do(req)
 
- 	require.NoError(t, err)
 
- 	defer resp.Body.Close()
 
- 	assert.Equal(t, http.StatusNotFound, resp.StatusCode)
 
- 	req, err = http.NewRequest(http.MethodGet, urlString, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, "invalid token")
 
- 	resp, err = httpclient.GetHTTPClient().Do(req)
 
- 	require.NoError(t, err)
 
- 	defer resp.Body.Close()
 
- 	assert.Equal(t, http.StatusNotFound, resp.StatusCode)
 
- 	urlString = httpBaseURL + webBasePathClient + "/a"
 
- 	req, err = http.NewRequest(http.MethodGet, urlString, nil)
 
- 	assert.NoError(t, err)
 
- 	resp, err = httpclient.GetHTTPClient().Do(req)
 
- 	require.NoError(t, err)
 
- 	defer resp.Body.Close()
 
- 	assert.Equal(t, http.StatusNotFound, resp.StatusCode)
 
- 	req, err = http.NewRequest(http.MethodGet, urlString, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, "invalid client token")
 
- 	resp, err = httpclient.GetHTTPClient().Do(req)
 
- 	require.NoError(t, err)
 
- 	defer resp.Body.Close()
 
- 	assert.Equal(t, http.StatusNotFound, resp.StatusCode)
 
- }
 
- func TestLogout(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodGet, serverStatusPath, nil)
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, logoutPath, nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, serverStatusPath, nil)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusUnauthorized, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Your token is no longer valid")
 
- }
 
- func TestDefenderAPIInvalidIDMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodGet, path.Join(defenderHosts, "abc"), nil) // not hex id
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "invalid host id")
 
- }
 
- func TestTokenHeaderCookie(t *testing.T) {
 
- 	apiToken, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	webToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodGet, serverStatusPath, nil)
 
- 	setJWTCookieForReq(req, apiToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusUnauthorized, rr)
 
- 	assert.Contains(t, rr.Body.String(), "no token found")
 
- 	req, _ = http.NewRequest(http.MethodGet, serverStatusPath, nil)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, webStatusPath, nil)
 
- 	setBearerForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusFound, rr)
 
- 	assert.Equal(t, webLoginPath, rr.Header().Get("Location"))
 
- 	req, _ = http.NewRequest(http.MethodGet, webStatusPath, nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- }
 
- func TestTokenAudience(t *testing.T) {
 
- 	webToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	apiToken, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodGet, serverStatusPath, nil)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, serverStatusPath, nil)
 
- 	setBearerForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusUnauthorized, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Your token audience is not valid")
 
- 	req, _ = http.NewRequest(http.MethodGet, webStatusPath, nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, webStatusPath, nil)
 
- 	setJWTCookieForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusFound, rr)
 
- 	assert.Equal(t, webLoginPath, rr.Header().Get("Location"))
 
- }
 
- func TestWebAPILoginMock(t *testing.T) {
 
- 	_, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.Error(t, err)
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	_, err = getJWTAPIUserTokenFromTestServer(defaultUsername+"1", defaultPassword)
 
- 	assert.Error(t, err)
 
- 	_, err = getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword+"1")
 
- 	assert.Error(t, err)
 
- 	apiToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	webToken, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	// a web token is not valid for API usage
 
- 	req, err := http.NewRequest(http.MethodGet, userDirsPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusUnauthorized, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Your token audience is not valid")
 
- 	req, err = http.NewRequest(http.MethodGet, userDirsPath+"/?path=%2F", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// API token is not valid for web usage
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientProfilePath, nil)
 
- 	setJWTCookieForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusFound, rr)
 
- 	assert.Equal(t, webClientLoginPath, rr.Header().Get("Location"))
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientProfilePath, nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- }
 
- func TestWebClientLoginMock(t *testing.T) {
 
- 	_, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.Error(t, err)
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	webToken, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	// a web token is not valid for API or WebAdmin usage
 
- 	req, _ := http.NewRequest(http.MethodGet, serverStatusPath, nil)
 
- 	setBearerForReq(req, webToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusUnauthorized, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Your token audience is not valid")
 
- 	req, _ = http.NewRequest(http.MethodGet, webStatusPath, nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusFound, rr)
 
- 	assert.Equal(t, webLoginPath, rr.Header().Get("Location"))
 
- 	// bearer should not work
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientProfilePath, nil)
 
- 	setBearerForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusFound, rr)
 
- 	assert.Equal(t, webClientLoginPath, rr.Header().Get("Location"))
 
- 	// now try to render client pages
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientProfilePath, nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientFilesPath, nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// now logout
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientLogoutPath, nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusFound, rr)
 
- 	assert.Equal(t, webClientLoginPath, rr.Header().Get("Location"))
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientProfilePath, nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusFound, rr)
 
- 	assert.Equal(t, webClientLoginPath, rr.Header().Get("Location"))
 
- 	// get a new token and use it after removing the user
 
- 	webToken, err = getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	apiUserToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientProfilePath, nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusInternalServerError, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientFilesPath, nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Unable to retrieve your user")
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientDirsPath, nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Unable to retrieve your user")
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientDownloadZipPath, nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Unable to retrieve your user")
 
- 	req, _ = http.NewRequest(http.MethodGet, userDirsPath, nil)
 
- 	setBearerForReq(req, apiUserToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Unable to retrieve your user")
 
- 	req, _ = http.NewRequest(http.MethodGet, userFilesPath, nil)
 
- 	setBearerForReq(req, apiUserToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Unable to retrieve your user")
 
- 	req, _ = http.NewRequest(http.MethodPost, userStreamZipPath, bytes.NewBuffer([]byte(`{}`)))
 
- 	setBearerForReq(req, apiUserToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Unable to retrieve your user")
 
- 	req, _ = http.NewRequest(http.MethodGet, userPublicKeysPath, nil)
 
- 	setBearerForReq(req, apiUserToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Unable to retrieve your user")
 
- 	req, _ = http.NewRequest(http.MethodPut, userPublicKeysPath, bytes.NewBuffer([]byte(`{}`)))
 
- 	setBearerForReq(req, apiUserToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Unable to retrieve your user")
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webClientLoginPath)
 
- 	assert.NoError(t, err)
 
- 	form := make(url.Values)
 
- 	form.Set("public_keys", testPubKey)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	req, _ = http.NewRequest(http.MethodPost, webClientProfilePath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusInternalServerError, rr)
 
- }
 
- func TestWebClientLoginErrorsMock(t *testing.T) {
 
- 	form := getLoginForm("", "", "")
 
- 	req, _ := http.NewRequest(http.MethodPost, webClientLoginPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr := executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "Invalid credentials")
 
- 	form = getLoginForm(defaultUsername, defaultPassword, "")
 
- 	req, _ = http.NewRequest(http.MethodPost, webClientLoginPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "unable to verify form token")
 
- }
 
- func TestWebClientMaxConnections(t *testing.T) {
 
- 	oldValue := common.Config.MaxTotalConnections
 
- 	common.Config.MaxTotalConnections = 1
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	webToken, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodGet, webClientFilesPath, nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// now add a fake connection
 
- 	fs := vfs.NewOsFs("id", os.TempDir(), "")
 
- 	connection := &httpd.Connection{
 
- 		BaseConnection: common.NewBaseConnection(fs.ConnectionID(), common.ProtocolHTTP, "", "", user),
 
- 	}
 
- 	common.Connections.Add(connection)
 
- 	_, err = getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.Error(t, err)
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientFilesPath, nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "configured connections limit reached")
 
- 	common.Connections.Remove(connection.GetID())
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, common.Connections.GetStats(), 0)
 
- 	common.Config.MaxTotalConnections = oldValue
 
- }
 
- func TestDefender(t *testing.T) {
 
- 	oldConfig := config.GetCommonConfig()
 
- 	cfg := config.GetCommonConfig()
 
- 	cfg.DefenderConfig.Enabled = true
 
- 	cfg.DefenderConfig.Threshold = 3
 
- 	cfg.DefenderConfig.ScoreLimitExceeded = 2
 
- 	err := common.Initialize(cfg, 0)
 
- 	assert.NoError(t, err)
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	remoteAddr := "172.16.5.6:9876"
 
- 	webAdminToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	webToken, err := getJWTWebClientTokenFromTestServerWithAddr(defaultUsername, defaultPassword, remoteAddr)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodGet, webClientFilesPath, nil)
 
- 	req.RemoteAddr = remoteAddr
 
- 	req.RequestURI = webClientFilesPath
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	for i := 0; i < 3; i++ {
 
- 		_, err = getJWTWebClientTokenFromTestServerWithAddr(defaultUsername, "wrong pwd", remoteAddr)
 
- 		assert.Error(t, err)
 
- 	}
 
- 	_, err = getJWTWebClientTokenFromTestServerWithAddr(defaultUsername, defaultPassword, remoteAddr)
 
- 	assert.Error(t, err)
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientFilesPath, nil)
 
- 	req.RemoteAddr = remoteAddr
 
- 	req.RequestURI = webClientFilesPath
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "your IP address is banned")
 
- 	req, _ = http.NewRequest(http.MethodGet, webUsersPath, nil)
 
- 	req.RemoteAddr = remoteAddr
 
- 	req.RequestURI = webUsersPath
 
- 	setJWTCookieForReq(req, webAdminToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "your IP address is banned")
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientFilesPath, nil)
 
- 	req.RemoteAddr = remoteAddr
 
- 	req.Header.Set("X-Real-IP", "127.0.0.1:2345")
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "your IP address is banned")
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- 	err = common.Initialize(oldConfig, 0)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestPostConnectHook(t *testing.T) {
 
- 	if runtime.GOOS == osWindows {
 
- 		t.Skip("this test is not available on Windows")
 
- 	}
 
- 	common.Config.PostConnectHook = postConnectPath
 
- 	u := getTestUser()
 
- 	u.Filters.AllowAPIKeyAuth = true
 
- 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	apiKey, _, err := httpdtest.AddAPIKey(dataprovider.APIKey{
 
- 		Name:  "name",
 
- 		Scope: dataprovider.APIKeyScopeUser,
 
- 		User:  user.Username,
 
- 	}, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	err = os.WriteFile(postConnectPath, getExitCodeScriptContent(0), os.ModePerm)
 
- 	assert.NoError(t, err)
 
- 	_, err = getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	_, err = getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodGet, userDirsPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, apiKey.Key, "")
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	err = os.WriteFile(postConnectPath, getExitCodeScriptContent(1), os.ModePerm)
 
- 	assert.NoError(t, err)
 
- 	_, err = getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.Error(t, err)
 
- 	_, err = getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.Error(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, userDirsPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, apiKey.Key, "")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusUnauthorized, rr)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- 	common.Config.PostConnectHook = ""
 
- }
 
- func TestMaxSessions(t *testing.T) {
 
- 	u := getTestUser()
 
- 	u.MaxSessions = 1
 
- 	u.Email = "[email protected]"
 
- 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	_, err = getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	_, err = getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	// now add a fake connection
 
- 	fs := vfs.NewOsFs("id", os.TempDir(), "")
 
- 	connection := &httpd.Connection{
 
- 		BaseConnection: common.NewBaseConnection(fs.ConnectionID(), common.ProtocolHTTP, "", "", user),
 
- 	}
 
- 	common.Connections.Add(connection)
 
- 	_, err = getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.Error(t, err)
 
- 	_, err = getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.Error(t, err)
 
- 	// test reset password
 
- 	smtpCfg := smtp.Config{
 
- 		Host:          "127.0.0.1",
 
- 		Port:          3525,
 
- 		TemplatesPath: "templates",
 
- 	}
 
- 	err = smtpCfg.Initialize("..")
 
- 	assert.NoError(t, err)
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath)
 
- 	assert.NoError(t, err)
 
- 	form := make(url.Values)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	form.Set("username", user.Username)
 
- 	lastResetCode = ""
 
- 	req, err := http.NewRequest(http.MethodPost, webClientForgotPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr := executeRequest(req)
 
- 	assert.Equal(t, http.StatusFound, rr.Code)
 
- 	assert.GreaterOrEqual(t, len(lastResetCode), 20)
 
- 	form = make(url.Values)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	form.Set("password", defaultPassword)
 
- 	form.Set("code", lastResetCode)
 
- 	req, err = http.NewRequest(http.MethodPost, webClientResetPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "Password reset successfully but unable to login")
 
- 	smtpCfg = smtp.Config{}
 
- 	err = smtpCfg.Initialize("..")
 
- 	require.NoError(t, err)
 
- 	common.Connections.Remove(connection.GetID())
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, common.Connections.GetStats(), 0)
 
- }
 
- func TestSFTPLoopError(t *testing.T) {
 
- 	user1 := getTestUser()
 
- 	user2 := getTestUser()
 
- 	user1.Username += "1"
 
- 	user1.Email = "[email protected]"
 
- 	user2.Username += "2"
 
- 	user1.FsConfig = vfs.Filesystem{
 
- 		Provider: sdk.SFTPFilesystemProvider,
 
- 		SFTPConfig: vfs.SFTPFsConfig{
 
- 			BaseSFTPFsConfig: sdk.BaseSFTPFsConfig{
 
- 				Endpoint: sftpServerAddr,
 
- 				Username: user2.Username,
 
- 			},
 
- 			Password: kms.NewPlainSecret(defaultPassword),
 
- 		},
 
- 	}
 
- 	user2.FsConfig.Provider = sdk.SFTPFilesystemProvider
 
- 	user2.FsConfig.SFTPConfig = vfs.SFTPFsConfig{
 
- 		BaseSFTPFsConfig: sdk.BaseSFTPFsConfig{
 
- 			Endpoint: sftpServerAddr,
 
- 			Username: user1.Username,
 
- 		},
 
- 		Password: kms.NewPlainSecret(defaultPassword),
 
- 	}
 
- 	user1, resp, err := httpdtest.AddUser(user1, http.StatusCreated)
 
- 	assert.NoError(t, err, string(resp))
 
- 	user2, resp, err = httpdtest.AddUser(user2, http.StatusCreated)
 
- 	assert.NoError(t, err, string(resp))
 
- 	// test reset password
 
- 	smtpCfg := smtp.Config{
 
- 		Host:          "127.0.0.1",
 
- 		Port:          3525,
 
- 		TemplatesPath: "templates",
 
- 	}
 
- 	err = smtpCfg.Initialize("..")
 
- 	assert.NoError(t, err)
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath)
 
- 	assert.NoError(t, err)
 
- 	form := make(url.Values)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	form.Set("username", user1.Username)
 
- 	lastResetCode = ""
 
- 	req, err := http.NewRequest(http.MethodPost, webClientForgotPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr := executeRequest(req)
 
- 	assert.Equal(t, http.StatusFound, rr.Code)
 
- 	assert.GreaterOrEqual(t, len(lastResetCode), 20)
 
- 	form = make(url.Values)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	form.Set("password", defaultPassword)
 
- 	form.Set("code", lastResetCode)
 
- 	req, err = http.NewRequest(http.MethodPost, webClientResetPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "Password reset successfully but unable to login")
 
- 	smtpCfg = smtp.Config{}
 
- 	err = smtpCfg.Initialize("..")
 
- 	require.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(user1, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user1.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(user2, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user2.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- }
 
- func TestLoginInvalidFs(t *testing.T) {
 
- 	u := getTestUser()
 
- 	u.Filters.AllowAPIKeyAuth = true
 
- 	u.FsConfig.Provider = sdk.GCSFilesystemProvider
 
- 	u.FsConfig.GCSConfig.Bucket = "test"
 
- 	u.FsConfig.GCSConfig.Credentials = kms.NewPlainSecret("invalid JSON for credentials")
 
- 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	apiKey, _, err := httpdtest.AddAPIKey(dataprovider.APIKey{
 
- 		Name:  "testk",
 
- 		Scope: dataprovider.APIKeyScopeUser,
 
- 		User:  u.Username,
 
- 	}, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	credentialsFile := filepath.Join(credentialsPath, fmt.Sprintf("%v_gcs_credentials.json", u.Username))
 
- 	if !filepath.IsAbs(credentialsFile) {
 
- 		credentialsFile = filepath.Join(configDir, credentialsFile)
 
- 	}
 
- 	// now remove the credentials file so the filesystem creation will fail
 
- 	err = os.Remove(credentialsFile)
 
- 	assert.NoError(t, err)
 
- 	_, err = getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.Error(t, err)
 
- 	_, err = getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.Error(t, err)
 
- 	req, err := http.NewRequest(http.MethodGet, userDirsPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, apiKey.Key, "")
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusInternalServerError, rr)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- }
 
- func TestWebClientChangePwd(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	webToken, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webClientLoginPath)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodGet, webChangeClientPwdPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	form := make(url.Values)
 
- 	form.Set("current_password", defaultPassword)
 
- 	form.Set("new_password1", defaultPassword)
 
- 	form.Set("new_password2", defaultPassword)
 
- 	// no csrf token
 
- 	req, err = http.NewRequest(http.MethodPost, webChangeClientPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "unable to verify form token")
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	req, _ = http.NewRequest(http.MethodPost, webChangeClientPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "the new password must be different from the current one")
 
- 	form.Set("current_password", defaultPassword+"2")
 
- 	form.Set("new_password1", defaultPassword+"1")
 
- 	form.Set("new_password2", defaultPassword+"1")
 
- 	req, _ = http.NewRequest(http.MethodPost, webChangeClientPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "current password does not match")
 
- 	form.Set("current_password", defaultPassword)
 
- 	form.Set("new_password1", defaultPassword+"1")
 
- 	form.Set("new_password2", defaultPassword+"1")
 
- 	req, _ = http.NewRequest(http.MethodPost, webChangeClientPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusFound, rr)
 
- 	assert.Equal(t, webClientLoginPath, rr.Header().Get("Location"))
 
- 	_, err = getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.Error(t, err)
 
- 	_, err = getJWTWebClientTokenFromTestServer(defaultUsername+"1", defaultPassword+"1")
 
- 	assert.Error(t, err)
 
- 	_, err = getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword+"1")
 
- 	assert.NoError(t, err)
 
- 	// remove the change password permission
 
- 	user.Filters.WebClient = []string{sdk.WebClientPasswordChangeDisabled}
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, user.Filters.WebClient, 1)
 
- 	assert.Contains(t, user.Filters.WebClient, sdk.WebClientPasswordChangeDisabled)
 
- 	webToken, err = getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword+"1")
 
- 	assert.NoError(t, err)
 
- 	form.Set("current_password", defaultPassword+"1")
 
- 	form.Set("new_password1", defaultPassword)
 
- 	form.Set("new_password2", defaultPassword)
 
- 	req, _ = http.NewRequest(http.MethodPost, webChangeClientPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- }
 
- func TestWebAPIPublicKeys(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	apiToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodGet, userPublicKeysPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var keys []string
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &keys)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, keys, 0)
 
- 	keys = []string{testPubKey, testPubKey1}
 
- 	asJSON, err := json.Marshal(keys)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPut, userPublicKeysPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, userPublicKeysPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	keys = nil
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &keys)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, keys, 2)
 
- 	req, err = http.NewRequest(http.MethodPut, userPublicKeysPath, bytes.NewBuffer([]byte(`invalid json`)))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	keys = []string{`not a public key`}
 
- 	asJSON, err = json.Marshal(keys)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPut, userPublicKeysPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "could not parse key")
 
- 	user.Filters.WebClient = append(user.Filters.WebClient, sdk.WebClientPubKeyChangeDisabled)
 
- 	_, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	apiToken, err = getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, userPublicKeysPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- }
 
- func TestPreDownloadHook(t *testing.T) {
 
- 	if runtime.GOOS == osWindows {
 
- 		t.Skip("this test is not available on Windows")
 
- 	}
 
- 	oldExecuteOn := common.Config.Actions.ExecuteOn
 
- 	oldHook := common.Config.Actions.Hook
 
- 	common.Config.Actions.ExecuteOn = []string{common.OperationPreDownload}
 
- 	common.Config.Actions.Hook = preActionPath
 
- 	u := getTestUser()
 
- 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	err = os.WriteFile(preActionPath, getExitCodeScriptContent(0), os.ModePerm)
 
- 	assert.NoError(t, err)
 
- 	testFileName := "testfile"
 
- 	testFileContents := []byte("file contents")
 
- 	err = os.MkdirAll(filepath.Join(user.GetHomeDir()), os.ModePerm)
 
- 	assert.NoError(t, err)
 
- 	err = os.WriteFile(filepath.Join(user.GetHomeDir(), testFileName), testFileContents, os.ModePerm)
 
- 	assert.NoError(t, err)
 
- 	webToken, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	webAPIToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodGet, webClientFilesPath+"?path="+testFileName, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Equal(t, testFileContents, rr.Body.Bytes())
 
- 	req, err = http.NewRequest(http.MethodGet, userFilesPath+"?path="+testFileName, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Equal(t, testFileContents, rr.Body.Bytes())
 
- 	err = os.WriteFile(preActionPath, getExitCodeScriptContent(1), os.ModePerm)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, webClientFilesPath+"?path="+testFileName, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "permission denied")
 
- 	req, err = http.NewRequest(http.MethodGet, userFilesPath+"?path="+testFileName, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "permission denied")
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- 	common.Config.Actions.ExecuteOn = oldExecuteOn
 
- 	common.Config.Actions.Hook = oldHook
 
- }
 
- func TestPreUploadHook(t *testing.T) {
 
- 	if runtime.GOOS == osWindows {
 
- 		t.Skip("this test is not available on Windows")
 
- 	}
 
- 	oldExecuteOn := common.Config.Actions.ExecuteOn
 
- 	oldHook := common.Config.Actions.Hook
 
- 	common.Config.Actions.ExecuteOn = []string{common.OperationPreUpload}
 
- 	common.Config.Actions.Hook = preActionPath
 
- 	u := getTestUser()
 
- 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	err = os.WriteFile(preActionPath, getExitCodeScriptContent(0), os.ModePerm)
 
- 	assert.NoError(t, err)
 
- 	webAPIToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	body := new(bytes.Buffer)
 
- 	writer := multipart.NewWriter(body)
 
- 	part, err := writer.CreateFormFile("filenames", "filepre")
 
- 	assert.NoError(t, err)
 
- 	_, err = part.Write([]byte("file content"))
 
- 	assert.NoError(t, err)
 
- 	err = writer.Close()
 
- 	assert.NoError(t, err)
 
- 	reader := bytes.NewReader(body.Bytes())
 
- 	_, err = reader.Seek(0, io.SeekStart)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodPost, userFilesPath, reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	req, err = http.NewRequest(http.MethodPost, userUploadFilePath+"?path=filepre",
 
- 		bytes.NewBuffer([]byte("single upload content")))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	err = os.WriteFile(preActionPath, getExitCodeScriptContent(1), os.ModePerm)
 
- 	assert.NoError(t, err)
 
- 	_, err = reader.Seek(0, io.SeekStart)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userFilesPath, reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	req, err = http.NewRequest(http.MethodPost, userUploadFilePath+"?path=filepre",
 
- 		bytes.NewBuffer([]byte("single upload content")))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- 	common.Config.Actions.ExecuteOn = oldExecuteOn
 
- 	common.Config.Actions.Hook = oldHook
 
- }
 
- func TestShareUsage(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	testFileName := "testfile.dat"
 
- 	testFileSize := int64(65536)
 
- 	testFilePath := filepath.Join(user.GetHomeDir(), testFileName)
 
- 	err = createTestFile(testFilePath, testFileSize)
 
- 	assert.NoError(t, err)
 
- 	token, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	share := dataprovider.Share{
 
- 		Name:      "test share",
 
- 		Scope:     dataprovider.ShareScopeRead,
 
- 		Paths:     []string{"/"},
 
- 		Password:  defaultPassword,
 
- 		MaxTokens: 2,
 
- 		ExpiresAt: util.GetTimeAsMsSinceEpoch(time.Now().Add(1 * time.Second)),
 
- 	}
 
- 	asJSON, err := json.Marshal(share)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	objectID := rr.Header().Get("X-Object-ID")
 
- 	assert.NotEmpty(t, objectID)
 
- 	req, err = http.NewRequest(http.MethodGet, sharesPath+"/unknownid", nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, sharesPath+"/"+objectID, nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusUnauthorized, rr)
 
- 	req.SetBasicAuth(defaultUsername, "wrong password")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusUnauthorized, rr)
 
- 	req.SetBasicAuth(defaultUsername, defaultPassword)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	time.Sleep(2 * time.Second)
 
- 	req, err = http.NewRequest(http.MethodGet, webClientPubSharesPath+"/"+objectID, nil)
 
- 	assert.NoError(t, err)
 
- 	req.SetBasicAuth(defaultUsername, defaultPassword)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	share.ExpiresAt = 0
 
- 	jsonReq := make(map[string]interface{})
 
- 	jsonReq["name"] = share.Name
 
- 	jsonReq["scope"] = share.Scope
 
- 	jsonReq["paths"] = share.Paths
 
- 	jsonReq["password"] = share.Password
 
- 	jsonReq["max_tokens"] = share.MaxTokens
 
- 	jsonReq["expires_at"] = share.ExpiresAt
 
- 	asJSON, err = json.Marshal(jsonReq)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPut, userSharesPath+"/"+objectID, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, webClientPubSharesPath+"/"+objectID, nil)
 
- 	assert.NoError(t, err)
 
- 	req.SetBasicAuth(defaultUsername, defaultPassword)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodPost, sharesPath+"/"+objectID, nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Invalid share scope")
 
- 	share.MaxTokens = 3
 
- 	share.Scope = dataprovider.ShareScopeWrite
 
- 	asJSON, err = json.Marshal(share)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPut, userSharesPath+"/"+objectID, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	body := new(bytes.Buffer)
 
- 	writer := multipart.NewWriter(body)
 
- 	part1, err := writer.CreateFormFile("filenames", "file1.txt")
 
- 	assert.NoError(t, err)
 
- 	_, err = part1.Write([]byte("file1 content"))
 
- 	assert.NoError(t, err)
 
- 	part2, err := writer.CreateFormFile("filenames", "file2.txt")
 
- 	assert.NoError(t, err)
 
- 	_, err = part2.Write([]byte("file2 content"))
 
- 	assert.NoError(t, err)
 
- 	err = writer.Close()
 
- 	assert.NoError(t, err)
 
- 	reader := bytes.NewReader(body.Bytes())
 
- 	req, err = http.NewRequest(http.MethodPost, sharesPath+"/"+objectID, reader)
 
- 	assert.NoError(t, err)
 
- 	req.SetBasicAuth(defaultUsername, defaultPassword)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Unable to parse multipart form")
 
- 	_, err = reader.Seek(0, io.SeekStart)
 
- 	assert.NoError(t, err)
 
- 	// set the proper content type
 
- 	req, err = http.NewRequest(http.MethodPost, sharesPath+"/"+objectID, reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	req.SetBasicAuth(defaultUsername, defaultPassword)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Allowed usage exceeded")
 
- 	share.MaxTokens = 6
 
- 	share.Scope = dataprovider.ShareScopeWrite
 
- 	asJSON, err = json.Marshal(share)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPut, userSharesPath+"/"+objectID, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	_, err = reader.Seek(0, io.SeekStart)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, sharesPath+"/"+objectID, reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	req.SetBasicAuth(defaultUsername, defaultPassword)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	_, err = reader.Seek(0, io.SeekStart)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, webClientPubSharesPath+"/"+objectID, reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	req.SetBasicAuth(defaultUsername, defaultPassword)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	share, err = dataprovider.ShareExists(objectID, user.Username)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, 6, share.UsedTokens)
 
- 	_, err = reader.Seek(0, io.SeekStart)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, sharesPath+"/"+objectID, reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	req.SetBasicAuth(defaultUsername, defaultPassword)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	share.MaxTokens = 0
 
- 	err = dataprovider.UpdateShare(&share, user.Username, "")
 
- 	assert.NoError(t, err)
 
- 	user.Permissions["/"] = []string{dataprovider.PermListItems, dataprovider.PermDownload}
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	_, err = reader.Seek(0, io.SeekStart)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, sharesPath+"/"+objectID, reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	req.SetBasicAuth(defaultUsername, defaultPassword)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "permission denied")
 
- 	body = new(bytes.Buffer)
 
- 	writer = multipart.NewWriter(body)
 
- 	part, err := writer.CreateFormFile("filename", "file1.txt")
 
- 	assert.NoError(t, err)
 
- 	_, err = part.Write([]byte("file content"))
 
- 	assert.NoError(t, err)
 
- 	err = writer.Close()
 
- 	assert.NoError(t, err)
 
- 	reader = bytes.NewReader(body.Bytes())
 
- 	req, err = http.NewRequest(http.MethodPost, sharesPath+"/"+objectID, reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	req.SetBasicAuth(defaultUsername, defaultPassword)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "No files uploaded!")
 
- 	share.Scope = dataprovider.ShareScopeRead
 
- 	share.Paths = []string{"/missing"}
 
- 	err = dataprovider.UpdateShare(&share, user.Username, "")
 
- 	assert.NoError(t, err)
 
- 	defer func() {
 
- 		rcv := recover()
 
- 		assert.Equal(t, http.ErrAbortHandler, rcv)
 
- 		share, err = dataprovider.ShareExists(objectID, user.Username)
 
- 		assert.NoError(t, err)
 
- 		assert.Equal(t, 6, share.UsedTokens)
 
- 		_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 		assert.NoError(t, err)
 
- 		err = os.RemoveAll(user.GetHomeDir())
 
- 		assert.NoError(t, err)
 
- 	}()
 
- 	req, err = http.NewRequest(http.MethodGet, sharesPath+"/"+objectID, nil)
 
- 	assert.NoError(t, err)
 
- 	req.SetBasicAuth(defaultUsername, defaultPassword)
 
- 	executeRequest(req)
 
- }
 
- func TestShareUploadSingle(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	token, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	share := dataprovider.Share{
 
- 		Name:      "test share",
 
- 		Scope:     dataprovider.ShareScopeWrite,
 
- 		Paths:     []string{"/"},
 
- 		Password:  defaultPassword,
 
- 		MaxTokens: 0,
 
- 	}
 
- 	asJSON, err := json.Marshal(share)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	objectID := rr.Header().Get("X-Object-ID")
 
- 	assert.NotEmpty(t, objectID)
 
- 	content := []byte("shared file content")
 
- 	modTime := time.Now().Add(-12 * time.Hour)
 
- 	req, err = http.NewRequest(http.MethodPost, path.Join(sharesPath, objectID, "file.txt"), bytes.NewBuffer(content))
 
- 	assert.NoError(t, err)
 
- 	req.SetBasicAuth(defaultUsername, defaultPassword)
 
- 	req.Header.Set("X-SFTPGO-MTIME", strconv.FormatInt(util.GetTimeAsMsSinceEpoch(modTime), 10))
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	info, err := os.Stat(filepath.Join(user.GetHomeDir(), "file.txt"))
 
- 	if assert.NoError(t, err) {
 
- 		assert.InDelta(t, util.GetTimeAsMsSinceEpoch(modTime), util.GetTimeAsMsSinceEpoch(info.ModTime()), float64(1000))
 
- 	}
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(webClientPubSharesPath, objectID, "upload"), nil)
 
- 	assert.NoError(t, err)
 
- 	req.SetBasicAuth(defaultUsername, defaultPassword)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, err = http.NewRequest(http.MethodPost, path.Join(webClientPubSharesPath, objectID, "file.txt"), bytes.NewBuffer(content))
 
- 	assert.NoError(t, err)
 
- 	req.SetBasicAuth(defaultUsername, defaultPassword)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	info, err = os.Stat(filepath.Join(user.GetHomeDir(), "file.txt"))
 
- 	if assert.NoError(t, err) {
 
- 		assert.InDelta(t, util.GetTimeAsMsSinceEpoch(time.Now()), util.GetTimeAsMsSinceEpoch(info.ModTime()), float64(3000))
 
- 	}
 
- 	// we don't allow to create the file in subdirectories
 
- 	req, err = http.NewRequest(http.MethodPost, path.Join(sharesPath, objectID, "%2Fdir%2Ffile1.txt"), bytes.NewBuffer(content))
 
- 	assert.NoError(t, err)
 
- 	req.SetBasicAuth(defaultUsername, defaultPassword)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	req, err = http.NewRequest(http.MethodPost, path.Join(sharesPath, objectID, "dir", "file.dat"), bytes.NewBuffer(content))
 
- 	assert.NoError(t, err)
 
- 	req.SetBasicAuth(defaultUsername, defaultPassword)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodPost, path.Join(sharesPath, objectID, "%2F"), bytes.NewBuffer(content))
 
- 	assert.NoError(t, err)
 
- 	req.SetBasicAuth(defaultUsername, defaultPassword)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	err = os.MkdirAll(filepath.Join(user.GetHomeDir(), "dir"), os.ModePerm)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, path.Join(sharesPath, objectID, "dir"), bytes.NewBuffer(content))
 
- 	assert.NoError(t, err)
 
- 	req.SetBasicAuth(defaultUsername, defaultPassword)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "operation unsupported")
 
- 	share, err = dataprovider.ShareExists(objectID, user.Username)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, 2, share.UsedTokens)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, path.Join(sharesPath, objectID, "file1.txt"), bytes.NewBuffer(content))
 
- 	assert.NoError(t, err)
 
- 	req.SetBasicAuth(defaultUsername, defaultPassword)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- }
 
- func TestShareUncompressed(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	testFileName := "testfile.dat"
 
- 	testFileSize := int64(65536)
 
- 	testFilePath := filepath.Join(user.GetHomeDir(), testFileName)
 
- 	err = createTestFile(testFilePath, testFileSize)
 
- 	assert.NoError(t, err)
 
- 	token, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	share := dataprovider.Share{
 
- 		Name:      "test share",
 
- 		Scope:     dataprovider.ShareScopeRead,
 
- 		Paths:     []string{"/"},
 
- 		Password:  defaultPassword,
 
- 		MaxTokens: 0,
 
- 	}
 
- 	asJSON, err := json.Marshal(share)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	objectID := rr.Header().Get("X-Object-ID")
 
- 	assert.NotEmpty(t, objectID)
 
- 	req, err = http.NewRequest(http.MethodGet, webClientPubSharesPath+"/"+objectID, nil)
 
- 	assert.NoError(t, err)
 
- 	req.SetBasicAuth(defaultUsername, defaultPassword)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Equal(t, "application/zip", rr.Header().Get("Content-Type"))
 
- 	req, err = http.NewRequest(http.MethodGet, webClientPubSharesPath+"/"+objectID+"?compress=false", nil)
 
- 	assert.NoError(t, err)
 
- 	req.SetBasicAuth(defaultUsername, defaultPassword)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Equal(t, "application/zip", rr.Header().Get("Content-Type"))
 
- 	share = dataprovider.Share{
 
- 		Name:      "test share1",
 
- 		Scope:     dataprovider.ShareScopeRead,
 
- 		Paths:     []string{testFileName},
 
- 		Password:  defaultPassword,
 
- 		MaxTokens: 0,
 
- 	}
 
- 	asJSON, err = json.Marshal(share)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	objectID = rr.Header().Get("X-Object-ID")
 
- 	assert.NotEmpty(t, objectID)
 
- 	req, err = http.NewRequest(http.MethodGet, webClientPubSharesPath+"/"+objectID, nil)
 
- 	assert.NoError(t, err)
 
- 	req.SetBasicAuth(defaultUsername, defaultPassword)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Equal(t, "application/zip", rr.Header().Get("Content-Type"))
 
- 	req, err = http.NewRequest(http.MethodGet, webClientPubSharesPath+"/"+objectID+"?compress=false", nil)
 
- 	assert.NoError(t, err)
 
- 	req.SetBasicAuth(defaultUsername, defaultPassword)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Equal(t, "application/octet-stream", rr.Header().Get("Content-Type"))
 
- 	share, err = dataprovider.ShareExists(objectID, user.Username)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, 2, share.UsedTokens)
 
- 	user.Permissions["/"] = []string{dataprovider.PermListItems, dataprovider.PermUpload}
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, webClientPubSharesPath+"/"+objectID+"?compress=false", nil)
 
- 	assert.NoError(t, err)
 
- 	req.SetBasicAuth(defaultUsername, defaultPassword)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	share, err = dataprovider.ShareExists(objectID, user.Username)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, 2, share.UsedTokens)
 
- 	user.Permissions["/"] = []string{dataprovider.PermAny}
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	err = os.Remove(testFilePath)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, webClientPubSharesPath+"/"+objectID+"?compress=false", nil)
 
- 	assert.NoError(t, err)
 
- 	req.SetBasicAuth(defaultUsername, defaultPassword)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- }
 
- func TestDownloadFromShareError(t *testing.T) {
 
- 	u := getTestUser()
 
- 	u.DownloadDataTransfer = 1
 
- 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	user.UsedDownloadDataTransfer = 1024*1024 - 32768
 
- 	_, err = httpdtest.UpdateTransferQuotaUsage(user, "add", http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, int64(1024*1024-32768), user.UsedDownloadDataTransfer)
 
- 	testFileName := "test_share_file.dat"
 
- 	testFileSize := int64(524288)
 
- 	testFilePath := filepath.Join(user.GetHomeDir(), testFileName)
 
- 	err = createTestFile(testFilePath, testFileSize)
 
- 	assert.NoError(t, err)
 
- 	token, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	share := dataprovider.Share{
 
- 		Name:      "test share root browse",
 
- 		Scope:     dataprovider.ShareScopeRead,
 
- 		Paths:     []string{"/"},
 
- 		MaxTokens: 2,
 
- 	}
 
- 	asJSON, err := json.Marshal(share)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	objectID := rr.Header().Get("X-Object-ID")
 
- 	assert.NotEmpty(t, objectID)
 
- 	defer func() {
 
- 		rcv := recover()
 
- 		assert.Equal(t, http.ErrAbortHandler, rcv)
 
- 		share, err = dataprovider.ShareExists(objectID, user.Username)
 
- 		assert.NoError(t, err)
 
- 		assert.Equal(t, 0, share.UsedTokens)
 
- 		_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 		assert.NoError(t, err)
 
- 		err = os.RemoveAll(user.GetHomeDir())
 
- 		assert.NoError(t, err)
 
- 	}()
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(webClientPubSharesPath, objectID, "browse?path="+testFileName), nil)
 
- 	assert.NoError(t, err)
 
- 	executeRequest(req)
 
- }
 
- func TestBrowseShares(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	testFileName := "testsharefile.dat"
 
- 	testFileNameLink := "testsharefile.link"
 
- 	shareDir := "share"
 
- 	subDir := "sub"
 
- 	testFileSize := int64(65536)
 
- 	testFilePath := filepath.Join(user.GetHomeDir(), shareDir, testFileName)
 
- 	testLinkPath := filepath.Join(user.GetHomeDir(), shareDir, testFileNameLink)
 
- 	err = createTestFile(testFilePath, testFileSize)
 
- 	assert.NoError(t, err)
 
- 	err = createTestFile(filepath.Join(user.GetHomeDir(), shareDir, subDir, testFileName), testFileSize)
 
- 	assert.NoError(t, err)
 
- 	err = os.Symlink(testFilePath, testLinkPath)
 
- 	assert.NoError(t, err)
 
- 	token, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	share := dataprovider.Share{
 
- 		Name:      "test share browse",
 
- 		Scope:     dataprovider.ShareScopeRead,
 
- 		Paths:     []string{shareDir},
 
- 		MaxTokens: 0,
 
- 	}
 
- 	asJSON, err := json.Marshal(share)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	objectID := rr.Header().Get("X-Object-ID")
 
- 	assert.NotEmpty(t, objectID)
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(webClientPubSharesPath, objectID, "upload"), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Invalid share scope")
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(webClientPubSharesPath, objectID, "browse?path=%2F"), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(sharesPath, objectID, "files?path=%2F"), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Please set the path to a valid file")
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(webClientPubSharesPath, objectID, "dirs?path=%2F"), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	contents := make([]map[string]interface{}, 0)
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &contents)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, contents, 2)
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(sharesPath, objectID, "dirs?path=%2F"), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	contents = make([]map[string]interface{}, 0)
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &contents)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, contents, 2)
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(sharesPath, objectID, "dirs?path=%2F"+subDir), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	contents = make([]map[string]interface{}, 0)
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &contents)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, contents, 1)
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(webClientPubSharesPath, objectID, "browse?path=%2F.."), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Invalid share path")
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(webClientPubSharesPath, objectID, "dirs?path=%2F.."), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(sharesPath, objectID, "dirs?path=%2F.."), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(sharesPath, objectID, "files?path=%2F..%2F"+testFileName), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(webClientPubSharesPath, objectID, "browse?path="+testFileName), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	contentDisposition := rr.Header().Get("Content-Disposition")
 
- 	assert.NotEmpty(t, contentDisposition)
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(sharesPath, objectID, "files?path="+testFileName), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	contentDisposition = rr.Header().Get("Content-Disposition")
 
- 	assert.NotEmpty(t, contentDisposition)
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(webClientPubSharesPath, objectID, "browse?path="+subDir+"%2F"+testFileName), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	contentDisposition = rr.Header().Get("Content-Disposition")
 
- 	assert.NotEmpty(t, contentDisposition)
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(webClientPubSharesPath, objectID, "browse?path=missing"), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "file does not exist")
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(sharesPath, objectID, "files?path=missing"), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(webClientPubSharesPath, objectID, "dirs?path=missing"), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(sharesPath, objectID, "dirs?path=missing"), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(webClientPubSharesPath, objectID, "browse?path="+testFileNameLink), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "non regular files are not supported for shares")
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(sharesPath, objectID, "files?path="+testFileNameLink), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "non regular files are not supported for shares")
 
- 	// share a symlink
 
- 	share = dataprovider.Share{
 
- 		Name:      "test share browse",
 
- 		Scope:     dataprovider.ShareScopeRead,
 
- 		Paths:     []string{path.Join(shareDir, testFileNameLink)},
 
- 		MaxTokens: 0,
 
- 	}
 
- 	asJSON, err = json.Marshal(share)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	objectID = rr.Header().Get("X-Object-ID")
 
- 	assert.NotEmpty(t, objectID)
 
- 	// uncompressed download should not work
 
- 	req, err = http.NewRequest(http.MethodGet, webClientPubSharesPath+"/"+objectID+"?compress=false", nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Equal(t, "application/zip", rr.Header().Get("Content-Type"))
 
- 	// this share is not browsable, it does not contains a directory
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(sharesPath, objectID, "dirs"), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(sharesPath, objectID, "files?path="+testFileName), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(webClientPubSharesPath, objectID, "dirs?path=%2F"), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "The shared object is not a directory and so it is not browsable")
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(webClientPubSharesPath, objectID, "browse?path=%2F"), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "The shared object is not a directory and so it is not browsable")
 
- 	// now test a missing shareID
 
- 	objectID = "123456"
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(sharesPath, objectID, "dirs"), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(sharesPath, objectID, "files?path="+testFileName), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(webClientPubSharesPath, objectID, "dirs?path=%2F"), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(webClientPubSharesPath, objectID, "browse?path=%2F"), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	// share a missing base path
 
- 	share = dataprovider.Share{
 
- 		Name:      "test share",
 
- 		Scope:     dataprovider.ShareScopeRead,
 
- 		Paths:     []string{path.Join(shareDir, "missingdir")},
 
- 		MaxTokens: 0,
 
- 	}
 
- 	asJSON, err = json.Marshal(share)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	objectID = rr.Header().Get("X-Object-ID")
 
- 	assert.NotEmpty(t, objectID)
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(sharesPath, objectID, "dirs"), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusInternalServerError, rr)
 
- 	assert.Contains(t, rr.Body.String(), "unable to check the share directory")
 
- 	// share multiple paths
 
- 	share = dataprovider.Share{
 
- 		Name:      "test share",
 
- 		Scope:     dataprovider.ShareScopeRead,
 
- 		Paths:     []string{shareDir, "/anotherdir"},
 
- 		MaxTokens: 0,
 
- 	}
 
- 	asJSON, err = json.Marshal(share)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	objectID = rr.Header().Get("X-Object-ID")
 
- 	assert.NotEmpty(t, objectID)
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(webClientPubSharesPath, objectID, "browse?path=%2F"), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "A share with multiple paths is not browsable")
 
- 	// share the root path
 
- 	share = dataprovider.Share{
 
- 		Name:      "test share root",
 
- 		Scope:     dataprovider.ShareScopeRead,
 
- 		Paths:     []string{"/"},
 
- 		MaxTokens: 0,
 
- 	}
 
- 	asJSON, err = json.Marshal(share)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	objectID = rr.Header().Get("X-Object-ID")
 
- 	assert.NotEmpty(t, objectID)
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(webClientPubSharesPath, objectID, "browse?path=%2F"), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(sharesPath, objectID, "dirs?path=%2F"), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	contents = make([]map[string]interface{}, 0)
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &contents)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, contents, 1)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUserAPIShareErrors(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	token, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	share := dataprovider.Share{
 
- 		Scope: 1000,
 
- 	}
 
- 	asJSON, err := json.Marshal(share)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "invalid scope")
 
- 	// invalid json
 
- 	req, err = http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer([]byte("{")))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	share.Scope = dataprovider.ShareScopeWrite
 
- 	asJSON, err = json.Marshal(share)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "at least a shared path is required")
 
- 	share.Paths = []string{"path1", "../path1", "/path2"}
 
- 	asJSON, err = json.Marshal(share)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "the write share scope requires exactly one path")
 
- 	share.Paths = []string{"", ""}
 
- 	asJSON, err = json.Marshal(share)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "at least a shared path is required")
 
- 	share.Paths = []string{"path1", "../path1", "/path1"}
 
- 	share.Password = redactedSecret
 
- 	asJSON, err = json.Marshal(share)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "cannot save a share with a redacted password")
 
- 	share.Password = "newpass"
 
- 	share.AllowFrom = []string{"not valid"}
 
- 	asJSON, err = json.Marshal(share)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "could not parse allow from entry")
 
- 	share.AllowFrom = []string{"127.0.0.1/8"}
 
- 	share.ExpiresAt = util.GetTimeAsMsSinceEpoch(time.Now().Add(-12 * time.Hour))
 
- 	asJSON, err = json.Marshal(share)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "expiration must be in the future")
 
- 	share.ExpiresAt = util.GetTimeAsMsSinceEpoch(time.Now().Add(12 * time.Hour))
 
- 	asJSON, err = json.Marshal(share)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	location := rr.Header().Get("Location")
 
- 	asJSON, err = json.Marshal(share)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPut, location, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "name is mandatory")
 
- 	// invalid json
 
- 	req, err = http.NewRequest(http.MethodPut, location, bytes.NewBuffer([]byte("}")))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, userSharesPath+"?limit=a", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUserAPIShares(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	token, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	u := getTestUser()
 
- 	u.Username = altAdminUsername
 
- 	user1, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	token1, err := getJWTAPIUserTokenFromTestServer(user1.Username, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	// the share username will be set from the claims
 
- 	share := dataprovider.Share{
 
- 		Name:        "share1",
 
- 		Description: "description1",
 
- 		Scope:       dataprovider.ShareScopeRead,
 
- 		Paths:       []string{"/"},
 
- 		CreatedAt:   1,
 
- 		UpdatedAt:   2,
 
- 		LastUseAt:   3,
 
- 		ExpiresAt:   util.GetTimeAsMsSinceEpoch(time.Now().Add(2 * time.Hour)),
 
- 		Password:    defaultPassword,
 
- 		MaxTokens:   10,
 
- 		UsedTokens:  2,
 
- 		AllowFrom:   []string{"192.168.1.0/24"},
 
- 	}
 
- 	asJSON, err := json.Marshal(share)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	location := rr.Header().Get("Location")
 
- 	assert.NotEmpty(t, location)
 
- 	objectID := rr.Header().Get("X-Object-ID")
 
- 	assert.NotEmpty(t, objectID)
 
- 	assert.Equal(t, fmt.Sprintf("%v/%v", userSharesPath, objectID), location)
 
- 	req, err = http.NewRequest(http.MethodGet, location, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var shareGet dataprovider.Share
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &shareGet)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, objectID, shareGet.ShareID)
 
- 	assert.Equal(t, share.Name, shareGet.Name)
 
- 	assert.Equal(t, share.Description, shareGet.Description)
 
- 	assert.Equal(t, share.Scope, shareGet.Scope)
 
- 	assert.Equal(t, share.Paths, shareGet.Paths)
 
- 	assert.Equal(t, int64(0), shareGet.LastUseAt)
 
- 	assert.Greater(t, shareGet.CreatedAt, share.CreatedAt)
 
- 	assert.Greater(t, shareGet.UpdatedAt, share.UpdatedAt)
 
- 	assert.Equal(t, share.ExpiresAt, shareGet.ExpiresAt)
 
- 	assert.Equal(t, share.MaxTokens, shareGet.MaxTokens)
 
- 	assert.Equal(t, 0, shareGet.UsedTokens)
 
- 	assert.Equal(t, share.Paths, shareGet.Paths)
 
- 	assert.Equal(t, redactedSecret, shareGet.Password)
 
- 	req, err = http.NewRequest(http.MethodGet, location, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token1)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	s, err := dataprovider.ShareExists(objectID, defaultUsername)
 
- 	assert.NoError(t, err)
 
- 	match, err := s.CheckCredentials(defaultUsername, defaultPassword)
 
- 	assert.True(t, match)
 
- 	assert.NoError(t, err)
 
- 	match, err = s.CheckCredentials(defaultUsername, defaultPassword+"mod")
 
- 	assert.False(t, match)
 
- 	assert.Error(t, err)
 
- 	match, err = s.CheckCredentials(altAdminUsername, defaultPassword)
 
- 	assert.False(t, match)
 
- 	assert.Error(t, err)
 
- 	shareGet.ExpiresAt = util.GetTimeAsMsSinceEpoch(time.Now().Add(3 * time.Hour))
 
- 	asJSON, err = json.Marshal(shareGet)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPut, location, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	s, err = dataprovider.ShareExists(objectID, defaultUsername)
 
- 	assert.NoError(t, err)
 
- 	match, err = s.CheckCredentials(defaultUsername, defaultPassword)
 
- 	assert.True(t, match)
 
- 	assert.NoError(t, err)
 
- 	match, err = s.CheckCredentials(defaultUsername, defaultPassword+"mod")
 
- 	assert.False(t, match)
 
- 	assert.Error(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, location, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var shareGetNew dataprovider.Share
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &shareGetNew)
 
- 	assert.NoError(t, err)
 
- 	assert.NotEqual(t, shareGet.UpdatedAt, shareGetNew.UpdatedAt)
 
- 	shareGet.UpdatedAt = shareGetNew.UpdatedAt
 
- 	assert.Equal(t, shareGet, shareGetNew)
 
- 	req, err = http.NewRequest(http.MethodGet, userSharesPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var shares []dataprovider.Share
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &shares)
 
- 	assert.NoError(t, err)
 
- 	if assert.Len(t, shares, 1) {
 
- 		assert.Equal(t, shareGetNew, shares[0])
 
- 	}
 
- 	err = dataprovider.UpdateShareLastUse(&shareGetNew, 2)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, location, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	shareGetNew = dataprovider.Share{}
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &shareGetNew)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, 2, shareGetNew.UsedTokens, "share: %v", shareGetNew)
 
- 	assert.Greater(t, shareGetNew.LastUseAt, int64(0), "share: %v", shareGetNew)
 
- 	req, err = http.NewRequest(http.MethodGet, userSharesPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token1)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	shares = nil
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &shares)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, shares, 0)
 
- 	// set an empty password
 
- 	shareGet.Password = ""
 
- 	asJSON, err = json.Marshal(shareGet)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPut, location, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, location, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	shareGetNew = dataprovider.Share{}
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &shareGetNew)
 
- 	assert.NoError(t, err)
 
- 	assert.Empty(t, shareGetNew.Password)
 
- 	req, err = http.NewRequest(http.MethodDelete, location, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	share.Name = ""
 
- 	asJSON, err = json.Marshal(share)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	location = rr.Header().Get("Location")
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- 	// the share should be deleted with the associated user
 
- 	req, err = http.NewRequest(http.MethodGet, location, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodPut, location, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodDelete, location, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	_, err = httpdtest.RemoveUser(user1, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user1.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUsersAPISharesNoPasswordDisabled(t *testing.T) {
 
- 	u := getTestUser()
 
- 	u.Filters.WebClient = []string{sdk.WebClientShareNoPasswordDisabled}
 
- 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	token, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	share := dataprovider.Share{
 
- 		Name:  "s",
 
- 		Scope: dataprovider.ShareScopeRead,
 
- 		Paths: []string{"/"},
 
- 	}
 
- 	asJSON, err := json.Marshal(share)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "You are not authorized to share files/folders without a password")
 
- 	share.Password = defaultPassword
 
- 	asJSON, err = json.Marshal(share)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	location := rr.Header().Get("Location")
 
- 	assert.NotEmpty(t, location)
 
- 	objectID := rr.Header().Get("X-Object-ID")
 
- 	assert.NotEmpty(t, objectID)
 
- 	assert.Equal(t, fmt.Sprintf("%v/%v", userSharesPath, objectID), location)
 
- 	share.Password = ""
 
- 	asJSON, err = json.Marshal(share)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPut, location, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "You are not authorized to share files/folders without a password")
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUserAPIKey(t *testing.T) {
 
- 	u := getTestUser()
 
- 	u.Filters.AllowAPIKeyAuth = true
 
- 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	apiKey := dataprovider.APIKey{
 
- 		Name:  "testkey",
 
- 		User:  user.Username + "1",
 
- 		Scope: dataprovider.APIKeyScopeUser,
 
- 	}
 
- 	_, _, err = httpdtest.AddAPIKey(apiKey, http.StatusBadRequest)
 
- 	assert.NoError(t, err)
 
- 	apiKey.User = user.Username
 
- 	apiKey, _, err = httpdtest.AddAPIKey(apiKey, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	body := new(bytes.Buffer)
 
- 	writer := multipart.NewWriter(body)
 
- 	part, err := writer.CreateFormFile("filenames", "filenametest")
 
- 	assert.NoError(t, err)
 
- 	_, err = part.Write([]byte("test file content"))
 
- 	assert.NoError(t, err)
 
- 	err = writer.Close()
 
- 	assert.NoError(t, err)
 
- 	reader := bytes.NewReader(body.Bytes())
 
- 	_, err = reader.Seek(0, io.SeekStart)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodPost, userFilesPath, reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setAPIKeyForReq(req, apiKey.Key, "")
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, userDirsPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, apiKey.Key, "")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var dirEntries []map[string]interface{}
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &dirEntries)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, dirEntries, 1)
 
- 	user.Status = 0
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, userDirsPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, apiKey.Key, "")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusUnauthorized, rr)
 
- 	user.Status = 1
 
- 	user.Filters.DeniedProtocols = []string{common.ProtocolHTTP}
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, userDirsPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, apiKey.Key, "")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusUnauthorized, rr)
 
- 	user.Filters.DeniedProtocols = []string{common.ProtocolFTP}
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, userDirsPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, apiKey.Key, "")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	apiKeyNew := dataprovider.APIKey{
 
- 		Name:  apiKey.Name,
 
- 		Scope: dataprovider.APIKeyScopeUser,
 
- 	}
 
- 	apiKeyNew, _, err = httpdtest.AddAPIKey(apiKeyNew, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, userDirsPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, apiKeyNew.Key, "")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusUnauthorized, rr)
 
- 	// now associate a user
 
- 	req, err = http.NewRequest(http.MethodGet, userDirsPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, apiKeyNew.Key, user.Username)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// now with a missing user
 
- 	req, err = http.NewRequest(http.MethodGet, userDirsPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, apiKeyNew.Key, user.Username+"1")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusUnauthorized, rr)
 
- 	// empty user and key not associated to any user
 
- 	req, err = http.NewRequest(http.MethodGet, userDirsPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, apiKeyNew.Key, "")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusUnauthorized, rr)
 
- 	apiKeyNew.ExpiresAt = util.GetTimeAsMsSinceEpoch(time.Now().Add(-24 * time.Hour))
 
- 	_, _, err = httpdtest.UpdateAPIKey(apiKeyNew, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	// expired API key
 
- 	req, err = http.NewRequest(http.MethodGet, userDirsPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, apiKeyNew.Key, user.Username)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusUnauthorized, rr)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveAPIKey(apiKeyNew, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestWebClientViewPDF(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	webToken, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodGet, webClientViewPDFPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, webClientViewPDFPath+"?path=test.pdf", nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- }
 
- func TestWebEditFile(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	testFile1 := "testfile1.txt"
 
- 	testFile2 := "testfile2"
 
- 	file1Size := int64(65536)
 
- 	file2Size := int64(1048576 * 2)
 
- 	err = createTestFile(filepath.Join(user.GetHomeDir(), testFile1), file1Size)
 
- 	assert.NoError(t, err)
 
- 	err = createTestFile(filepath.Join(user.GetHomeDir(), testFile2), file2Size)
 
- 	assert.NoError(t, err)
 
- 	webToken, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodGet, webClientEditFilePath+"?path="+testFile1, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, webClientEditFilePath+"?path="+testFile2, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "exceeds the maximum allowed size")
 
- 	req, err = http.NewRequest(http.MethodGet, webClientEditFilePath+"?path=missing", nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Unable to stat file")
 
- 	req, err = http.NewRequest(http.MethodGet, webClientEditFilePath+"?path=%2F", nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "does not point to a file")
 
- 	user.Filters.DeniedProtocols = []string{common.ProtocolHTTP}
 
- 	_, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, webClientEditFilePath+"?path="+testFile1, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	user.Filters.DeniedProtocols = []string{common.ProtocolFTP}
 
- 	user.Filters.FilePatterns = []sdk.PatternsFilter{
 
- 		{
 
- 			Path:           "/",
 
- 			DeniedPatterns: []string{"*.txt"},
 
- 		},
 
- 	}
 
- 	_, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, webClientEditFilePath+"?path="+testFile1, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Unable to get a reader")
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, webClientEditFilePath+"?path="+testFile1, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- }
 
- func TestWebGetFiles(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	testFileName := "testfile"
 
- 	testDir := "testdir"
 
- 	testFileContents := []byte("file contents")
 
- 	err = os.MkdirAll(filepath.Join(user.GetHomeDir(), testDir), os.ModePerm)
 
- 	assert.NoError(t, err)
 
- 	extensions := []string{"", ".doc", ".ppt", ".xls", ".pdf", ".mkv", ".png", ".go", ".zip", ".txt"}
 
- 	for _, ext := range extensions {
 
- 		err = os.WriteFile(filepath.Join(user.GetHomeDir(), testFileName+ext), testFileContents, os.ModePerm)
 
- 		assert.NoError(t, err)
 
- 	}
 
- 	err = os.Symlink(filepath.Join(user.GetHomeDir(), testFileName+".doc"), filepath.Join(user.GetHomeDir(), testDir, testFileName+".link"))
 
- 	assert.NoError(t, err)
 
- 	webToken, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	webAPIToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodGet, webClientFilesPath, nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientFilesPath+"?path="+testDir, nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientDirsPath+"?path="+testDir, nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var dirContents []map[string]string
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &dirContents)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, dirContents, 1)
 
- 	req, _ = http.NewRequest(http.MethodGet, userDirsPath+"?path="+testDir, nil)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var dirEntries []map[string]interface{}
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &dirEntries)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, dirEntries, 1)
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientDownloadZipPath+"?path="+url.QueryEscape("/")+"&files="+
 
- 		url.QueryEscape(fmt.Sprintf(`["%v","%v","%v"]`, testFileName, testDir, testFileName+extensions[2])), nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	filesList := []string{testFileName, testDir, testFileName + extensions[2]}
 
- 	asJSON, err := json.Marshal(filesList)
 
- 	assert.NoError(t, err)
 
- 	req, _ = http.NewRequest(http.MethodPost, userStreamZipPath, bytes.NewBuffer(asJSON))
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.NoError(t, err)
 
- 	req, _ = http.NewRequest(http.MethodPost, userStreamZipPath, bytes.NewBuffer([]byte(`file`)))
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientDownloadZipPath+"?path="+url.QueryEscape("/")+"&files="+
 
- 		url.QueryEscape(fmt.Sprintf(`["%v"]`, testDir)), nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientDownloadZipPath+"?path="+url.QueryEscape("/")+"&files=notalist", nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusInternalServerError, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Unable to get files list")
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientDirsPath+"?path=/", nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	dirContents = nil
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &dirContents)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, dirContents, len(extensions)+1)
 
- 	req, _ = http.NewRequest(http.MethodGet, userDirsPath+"?path=/", nil)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	dirEntries = nil
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &dirEntries)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, dirEntries, len(extensions)+1)
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientDirsPath+"?path=/missing", nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Unable to get directory contents")
 
- 	req, _ = http.NewRequest(http.MethodGet, userDirsPath+"?path=missing", nil)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Unable to get directory contents")
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientFilesPath+"?path="+testFileName, nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Equal(t, testFileContents, rr.Body.Bytes())
 
- 	req, _ = http.NewRequest(http.MethodGet, userFilesPath+"?path="+testFileName, nil)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Equal(t, testFileContents, rr.Body.Bytes())
 
- 	req, _ = http.NewRequest(http.MethodGet, userFilesPath+"?path=", nil)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Please set the path to a valid file")
 
- 	req, _ = http.NewRequest(http.MethodGet, userFilesPath+"?path="+testDir, nil)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "is a directory")
 
- 	req, _ = http.NewRequest(http.MethodGet, userFilesPath+"?path=notafile", nil)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Unable to stat the requested file")
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientFilesPath+"?path="+testFileName, nil)
 
- 	req.Header.Set("Range", "bytes=2-")
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusPartialContent, rr)
 
- 	assert.Equal(t, testFileContents[2:], rr.Body.Bytes())
 
- 	req, _ = http.NewRequest(http.MethodGet, userFilesPath+"?path="+testFileName, nil)
 
- 	req.Header.Set("Range", "bytes=2-")
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusPartialContent, rr)
 
- 	assert.Equal(t, testFileContents[2:], rr.Body.Bytes())
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientFilesPath+"?path="+testFileName, nil)
 
- 	req.Header.Set("Range", "bytes=-2")
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusPartialContent, rr)
 
- 	assert.Equal(t, testFileContents[11:], rr.Body.Bytes())
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientFilesPath+"?path="+testFileName, nil)
 
- 	req.Header.Set("Range", "bytes=-2,")
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusRequestedRangeNotSatisfiable, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientFilesPath+"?path="+testFileName, nil)
 
- 	req.Header.Set("Range", "bytes=1a-")
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusRequestedRangeNotSatisfiable, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, userFilesPath+"?path="+testFileName, nil)
 
- 	req.Header.Set("Range", "bytes=2b-")
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusRequestedRangeNotSatisfiable, rr)
 
- 	req, _ = http.NewRequest(http.MethodHead, webClientFilesPath+"?path="+testFileName, nil)
 
- 	req.Header.Set("Range", "bytes=2-")
 
- 	req.Header.Set("If-Range", time.Now().UTC().Add(120*time.Second).Format(http.TimeFormat))
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusPartialContent, rr)
 
- 	req, _ = http.NewRequest(http.MethodHead, webClientFilesPath+"?path="+testFileName, nil)
 
- 	req.Header.Set("Range", "bytes=2-")
 
- 	req.Header.Set("If-Range", time.Now().UTC().Add(-120*time.Second).Format(http.TimeFormat))
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodHead, webClientFilesPath+"?path="+testFileName, nil)
 
- 	req.Header.Set("If-Modified-Since", time.Now().UTC().Add(-120*time.Second).Format(http.TimeFormat))
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodHead, webClientFilesPath+"?path="+testFileName, nil)
 
- 	req.Header.Set("If-Modified-Since", time.Now().UTC().Add(120*time.Second).Format(http.TimeFormat))
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotModified, rr)
 
- 	req, _ = http.NewRequest(http.MethodHead, webClientFilesPath+"?path="+testFileName, nil)
 
- 	req.Header.Set("If-Unmodified-Since", time.Now().UTC().Add(-120*time.Second).Format(http.TimeFormat))
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusPreconditionFailed, rr)
 
- 	req, _ = http.NewRequest(http.MethodHead, userFilesPath+"?path="+testFileName, nil)
 
- 	req.Header.Set("If-Unmodified-Since", time.Now().UTC().Add(-120*time.Second).Format(http.TimeFormat))
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusPreconditionFailed, rr)
 
- 	req, _ = http.NewRequest(http.MethodHead, webClientFilesPath+"?path="+testFileName, nil)
 
- 	req.Header.Set("If-Unmodified-Since", time.Now().UTC().Add(120*time.Second).Format(http.TimeFormat))
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	user.Filters.DeniedProtocols = []string{common.ProtocolHTTP}
 
- 	_, resp, err := httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err, string(resp))
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientFilesPath, nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientDirsPath+"?path=/", nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, userFilesPath+"?path="+testFileName, nil)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, userDirsPath+"?path="+testDir, nil)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	filesList = []string{testDir}
 
- 	asJSON, err = json.Marshal(filesList)
 
- 	assert.NoError(t, err)
 
- 	req, _ = http.NewRequest(http.MethodPost, userStreamZipPath, bytes.NewBuffer(asJSON))
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	user.Filters.DeniedProtocols = []string{common.ProtocolFTP}
 
- 	user.Filters.DeniedLoginMethods = []string{dataprovider.LoginMethodPassword}
 
- 	_, resp, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err, string(resp))
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientFilesPath, nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientDownloadZipPath, nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, userDirsPath+"?path="+testDir, nil)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- }
 
- func TestWebDirsAPI(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	webAPIToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	testDir := "testdir"
 
- 	req, err := http.NewRequest(http.MethodGet, userDirsPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var contents []map[string]interface{}
 
- 	err = json.NewDecoder(rr.Body).Decode(&contents)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, contents, 0)
 
- 	// rename a missing folder
 
- 	req, err = http.NewRequest(http.MethodPatch, userDirsPath+"?path="+testDir+"&target="+testDir+"new", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	// delete a missing folder
 
- 	req, err = http.NewRequest(http.MethodDelete, userDirsPath+"?path="+testDir, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	// create a dir
 
- 	req, err = http.NewRequest(http.MethodPost, userDirsPath+"?path="+testDir, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	// check the dir was created
 
- 	req, err = http.NewRequest(http.MethodGet, userDirsPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	contents = nil
 
- 	err = json.NewDecoder(rr.Body).Decode(&contents)
 
- 	assert.NoError(t, err)
 
- 	if assert.Len(t, contents, 1) {
 
- 		assert.Equal(t, testDir, contents[0]["name"])
 
- 	}
 
- 	// rename a dir with the same source and target name
 
- 	req, err = http.NewRequest(http.MethodPatch, userDirsPath+"?path="+testDir+"&target="+testDir, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "operation unsupported")
 
- 	req, err = http.NewRequest(http.MethodPatch, userDirsPath+"?path="+testDir+"&target=%2F"+testDir+"%2F", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "operation unsupported")
 
- 	// create a dir with missing parents
 
- 	req, err = http.NewRequest(http.MethodPost, userDirsPath+"?path="+url.QueryEscape(path.Join("/sub/dir", testDir)), nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	// setting the mkdir_parents param will work
 
- 	req, err = http.NewRequest(http.MethodPost, userDirsPath+"?mkdir_parents=true&path="+url.QueryEscape(path.Join("/sub/dir", testDir)), nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	// rename the dir
 
- 	req, err = http.NewRequest(http.MethodPatch, userDirsPath+"?path="+testDir+"&target="+testDir+"new", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// delete the dir
 
- 	req, err = http.NewRequest(http.MethodDelete, userDirsPath+"?path="+testDir+"new", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// the root dir cannot be created
 
- 	req, err = http.NewRequest(http.MethodPost, userDirsPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusInternalServerError, rr)
 
- 	user.Permissions["/"] = []string{dataprovider.PermListItems}
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	// the user has no more the permission to create the directory
 
- 	req, err = http.NewRequest(http.MethodPost, userDirsPath+"?path="+testDir, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- 	// the user is deleted, any API call should fail
 
- 	req, err = http.NewRequest(http.MethodPost, userDirsPath+"?path="+testDir, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodPatch, userDirsPath+"?path="+testDir+"&target="+testDir+"new", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodDelete, userDirsPath+"?path="+testDir+"new", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- }
 
- func TestWebUploadSingleFile(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	webAPIToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	content := []byte("test content")
 
- 	req, err := http.NewRequest(http.MethodPost, userUploadFilePath, bytes.NewBuffer(content))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "please set a file path")
 
- 	modTime := time.Now().Add(-24 * time.Hour)
 
- 	req, err = http.NewRequest(http.MethodPost, userUploadFilePath+"?path=file.txt", bytes.NewBuffer(content))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	req.Header.Set("X-SFTPGO-MTIME", strconv.FormatInt(util.GetTimeAsMsSinceEpoch(modTime), 10))
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	info, err := os.Stat(filepath.Join(user.GetHomeDir(), "file.txt"))
 
- 	if assert.NoError(t, err) {
 
- 		assert.InDelta(t, util.GetTimeAsMsSinceEpoch(modTime), util.GetTimeAsMsSinceEpoch(info.ModTime()), float64(1000))
 
- 	}
 
- 	// invalid modification time will be ignored
 
- 	req, err = http.NewRequest(http.MethodPost, userUploadFilePath+"?path=file.txt", bytes.NewBuffer(content))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	req.Header.Set("X-SFTPGO-MTIME", "123abc")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	info, err = os.Stat(filepath.Join(user.GetHomeDir(), "file.txt"))
 
- 	if assert.NoError(t, err) {
 
- 		assert.InDelta(t, util.GetTimeAsMsSinceEpoch(time.Now()), util.GetTimeAsMsSinceEpoch(info.ModTime()), float64(3000))
 
- 	}
 
- 	// upload to a missing dir will fail without the mkdir_parents param
 
- 	req, err = http.NewRequest(http.MethodPost, userUploadFilePath+"?path="+url.QueryEscape("/subdir/file.txt"), bytes.NewBuffer(content))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodPost, userUploadFilePath+"?mkdir_parents=true&path="+url.QueryEscape("/subdir/file.txt"), bytes.NewBuffer(content))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	metadataReq := make(map[string]int64)
 
- 	metadataReq["modification_time"] = util.GetTimeAsMsSinceEpoch(modTime)
 
- 	asJSON, err := json.Marshal(metadataReq)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPatch, userFilesDirsMetadataPath+"?path=file.txt", bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	info, err = os.Stat(filepath.Join(user.GetHomeDir(), "file.txt"))
 
- 	if assert.NoError(t, err) {
 
- 		assert.InDelta(t, util.GetTimeAsMsSinceEpoch(modTime), util.GetTimeAsMsSinceEpoch(info.ModTime()), float64(1000))
 
- 	}
 
- 	// missing file
 
- 	req, err = http.NewRequest(http.MethodPatch, userFilesDirsMetadataPath+"?path=file2.txt", bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Unable to set metadata for path")
 
- 	// invalid JSON
 
- 	req, err = http.NewRequest(http.MethodPatch, userFilesDirsMetadataPath+"?path=file.txt", bytes.NewBuffer(content))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	// missing mandatory parameter
 
- 	req, err = http.NewRequest(http.MethodPatch, userFilesDirsMetadataPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "please set a modification_time and a path")
 
- 	metadataReq = make(map[string]int64)
 
- 	asJSON, err = json.Marshal(metadataReq)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPatch, userFilesDirsMetadataPath+"?path=file.txt", bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "please set a modification_time and a path")
 
- 	req, err = http.NewRequest(http.MethodPost, userUploadFilePath+"?path=%2Fdir%2Ffile.txt", bytes.NewBuffer(content))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Unable to write file")
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userUploadFilePath+"?path=file.txt", bytes.NewBuffer(content))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Unable to retrieve your user")
 
- 	metadataReq["modification_time"] = util.GetTimeAsMsSinceEpoch(modTime)
 
- 	asJSON, err = json.Marshal(metadataReq)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPatch, userFilesDirsMetadataPath+"?path=file.txt", bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Unable to retrieve your user")
 
- }
 
- func TestWebFilesAPI(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	webAPIToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	body := new(bytes.Buffer)
 
- 	writer := multipart.NewWriter(body)
 
- 	part1, err := writer.CreateFormFile("filenames", "file1.txt")
 
- 	assert.NoError(t, err)
 
- 	_, err = part1.Write([]byte("file1 content"))
 
- 	assert.NoError(t, err)
 
- 	part2, err := writer.CreateFormFile("filenames", "file2.txt")
 
- 	assert.NoError(t, err)
 
- 	_, err = part2.Write([]byte("file2 content"))
 
- 	assert.NoError(t, err)
 
- 	err = writer.Close()
 
- 	assert.NoError(t, err)
 
- 	reader := bytes.NewReader(body.Bytes())
 
- 	req, err := http.NewRequest(http.MethodPost, userFilesPath, reader)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Unable to parse multipart form")
 
- 	_, err = reader.Seek(0, io.SeekStart)
 
- 	assert.NoError(t, err)
 
- 	// set the proper content type
 
- 	req, err = http.NewRequest(http.MethodPost, userFilesPath, reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	// check we have 2 files
 
- 	req, err = http.NewRequest(http.MethodGet, userDirsPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var contents []map[string]interface{}
 
- 	err = json.NewDecoder(rr.Body).Decode(&contents)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, contents, 2)
 
- 	// overwrite the existing files
 
- 	_, err = reader.Seek(0, io.SeekStart)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userFilesPath, reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, userDirsPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	contents = nil
 
- 	err = json.NewDecoder(rr.Body).Decode(&contents)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, contents, 2)
 
- 	// now create a dir and upload to that dir
 
- 	testDir := "tdir"
 
- 	req, err = http.NewRequest(http.MethodPost, userDirsPath+"?path="+testDir, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	_, err = reader.Seek(0, io.SeekStart)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userFilesPath+"?path="+testDir, reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	// upload to a missing subdir will fail without the mkdir_parents param
 
- 	_, err = reader.Seek(0, io.SeekStart)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userFilesPath+"?path="+url.QueryEscape("/sub/"+testDir), reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	_, err = reader.Seek(0, io.SeekStart)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userFilesPath+"?mkdir_parents=true&path="+url.QueryEscape("/sub/"+testDir), reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, userDirsPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	contents = nil
 
- 	err = json.NewDecoder(rr.Body).Decode(&contents)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, contents, 4)
 
- 	req, err = http.NewRequest(http.MethodGet, userDirsPath+"?path="+testDir, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	contents = nil
 
- 	err = json.NewDecoder(rr.Body).Decode(&contents)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, contents, 2)
 
- 	// rename a file
 
- 	req, err = http.NewRequest(http.MethodPatch, userFilesPath+"?path=file1.txt&target=%2Ftdir%2Ffile3.txt", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// rename a missing file
 
- 	req, err = http.NewRequest(http.MethodPatch, userFilesPath+"?path=file1.txt&target=%2Ftdir%2Ffile3.txt", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	// rename a file with target name equal to source name
 
- 	req, err = http.NewRequest(http.MethodPatch, userFilesPath+"?path=file1.txt&target=file1.txt", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "operation unsupported")
 
- 	// delete a file
 
- 	req, err = http.NewRequest(http.MethodDelete, userFilesPath+"?path=file2.txt", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// delete a missing file
 
- 	req, err = http.NewRequest(http.MethodDelete, userFilesPath+"?path=file2.txt", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	// delete a directory
 
- 	req, err = http.NewRequest(http.MethodDelete, userFilesPath+"?path=tdir", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	// make a symlink outside the home dir and then try to delete it
 
- 	extPath := filepath.Join(os.TempDir(), "file")
 
- 	err = os.WriteFile(extPath, []byte("contents"), os.ModePerm)
 
- 	assert.NoError(t, err)
 
- 	err = os.Symlink(extPath, filepath.Join(user.GetHomeDir(), "file"))
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodDelete, userFilesPath+"?path=file", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	err = os.Remove(extPath)
 
- 	assert.NoError(t, err)
 
- 	// remove delete and overwrite permissions
 
- 	user.Permissions["/"] = []string{dataprovider.PermListItems, dataprovider.PermDownload, dataprovider.PermUpload}
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	_, err = reader.Seek(0, io.SeekStart)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userFilesPath+"?path=tdir", reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	req, err = http.NewRequest(http.MethodDelete, userFilesPath+"?path=%2Ftdir%2Ffile1.txt", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- 	// the user is deleted, any API call should fail
 
- 	_, err = reader.Seek(0, io.SeekStart)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userFilesPath, reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodPatch, userFilesPath+"?path=file1.txt&target=%2Ftdir%2Ffile3.txt", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodDelete, userFilesPath+"?path=file2.txt", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- }
 
- func TestWebFilesTransferQuotaLimits(t *testing.T) {
 
- 	u := getTestUser()
 
- 	u.UploadDataTransfer = 1
 
- 	u.DownloadDataTransfer = 1
 
- 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	webAPIToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	testFileName := "file.data"
 
- 	testFileSize := 550000
 
- 	testFileContents := make([]byte, testFileSize)
 
- 	n, err := io.ReadFull(rand.Reader, testFileContents)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, testFileSize, n)
 
- 	body := new(bytes.Buffer)
 
- 	writer := multipart.NewWriter(body)
 
- 	part, err := writer.CreateFormFile("filenames", testFileName)
 
- 	assert.NoError(t, err)
 
- 	_, err = part.Write(testFileContents)
 
- 	assert.NoError(t, err)
 
- 	err = writer.Close()
 
- 	assert.NoError(t, err)
 
- 	reader := bytes.NewReader(body.Bytes())
 
- 	req, err := http.NewRequest(http.MethodPost, userFilesPath, reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, userFilesPath+"?path="+testFileName, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Equal(t, testFileContents, rr.Body.Bytes())
 
- 	// error while download is active
 
- 	downloadFunc := func() {
 
- 		defer func() {
 
- 			rcv := recover()
 
- 			assert.Equal(t, http.ErrAbortHandler, rcv)
 
- 		}()
 
- 		req, err = http.NewRequest(http.MethodGet, userFilesPath+"?path="+testFileName, nil)
 
- 		assert.NoError(t, err)
 
- 		setBearerForReq(req, webAPIToken)
 
- 		rr = executeRequest(req)
 
- 		checkResponseCode(t, http.StatusOK, rr)
 
- 	}
 
- 	downloadFunc()
 
- 	// error before starting the download
 
- 	req, err = http.NewRequest(http.MethodGet, userFilesPath+"?path="+testFileName, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	// error while upload is active
 
- 	_, err = reader.Seek(0, io.SeekStart)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userFilesPath, reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusRequestEntityTooLarge, rr)
 
- 	// error before starting the upload
 
- 	_, err = reader.Seek(0, io.SeekStart)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userFilesPath, reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusRequestEntityTooLarge, rr)
 
- 	// now test upload/download to/from shares
 
- 	share1 := dataprovider.Share{
 
- 		Name:  "share1",
 
- 		Scope: dataprovider.ShareScopeRead,
 
- 		Paths: []string{"/"},
 
- 	}
 
- 	asJSON, err := json.Marshal(share1)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	objectID := rr.Header().Get("X-Object-ID")
 
- 	assert.NotEmpty(t, objectID)
 
- 	req, err = http.NewRequest(http.MethodGet, sharesPath+"/"+objectID, nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	share2 := dataprovider.Share{
 
- 		Name:  "share2",
 
- 		Scope: dataprovider.ShareScopeWrite,
 
- 		Paths: []string{"/"},
 
- 	}
 
- 	asJSON, err = json.Marshal(share2)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	objectID = rr.Header().Get("X-Object-ID")
 
- 	assert.NotEmpty(t, objectID)
 
- 	_, err = reader.Seek(0, io.SeekStart)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, sharesPath+"/"+objectID, reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusRequestEntityTooLarge, rr)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- }
 
- func TestWebUploadErrors(t *testing.T) {
 
- 	u := getTestUser()
 
- 	u.QuotaSize = 65535
 
- 	subDir1 := "sub1"
 
- 	subDir2 := "sub2"
 
- 	u.Permissions[path.Join("/", subDir1)] = []string{dataprovider.PermListItems}
 
- 	u.Permissions[path.Join("/", subDir2)] = []string{dataprovider.PermListItems, dataprovider.PermUpload,
 
- 		dataprovider.PermDelete}
 
- 	u.Filters.FilePatterns = []sdk.PatternsFilter{
 
- 		{
 
- 			Path:            "/sub2",
 
- 			AllowedPatterns: []string{},
 
- 			DeniedPatterns:  []string{"*.zip"},
 
- 		},
 
- 	}
 
- 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	webAPIToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	body := new(bytes.Buffer)
 
- 	writer := multipart.NewWriter(body)
 
- 	part, err := writer.CreateFormFile("filenames", "file.zip")
 
- 	assert.NoError(t, err)
 
- 	_, err = part.Write([]byte("file content"))
 
- 	assert.NoError(t, err)
 
- 	err = writer.Close()
 
- 	assert.NoError(t, err)
 
- 	reader := bytes.NewReader(body.Bytes())
 
- 	_, err = reader.Seek(0, io.SeekStart)
 
- 	assert.NoError(t, err)
 
- 	// zip file are not allowed within sub2
 
- 	req, err := http.NewRequest(http.MethodPost, userFilesPath+"?path=sub2", reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	_, err = reader.Seek(0, io.SeekStart)
 
- 	assert.NoError(t, err)
 
- 	// we have no upload permissions within sub1
 
- 	req, err = http.NewRequest(http.MethodPost, userFilesPath+"?path=sub1", reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	// we cannot create dirs in sub2
 
- 	_, err = reader.Seek(0, io.SeekStart)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userFilesPath+"?mkdir_parents=true&path="+url.QueryEscape("/sub2/dir"), reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "unable to check/create missing parent dir")
 
- 	req, err = http.NewRequest(http.MethodPost, userDirsPath+"?mkdir_parents=true&path="+url.QueryEscape("/sub2/dir/test"), nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Error checking parent directories")
 
- 	req, err = http.NewRequest(http.MethodPost, userUploadFilePath+"?mkdir_parents=true&path="+url.QueryEscape("/sub2/dir1/file.txt"), bytes.NewBuffer([]byte("")))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Error checking parent directories")
 
- 	// create a dir and try to overwrite it with a file
 
- 	req, err = http.NewRequest(http.MethodPost, userDirsPath+"?path=file.zip", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	_, err = reader.Seek(0, io.SeekStart)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userFilesPath, reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "operation unsupported")
 
- 	// try to upload to a missing parent directory
 
- 	_, err = reader.Seek(0, io.SeekStart)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userFilesPath+"?path=missingdir", reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodDelete, userDirsPath+"?path=file.zip", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// upload will work now
 
- 	_, err = reader.Seek(0, io.SeekStart)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userFilesPath, reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	// overwrite the file
 
- 	_, err = reader.Seek(0, io.SeekStart)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userFilesPath, reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	vfs.SetTempPath(filepath.Join(os.TempDir(), "missingpath"))
 
- 	_, err = reader.Seek(0, io.SeekStart)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userFilesPath, reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	if runtime.GOOS != osWindows {
 
- 		req, err = http.NewRequest(http.MethodDelete, userFilesPath+"?path=file.zip", nil)
 
- 		assert.NoError(t, err)
 
- 		setBearerForReq(req, webAPIToken)
 
- 		rr = executeRequest(req)
 
- 		checkResponseCode(t, http.StatusOK, rr)
 
- 		vfs.SetTempPath(filepath.Clean(os.TempDir()))
 
- 		err = os.Chmod(user.GetHomeDir(), 0555)
 
- 		assert.NoError(t, err)
 
- 		_, err = reader.Seek(0, io.SeekStart)
 
- 		assert.NoError(t, err)
 
- 		req, err = http.NewRequest(http.MethodPost, userFilesPath, reader)
 
- 		assert.NoError(t, err)
 
- 		req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 		setBearerForReq(req, webAPIToken)
 
- 		rr = executeRequest(req)
 
- 		checkResponseCode(t, http.StatusForbidden, rr)
 
- 		assert.Contains(t, rr.Body.String(), "Error closing file")
 
- 		req, err = http.NewRequest(http.MethodPost, userUploadFilePath+"?path=file.zip", bytes.NewBuffer(nil))
 
- 		assert.NoError(t, err)
 
- 		setBearerForReq(req, webAPIToken)
 
- 		rr = executeRequest(req)
 
- 		checkResponseCode(t, http.StatusForbidden, rr)
 
- 		assert.Contains(t, rr.Body.String(), "Error closing file")
 
- 		err = os.Chmod(user.GetHomeDir(), os.ModePerm)
 
- 		assert.NoError(t, err)
 
- 	}
 
- 	vfs.SetTempPath("")
 
- 	// upload a multipart form with no files
 
- 	body = new(bytes.Buffer)
 
- 	writer = multipart.NewWriter(body)
 
- 	err = writer.Close()
 
- 	assert.NoError(t, err)
 
- 	reader = bytes.NewReader(body.Bytes())
 
- 	_, err = reader.Seek(0, io.SeekStart)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userFilesPath+"?path=sub2", reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "No files uploaded!")
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- }
 
- func TestWebAPIVFolder(t *testing.T) {
 
- 	u := getTestUser()
 
- 	u.QuotaSize = 65535
 
- 	vdir := "/vdir"
 
- 	mappedPath := filepath.Join(os.TempDir(), "vdir")
 
- 	folderName := filepath.Base(mappedPath)
 
- 	u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
 
- 		BaseVirtualFolder: vfs.BaseVirtualFolder{
 
- 			Name:       folderName,
 
- 			MappedPath: mappedPath,
 
- 		},
 
- 		VirtualPath: vdir,
 
- 		QuotaSize:   -1,
 
- 		QuotaFiles:  -1,
 
- 	})
 
- 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	webAPIToken, err := getJWTAPIUserTokenFromTestServer(user.Username, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	fileContents := []byte("test contents")
 
- 	body := new(bytes.Buffer)
 
- 	writer := multipart.NewWriter(body)
 
- 	part, err := writer.CreateFormFile("filenames", "file.txt")
 
- 	assert.NoError(t, err)
 
- 	_, err = part.Write(fileContents)
 
- 	assert.NoError(t, err)
 
- 	err = writer.Close()
 
- 	assert.NoError(t, err)
 
- 	reader := bytes.NewReader(body.Bytes())
 
- 	req, err := http.NewRequest(http.MethodPost, userFilesPath+"?path=vdir", reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, int64(len(fileContents)), user.UsedQuotaSize)
 
- 	folder, _, err := httpdtest.GetFolderByName(folderName, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, int64(len(fileContents)), folder.UsedQuotaSize)
 
- 	_, err = reader.Seek(0, io.SeekStart)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userFilesPath+"?path=vdir", reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, int64(len(fileContents)), user.UsedQuotaSize)
 
- 	folder, _, err = httpdtest.GetFolderByName(folderName, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, int64(len(fileContents)), folder.UsedQuotaSize)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveFolder(vfs.BaseVirtualFolder{Name: folderName}, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(mappedPath)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestWebAPIWritePermission(t *testing.T) {
 
- 	u := getTestUser()
 
- 	u.Filters.WebClient = append(u.Filters.WebClient, sdk.WebClientWriteDisabled)
 
- 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	webAPIToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	body := new(bytes.Buffer)
 
- 	writer := multipart.NewWriter(body)
 
- 	part, err := writer.CreateFormFile("filenames", "file.txt")
 
- 	assert.NoError(t, err)
 
- 	_, err = part.Write([]byte(""))
 
- 	assert.NoError(t, err)
 
- 	err = writer.Close()
 
- 	assert.NoError(t, err)
 
- 	reader := bytes.NewReader(body.Bytes())
 
- 	req, err := http.NewRequest(http.MethodPost, userFilesPath, reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	req, err = http.NewRequest(http.MethodPatch, userFilesPath+"?path=a&target=b", nil)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	req, err = http.NewRequest(http.MethodDelete, userFilesPath+"?path=a", nil)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, userFilesPath+"?path=a.txt", nil)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, userDirsPath, nil)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, err = http.NewRequest(http.MethodPost, userDirsPath+"?path=dir", nil)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	req, err = http.NewRequest(http.MethodPatch, userDirsPath+"?path=dir&target=dir1", nil)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	req, err = http.NewRequest(http.MethodDelete, userDirsPath+"?path=dir", nil)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- }
 
- func TestWebAPICryptFs(t *testing.T) {
 
- 	u := getTestUser()
 
- 	u.QuotaSize = 65535
 
- 	u.FsConfig.Provider = sdk.CryptedFilesystemProvider
 
- 	u.FsConfig.CryptConfig.Passphrase = kms.NewPlainSecret(defaultPassword)
 
- 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	webAPIToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	body := new(bytes.Buffer)
 
- 	writer := multipart.NewWriter(body)
 
- 	part, err := writer.CreateFormFile("filenames", "file.txt")
 
- 	assert.NoError(t, err)
 
- 	_, err = part.Write([]byte("content"))
 
- 	assert.NoError(t, err)
 
- 	err = writer.Close()
 
- 	assert.NoError(t, err)
 
- 	reader := bytes.NewReader(body.Bytes())
 
- 	req, err := http.NewRequest(http.MethodPost, userFilesPath, reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	_, err = reader.Seek(0, io.SeekStart)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userFilesPath, reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- }
 
- func TestWebUploadSFTP(t *testing.T) {
 
- 	u := getTestUser()
 
- 	localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	u = getTestSFTPUser()
 
- 	u.QuotaFiles = 100
 
- 	u.FsConfig.SFTPConfig.BufferSize = 2
 
- 	u.HomeDir = filepath.Join(os.TempDir(), u.Username)
 
- 	sftpUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	webAPIToken, err := getJWTAPIUserTokenFromTestServer(sftpUser.Username, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	body := new(bytes.Buffer)
 
- 	writer := multipart.NewWriter(body)
 
- 	part, err := writer.CreateFormFile("filenames", "file.txt")
 
- 	assert.NoError(t, err)
 
- 	_, err = part.Write([]byte("test file content"))
 
- 	assert.NoError(t, err)
 
- 	err = writer.Close()
 
- 	assert.NoError(t, err)
 
- 	reader := bytes.NewReader(body.Bytes())
 
- 	req, err := http.NewRequest(http.MethodPost, userFilesPath, reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	expectedQuotaSize := int64(17)
 
- 	expectedQuotaFiles := 1
 
- 	user, _, err := httpdtest.GetUserByUsername(sftpUser.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, expectedQuotaFiles, user.UsedQuotaFiles)
 
- 	assert.Equal(t, expectedQuotaSize, user.UsedQuotaSize)
 
- 	user.QuotaSize = 10
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	// we are now overquota on overwrite
 
- 	_, err = reader.Seek(0, io.SeekStart)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userFilesPath, reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusRequestEntityTooLarge, rr)
 
- 	assert.Contains(t, rr.Body.String(), "denying write due to space limit")
 
- 	assert.Contains(t, rr.Body.String(), "Unable to write file")
 
- 	// delete the file
 
- 	req, err = http.NewRequest(http.MethodDelete, userFilesPath+"?path=file.txt", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	user, _, err = httpdtest.GetUserByUsername(sftpUser.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, 0, user.UsedQuotaFiles)
 
- 	assert.Equal(t, int64(0), user.UsedQuotaSize)
 
- 	req, err = http.NewRequest(http.MethodPost, userUploadFilePath+"?path=file.txt",
 
- 		bytes.NewBuffer([]byte("test upload single file content")))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusRequestEntityTooLarge, rr)
 
- 	assert.Contains(t, rr.Body.String(), "denying write due to space limit")
 
- 	assert.Contains(t, rr.Body.String(), "Error saving file")
 
- 	// delete the file
 
- 	req, err = http.NewRequest(http.MethodDelete, userFilesPath+"?path=file.txt", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	_, err = reader.Seek(0, io.SeekStart)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, userFilesPath, reader)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusRequestEntityTooLarge, rr)
 
- 	assert.Contains(t, rr.Body.String(), "denying write due to space limit")
 
- 	assert.Contains(t, rr.Body.String(), "Error saving file")
 
- 	// delete the file
 
- 	req, err = http.NewRequest(http.MethodDelete, userFilesPath+"?path=file.txt", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	user, _, err = httpdtest.GetUserByUsername(sftpUser.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, 0, user.UsedQuotaFiles)
 
- 	assert.Equal(t, int64(0), user.UsedQuotaSize)
 
- 	_, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(localUser, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(localUser.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(sftpUser.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- }
 
- func TestWebUploadMultipartFormReadError(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	webAPIToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodPost, userFilesPath, nil)
 
- 	assert.NoError(t, err)
 
- 	mpartForm := &multipart.Form{
 
- 		File: make(map[string][]*multipart.FileHeader),
 
- 	}
 
- 	mpartForm.File["filenames"] = append(mpartForm.File["filenames"], &multipart.FileHeader{Filename: "missing"})
 
- 	req.MultipartForm = mpartForm
 
- 	req.Header.Add("Content-Type", "multipart/form-data")
 
- 	setBearerForReq(req, webAPIToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Unable to read uploaded file")
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- }
 
- func TestCompressionErrorMock(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	defer func() {
 
- 		rcv := recover()
 
- 		assert.Equal(t, http.ErrAbortHandler, rcv)
 
- 		_, err := httpdtest.RemoveUser(user, http.StatusOK)
 
- 		assert.NoError(t, err)
 
- 		err = os.RemoveAll(user.GetHomeDir())
 
- 		assert.NoError(t, err)
 
- 	}()
 
- 	webToken, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodGet, webClientDownloadZipPath+"?path="+url.QueryEscape("/")+"&files="+
 
- 		url.QueryEscape(`["missing"]`), nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	executeRequest(req)
 
- }
 
- func TestGetFilesSFTPBackend(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	u := getTestSFTPUser()
 
- 	u.FsConfig.SFTPConfig.BufferSize = 2
 
- 	u.Permissions["/adir"] = nil
 
- 	u.Permissions["/adir1"] = []string{dataprovider.PermListItems}
 
- 	u.Filters.FilePatterns = []sdk.PatternsFilter{
 
- 		{
 
- 			Path:           "/adir2",
 
- 			DeniedPatterns: []string{"*.txt"},
 
- 		},
 
- 	}
 
- 	sftpUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	testFileName := "testsftpfile"
 
- 	testDir := "testsftpdir"
 
- 	testFileContents := []byte("sftp file contents")
 
- 	err = os.MkdirAll(filepath.Join(user.GetHomeDir(), testDir, "sub"), os.ModePerm)
 
- 	assert.NoError(t, err)
 
- 	err = os.MkdirAll(filepath.Join(user.GetHomeDir(), "adir1"), os.ModePerm)
 
- 	assert.NoError(t, err)
 
- 	err = os.MkdirAll(filepath.Join(user.GetHomeDir(), "adir2"), os.ModePerm)
 
- 	assert.NoError(t, err)
 
- 	err = os.WriteFile(filepath.Join(user.GetHomeDir(), testFileName), testFileContents, os.ModePerm)
 
- 	assert.NoError(t, err)
 
- 	err = os.WriteFile(filepath.Join(user.GetHomeDir(), "adir1", "afile"), testFileContents, os.ModePerm)
 
- 	assert.NoError(t, err)
 
- 	err = os.WriteFile(filepath.Join(user.GetHomeDir(), "adir2", "afile.txt"), testFileContents, os.ModePerm)
 
- 	assert.NoError(t, err)
 
- 	webToken, err := getJWTWebClientTokenFromTestServer(sftpUser.Username, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodGet, webClientFilesPath, nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientFilesPath+"?path="+path.Join(testDir, "sub"), nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientFilesPath+"?path="+path.Join(testDir, "missing"), nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "card-body text-form-error")
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientFilesPath+"?path=adir/sub", nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "card-body text-form-error")
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientFilesPath+"?path=adir1/afile", nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "card-body text-form-error")
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientFilesPath+"?path=adir2/afile.txt", nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "card-body text-form-error")
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientFilesPath+"?path="+testFileName, nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Equal(t, testFileContents, rr.Body.Bytes())
 
- 	req, _ = http.NewRequest(http.MethodGet, webClientFilesPath+"?path="+testFileName, nil)
 
- 	req.Header.Set("Range", "bytes=2-")
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusPartialContent, rr)
 
- 	assert.Equal(t, testFileContents[2:], rr.Body.Bytes())
 
- 	_, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(sftpUser.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- }
 
- func TestClientUserClose(t *testing.T) {
 
- 	u := getTestUser()
 
- 	u.UploadBandwidth = 32
 
- 	u.DownloadBandwidth = 32
 
- 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	testFileName := "file.dat"
 
- 	testFileSize := int64(524288)
 
- 	testFilePath := filepath.Join(user.GetHomeDir(), testFileName)
 
- 	err = createTestFile(testFilePath, testFileSize)
 
- 	assert.NoError(t, err)
 
- 	uploadContent := make([]byte, testFileSize)
 
- 	_, err = rand.Read(uploadContent)
 
- 	assert.NoError(t, err)
 
- 	webToken, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	webAPIToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	var wg sync.WaitGroup
 
- 	wg.Add(1)
 
- 	go func() {
 
- 		defer wg.Done()
 
- 		defer func() {
 
- 			rcv := recover()
 
- 			assert.Equal(t, http.ErrAbortHandler, rcv)
 
- 		}()
 
- 		req, _ := http.NewRequest(http.MethodGet, webClientFilesPath+"?path="+testFileName, nil)
 
- 		setJWTCookieForReq(req, webToken)
 
- 		rr := executeRequest(req)
 
- 		checkResponseCode(t, http.StatusOK, rr)
 
- 	}()
 
- 	wg.Add(1)
 
- 	go func() {
 
- 		defer wg.Done()
 
- 		req, _ := http.NewRequest(http.MethodGet, webClientEditFilePath+"?path="+testFileName, nil)
 
- 		setJWTCookieForReq(req, webToken)
 
- 		rr := executeRequest(req)
 
- 		checkResponseCode(t, http.StatusInternalServerError, rr)
 
- 		assert.Contains(t, rr.Body.String(), "Unable to read the file")
 
- 	}()
 
- 	wg.Add(1)
 
- 	go func() {
 
- 		defer wg.Done()
 
- 		body := new(bytes.Buffer)
 
- 		writer := multipart.NewWriter(body)
 
- 		part, err := writer.CreateFormFile("filenames", "upload.dat")
 
- 		assert.NoError(t, err)
 
- 		n, err := part.Write(uploadContent)
 
- 		assert.NoError(t, err)
 
- 		assert.Equal(t, testFileSize, int64(n))
 
- 		err = writer.Close()
 
- 		assert.NoError(t, err)
 
- 		reader := bytes.NewReader(body.Bytes())
 
- 		req, err := http.NewRequest(http.MethodPost, userFilesPath, reader)
 
- 		assert.NoError(t, err)
 
- 		req.Header.Add("Content-Type", writer.FormDataContentType())
 
- 		setBearerForReq(req, webAPIToken)
 
- 		rr := executeRequest(req)
 
- 		checkResponseCode(t, http.StatusBadRequest, rr)
 
- 		assert.Contains(t, rr.Body.String(), "transfer aborted")
 
- 	}()
 
- 	// wait for the transfers
 
- 	assert.Eventually(t, func() bool {
 
- 		stats := common.Connections.GetStats()
 
- 		if len(stats) == 3 {
 
- 			if len(stats[0].Transfers) > 0 && len(stats[1].Transfers) > 0 {
 
- 				return true
 
- 			}
 
- 		}
 
- 		return false
 
- 	}, 1*time.Second, 50*time.Millisecond)
 
- 	for _, stat := range common.Connections.GetStats() {
 
- 		// close all the active transfers
 
- 		common.Connections.Close(stat.ConnectionID)
 
- 	}
 
- 	wg.Wait()
 
- 	assert.Eventually(t, func() bool { return len(common.Connections.GetStats()) == 0 },
 
- 		1*time.Second, 100*time.Millisecond)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- }
 
- func TestWebAdminSetupMock(t *testing.T) {
 
- 	req, err := http.NewRequest(http.MethodGet, webAdminSetupPath, nil)
 
- 	assert.NoError(t, err)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusFound, rr)
 
- 	assert.Equal(t, webLoginPath, rr.Header().Get("Location"))
 
- 	// now delete all the admins
 
- 	admins, err := dataprovider.GetAdmins(100, 0, dataprovider.OrderASC)
 
- 	assert.NoError(t, err)
 
- 	for _, admin := range admins {
 
- 		err = dataprovider.DeleteAdmin(admin.Username, "", "")
 
- 		assert.NoError(t, err)
 
- 	}
 
- 	// close the provider and initializes it without creating the default admin
 
- 	os.Setenv("SFTPGO_DATA_PROVIDER__CREATE_DEFAULT_ADMIN", "0")
 
- 	err = dataprovider.Close()
 
- 	assert.NoError(t, err)
 
- 	err = config.LoadConfig(configDir, "")
 
- 	assert.NoError(t, err)
 
- 	providerConf := config.GetProviderConf()
 
- 	providerConf.CredentialsPath = credentialsPath
 
- 	err = os.RemoveAll(credentialsPath)
 
- 	assert.NoError(t, err)
 
- 	err = dataprovider.Initialize(providerConf, configDir, true)
 
- 	assert.NoError(t, err)
 
- 	// now the setup page must be rendered
 
- 	req, err = http.NewRequest(http.MethodGet, webAdminSetupPath, nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// check redirects to the setup page
 
- 	req, err = http.NewRequest(http.MethodGet, "/", nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusFound, rr)
 
- 	assert.Equal(t, webAdminSetupPath, rr.Header().Get("Location"))
 
- 	req, err = http.NewRequest(http.MethodGet, webBasePath, nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusFound, rr)
 
- 	assert.Equal(t, webAdminSetupPath, rr.Header().Get("Location"))
 
- 	req, err = http.NewRequest(http.MethodGet, webBasePathAdmin, nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusFound, rr)
 
- 	assert.Equal(t, webAdminSetupPath, rr.Header().Get("Location"))
 
- 	req, err = http.NewRequest(http.MethodGet, webLoginPath, nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusFound, rr)
 
- 	assert.Equal(t, webAdminSetupPath, rr.Header().Get("Location"))
 
- 	req, err = http.NewRequest(http.MethodGet, webClientLoginPath, nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusFound, rr)
 
- 	assert.Equal(t, webAdminSetupPath, rr.Header().Get("Location"))
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webAdminSetupPath)
 
- 	assert.NoError(t, err)
 
- 	form := make(url.Values)
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminSetupPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminSetupPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Please set a username")
 
- 	form.Set("username", defaultTokenAuthUser)
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminSetupPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Please set a password")
 
- 	form.Set("password", defaultTokenAuthPass)
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminSetupPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Passwords mismatch")
 
- 	form.Set("confirm_password", defaultTokenAuthPass)
 
- 	// test a parse form error
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminSetupPath+"?param=p%C3%AO%GH", bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// test a dataprovider error
 
- 	err = dataprovider.Close()
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminSetupPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// finally initialize the provider and create the default admin
 
- 	err = config.LoadConfig(configDir, "")
 
- 	assert.NoError(t, err)
 
- 	providerConf = config.GetProviderConf()
 
- 	providerConf.CredentialsPath = credentialsPath
 
- 	err = os.RemoveAll(credentialsPath)
 
- 	assert.NoError(t, err)
 
- 	err = dataprovider.Initialize(providerConf, configDir, true)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminSetupPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusFound, rr)
 
- 	assert.Equal(t, webUsersPath, rr.Header().Get("Location"))
 
- 	// if we resubmit the form we get a bad request, an admin already exists
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminSetupPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "an admin user already exists")
 
- 	os.Setenv("SFTPGO_DATA_PROVIDER__CREATE_DEFAULT_ADMIN", "1")
 
- }
 
- func TestWebAdminLoginMock(t *testing.T) {
 
- 	webToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	apiToken, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodGet, serverStatusPath, nil)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, webStatusPath+"notfound", nil)
 
- 	req.RequestURI = webStatusPath + "notfound"
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, webStatusPath, nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, webLogoutPath, nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusFound, rr)
 
- 	cookie := rr.Header().Get("Cookie")
 
- 	assert.Empty(t, cookie)
 
- 	req, _ = http.NewRequest(http.MethodGet, logoutPath, nil)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, serverStatusPath, nil)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusUnauthorized, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Your token is no longer valid")
 
- 	req, _ = http.NewRequest(http.MethodGet, webStatusPath, nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusFound, rr)
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath)
 
- 	assert.NoError(t, err)
 
- 	// now try using wrong credentials
 
- 	form := getLoginForm(defaultTokenAuthUser, "wrong pwd", csrfToken)
 
- 	req, _ = http.NewRequest(http.MethodPost, webLoginPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// try from an ip not allowed
 
- 	a := getTestAdmin()
 
- 	a.Username = altAdminUsername
 
- 	a.Password = altAdminPassword
 
- 	a.Filters.AllowList = []string{"10.0.0.0/8"}
 
- 	_, _, err = httpdtest.AddAdmin(a, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	form = getLoginForm(altAdminUsername, altAdminPassword, csrfToken)
 
- 	req, _ = http.NewRequest(http.MethodPost, webLoginPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	req.RemoteAddr = "127.1.1.1:1234"
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "login from IP 127.1.1.1 not allowed")
 
- 	req, _ = http.NewRequest(http.MethodPost, webLoginPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	req.RemoteAddr = "10.9.9.9:1234"
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusFound, rr)
 
- 	req, _ = http.NewRequest(http.MethodPost, webLoginPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	req.RemoteAddr = "127.0.1.1:4567"
 
- 	req.Header.Set("X-Forwarded-For", "10.9.9.9")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "login from IP 127.0.1.1 not allowed")
 
- 	// invalid csrf token
 
- 	form = getLoginForm(altAdminUsername, altAdminPassword, "invalid csrf")
 
- 	req, _ = http.NewRequest(http.MethodPost, webLoginPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	req.RemoteAddr = "10.9.9.8:1234"
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "unable to verify form token")
 
- 	req, _ = http.NewRequest(http.MethodGet, webLoginPath, nil)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	_, err = httpdtest.RemoveAdmin(a, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestAdminNoToken(t *testing.T) {
 
- 	req, _ := http.NewRequest(http.MethodGet, webAdminProfilePath, nil)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusFound, rr)
 
- 	assert.Equal(t, webLoginPath, rr.Header().Get("Location"))
 
- 	req, _ = http.NewRequest(http.MethodGet, webUserPath, nil)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusFound, rr)
 
- 	assert.Equal(t, webLoginPath, rr.Header().Get("Location"))
 
- 	req, _ = http.NewRequest(http.MethodGet, userPath, nil)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusUnauthorized, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, activeConnectionsPath, nil)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusUnauthorized, rr)
 
- }
 
- func TestWebUserShare(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webClientLoginPath)
 
- 	assert.NoError(t, err)
 
- 	token, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	userAPItoken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	share := dataprovider.Share{
 
- 		Name:        "test share",
 
- 		Description: "test share desc",
 
- 		Scope:       dataprovider.ShareScopeRead,
 
- 		Paths:       []string{"/"},
 
- 		ExpiresAt:   util.GetTimeAsMsSinceEpoch(time.Now().Add(24 * time.Hour)),
 
- 		MaxTokens:   100,
 
- 		AllowFrom:   []string{"127.0.0.0/8", "172.16.0.0/16"},
 
- 		Password:    defaultPassword,
 
- 	}
 
- 	form := make(url.Values)
 
- 	form.Set("name", share.Name)
 
- 	form.Set("scope", strconv.Itoa(int(share.Scope)))
 
- 	form.Set("paths", "/")
 
- 	form.Set("max_tokens", strconv.Itoa(share.MaxTokens))
 
- 	form.Set("allowed_ip", strings.Join(share.AllowFrom, ","))
 
- 	form.Set("description", share.Description)
 
- 	form.Set("password", share.Password)
 
- 	form.Set("expiration_date", "123")
 
- 	// invalid expiration date
 
- 	req, err := http.NewRequest(http.MethodPost, webClientSharePath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "cannot parse")
 
- 	form.Set("expiration_date", util.GetTimeFromMsecSinceEpoch(share.ExpiresAt).UTC().Format("2006-01-02 15:04:05"))
 
- 	form.Set("scope", "")
 
- 	// invalid scope
 
- 	req, err = http.NewRequest(http.MethodPost, webClientSharePath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "invalid syntax")
 
- 	form.Set("scope", strconv.Itoa(int(share.Scope)))
 
- 	// invalid max tokens
 
- 	form.Set("max_tokens", "t")
 
- 	req, err = http.NewRequest(http.MethodPost, webClientSharePath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "invalid syntax")
 
- 	form.Set("max_tokens", strconv.Itoa(share.MaxTokens))
 
- 	// no csrf token
 
- 	req, err = http.NewRequest(http.MethodPost, webClientSharePath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "unable to verify form token")
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	form.Set("scope", "100")
 
- 	req, err = http.NewRequest(http.MethodPost, webClientSharePath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Validation error: invalid scope")
 
- 	form.Set("scope", strconv.Itoa(int(share.Scope)))
 
- 	req, err = http.NewRequest(http.MethodPost, webClientSharePath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusSeeOther, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, userSharesPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, userAPItoken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var shares []dataprovider.Share
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &shares)
 
- 	assert.NoError(t, err)
 
- 	if assert.Len(t, shares, 1) {
 
- 		s := shares[0]
 
- 		assert.Equal(t, share.Name, s.Name)
 
- 		assert.Equal(t, share.Description, s.Description)
 
- 		assert.Equal(t, share.Scope, s.Scope)
 
- 		assert.Equal(t, share.Paths, s.Paths)
 
- 		assert.InDelta(t, share.ExpiresAt, s.ExpiresAt, 999)
 
- 		assert.Equal(t, share.MaxTokens, s.MaxTokens)
 
- 		assert.Equal(t, share.AllowFrom, s.AllowFrom)
 
- 		assert.Equal(t, redactedSecret, s.Password)
 
- 		share.ShareID = s.ShareID
 
- 	}
 
- 	form.Set("password", redactedSecret)
 
- 	form.Set("expiration_date", "123")
 
- 	req, err = http.NewRequest(http.MethodPost, webClientSharePath+"/unknowid", bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodPost, webClientSharePath+"/"+share.ShareID, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "cannot parse")
 
- 	form.Set("expiration_date", "")
 
- 	form.Set(csrfFormToken, "")
 
- 	req, err = http.NewRequest(http.MethodPost, webClientSharePath+"/"+share.ShareID, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "unable to verify form token")
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	form.Set("allowed_ip", "1.1.1")
 
- 	req, err = http.NewRequest(http.MethodPost, webClientSharePath+"/"+share.ShareID, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Validation error: could not parse allow from entry")
 
- 	form.Set("allowed_ip", "")
 
- 	req, err = http.NewRequest(http.MethodPost, webClientSharePath+"/"+share.ShareID, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusSeeOther, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, userSharesPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, userAPItoken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	shares = nil
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &shares)
 
- 	assert.NoError(t, err)
 
- 	if assert.Len(t, shares, 1) {
 
- 		s := shares[0]
 
- 		assert.Equal(t, share.Name, s.Name)
 
- 		assert.Equal(t, share.Description, s.Description)
 
- 		assert.Equal(t, share.Scope, s.Scope)
 
- 		assert.Equal(t, share.Paths, s.Paths)
 
- 		assert.Equal(t, int64(0), s.ExpiresAt)
 
- 		assert.Equal(t, share.MaxTokens, s.MaxTokens)
 
- 		assert.Empty(t, s.AllowFrom)
 
- 	}
 
- 	// check the password
 
- 	s, err := dataprovider.ShareExists(share.ShareID, user.Username)
 
- 	assert.NoError(t, err)
 
- 	match, err := s.CheckCredentials(user.Username, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	assert.True(t, match)
 
- 	req, err = http.NewRequest(http.MethodGet, webClientSharePath+"?path=%2F&files=a", nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Invalid share list")
 
- 	req, err = http.NewRequest(http.MethodGet, webClientSharePath+"?path=%2F&files=%5B\"adir\"%5D", nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, webClientSharePath+"/unknown", nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, webClientSharePath+"/"+share.ShareID, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, webClientSharesPath+"?qlimit=a", nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, webClientSharesPath+"?qlimit=1", nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestWebUserShareNoPasswordDisabled(t *testing.T) {
 
- 	u := getTestUser()
 
- 	u.Filters.WebClient = []string{sdk.WebClientShareNoPasswordDisabled}
 
- 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webClientLoginPath)
 
- 	assert.NoError(t, err)
 
- 	token, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	userAPItoken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	share := dataprovider.Share{
 
- 		Name:  "s",
 
- 		Scope: dataprovider.ShareScopeRead,
 
- 		Paths: []string{"/"},
 
- 	}
 
- 	form := make(url.Values)
 
- 	form.Set("name", share.Name)
 
- 	form.Set("scope", strconv.Itoa(int(share.Scope)))
 
- 	form.Set("paths", "/")
 
- 	form.Set("max_tokens", "0")
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	req, err := http.NewRequest(http.MethodPost, webClientSharePath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "You are not authorized to share files/folders without a password")
 
- 	form.Set("password", defaultPassword)
 
- 	req, err = http.NewRequest(http.MethodPost, webClientSharePath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusSeeOther, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, userSharesPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, userAPItoken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var shares []dataprovider.Share
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &shares)
 
- 	assert.NoError(t, err)
 
- 	if assert.Len(t, shares, 1) {
 
- 		s := shares[0]
 
- 		assert.Equal(t, share.Name, s.Name)
 
- 		assert.Equal(t, share.Scope, s.Scope)
 
- 		assert.Equal(t, share.Paths, s.Paths)
 
- 		share.ShareID = s.ShareID
 
- 	}
 
- 	assert.NotEmpty(t, share.ShareID)
 
- 	form.Set("password", "")
 
- 	req, err = http.NewRequest(http.MethodPost, webClientSharePath+"/"+share.ShareID, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "You are not authorized to share files/folders without a password")
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestWebUserProfile(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webClientLoginPath)
 
- 	assert.NoError(t, err)
 
- 	token, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	email := "[email protected]"
 
- 	description := "User"
 
- 	form := make(url.Values)
 
- 	form.Set("allow_api_key_auth", "1")
 
- 	form.Set("email", email)
 
- 	form.Set("description", description)
 
- 	form.Set("public_keys", testPubKey)
 
- 	form.Add("public_keys", testPubKey1)
 
- 	// no csrf token
 
- 	req, err := http.NewRequest(http.MethodPost, webClientProfilePath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "unable to verify form token")
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	req, _ = http.NewRequest(http.MethodPost, webClientProfilePath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Your profile has been successfully updated")
 
- 	user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.True(t, user.Filters.AllowAPIKeyAuth)
 
- 	assert.Len(t, user.PublicKeys, 2)
 
- 	assert.Equal(t, email, user.Email)
 
- 	assert.Equal(t, description, user.Description)
 
- 	// set an invalid email
 
- 	form.Set("email", "not an email")
 
- 	req, _ = http.NewRequest(http.MethodPost, webClientProfilePath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Validation error: email")
 
- 	// invalid public key
 
- 	form.Set("email", email)
 
- 	form.Set("public_keys", "invalid")
 
- 	req, _ = http.NewRequest(http.MethodPost, webClientProfilePath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Validation error: could not parse key")
 
- 	// now remove permissions
 
- 	form.Set("public_keys", testPubKey)
 
- 	user.Filters.WebClient = []string{sdk.WebClientAPIKeyAuthChangeDisabled}
 
- 	_, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	token, err = getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	form.Set("allow_api_key_auth", "0")
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	req, _ = http.NewRequest(http.MethodPost, webClientProfilePath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Your profile has been successfully updated")
 
- 	user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.True(t, user.Filters.AllowAPIKeyAuth)
 
- 	assert.Len(t, user.PublicKeys, 1)
 
- 	assert.Equal(t, email, user.Email)
 
- 	assert.Equal(t, description, user.Description)
 
- 	user.Filters.WebClient = []string{sdk.WebClientAPIKeyAuthChangeDisabled, sdk.WebClientPubKeyChangeDisabled}
 
- 	_, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	token, err = getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	form.Set("public_keys", testPubKey)
 
- 	form.Add("public_keys", testPubKey1)
 
- 	req, _ = http.NewRequest(http.MethodPost, webClientProfilePath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Your profile has been successfully updated")
 
- 	user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.True(t, user.Filters.AllowAPIKeyAuth)
 
- 	assert.Len(t, user.PublicKeys, 1)
 
- 	assert.Equal(t, email, user.Email)
 
- 	assert.Equal(t, description, user.Description)
 
- 	user.Filters.WebClient = []string{sdk.WebClientAPIKeyAuthChangeDisabled, sdk.WebClientInfoChangeDisabled}
 
- 	_, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	token, err = getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	form.Set("email", "[email protected]")
 
- 	form.Set("description", "new description")
 
- 	req, _ = http.NewRequest(http.MethodPost, webClientProfilePath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Your profile has been successfully updated")
 
- 	user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.True(t, user.Filters.AllowAPIKeyAuth)
 
- 	assert.Len(t, user.PublicKeys, 2)
 
- 	assert.Equal(t, email, user.Email)
 
- 	assert.Equal(t, description, user.Description)
 
- 	// finally disable all profile permissions
 
- 	user.Filters.WebClient = []string{sdk.WebClientAPIKeyAuthChangeDisabled, sdk.WebClientInfoChangeDisabled,
 
- 		sdk.WebClientPubKeyChangeDisabled}
 
- 	_, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	token, err = getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	req, _ = http.NewRequest(http.MethodPost, webClientProfilePath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	form = make(url.Values)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	req, _ = http.NewRequest(http.MethodPost, webClientProfilePath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusInternalServerError, rr)
 
- }
 
- func TestWebAdminProfile(t *testing.T) {
 
- 	admin := getTestAdmin()
 
- 	admin.Username = altAdminUsername
 
- 	admin.Password = altAdminPassword
 
- 	admin, _, err := httpdtest.AddAdmin(admin, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	token, err := getJWTWebTokenFromTestServer(admin.Username, altAdminPassword)
 
- 	assert.NoError(t, err)
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodGet, webAdminProfilePath, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	form := make(url.Values)
 
- 	form.Set("allow_api_key_auth", "1")
 
- 	form.Set("email", "[email protected]")
 
- 	form.Set("description", "admin desc")
 
- 	// no csrf token
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminProfilePath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "unable to verify form token")
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	req, _ = http.NewRequest(http.MethodPost, webAdminProfilePath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Your profile has been successfully updated")
 
- 	admin, _, err = httpdtest.GetAdminByUsername(admin.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.True(t, admin.Filters.AllowAPIKeyAuth)
 
- 	assert.Equal(t, "[email protected]", admin.Email)
 
- 	assert.Equal(t, "admin desc", admin.Description)
 
- 	form = make(url.Values)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	req, _ = http.NewRequest(http.MethodPost, webAdminProfilePath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Your profile has been successfully updated")
 
- 	admin, _, err = httpdtest.GetAdminByUsername(admin.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.False(t, admin.Filters.AllowAPIKeyAuth)
 
- 	assert.Empty(t, admin.Email)
 
- 	assert.Empty(t, admin.Description)
 
- 	_, err = httpdtest.RemoveAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	form = make(url.Values)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	req, _ = http.NewRequest(http.MethodPost, webAdminProfilePath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusInternalServerError, rr)
 
- }
 
- func TestWebAdminPwdChange(t *testing.T) {
 
- 	admin := getTestAdmin()
 
- 	admin.Username = altAdminUsername
 
- 	admin.Password = altAdminPassword
 
- 	admin, _, err := httpdtest.AddAdmin(admin, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	token, err := getJWTWebTokenFromTestServer(admin.Username, altAdminPassword)
 
- 	assert.NoError(t, err)
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodGet, webChangeAdminPwdPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	form := make(url.Values)
 
- 	form.Set("current_password", altAdminPassword)
 
- 	form.Set("new_password1", altAdminPassword)
 
- 	form.Set("new_password2", altAdminPassword)
 
- 	// no csrf token
 
- 	req, _ = http.NewRequest(http.MethodPost, webChangeAdminPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "unable to verify form token")
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	req, _ = http.NewRequest(http.MethodPost, webChangeAdminPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "the new password must be different from the current one")
 
- 	form.Set("new_password1", altAdminPassword+"1")
 
- 	form.Set("new_password2", altAdminPassword+"1")
 
- 	req, _ = http.NewRequest(http.MethodPost, webChangeAdminPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusFound, rr)
 
- 	assert.Equal(t, webLoginPath, rr.Header().Get("Location"))
 
- 	_, err = httpdtest.RemoveAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestAPIKeysManagement(t *testing.T) {
 
- 	admin := getTestAdmin()
 
- 	admin.Username = altAdminUsername
 
- 	admin.Password = altAdminPassword
 
- 	admin, _, err := httpdtest.AddAdmin(admin, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	apiKey := dataprovider.APIKey{
 
- 		Name:  "test key",
 
- 		Scope: dataprovider.APIKeyScopeAdmin,
 
- 	}
 
- 	asJSON, err := json.Marshal(apiKey)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodPost, apiKeysPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	location := rr.Header().Get("Location")
 
- 	assert.NotEmpty(t, location)
 
- 	objectID := rr.Header().Get("X-Object-ID")
 
- 	assert.NotEmpty(t, objectID)
 
- 	assert.Equal(t, fmt.Sprintf("%v/%v", apiKeysPath, objectID), location)
 
- 	apiKey.KeyID = objectID
 
- 	response := make(map[string]string)
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &response)
 
- 	assert.NoError(t, err)
 
- 	key := response["key"]
 
- 	assert.NotEmpty(t, key)
 
- 	assert.True(t, strings.HasPrefix(key, apiKey.KeyID+"."))
 
- 	req, err = http.NewRequest(http.MethodGet, location, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var keyGet dataprovider.APIKey
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &keyGet)
 
- 	assert.NoError(t, err)
 
- 	assert.Empty(t, keyGet.Key)
 
- 	assert.Equal(t, apiKey.KeyID, keyGet.KeyID)
 
- 	assert.Equal(t, apiKey.Scope, keyGet.Scope)
 
- 	assert.Equal(t, apiKey.Name, keyGet.Name)
 
- 	assert.Equal(t, int64(0), keyGet.ExpiresAt)
 
- 	assert.Equal(t, int64(0), keyGet.LastUseAt)
 
- 	assert.Greater(t, keyGet.CreatedAt, int64(0))
 
- 	assert.Greater(t, keyGet.UpdatedAt, int64(0))
 
- 	assert.Empty(t, keyGet.Description)
 
- 	assert.Empty(t, keyGet.User)
 
- 	assert.Empty(t, keyGet.Admin)
 
- 	// API key is not enabled for the admin user so this request should fail
 
- 	req, err = http.NewRequest(http.MethodGet, versionPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, key, admin.Username)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusUnauthorized, rr)
 
- 	assert.Contains(t, rr.Body.String(), "the admin associated with the provided api key cannot be authenticated")
 
- 	admin.Filters.AllowAPIKeyAuth = true
 
- 	admin, _, err = httpdtest.UpdateAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, versionPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, key, admin.Username)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, versionPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, key, admin.Username+"1")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusUnauthorized, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, versionPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, key, "")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusUnauthorized, rr)
 
- 	// now associate the key directly to the admin
 
- 	apiKey.Admin = admin.Username
 
- 	apiKey.Description = "test description"
 
- 	asJSON, err = json.Marshal(apiKey)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPut, location, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, apiKeysPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var keys []dataprovider.APIKey
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &keys)
 
- 	assert.NoError(t, err)
 
- 	if assert.GreaterOrEqual(t, len(keys), 1) {
 
- 		found := false
 
- 		for _, k := range keys {
 
- 			if k.KeyID == apiKey.KeyID {
 
- 				found = true
 
- 				assert.Empty(t, k.Key)
 
- 				assert.Equal(t, apiKey.Scope, k.Scope)
 
- 				assert.Equal(t, apiKey.Name, k.Name)
 
- 				assert.Equal(t, int64(0), k.ExpiresAt)
 
- 				assert.Greater(t, k.LastUseAt, int64(0))
 
- 				assert.Equal(t, k.CreatedAt, keyGet.CreatedAt)
 
- 				assert.Greater(t, k.UpdatedAt, keyGet.UpdatedAt)
 
- 				assert.Equal(t, apiKey.Description, k.Description)
 
- 				assert.Empty(t, k.User)
 
- 				assert.Equal(t, admin.Username, k.Admin)
 
- 			}
 
- 		}
 
- 		assert.True(t, found)
 
- 	}
 
- 	req, err = http.NewRequest(http.MethodGet, versionPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, key, "")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// invalid API keys
 
- 	req, err = http.NewRequest(http.MethodGet, versionPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, key+"invalid", "")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusUnauthorized, rr)
 
- 	assert.Contains(t, rr.Body.String(), "the provided api key cannot be authenticated")
 
- 	req, err = http.NewRequest(http.MethodGet, versionPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, "invalid", "")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	// using an API key we cannot modify/get API keys
 
- 	req, err = http.NewRequest(http.MethodPut, location, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, key, "")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, location, nil)
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, key, "")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	admin.Filters.AllowList = []string{"172.16.18.0/24"}
 
- 	admin, _, err = httpdtest.UpdateAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, versionPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, key, "")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusUnauthorized, rr)
 
- 	req, err = http.NewRequest(http.MethodDelete, location, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, versionPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, key, "")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "the provided api key is not valid")
 
- 	_, err = httpdtest.RemoveAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestAPIKeySearch(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	apiKey := dataprovider.APIKey{
 
- 		Scope: dataprovider.APIKeyScopeAdmin,
 
- 	}
 
- 	for i := 1; i < 5; i++ {
 
- 		apiKey.Name = fmt.Sprintf("testapikey%v", i)
 
- 		asJSON, err := json.Marshal(apiKey)
 
- 		assert.NoError(t, err)
 
- 		req, err := http.NewRequest(http.MethodPost, apiKeysPath, bytes.NewBuffer(asJSON))
 
- 		assert.NoError(t, err)
 
- 		setBearerForReq(req, token)
 
- 		rr := executeRequest(req)
 
- 		checkResponseCode(t, http.StatusCreated, rr)
 
- 	}
 
- 	req, err := http.NewRequest(http.MethodGet, apiKeysPath+"?limit=1&order=ASC", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var keys []dataprovider.APIKey
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &keys)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, keys, 1)
 
- 	firstKey := keys[0]
 
- 	req, err = http.NewRequest(http.MethodGet, apiKeysPath+"?limit=1&order=DESC", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	keys = nil
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &keys)
 
- 	assert.NoError(t, err)
 
- 	if assert.Len(t, keys, 1) {
 
- 		assert.NotEqual(t, firstKey.KeyID, keys[0].KeyID)
 
- 	}
 
- 	req, err = http.NewRequest(http.MethodGet, apiKeysPath+"?limit=1&offset=100", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	keys = nil
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &keys)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, keys, 0)
 
- 	req, err = http.NewRequest(http.MethodGet, apiKeysPath+"?limit=a", nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%v/%v", apiKeysPath, "missingid"), nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, apiKeysPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	keys = nil
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &keys)
 
- 	assert.NoError(t, err)
 
- 	counter := 0
 
- 	for _, k := range keys {
 
- 		if strings.HasPrefix(k.Name, "testapikey") {
 
- 			req, err = http.NewRequest(http.MethodDelete, fmt.Sprintf("%v/%v", apiKeysPath, k.KeyID), nil)
 
- 			assert.NoError(t, err)
 
- 			setBearerForReq(req, token)
 
- 			rr = executeRequest(req)
 
- 			checkResponseCode(t, http.StatusOK, rr)
 
- 			counter++
 
- 		}
 
- 	}
 
- 	assert.Equal(t, 4, counter)
 
- }
 
- func TestAPIKeyErrors(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	apiKey := dataprovider.APIKey{
 
- 		Name:  "testkey",
 
- 		Scope: dataprovider.APIKeyScopeUser,
 
- 	}
 
- 	asJSON, err := json.Marshal(apiKey)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodPost, apiKeysPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	location := rr.Header().Get("Location")
 
- 	assert.NotEmpty(t, location)
 
- 	// invalid API scope
 
- 	apiKey.Scope = 1000
 
- 	asJSON, err = json.Marshal(apiKey)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, apiKeysPath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	req, err = http.NewRequest(http.MethodPut, location, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	// invalid JSON
 
- 	req, err = http.NewRequest(http.MethodPost, apiKeysPath, bytes.NewBuffer([]byte(`invalid JSON`)))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	req, err = http.NewRequest(http.MethodPut, location, bytes.NewBuffer([]byte(`invalid JSON`)))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	req, err = http.NewRequest(http.MethodDelete, location, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, err = http.NewRequest(http.MethodDelete, location, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodPut, location, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- }
 
- func TestAPIKeyOnDeleteCascade(t *testing.T) {
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	admin := getTestAdmin()
 
- 	admin.Username = altAdminUsername
 
- 	admin.Password = altAdminPassword
 
- 	admin, _, err = httpdtest.AddAdmin(admin, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	apiKey := dataprovider.APIKey{
 
- 		Name:  "user api key",
 
- 		Scope: dataprovider.APIKeyScopeUser,
 
- 		User:  user.Username,
 
- 	}
 
- 	apiKey, _, err = httpdtest.AddAPIKey(apiKey, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodGet, userDirsPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, apiKey.Key, "")
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusUnauthorized, rr)
 
- 	user.Filters.AllowAPIKeyAuth = true
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, userDirsPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setAPIKeyForReq(req, apiKey.Key, "")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var contents []map[string]interface{}
 
- 	err = json.NewDecoder(rr.Body).Decode(&contents)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, contents, 0)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.GetAPIKeyByID(apiKey.KeyID, http.StatusNotFound)
 
- 	assert.NoError(t, err)
 
- 	apiKey.User = ""
 
- 	apiKey.Admin = admin.Username
 
- 	apiKey.Scope = dataprovider.APIKeyScopeAdmin
 
- 	apiKey, _, err = httpdtest.AddAPIKey(apiKey, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.GetAPIKeyByID(apiKey.KeyID, http.StatusNotFound)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestBasicWebUsersMock(t *testing.T) {
 
- 	token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	user := getTestUser()
 
- 	userAsJSON := getUserAsJSON(t, user)
 
- 	req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	err = render.DecodeJSON(rr.Body, &user)
 
- 	assert.NoError(t, err)
 
- 	user1 := getTestUser()
 
- 	user1.Username += "1"
 
- 	user1AsJSON := getUserAsJSON(t, user1)
 
- 	req, _ = http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(user1AsJSON))
 
- 	setBearerForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	err = render.DecodeJSON(rr.Body, &user1)
 
- 	assert.NoError(t, err)
 
- 	webToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	req, _ = http.NewRequest(http.MethodGet, webUsersPath, nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, webUsersPath+"?qlimit=a", nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, webUsersPath+"?qlimit=1", nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, webUserPath, nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, path.Join(webUserPath, user.Username), nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, webUserPath+"/0", nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath)
 
- 	assert.NoError(t, err)
 
- 	form := make(url.Values)
 
- 	form.Set("username", user.Username)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	b, contentType, _ := getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, webUserPath+"/0", &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, _ = http.NewRequest(http.MethodPost, webUserPath+"/aaa", &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(webUserPath, user.Username), nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Invalid token")
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(webUserPath, user.Username), nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	setCSRFHeaderForReq(req, csrfToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(webUserPath, user1.Username), nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	setCSRFHeaderForReq(req, csrfToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- }
 
- func TestRenderDefenderPageMock(t *testing.T) {
 
- 	token, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodGet, webDefenderPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "View and manage blocklist")
 
- }
 
- func TestWebAdminBasicMock(t *testing.T) {
 
- 	token, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	admin := getTestAdmin()
 
- 	admin.Username = altAdminUsername
 
- 	admin.Password = altAdminPassword
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath)
 
- 	assert.NoError(t, err)
 
- 	form := make(url.Values)
 
- 	form.Set("username", admin.Username)
 
- 	form.Set("password", "")
 
- 	form.Set("status", "1")
 
- 	form.Set("permissions", "*")
 
- 	form.Set("description", admin.Description)
 
- 	req, _ := http.NewRequest(http.MethodPost, webAdminPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "unable to verify form token")
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	form.Set("status", "a")
 
- 	req, _ = http.NewRequest(http.MethodPost, webAdminPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	form.Set("status", "1")
 
- 	req, _ = http.NewRequest(http.MethodPost, webAdminPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	form.Set("password", admin.Password)
 
- 	req, _ = http.NewRequest(http.MethodPost, webAdminPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusSeeOther, rr)
 
- 	// add TOTP config
 
- 	configName, _, secret, _, err := mfa.GenerateTOTPSecret(mfa.GetAvailableTOTPConfigNames()[0], altAdminUsername)
 
- 	assert.NoError(t, err)
 
- 	altToken, err := getJWTWebTokenFromTestServer(altAdminUsername, altAdminPassword)
 
- 	assert.NoError(t, err)
 
- 	adminTOTPConfig := dataprovider.AdminTOTPConfig{
 
- 		Enabled:    true,
 
- 		ConfigName: configName,
 
- 		Secret:     kms.NewPlainSecret(secret),
 
- 	}
 
- 	asJSON, err := json.Marshal(adminTOTPConfig)
 
- 	assert.NoError(t, err)
 
- 	// no CSRF token
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminTOTPSavePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, altToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Invalid token")
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminTOTPSavePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, altToken)
 
- 	setCSRFHeaderForReq(req, csrfToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	admin, _, err = httpdtest.GetAdminByUsername(altAdminUsername, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.True(t, admin.Filters.TOTPConfig.Enabled)
 
- 	secretPayload := admin.Filters.TOTPConfig.Secret.GetPayload()
 
- 	assert.NotEmpty(t, secretPayload)
 
- 	adminTOTPConfig = dataprovider.AdminTOTPConfig{
 
- 		Enabled:    true,
 
- 		ConfigName: configName,
 
- 		Secret:     kms.NewEmptySecret(),
 
- 	}
 
- 	asJSON, err = json.Marshal(adminTOTPConfig)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminTOTPSavePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, altToken)
 
- 	setCSRFHeaderForReq(req, csrfToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	admin, _, err = httpdtest.GetAdminByUsername(altAdminUsername, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.True(t, admin.Filters.TOTPConfig.Enabled)
 
- 	assert.Equal(t, secretPayload, admin.Filters.TOTPConfig.Secret.GetPayload())
 
- 	adminTOTPConfig = dataprovider.AdminTOTPConfig{
 
- 		Enabled:    true,
 
- 		ConfigName: configName,
 
- 		Secret:     nil,
 
- 	}
 
- 	asJSON, err = json.Marshal(adminTOTPConfig)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminTOTPSavePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, altToken)
 
- 	setCSRFHeaderForReq(req, csrfToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, webAdminsPath+"?qlimit=a", nil)
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, webAdminsPath+"?qlimit=1", nil)
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, webAdminPath, nil)
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	form.Set("password", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webAdminPath, altAdminUsername), bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusSeeOther, rr)
 
- 	form.Set(csrfFormToken, "invalid csrf")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webAdminPath, altAdminUsername), bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "unable to verify form token")
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	form.Set("email", "not-an-email")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webAdminPath, altAdminUsername), bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	form.Set("email", "")
 
- 	form.Set("status", "b")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webAdminPath, altAdminUsername), bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	form.Set("email", "[email protected]")
 
- 	form.Set("status", "0")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webAdminPath, altAdminUsername), bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusSeeOther, rr)
 
- 	admin, _, err = httpdtest.GetAdminByUsername(altAdminUsername, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.True(t, admin.Filters.TOTPConfig.Enabled)
 
- 	assert.Equal(t, "[email protected]", admin.Email)
 
- 	assert.Equal(t, 0, admin.Status)
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webAdminPath, altAdminUsername+"1"), bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, path.Join(webAdminPath, altAdminUsername), nil)
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, path.Join(webAdminPath, altAdminUsername+"1"), nil)
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(webAdminPath, altAdminUsername), nil)
 
- 	setJWTCookieForReq(req, token)
 
- 	setCSRFHeaderForReq(req, csrfToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	_, err = httpdtest.RemoveAdmin(admin, http.StatusNotFound)
 
- 	assert.NoError(t, err)
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(webAdminPath, defaultTokenAuthUser), nil)
 
- 	setJWTCookieForReq(req, token)
 
- 	setCSRFHeaderForReq(req, csrfToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "you cannot delete yourself")
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(webAdminPath, defaultTokenAuthUser), nil)
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Invalid token")
 
- }
 
- func TestWebAdminPermissions(t *testing.T) {
 
- 	admin := getTestAdmin()
 
- 	admin.Username = altAdminUsername
 
- 	admin.Password = altAdminPassword
 
- 	admin.Permissions = []string{dataprovider.PermAdminAddUsers}
 
- 	_, _, err := httpdtest.AddAdmin(admin, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	token, err := getJWTWebToken(altAdminUsername, altAdminPassword)
 
- 	require.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodGet, httpBaseURL+webUserPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, token)
 
- 	resp, err := httpclient.GetHTTPClient().Do(req)
 
- 	require.NoError(t, err)
 
- 	defer resp.Body.Close()
 
- 	assert.Equal(t, http.StatusOK, resp.StatusCode)
 
- 	req, err = http.NewRequest(http.MethodGet, httpBaseURL+path.Join(webUserPath, "auser"), nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, token)
 
- 	resp, err = httpclient.GetHTTPClient().Do(req)
 
- 	require.NoError(t, err)
 
- 	defer resp.Body.Close()
 
- 	assert.Equal(t, http.StatusForbidden, resp.StatusCode)
 
- 	req, err = http.NewRequest(http.MethodGet, httpBaseURL+webFolderPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, token)
 
- 	resp, err = httpclient.GetHTTPClient().Do(req)
 
- 	require.NoError(t, err)
 
- 	defer resp.Body.Close()
 
- 	assert.Equal(t, http.StatusOK, resp.StatusCode)
 
- 	req, err = http.NewRequest(http.MethodGet, httpBaseURL+webStatusPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, token)
 
- 	resp, err = httpclient.GetHTTPClient().Do(req)
 
- 	require.NoError(t, err)
 
- 	defer resp.Body.Close()
 
- 	assert.Equal(t, http.StatusForbidden, resp.StatusCode)
 
- 	req, err = http.NewRequest(http.MethodGet, httpBaseURL+webConnectionsPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, token)
 
- 	resp, err = httpclient.GetHTTPClient().Do(req)
 
- 	require.NoError(t, err)
 
- 	defer resp.Body.Close()
 
- 	assert.Equal(t, http.StatusForbidden, resp.StatusCode)
 
- 	req, err = http.NewRequest(http.MethodGet, httpBaseURL+webAdminPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, token)
 
- 	resp, err = httpclient.GetHTTPClient().Do(req)
 
- 	require.NoError(t, err)
 
- 	defer resp.Body.Close()
 
- 	assert.Equal(t, http.StatusForbidden, resp.StatusCode)
 
- 	req, err = http.NewRequest(http.MethodGet, httpBaseURL+path.Join(webAdminPath, "a"), nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, token)
 
- 	resp, err = httpclient.GetHTTPClient().Do(req)
 
- 	require.NoError(t, err)
 
- 	defer resp.Body.Close()
 
- 	assert.Equal(t, http.StatusForbidden, resp.StatusCode)
 
- 	_, err = httpdtest.RemoveAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestAdminUpdateSelfMock(t *testing.T) {
 
- 	admin, _, err := httpdtest.GetAdminByUsername(defaultTokenAuthUser, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	token, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath)
 
- 	assert.NoError(t, err)
 
- 	form := make(url.Values)
 
- 	form.Set("username", admin.Username)
 
- 	form.Set("password", admin.Password)
 
- 	form.Set("status", "0")
 
- 	form.Set("permissions", dataprovider.PermAdminAddUsers)
 
- 	form.Set("permissions", dataprovider.PermAdminCloseConnections)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	req, _ := http.NewRequest(http.MethodPost, path.Join(webAdminPath, defaultTokenAuthUser), bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "You cannot remove these permissions to yourself")
 
- 	form.Set("permissions", dataprovider.PermAdminAny)
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webAdminPath, defaultTokenAuthUser), bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "You cannot disable yourself")
 
- }
 
- func TestWebMaintenanceMock(t *testing.T) {
 
- 	token, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodGet, webMaintenancePath, nil)
 
- 	setJWTCookieForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath)
 
- 	assert.NoError(t, err)
 
- 	form := make(url.Values)
 
- 	form.Set("mode", "a")
 
- 	b, contentType, _ := getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, webRestorePath, &b)
 
- 	setJWTCookieForReq(req, token)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "unable to verify form token")
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, webRestorePath, &b)
 
- 	setJWTCookieForReq(req, token)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	form.Set("mode", "0")
 
- 	form.Set("quota", "a")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, webRestorePath, &b)
 
- 	setJWTCookieForReq(req, token)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	form.Set("quota", "0")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, webRestorePath, &b)
 
- 	setJWTCookieForReq(req, token)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodPost, webRestorePath+"?a=%3", &b)
 
- 	setJWTCookieForReq(req, token)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	backupFilePath := filepath.Join(os.TempDir(), "backup.json")
 
- 	err = createTestFile(backupFilePath, 0)
 
- 	assert.NoError(t, err)
 
- 	b, contentType, _ = getMultipartFormData(form, "backup_file", backupFilePath)
 
- 	req, _ = http.NewRequest(http.MethodPost, webRestorePath, &b)
 
- 	setJWTCookieForReq(req, token)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	err = createTestFile(backupFilePath, 10)
 
- 	assert.NoError(t, err)
 
- 	b, contentType, _ = getMultipartFormData(form, "backup_file", backupFilePath)
 
- 	req, _ = http.NewRequest(http.MethodPost, webRestorePath, &b)
 
- 	setJWTCookieForReq(req, token)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	user := getTestUser()
 
- 	user.ID = 1
 
- 	user.Username = "test_user_web_restore"
 
- 	admin := getTestAdmin()
 
- 	admin.ID = 1
 
- 	admin.Username = "test_admin_web_restore"
 
- 	apiKey := dataprovider.APIKey{
 
- 		Name:  "key name",
 
- 		KeyID: util.GenerateUniqueID(),
 
- 		Key:   fmt.Sprintf("%v.%v", util.GenerateUniqueID(), util.GenerateUniqueID()),
 
- 		Scope: dataprovider.APIKeyScopeAdmin,
 
- 	}
 
- 	backupData := dataprovider.BackupData{}
 
- 	backupData.Users = append(backupData.Users, user)
 
- 	backupData.Admins = append(backupData.Admins, admin)
 
- 	backupData.APIKeys = append(backupData.APIKeys, apiKey)
 
- 	backupContent, err := json.Marshal(backupData)
 
- 	assert.NoError(t, err)
 
- 	err = os.WriteFile(backupFilePath, backupContent, os.ModePerm)
 
- 	assert.NoError(t, err)
 
- 	b, contentType, _ = getMultipartFormData(form, "backup_file", backupFilePath)
 
- 	req, _ = http.NewRequest(http.MethodPost, webRestorePath, &b)
 
- 	setJWTCookieForReq(req, token)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Your backup was successfully restored")
 
- 	user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	admin, _, err = httpdtest.GetAdminByUsername(admin.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.GetAPIKeyByID(apiKey.KeyID, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveAPIKey(apiKey, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.Remove(backupFilePath)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestWebUserAddMock(t *testing.T) {
 
- 	webToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	apiToken, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath)
 
- 	assert.NoError(t, err)
 
- 	user := getTestUser()
 
- 	user.UploadBandwidth = 32
 
- 	user.DownloadBandwidth = 64
 
- 	user.UploadDataTransfer = 1000
 
- 	user.DownloadDataTransfer = 2000
 
- 	user.UID = 1000
 
- 	user.AdditionalInfo = "info"
 
- 	user.Description = "user dsc"
 
- 	user.Email = "[email protected]"
 
- 	mappedDir := filepath.Join(os.TempDir(), "mapped")
 
- 	folderName := filepath.Base(mappedDir)
 
- 	f := vfs.BaseVirtualFolder{
 
- 		Name:       folderName,
 
- 		MappedPath: mappedDir,
 
- 	}
 
- 	folderAsJSON, err := json.Marshal(f)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodPost, folderPath, bytes.NewBuffer(folderAsJSON))
 
- 	setBearerForReq(req, apiToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	form := make(url.Values)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	form.Set("username", user.Username)
 
- 	form.Set("email", user.Email)
 
- 	form.Set("home_dir", user.HomeDir)
 
- 	form.Set("password", user.Password)
 
- 	form.Set("status", strconv.Itoa(user.Status))
 
- 	form.Set("expiration_date", "")
 
- 	form.Set("permissions", "*")
 
- 	form.Set("sub_perm_path0", "/subdir")
 
- 	form.Set("sub_perm_permissions0", "list")
 
- 	form.Add("sub_perm_permissions0", "download")
 
- 	form.Set("vfolder_path", " /vdir")
 
- 	form.Set("vfolder_name", folderName)
 
- 	form.Set("vfolder_quota_size", "1024")
 
- 	form.Set("vfolder_quota_files", "2")
 
- 	form.Set("pattern_path0", "/dir2")
 
- 	form.Set("patterns0", "*.jpg,*.png")
 
- 	form.Set("pattern_type0", "allowed")
 
- 	form.Set("pattern_policy0", "1")
 
- 	form.Set("pattern_path1", "/dir1")
 
- 	form.Set("patterns1", "*.png")
 
- 	form.Set("pattern_type1", "allowed")
 
- 	form.Set("pattern_path2", "/dir1")
 
- 	form.Set("patterns2", "*.zip")
 
- 	form.Set("pattern_type2", "denied")
 
- 	form.Set("pattern_path3", "/dir3")
 
- 	form.Set("patterns3", "*.rar")
 
- 	form.Set("pattern_type3", "denied")
 
- 	form.Set("pattern_path4", "/dir2")
 
- 	form.Set("patterns4", "*.mkv")
 
- 	form.Set("pattern_type4", "denied")
 
- 	form.Set("additional_info", user.AdditionalInfo)
 
- 	form.Set("description", user.Description)
 
- 	form.Add("hooks", "external_auth_disabled")
 
- 	form.Set("disable_fs_checks", "checked")
 
- 	form.Set("total_data_transfer", "0")
 
- 	form.Set("external_auth_cache_time", "0")
 
- 	b, contentType, _ := getMultipartFormData(form, "", "")
 
- 	// test invalid url escape
 
- 	req, _ = http.NewRequest(http.MethodPost, webUserPath+"?a=%2", &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	form.Set("public_keys", testPubKey)
 
- 	form.Add("public_keys", testPubKey1)
 
- 	form.Set("uid", strconv.FormatInt(int64(user.UID), 10))
 
- 	form.Set("gid", "a")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	// test invalid gid
 
- 	req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	form.Set("gid", "0")
 
- 	form.Set("max_sessions", "a")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	// test invalid max sessions
 
- 	req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	form.Set("max_sessions", "0")
 
- 	form.Set("quota_size", "a")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	// test invalid quota size
 
- 	req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	form.Set("quota_size", "0")
 
- 	form.Set("quota_files", "a")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	// test invalid quota files
 
- 	req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	form.Set("quota_files", "0")
 
- 	form.Set("upload_bandwidth", "a")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	// test invalid upload bandwidth
 
- 	req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	form.Set("upload_bandwidth", strconv.FormatInt(user.UploadBandwidth, 10))
 
- 	form.Set("download_bandwidth", "a")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	// test invalid download bandwidth
 
- 	req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	form.Set("download_bandwidth", strconv.FormatInt(user.DownloadBandwidth, 10))
 
- 	form.Set("upload_data_transfer", "a")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	// test invalid upload data transfer
 
- 	req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	form.Set("upload_data_transfer", strconv.FormatInt(user.UploadDataTransfer, 10))
 
- 	form.Set("download_data_transfer", "a")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	// test invalid download data transfer
 
- 	req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	form.Set("download_data_transfer", strconv.FormatInt(user.DownloadDataTransfer, 10))
 
- 	form.Set("total_data_transfer", "a")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	// test invalid total data transfer
 
- 	req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	form.Set("total_data_transfer", strconv.FormatInt(user.TotalDataTransfer, 10))
 
- 	form.Set("status", "a")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	// test invalid status
 
- 	req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	form.Set("status", strconv.Itoa(user.Status))
 
- 	form.Set("expiration_date", "123")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	// test invalid expiration date
 
- 	req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	form.Set("expiration_date", "")
 
- 	form.Set("allowed_ip", "invalid,ip")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	// test invalid allowed_ip
 
- 	req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	form.Set("allowed_ip", "")
 
- 	form.Set("denied_ip", "192.168.1.2") // it should be 192.168.1.2/32
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	// test invalid denied_ip
 
- 	req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	form.Set("denied_ip", "")
 
- 	// test invalid max file upload size
 
- 	form.Set("max_upload_file_size", "a")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	form.Set("max_upload_file_size", "1000")
 
- 	// test invalid tls username
 
- 	form.Set("tls_username", "username")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Validation error: invalid TLS username")
 
- 	form.Set("tls_username", string(sdk.TLSUsernameNone))
 
- 	// invalid upload_bandwidth_source0
 
- 	form.Set("bandwidth_limit_sources0", "192.168.1.0/24, 192.168.2.0/25")
 
- 	form.Set("upload_bandwidth_source0", "a")
 
- 	form.Set("download_bandwidth_source0", "0")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "invalid upload_bandwidth_source")
 
- 	// invalid download_bandwidth_source0
 
- 	form.Set("upload_bandwidth_source0", "256")
 
- 	form.Set("download_bandwidth_source0", "a")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "invalid download_bandwidth_source")
 
- 	form.Set("download_bandwidth_source0", "512")
 
- 	form.Set("download_bandwidth_source1", "1024")
 
- 	form.Set("bandwidth_limit_sources1", "1.1.1")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Validation error: could not parse bandwidth limit source")
 
- 	form.Set("bandwidth_limit_sources1", "127.0.0.1/32")
 
- 	form.Set("upload_bandwidth_source1", "-1")
 
- 	form.Set("data_transfer_limit_sources0", "127.0.1.1")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "could not parse data transfer limit source")
 
- 	form.Set("data_transfer_limit_sources0", "127.0.1.1/32")
 
- 	form.Set("upload_data_transfer_source0", "a")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "invalid upload_data_transfer_source")
 
- 	form.Set("upload_data_transfer_source0", "0")
 
- 	form.Set("download_data_transfer_source0", "a")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "invalid download_data_transfer_source")
 
- 	form.Set("download_data_transfer_source0", "0")
 
- 	form.Set("total_data_transfer_source0", "a")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "invalid total_data_transfer_source")
 
- 	form.Set("total_data_transfer_source0", "0")
 
- 	form.Set("data_transfer_limit_sources10", "192.168.5.0/24, 10.8.0.0/16")
 
- 	form.Set("download_data_transfer_source10", "100")
 
- 	form.Set("upload_data_transfer_source10", "120")
 
- 	form.Set("data_transfer_limit_sources12", "192.168.3.0/24, 10.8.2.0/24,::1/64")
 
- 	form.Set("download_data_transfer_source12", "100")
 
- 	form.Set("upload_data_transfer_source12", "120")
 
- 	form.Set("total_data_transfer_source12", "200")
 
- 	// invalid external auth cache size
 
- 	form.Set("external_auth_cache_time", "a")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	form.Set("external_auth_cache_time", "0")
 
- 	form.Set(csrfFormToken, "invalid form token")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "unable to verify form token")
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusSeeOther, rr)
 
- 	dbUser, err := dataprovider.UserExists(user.Username)
 
- 	assert.NoError(t, err)
 
- 	assert.NotEmpty(t, dbUser.Password)
 
- 	assert.True(t, dbUser.IsPasswordHashed())
 
- 	// the user already exists, was created with the above request
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	newUser := dataprovider.User{}
 
- 	err = render.DecodeJSON(rr.Body, &newUser)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, user.UID, newUser.UID)
 
- 	assert.Equal(t, user.UploadBandwidth, newUser.UploadBandwidth)
 
- 	assert.Equal(t, user.DownloadBandwidth, newUser.DownloadBandwidth)
 
- 	assert.Equal(t, user.UploadDataTransfer, newUser.UploadDataTransfer)
 
- 	assert.Equal(t, user.DownloadDataTransfer, newUser.DownloadDataTransfer)
 
- 	assert.Equal(t, user.TotalDataTransfer, newUser.TotalDataTransfer)
 
- 	assert.Equal(t, int64(1000), newUser.Filters.MaxUploadFileSize)
 
- 	assert.Equal(t, user.AdditionalInfo, newUser.AdditionalInfo)
 
- 	assert.Equal(t, user.Description, newUser.Description)
 
- 	assert.True(t, newUser.Filters.Hooks.ExternalAuthDisabled)
 
- 	assert.False(t, newUser.Filters.Hooks.PreLoginDisabled)
 
- 	assert.False(t, newUser.Filters.Hooks.CheckPasswordDisabled)
 
- 	assert.True(t, newUser.Filters.DisableFsChecks)
 
- 	assert.False(t, newUser.Filters.AllowAPIKeyAuth)
 
- 	assert.Equal(t, user.Email, newUser.Email)
 
- 	assert.True(t, util.IsStringInSlice(testPubKey, newUser.PublicKeys))
 
- 	if val, ok := newUser.Permissions["/subdir"]; ok {
 
- 		assert.True(t, util.IsStringInSlice(dataprovider.PermListItems, val))
 
- 		assert.True(t, util.IsStringInSlice(dataprovider.PermDownload, val))
 
- 	} else {
 
- 		assert.Fail(t, "user permissions must contain /somedir", "actual: %v", newUser.Permissions)
 
- 	}
 
- 	assert.Len(t, newUser.PublicKeys, 2)
 
- 	assert.Len(t, newUser.VirtualFolders, 1)
 
- 	for _, v := range newUser.VirtualFolders {
 
- 		assert.Equal(t, v.VirtualPath, "/vdir")
 
- 		assert.Equal(t, v.Name, folderName)
 
- 		assert.Equal(t, v.MappedPath, mappedDir)
 
- 		assert.Equal(t, v.QuotaFiles, 2)
 
- 		assert.Equal(t, v.QuotaSize, int64(1024))
 
- 	}
 
- 	assert.Len(t, newUser.Filters.FilePatterns, 3)
 
- 	for _, filter := range newUser.Filters.FilePatterns {
 
- 		switch filter.Path {
 
- 		case "/dir1":
 
- 			assert.Len(t, filter.DeniedPatterns, 1)
 
- 			assert.Len(t, filter.AllowedPatterns, 1)
 
- 			assert.True(t, util.IsStringInSlice("*.png", filter.AllowedPatterns))
 
- 			assert.True(t, util.IsStringInSlice("*.zip", filter.DeniedPatterns))
 
- 			assert.Equal(t, sdk.DenyPolicyDefault, filter.DenyPolicy)
 
- 		case "/dir2":
 
- 			assert.Len(t, filter.DeniedPatterns, 1)
 
- 			assert.Len(t, filter.AllowedPatterns, 2)
 
- 			assert.True(t, util.IsStringInSlice("*.jpg", filter.AllowedPatterns))
 
- 			assert.True(t, util.IsStringInSlice("*.png", filter.AllowedPatterns))
 
- 			assert.True(t, util.IsStringInSlice("*.mkv", filter.DeniedPatterns))
 
- 			assert.Equal(t, sdk.DenyPolicyHide, filter.DenyPolicy)
 
- 		case "/dir3":
 
- 			assert.Len(t, filter.DeniedPatterns, 1)
 
- 			assert.Len(t, filter.AllowedPatterns, 0)
 
- 			assert.True(t, util.IsStringInSlice("*.rar", filter.DeniedPatterns))
 
- 			assert.Equal(t, sdk.DenyPolicyDefault, filter.DenyPolicy)
 
- 		}
 
- 	}
 
- 	if assert.Len(t, newUser.Filters.BandwidthLimits, 2) {
 
- 		for _, bwLimit := range newUser.Filters.BandwidthLimits {
 
- 			if len(bwLimit.Sources) == 2 {
 
- 				assert.Equal(t, "192.168.1.0/24", bwLimit.Sources[0])
 
- 				assert.Equal(t, "192.168.2.0/25", bwLimit.Sources[1])
 
- 				assert.Equal(t, int64(256), bwLimit.UploadBandwidth)
 
- 				assert.Equal(t, int64(512), bwLimit.DownloadBandwidth)
 
- 			} else {
 
- 				assert.Equal(t, []string{"127.0.0.1/32"}, bwLimit.Sources)
 
- 				assert.Equal(t, int64(0), bwLimit.UploadBandwidth)
 
- 				assert.Equal(t, int64(1024), bwLimit.DownloadBandwidth)
 
- 			}
 
- 		}
 
- 	}
 
- 	if assert.Len(t, newUser.Filters.DataTransferLimits, 3) {
 
- 		for _, dtLimit := range newUser.Filters.DataTransferLimits {
 
- 			switch len(dtLimit.Sources) {
 
- 			case 3:
 
- 				assert.Equal(t, "192.168.3.0/24", dtLimit.Sources[0])
 
- 				assert.Equal(t, "10.8.2.0/24", dtLimit.Sources[1])
 
- 				assert.Equal(t, "::1/64", dtLimit.Sources[2])
 
- 				assert.Equal(t, int64(0), dtLimit.UploadDataTransfer)
 
- 				assert.Equal(t, int64(0), dtLimit.DownloadDataTransfer)
 
- 				assert.Equal(t, int64(200), dtLimit.TotalDataTransfer)
 
- 			case 2:
 
- 				assert.Equal(t, "192.168.5.0/24", dtLimit.Sources[0])
 
- 				assert.Equal(t, "10.8.0.0/16", dtLimit.Sources[1])
 
- 				assert.Equal(t, int64(120), dtLimit.UploadDataTransfer)
 
- 				assert.Equal(t, int64(100), dtLimit.DownloadDataTransfer)
 
- 				assert.Equal(t, int64(0), dtLimit.TotalDataTransfer)
 
- 			case 1:
 
- 				assert.Equal(t, "127.0.1.1/32", dtLimit.Sources[0])
 
- 				assert.Equal(t, int64(0), dtLimit.UploadDataTransfer)
 
- 				assert.Equal(t, int64(0), dtLimit.DownloadDataTransfer)
 
- 				assert.Equal(t, int64(0), dtLimit.TotalDataTransfer)
 
- 			}
 
- 		}
 
- 	}
 
- 	assert.Equal(t, sdk.TLSUsernameNone, newUser.Filters.TLSUsername)
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(userPath, newUser.Username), nil)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(folderPath, folderName), nil)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- }
 
- func TestWebUserUpdateMock(t *testing.T) {
 
- 	webToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	apiToken, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath)
 
- 	assert.NoError(t, err)
 
- 	user := getTestUser()
 
- 	user.Filters.BandwidthLimits = []sdk.BandwidthLimit{
 
- 		{
 
- 			Sources:           []string{"10.8.0.0/16", "192.168.1.0/25"},
 
- 			UploadBandwidth:   256,
 
- 			DownloadBandwidth: 512,
 
- 		},
 
- 	}
 
- 	user.TotalDataTransfer = 4000
 
- 	userAsJSON := getUserAsJSON(t, user)
 
- 	req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
 
- 	setBearerForReq(req, apiToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	// add TOTP config
 
- 	configName, _, secret, _, err := mfa.GenerateTOTPSecret(mfa.GetAvailableTOTPConfigNames()[0], user.Username)
 
- 	assert.NoError(t, err)
 
- 	userToken, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	userTOTPConfig := dataprovider.UserTOTPConfig{
 
- 		Enabled:    true,
 
- 		ConfigName: configName,
 
- 		Secret:     kms.NewPlainSecret(secret),
 
- 		Protocols:  []string{common.ProtocolSSH, common.ProtocolFTP},
 
- 	}
 
- 	asJSON, err := json.Marshal(userTOTPConfig)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, webClientTOTPSavePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, userToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Invalid token")
 
- 	req, err = http.NewRequest(http.MethodPost, webClientTOTPSavePath, bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, userToken)
 
- 	setCSRFHeaderForReq(req, csrfToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	assert.True(t, user.Filters.TOTPConfig.Enabled)
 
- 	assert.Equal(t, int64(4000), user.TotalDataTransfer)
 
- 	if assert.Len(t, user.Filters.BandwidthLimits, 1) {
 
- 		if assert.Len(t, user.Filters.BandwidthLimits[0].Sources, 2) {
 
- 			assert.Equal(t, "10.8.0.0/16", user.Filters.BandwidthLimits[0].Sources[0])
 
- 			assert.Equal(t, "192.168.1.0/25", user.Filters.BandwidthLimits[0].Sources[1])
 
- 		}
 
- 		assert.Equal(t, int64(256), user.Filters.BandwidthLimits[0].UploadBandwidth)
 
- 		assert.Equal(t, int64(512), user.Filters.BandwidthLimits[0].DownloadBandwidth)
 
- 	}
 
- 	dbUser, err := dataprovider.UserExists(user.Username)
 
- 	assert.NoError(t, err)
 
- 	assert.NotEmpty(t, dbUser.Password)
 
- 	assert.True(t, dbUser.IsPasswordHashed())
 
- 	err = render.DecodeJSON(rr.Body, &user)
 
- 	assert.NoError(t, err)
 
- 	user.MaxSessions = 1
 
- 	user.QuotaFiles = 2
 
- 	user.QuotaSize = 3
 
- 	user.GID = 1000
 
- 	user.Filters.AllowAPIKeyAuth = true
 
- 	user.AdditionalInfo = "new additional info"
 
- 	user.Email = "[email protected]"
 
- 	form := make(url.Values)
 
- 	form.Set("username", user.Username)
 
- 	form.Set("email", user.Email)
 
- 	form.Set("password", "")
 
- 	form.Set("public_keys", testPubKey)
 
- 	form.Set("home_dir", user.HomeDir)
 
- 	form.Set("uid", "0")
 
- 	form.Set("gid", strconv.FormatInt(int64(user.GID), 10))
 
- 	form.Set("max_sessions", strconv.FormatInt(int64(user.MaxSessions), 10))
 
- 	form.Set("quota_size", strconv.FormatInt(user.QuotaSize, 10))
 
- 	form.Set("quota_files", strconv.FormatInt(int64(user.QuotaFiles), 10))
 
- 	form.Set("upload_bandwidth", "0")
 
- 	form.Set("download_bandwidth", "0")
 
- 	form.Set("upload_data_transfer", "0")
 
- 	form.Set("download_data_transfer", "0")
 
- 	form.Set("total_data_transfer", "0")
 
- 	form.Set("permissions", "*")
 
- 	form.Set("sub_perm_path0", "/otherdir")
 
- 	form.Set("sub_perm_permissions0", "list")
 
- 	form.Add("sub_perm_permissions0", "upload")
 
- 	form.Set("status", strconv.Itoa(user.Status))
 
- 	form.Set("expiration_date", "2020-01-01 00:00:00")
 
- 	form.Set("allowed_ip", " 192.168.1.3/32, 192.168.2.0/24 ")
 
- 	form.Set("denied_ip", " 10.0.0.2/32 ")
 
- 	form.Set("pattern_path0", "/dir1")
 
- 	form.Set("patterns0", "*.zip")
 
- 	form.Set("pattern_type0", "denied")
 
- 	form.Set("ssh_login_methods", dataprovider.SSHLoginMethodKeyboardInteractive)
 
- 	form.Set("denied_protocols", common.ProtocolFTP)
 
- 	form.Set("max_upload_file_size", "100")
 
- 	form.Set("disconnect", "1")
 
- 	form.Set("additional_info", user.AdditionalInfo)
 
- 	form.Set("description", user.Description)
 
- 	form.Set("tls_username", string(sdk.TLSUsernameCN))
 
- 	form.Set("allow_api_key_auth", "1")
 
- 	form.Set("external_auth_cache_time", "120")
 
- 	b, contentType, _ := getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "unable to verify form token")
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusSeeOther, rr)
 
- 	dbUser, err = dataprovider.UserExists(user.Username)
 
- 	assert.NoError(t, err)
 
- 	assert.Empty(t, dbUser.Password)
 
- 	assert.False(t, dbUser.IsPasswordHashed())
 
- 	form.Set("password", defaultPassword)
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusSeeOther, rr)
 
- 	dbUser, err = dataprovider.UserExists(user.Username)
 
- 	assert.NoError(t, err)
 
- 	assert.NotEmpty(t, dbUser.Password)
 
- 	assert.True(t, dbUser.IsPasswordHashed())
 
- 	prevPwd := dbUser.Password
 
- 	form.Set("password", redactedSecret)
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusSeeOther, rr)
 
- 	dbUser, err = dataprovider.UserExists(user.Username)
 
- 	assert.NoError(t, err)
 
- 	assert.NotEmpty(t, dbUser.Password)
 
- 	assert.True(t, dbUser.IsPasswordHashed())
 
- 	assert.Equal(t, prevPwd, dbUser.Password)
 
- 	assert.True(t, dbUser.Filters.TOTPConfig.Enabled)
 
- 	req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var updateUser dataprovider.User
 
- 	err = render.DecodeJSON(rr.Body, &updateUser)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, user.Email, updateUser.Email)
 
- 	assert.Equal(t, user.HomeDir, updateUser.HomeDir)
 
- 	assert.Equal(t, user.MaxSessions, updateUser.MaxSessions)
 
- 	assert.Equal(t, user.QuotaFiles, updateUser.QuotaFiles)
 
- 	assert.Equal(t, user.QuotaSize, updateUser.QuotaSize)
 
- 	assert.Equal(t, user.UID, updateUser.UID)
 
- 	assert.Equal(t, user.GID, updateUser.GID)
 
- 	assert.Equal(t, user.AdditionalInfo, updateUser.AdditionalInfo)
 
- 	assert.Equal(t, user.Description, updateUser.Description)
 
- 	assert.Equal(t, int64(100), updateUser.Filters.MaxUploadFileSize)
 
- 	assert.Equal(t, sdk.TLSUsernameCN, updateUser.Filters.TLSUsername)
 
- 	assert.True(t, updateUser.Filters.AllowAPIKeyAuth)
 
- 	assert.True(t, updateUser.Filters.TOTPConfig.Enabled)
 
- 	assert.Equal(t, int64(0), updateUser.TotalDataTransfer)
 
- 	assert.Equal(t, int64(0), updateUser.DownloadDataTransfer)
 
- 	assert.Equal(t, int64(0), updateUser.UploadDataTransfer)
 
- 	assert.Equal(t, int64(0), updateUser.Filters.ExternalAuthCacheTime)
 
- 	if val, ok := updateUser.Permissions["/otherdir"]; ok {
 
- 		assert.True(t, util.IsStringInSlice(dataprovider.PermListItems, val))
 
- 		assert.True(t, util.IsStringInSlice(dataprovider.PermUpload, val))
 
- 	} else {
 
- 		assert.Fail(t, "user permissions must contains /otherdir", "actual: %v", updateUser.Permissions)
 
- 	}
 
- 	assert.True(t, util.IsStringInSlice("192.168.1.3/32", updateUser.Filters.AllowedIP))
 
- 	assert.True(t, util.IsStringInSlice("10.0.0.2/32", updateUser.Filters.DeniedIP))
 
- 	assert.True(t, util.IsStringInSlice(dataprovider.SSHLoginMethodKeyboardInteractive, updateUser.Filters.DeniedLoginMethods))
 
- 	assert.True(t, util.IsStringInSlice(common.ProtocolFTP, updateUser.Filters.DeniedProtocols))
 
- 	assert.True(t, util.IsStringInSlice("*.zip", updateUser.Filters.FilePatterns[0].DeniedPatterns))
 
- 	assert.Len(t, updateUser.Filters.BandwidthLimits, 0)
 
- 	req, err = http.NewRequest(http.MethodDelete, path.Join(userPath, user.Username), nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- }
 
- func TestRenderFolderTemplateMock(t *testing.T) {
 
- 	token, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodGet, webTemplateFolder, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	folder := vfs.BaseVirtualFolder{
 
- 		Name:        "templatefolder",
 
- 		MappedPath:  filepath.Join(os.TempDir(), "mapped"),
 
- 		Description: "template folder desc",
 
- 	}
 
- 	folder, _, err = httpdtest.AddFolder(folder, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, webTemplateFolder+fmt.Sprintf("?from=%v", folder.Name), nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, webTemplateFolder+"?from=unknown-folder", nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	_, err = httpdtest.RemoveFolder(folder, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestRenderUserTemplateMock(t *testing.T) {
 
- 	token, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodGet, webTemplateUser, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, webTemplateUser+fmt.Sprintf("?from=%v", user.Username), nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, webTemplateUser+"?from=unknown", nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUserTemplateWithFoldersMock(t *testing.T) {
 
- 	folder := vfs.BaseVirtualFolder{
 
- 		Name:        "vfolder",
 
- 		MappedPath:  filepath.Join(os.TempDir(), "mapped"),
 
- 		Description: "vfolder desc with spéciàl ch@rs",
 
- 	}
 
- 	token, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath)
 
- 	assert.NoError(t, err)
 
- 	user := getTestUser()
 
- 	form := make(url.Values)
 
- 	form.Set("username", user.Username)
 
- 	form.Set("home_dir", filepath.Join(os.TempDir(), "%username%"))
 
- 	form.Set("uid", strconv.FormatInt(int64(user.UID), 10))
 
- 	form.Set("gid", strconv.FormatInt(int64(user.GID), 10))
 
- 	form.Set("max_sessions", strconv.FormatInt(int64(user.MaxSessions), 10))
 
- 	form.Set("quota_size", strconv.FormatInt(user.QuotaSize, 10))
 
- 	form.Set("quota_files", strconv.FormatInt(int64(user.QuotaFiles), 10))
 
- 	form.Set("upload_bandwidth", "0")
 
- 	form.Set("download_bandwidth", "0")
 
- 	form.Set("upload_data_transfer", "0")
 
- 	form.Set("download_data_transfer", "0")
 
- 	form.Set("total_data_transfer", "0")
 
- 	form.Set("permissions", "*")
 
- 	form.Set("status", strconv.Itoa(user.Status))
 
- 	form.Set("expiration_date", "2020-01-01 00:00:00")
 
- 	form.Set("fs_provider", "0")
 
- 	form.Set("max_upload_file_size", "0")
 
- 	form.Set("external_auth_cache_time", "0")
 
- 	form.Set("description", "desc %username% %password%")
 
- 	form.Set("vfolder_path", "/vdir%username%")
 
- 	form.Set("vfolder_name", folder.Name)
 
- 	form.Set("vfolder_quota_size", "-1")
 
- 	form.Set("vfolder_quota_files", "-1")
 
- 	form.Add("tpl_username", "auser1")
 
- 	form.Add("tpl_password", "password1")
 
- 	form.Add("tpl_public_keys", " ")
 
- 	form.Add("tpl_username", "auser2")
 
- 	form.Add("tpl_password", "password2")
 
- 	form.Add("tpl_public_keys", testPubKey)
 
- 	form.Add("tpl_username", "auser1")
 
- 	form.Add("tpl_password", "password")
 
- 	form.Add("tpl_public_keys", "")
 
- 	form.Set("form_action", "export_from_template")
 
- 	b, contentType, _ := getMultipartFormData(form, "", "")
 
- 	req, _ := http.NewRequest(http.MethodPost, path.Join(webTemplateUser), &b)
 
- 	setJWTCookieForReq(req, token)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	require.Contains(t, rr.Body.String(), "unable to verify form token")
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webTemplateUser), &b)
 
- 	setJWTCookieForReq(req, token)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	require.Contains(t, rr.Body.String(), "invalid folder mapped path")
 
- 	folder, resp, err := httpdtest.AddFolder(folder, http.StatusCreated)
 
- 	assert.NoError(t, err, string(resp))
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webTemplateUser), &b)
 
- 	setJWTCookieForReq(req, token)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var dump dataprovider.BackupData
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &dump)
 
- 	assert.NoError(t, err)
 
- 	assert.Len(t, dump.Users, 2)
 
- 	assert.Len(t, dump.Folders, 1)
 
- 	user1 := dump.Users[0]
 
- 	user2 := dump.Users[1]
 
- 	folder1 := dump.Folders[0]
 
- 	assert.Equal(t, "auser1", user1.Username)
 
- 	assert.Equal(t, "auser2", user2.Username)
 
- 	assert.Equal(t, "desc auser1 password1", user1.Description)
 
- 	assert.Equal(t, "desc auser2 password2", user2.Description)
 
- 	assert.Equal(t, filepath.Join(os.TempDir(), user1.Username), user1.HomeDir)
 
- 	assert.Equal(t, filepath.Join(os.TempDir(), user2.Username), user2.HomeDir)
 
- 	assert.Equal(t, folder.Name, folder1.Name)
 
- 	assert.Equal(t, folder.MappedPath, folder1.MappedPath)
 
- 	assert.Equal(t, folder.Description, folder1.Description)
 
- 	assert.Len(t, user1.PublicKeys, 0)
 
- 	assert.Len(t, user2.PublicKeys, 1)
 
- 	assert.Len(t, user1.VirtualFolders, 1)
 
- 	assert.Len(t, user2.VirtualFolders, 1)
 
- 	assert.Equal(t, "/vdirauser1", user1.VirtualFolders[0].VirtualPath)
 
- 	assert.Equal(t, "/vdirauser2", user2.VirtualFolders[0].VirtualPath)
 
- 	_, err = httpdtest.RemoveFolder(folder, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUserSaveFromTemplateMock(t *testing.T) {
 
- 	token, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath)
 
- 	assert.NoError(t, err)
 
- 	user1 := "u1"
 
- 	user2 := "u2"
 
- 	form := make(url.Values)
 
- 	form.Set("username", "")
 
- 	form.Set("home_dir", filepath.Join(os.TempDir(), "%username%"))
 
- 	form.Set("upload_bandwidth", "0")
 
- 	form.Set("download_bandwidth", "0")
 
- 	form.Set("upload_data_transfer", "0")
 
- 	form.Set("download_data_transfer", "0")
 
- 	form.Set("total_data_transfer", "0")
 
- 	form.Set("uid", "0")
 
- 	form.Set("gid", "0")
 
- 	form.Set("max_sessions", "0")
 
- 	form.Set("quota_size", "0")
 
- 	form.Set("quota_files", "0")
 
- 	form.Set("permissions", "*")
 
- 	form.Set("status", "1")
 
- 	form.Set("expiration_date", "")
 
- 	form.Set("fs_provider", "0")
 
- 	form.Set("max_upload_file_size", "0")
 
- 	form.Set("external_auth_cache_time", "0")
 
- 	form.Add("tpl_username", user1)
 
- 	form.Add("tpl_password", "password1")
 
- 	form.Add("tpl_public_keys", " ")
 
- 	form.Add("tpl_username", user2)
 
- 	form.Add("tpl_public_keys", testPubKey)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	b, contentType, _ := getMultipartFormData(form, "", "")
 
- 	req, _ := http.NewRequest(http.MethodPost, webTemplateUser, &b)
 
- 	setJWTCookieForReq(req, token)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusSeeOther, rr)
 
- 	u1, _, err := httpdtest.GetUserByUsername(user1, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	u2, _, err := httpdtest.GetUserByUsername(user2, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(u1, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveUser(u2, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = dataprovider.Close()
 
- 	assert.NoError(t, err)
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, err = http.NewRequest(http.MethodPost, webTemplateUser, &b)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, token)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusInternalServerError, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Cannot save the defined users")
 
- 	err = config.LoadConfig(configDir, "")
 
- 	assert.NoError(t, err)
 
- 	providerConf := config.GetProviderConf()
 
- 	providerConf.CredentialsPath = credentialsPath
 
- 	err = os.RemoveAll(credentialsPath)
 
- 	assert.NoError(t, err)
 
- 	err = dataprovider.Initialize(providerConf, configDir, true)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUserTemplateMock(t *testing.T) {
 
- 	token, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	user := getTestUser()
 
- 	user.FsConfig.Provider = sdk.S3FilesystemProvider
 
- 	user.FsConfig.S3Config.Bucket = "test"
 
- 	user.FsConfig.S3Config.Region = "eu-central-1"
 
- 	user.FsConfig.S3Config.AccessKey = "%username%"
 
- 	user.FsConfig.S3Config.KeyPrefix = "somedir/subdir/"
 
- 	user.FsConfig.S3Config.UploadPartSize = 5
 
- 	user.FsConfig.S3Config.UploadConcurrency = 4
 
- 	user.FsConfig.S3Config.DownloadPartSize = 6
 
- 	user.FsConfig.S3Config.DownloadConcurrency = 3
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath)
 
- 	assert.NoError(t, err)
 
- 	form := make(url.Values)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	form.Set("username", user.Username)
 
- 	form.Set("home_dir", filepath.Join(os.TempDir(), "%username%"))
 
- 	form.Set("uid", "0")
 
- 	form.Set("gid", strconv.FormatInt(int64(user.GID), 10))
 
- 	form.Set("max_sessions", strconv.FormatInt(int64(user.MaxSessions), 10))
 
- 	form.Set("quota_size", strconv.FormatInt(user.QuotaSize, 10))
 
- 	form.Set("quota_files", strconv.FormatInt(int64(user.QuotaFiles), 10))
 
- 	form.Set("upload_bandwidth", "0")
 
- 	form.Set("download_bandwidth", "0")
 
- 	form.Set("upload_data_transfer", "0")
 
- 	form.Set("download_data_transfer", "0")
 
- 	form.Set("total_data_transfer", "0")
 
- 	form.Set("external_auth_cache_time", "0")
 
- 	form.Set("permissions", "*")
 
- 	form.Set("status", strconv.Itoa(user.Status))
 
- 	form.Set("expiration_date", "2020-01-01 00:00:00")
 
- 	form.Set("allowed_ip", "")
 
- 	form.Set("denied_ip", "")
 
- 	form.Set("fs_provider", "1")
 
- 	form.Set("s3_bucket", user.FsConfig.S3Config.Bucket)
 
- 	form.Set("s3_region", user.FsConfig.S3Config.Region)
 
- 	form.Set("s3_access_key", "%username%")
 
- 	form.Set("s3_access_secret", "%password%")
 
- 	form.Set("s3_key_prefix", "base/%username%")
 
- 	form.Set("allowed_extensions", "/dir1::.jpg,.png")
 
- 	form.Set("denied_extensions", "/dir2::.zip")
 
- 	form.Set("max_upload_file_size", "0")
 
- 	form.Add("hooks", "external_auth_disabled")
 
- 	form.Add("hooks", "check_password_disabled")
 
- 	form.Set("disable_fs_checks", "checked")
 
- 	form.Set("s3_download_part_max_time", "0")
 
- 	form.Set("s3_upload_part_max_time", "0")
 
- 	// test invalid s3_upload_part_size
 
- 	form.Set("s3_upload_part_size", "a")
 
- 	form.Set("form_action", "export_from_template")
 
- 	b, contentType, _ := getMultipartFormData(form, "", "")
 
- 	req, _ := http.NewRequest(http.MethodPost, webTemplateUser, &b)
 
- 	setJWTCookieForReq(req, token)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	form.Set("s3_upload_part_size", strconv.FormatInt(user.FsConfig.S3Config.UploadPartSize, 10))
 
- 	form.Set("s3_upload_concurrency", strconv.Itoa(user.FsConfig.S3Config.UploadConcurrency))
 
- 	form.Set("s3_download_part_size", strconv.FormatInt(user.FsConfig.S3Config.DownloadPartSize, 10))
 
- 	form.Set("s3_download_concurrency", strconv.Itoa(user.FsConfig.S3Config.DownloadConcurrency))
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, webTemplateUser, &b)
 
- 	setJWTCookieForReq(req, token)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	form.Set("tpl_username", "user1")
 
- 	form.Set("tpl_password", "password1")
 
- 	form.Set("tpl_public_keys", "invalid-pkey")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, webTemplateUser, &b)
 
- 	setJWTCookieForReq(req, token)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	require.Contains(t, rr.Body.String(), "Error validating user")
 
- 	form.Set("tpl_username", "user1")
 
- 	form.Set("tpl_password", " ")
 
- 	form.Set("tpl_public_keys", "")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, webTemplateUser, &b)
 
- 	setJWTCookieForReq(req, token)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	require.Contains(t, rr.Body.String(), "No valid users defined, unable to complete the requested action")
 
- 	form.Set("tpl_username", "user1")
 
- 	form.Set("tpl_password", "password1")
 
- 	form.Set("tpl_public_keys", " ")
 
- 	form.Add("tpl_username", "user2")
 
- 	form.Add("tpl_password", "password2")
 
- 	form.Add("tpl_public_keys", testPubKey)
 
- 	form.Add("tpl_username", "user3")
 
- 	form.Add("tpl_password", "")
 
- 	form.Add("tpl_public_keys", "")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, webTemplateUser, &b)
 
- 	setJWTCookieForReq(req, token)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var dump dataprovider.BackupData
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &dump)
 
- 	require.NoError(t, err)
 
- 	require.Len(t, dump.Users, 2)
 
- 	require.Len(t, dump.Admins, 0)
 
- 	require.Len(t, dump.Folders, 0)
 
- 	user1 := dump.Users[0]
 
- 	user2 := dump.Users[1]
 
- 	require.Equal(t, "user1", user1.Username)
 
- 	require.Equal(t, sdk.S3FilesystemProvider, user1.FsConfig.Provider)
 
- 	require.Equal(t, "user2", user2.Username)
 
- 	require.Equal(t, sdk.S3FilesystemProvider, user2.FsConfig.Provider)
 
- 	require.Len(t, user2.PublicKeys, 1)
 
- 	require.Equal(t, filepath.Join(os.TempDir(), user1.Username), user1.HomeDir)
 
- 	require.Equal(t, filepath.Join(os.TempDir(), user2.Username), user2.HomeDir)
 
- 	require.Equal(t, user1.Username, user1.FsConfig.S3Config.AccessKey)
 
- 	require.Equal(t, user2.Username, user2.FsConfig.S3Config.AccessKey)
 
- 	require.Equal(t, path.Join("base", user1.Username)+"/", user1.FsConfig.S3Config.KeyPrefix)
 
- 	require.Equal(t, path.Join("base", user2.Username)+"/", user2.FsConfig.S3Config.KeyPrefix)
 
- 	require.True(t, user1.FsConfig.S3Config.AccessSecret.IsEncrypted())
 
- 	err = user1.FsConfig.S3Config.AccessSecret.Decrypt()
 
- 	require.NoError(t, err)
 
- 	require.Equal(t, "password1", user1.FsConfig.S3Config.AccessSecret.GetPayload())
 
- 	require.True(t, user2.FsConfig.S3Config.AccessSecret.IsEncrypted())
 
- 	err = user2.FsConfig.S3Config.AccessSecret.Decrypt()
 
- 	require.NoError(t, err)
 
- 	require.Equal(t, "password2", user2.FsConfig.S3Config.AccessSecret.GetPayload())
 
- 	require.True(t, user1.Filters.Hooks.ExternalAuthDisabled)
 
- 	require.True(t, user1.Filters.Hooks.CheckPasswordDisabled)
 
- 	require.False(t, user1.Filters.Hooks.PreLoginDisabled)
 
- 	require.True(t, user2.Filters.Hooks.ExternalAuthDisabled)
 
- 	require.True(t, user2.Filters.Hooks.CheckPasswordDisabled)
 
- 	require.False(t, user2.Filters.Hooks.PreLoginDisabled)
 
- 	require.True(t, user1.Filters.DisableFsChecks)
 
- 	require.True(t, user2.Filters.DisableFsChecks)
 
- }
 
- func TestFolderSaveFromTemplateMock(t *testing.T) {
 
- 	folder1 := "f1"
 
- 	folder2 := "f2"
 
- 	token, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath)
 
- 	assert.NoError(t, err)
 
- 	form := make(url.Values)
 
- 	form.Set("name", "name")
 
- 	form.Set("mapped_path", filepath.Join(os.TempDir(), "%name%"))
 
- 	form.Set("description", "desc folder %name%")
 
- 	form.Add("tpl_foldername", folder1)
 
- 	form.Add("tpl_foldername", folder2)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	b, contentType, _ := getMultipartFormData(form, "", "")
 
- 	req, err := http.NewRequest(http.MethodPost, webTemplateFolder, &b)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, token)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusSeeOther, rr)
 
- 	_, _, err = httpdtest.GetFolderByName(folder1, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, _, err = httpdtest.GetFolderByName(folder2, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveFolder(vfs.BaseVirtualFolder{Name: folder1}, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	_, err = httpdtest.RemoveFolder(vfs.BaseVirtualFolder{Name: folder2}, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = dataprovider.Close()
 
- 	assert.NoError(t, err)
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, err = http.NewRequest(http.MethodPost, webTemplateFolder, &b)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, token)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusInternalServerError, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Cannot save the defined folders")
 
- 	err = config.LoadConfig(configDir, "")
 
- 	assert.NoError(t, err)
 
- 	providerConf := config.GetProviderConf()
 
- 	providerConf.CredentialsPath = credentialsPath
 
- 	err = os.RemoveAll(credentialsPath)
 
- 	assert.NoError(t, err)
 
- 	err = dataprovider.Initialize(providerConf, configDir, true)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestFolderTemplateMock(t *testing.T) {
 
- 	folderName := "vfolder-template"
 
- 	mappedPath := filepath.Join(os.TempDir(), "%name%mapped%name%path")
 
- 	token, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath)
 
- 	assert.NoError(t, err)
 
- 	form := make(url.Values)
 
- 	form.Set("name", folderName)
 
- 	form.Set("mapped_path", mappedPath)
 
- 	form.Set("description", "desc folder %name%")
 
- 	form.Add("tpl_foldername", "folder1")
 
- 	form.Add("tpl_foldername", "folder2")
 
- 	form.Add("tpl_foldername", "folder3")
 
- 	form.Add("tpl_foldername", "folder1 ")
 
- 	form.Add("tpl_foldername", " ")
 
- 	form.Set("form_action", "export_from_template")
 
- 	b, contentType, _ := getMultipartFormData(form, "", "")
 
- 	req, _ := http.NewRequest(http.MethodPost, webTemplateFolder, &b)
 
- 	setJWTCookieForReq(req, token)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "unable to verify form token")
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, webTemplateFolder+"?param=p%C3%AO%GG", &b)
 
- 	setJWTCookieForReq(req, token)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Error parsing folders fields")
 
- 	folder1 := "folder1"
 
- 	folder2 := "folder2"
 
- 	folder3 := "folder3"
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, webTemplateFolder, &b)
 
- 	setJWTCookieForReq(req, token)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var dump dataprovider.BackupData
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &dump)
 
- 	require.NoError(t, err)
 
- 	require.Len(t, dump.Users, 0)
 
- 	require.Len(t, dump.Admins, 0)
 
- 	require.Len(t, dump.Folders, 3)
 
- 	require.Equal(t, folder1, dump.Folders[0].Name)
 
- 	require.Equal(t, "desc folder folder1", dump.Folders[0].Description)
 
- 	require.True(t, strings.HasSuffix(dump.Folders[0].MappedPath, "folder1mappedfolder1path"))
 
- 	require.Equal(t, folder2, dump.Folders[1].Name)
 
- 	require.Equal(t, "desc folder folder2", dump.Folders[1].Description)
 
- 	require.True(t, strings.HasSuffix(dump.Folders[1].MappedPath, "folder2mappedfolder2path"))
 
- 	require.Equal(t, folder3, dump.Folders[2].Name)
 
- 	require.Equal(t, "desc folder folder3", dump.Folders[2].Description)
 
- 	require.True(t, strings.HasSuffix(dump.Folders[2].MappedPath, "folder3mappedfolder3path"))
 
- 	form.Set("fs_provider", "1")
 
- 	form.Set("s3_bucket", "bucket")
 
- 	form.Set("s3_region", "us-east-1")
 
- 	form.Set("s3_access_key", "%name%")
 
- 	form.Set("s3_access_secret", "pwd%name%")
 
- 	form.Set("s3_key_prefix", "base/%name%")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, webTemplateFolder, &b)
 
- 	setJWTCookieForReq(req, token)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Error parsing folders fields")
 
- 	form.Set("s3_upload_part_size", "5")
 
- 	form.Set("s3_upload_concurrency", "4")
 
- 	form.Set("s3_download_part_max_time", "0")
 
- 	form.Set("s3_upload_part_max_time", "0")
 
- 	form.Set("s3_download_part_size", "6")
 
- 	form.Set("s3_download_concurrency", "2")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, webTemplateFolder, &b)
 
- 	setJWTCookieForReq(req, token)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	dump = dataprovider.BackupData{}
 
- 	err = json.Unmarshal(rr.Body.Bytes(), &dump)
 
- 	require.NoError(t, err)
 
- 	require.Len(t, dump.Users, 0)
 
- 	require.Len(t, dump.Admins, 0)
 
- 	require.Len(t, dump.Folders, 3)
 
- 	require.Equal(t, folder1, dump.Folders[0].Name)
 
- 	require.Equal(t, folder1, dump.Folders[0].FsConfig.S3Config.AccessKey)
 
- 	err = dump.Folders[0].FsConfig.S3Config.AccessSecret.Decrypt()
 
- 	require.NoError(t, err)
 
- 	require.Equal(t, "pwd"+folder1, dump.Folders[0].FsConfig.S3Config.AccessSecret.GetPayload())
 
- 	require.Equal(t, "base/"+folder1+"/", dump.Folders[0].FsConfig.S3Config.KeyPrefix)
 
- 	require.Equal(t, folder2, dump.Folders[1].Name)
 
- 	require.Equal(t, folder2, dump.Folders[1].FsConfig.S3Config.AccessKey)
 
- 	err = dump.Folders[1].FsConfig.S3Config.AccessSecret.Decrypt()
 
- 	require.NoError(t, err)
 
- 	require.Equal(t, "pwd"+folder2, dump.Folders[1].FsConfig.S3Config.AccessSecret.GetPayload())
 
- 	require.Equal(t, "base/"+folder2+"/", dump.Folders[1].FsConfig.S3Config.KeyPrefix)
 
- 	require.Equal(t, folder3, dump.Folders[2].Name)
 
- 	require.Equal(t, folder3, dump.Folders[2].FsConfig.S3Config.AccessKey)
 
- 	err = dump.Folders[2].FsConfig.S3Config.AccessSecret.Decrypt()
 
- 	require.NoError(t, err)
 
- 	require.Equal(t, "pwd"+folder3, dump.Folders[2].FsConfig.S3Config.AccessSecret.GetPayload())
 
- 	require.Equal(t, "base/"+folder3+"/", dump.Folders[2].FsConfig.S3Config.KeyPrefix)
 
- 	form.Set("tpl_foldername", " ")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, webTemplateFolder, &b)
 
- 	setJWTCookieForReq(req, token)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "No valid folders defined")
 
- 	form.Set("tpl_foldername", "name")
 
- 	form.Set("mapped_path", "relative-path")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, webTemplateFolder, &b)
 
- 	setJWTCookieForReq(req, token)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Error validating folder")
 
- }
 
- func TestWebUserS3Mock(t *testing.T) {
 
- 	webToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	apiToken, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath)
 
- 	assert.NoError(t, err)
 
- 	user := getTestUser()
 
- 	userAsJSON := getUserAsJSON(t, user)
 
- 	req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
 
- 	setBearerForReq(req, apiToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	err = render.DecodeJSON(rr.Body, &user)
 
- 	assert.NoError(t, err)
 
- 	user.FsConfig.Provider = sdk.S3FilesystemProvider
 
- 	user.FsConfig.S3Config.Bucket = "test"
 
- 	user.FsConfig.S3Config.Region = "eu-west-1"
 
- 	user.FsConfig.S3Config.AccessKey = "access-key"
 
- 	user.FsConfig.S3Config.AccessSecret = kms.NewPlainSecret("access-secret")
 
- 	user.FsConfig.S3Config.SessionToken = "new session token"
 
- 	user.FsConfig.S3Config.RoleARN = "arn:aws:iam::123456789012:user/Development/product_1234/*"
 
- 	user.FsConfig.S3Config.Endpoint = "http://127.0.0.1:9000/path?a=b"
 
- 	user.FsConfig.S3Config.StorageClass = "Standard"
 
- 	user.FsConfig.S3Config.KeyPrefix = "somedir/subdir/"
 
- 	user.FsConfig.S3Config.UploadPartSize = 5
 
- 	user.FsConfig.S3Config.UploadConcurrency = 4
 
- 	user.FsConfig.S3Config.DownloadPartMaxTime = 60
 
- 	user.FsConfig.S3Config.UploadPartMaxTime = 120
 
- 	user.FsConfig.S3Config.DownloadPartSize = 6
 
- 	user.FsConfig.S3Config.DownloadConcurrency = 3
 
- 	user.FsConfig.S3Config.ForcePathStyle = true
 
- 	user.FsConfig.S3Config.ACL = "public-read"
 
- 	user.Description = "s3 tèst user"
 
- 	form := make(url.Values)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	form.Set("username", user.Username)
 
- 	form.Set("password", redactedSecret)
 
- 	form.Set("home_dir", user.HomeDir)
 
- 	form.Set("uid", "0")
 
- 	form.Set("gid", strconv.FormatInt(int64(user.GID), 10))
 
- 	form.Set("max_sessions", strconv.FormatInt(int64(user.MaxSessions), 10))
 
- 	form.Set("quota_size", strconv.FormatInt(user.QuotaSize, 10))
 
- 	form.Set("quota_files", strconv.FormatInt(int64(user.QuotaFiles), 10))
 
- 	form.Set("upload_bandwidth", "0")
 
- 	form.Set("download_bandwidth", "0")
 
- 	form.Set("upload_data_transfer", "0")
 
- 	form.Set("download_data_transfer", "0")
 
- 	form.Set("total_data_transfer", "0")
 
- 	form.Set("external_auth_cache_time", "0")
 
- 	form.Set("permissions", "*")
 
- 	form.Set("status", strconv.Itoa(user.Status))
 
- 	form.Set("expiration_date", "2020-01-01 00:00:00")
 
- 	form.Set("allowed_ip", "")
 
- 	form.Set("denied_ip", "")
 
- 	form.Set("fs_provider", "1")
 
- 	form.Set("s3_bucket", user.FsConfig.S3Config.Bucket)
 
- 	form.Set("s3_region", user.FsConfig.S3Config.Region)
 
- 	form.Set("s3_access_key", user.FsConfig.S3Config.AccessKey)
 
- 	form.Set("s3_access_secret", user.FsConfig.S3Config.AccessSecret.GetPayload())
 
- 	form.Set("s3_session_token", user.FsConfig.S3Config.SessionToken)
 
- 	form.Set("s3_role_arn", user.FsConfig.S3Config.RoleARN)
 
- 	form.Set("s3_storage_class", user.FsConfig.S3Config.StorageClass)
 
- 	form.Set("s3_acl", user.FsConfig.S3Config.ACL)
 
- 	form.Set("s3_endpoint", user.FsConfig.S3Config.Endpoint)
 
- 	form.Set("s3_key_prefix", user.FsConfig.S3Config.KeyPrefix)
 
- 	form.Set("pattern_path0", "/dir1")
 
- 	form.Set("patterns0", "*.jpg,*.png")
 
- 	form.Set("pattern_type0", "allowed")
 
- 	form.Set("pattern_policy0", "0")
 
- 	form.Set("pattern_path1", "/dir2")
 
- 	form.Set("patterns1", "*.zip")
 
- 	form.Set("pattern_type1", "denied")
 
- 	form.Set("pattern_policy1", "1")
 
- 	form.Set("max_upload_file_size", "0")
 
- 	form.Set("s3_force_path_style", "checked")
 
- 	form.Set("description", user.Description)
 
- 	form.Add("hooks", "pre_login_disabled")
 
- 	form.Add("allow_api_key_auth", "1")
 
- 	// test invalid s3_upload_part_size
 
- 	form.Set("s3_upload_part_size", "a")
 
- 	b, contentType, _ := getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// test invalid s3_upload_concurrency
 
- 	form.Set("s3_upload_part_size", strconv.FormatInt(user.FsConfig.S3Config.UploadPartSize, 10))
 
- 	form.Set("s3_upload_concurrency", "a")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// test invalid s3_download_part_size
 
- 	form.Set("s3_upload_concurrency", strconv.Itoa(user.FsConfig.S3Config.UploadConcurrency))
 
- 	form.Set("s3_download_part_size", "a")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// test invalid s3_download_concurrency
 
- 	form.Set("s3_download_part_size", strconv.FormatInt(user.FsConfig.S3Config.DownloadPartSize, 10))
 
- 	form.Set("s3_download_concurrency", "a")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// test invalid s3_download_part_max_time
 
- 	form.Set("s3_download_concurrency", strconv.Itoa(user.FsConfig.S3Config.DownloadConcurrency))
 
- 	form.Set("s3_download_part_max_time", "a")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// test invalid s3_upload_part_max_time
 
- 	form.Set("s3_download_part_max_time", strconv.Itoa(user.FsConfig.S3Config.DownloadPartMaxTime))
 
- 	form.Set("s3_upload_part_max_time", "a")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// now add the user
 
- 	form.Set("s3_upload_part_max_time", strconv.Itoa(user.FsConfig.S3Config.UploadPartMaxTime))
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusSeeOther, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var updateUser dataprovider.User
 
- 	err = render.DecodeJSON(rr.Body, &updateUser)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, int64(1577836800000), updateUser.ExpirationDate)
 
- 	assert.Equal(t, updateUser.FsConfig.S3Config.Bucket, user.FsConfig.S3Config.Bucket)
 
- 	assert.Equal(t, updateUser.FsConfig.S3Config.Region, user.FsConfig.S3Config.Region)
 
- 	assert.Equal(t, updateUser.FsConfig.S3Config.AccessKey, user.FsConfig.S3Config.AccessKey)
 
- 	assert.Equal(t, updateUser.FsConfig.S3Config.SessionToken, user.FsConfig.S3Config.SessionToken)
 
- 	assert.Equal(t, updateUser.FsConfig.S3Config.RoleARN, user.FsConfig.S3Config.RoleARN)
 
- 	assert.Equal(t, updateUser.FsConfig.S3Config.StorageClass, user.FsConfig.S3Config.StorageClass)
 
- 	assert.Equal(t, updateUser.FsConfig.S3Config.ACL, user.FsConfig.S3Config.ACL)
 
- 	assert.Equal(t, updateUser.FsConfig.S3Config.Endpoint, user.FsConfig.S3Config.Endpoint)
 
- 	assert.Equal(t, updateUser.FsConfig.S3Config.KeyPrefix, user.FsConfig.S3Config.KeyPrefix)
 
- 	assert.Equal(t, updateUser.FsConfig.S3Config.UploadPartSize, user.FsConfig.S3Config.UploadPartSize)
 
- 	assert.Equal(t, updateUser.FsConfig.S3Config.UploadConcurrency, user.FsConfig.S3Config.UploadConcurrency)
 
- 	assert.Equal(t, updateUser.FsConfig.S3Config.DownloadPartMaxTime, user.FsConfig.S3Config.DownloadPartMaxTime)
 
- 	assert.Equal(t, updateUser.FsConfig.S3Config.UploadPartMaxTime, user.FsConfig.S3Config.UploadPartMaxTime)
 
- 	assert.Equal(t, updateUser.FsConfig.S3Config.DownloadPartSize, user.FsConfig.S3Config.DownloadPartSize)
 
- 	assert.Equal(t, updateUser.FsConfig.S3Config.DownloadConcurrency, user.FsConfig.S3Config.DownloadConcurrency)
 
- 	assert.True(t, updateUser.FsConfig.S3Config.ForcePathStyle)
 
- 	if assert.Equal(t, 2, len(updateUser.Filters.FilePatterns)) {
 
- 		for _, filter := range updateUser.Filters.FilePatterns {
 
- 			switch filter.Path {
 
- 			case "/dir1":
 
- 				assert.Equal(t, sdk.DenyPolicyDefault, filter.DenyPolicy)
 
- 			case "/dir2":
 
- 				assert.Equal(t, sdk.DenyPolicyHide, filter.DenyPolicy)
 
- 			}
 
- 		}
 
- 	}
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, updateUser.FsConfig.S3Config.AccessSecret.GetStatus())
 
- 	assert.NotEmpty(t, updateUser.FsConfig.S3Config.AccessSecret.GetPayload())
 
- 	assert.Empty(t, updateUser.FsConfig.S3Config.AccessSecret.GetKey())
 
- 	assert.Empty(t, updateUser.FsConfig.S3Config.AccessSecret.GetAdditionalData())
 
- 	assert.Equal(t, user.Description, updateUser.Description)
 
- 	assert.True(t, updateUser.Filters.Hooks.PreLoginDisabled)
 
- 	assert.False(t, updateUser.Filters.Hooks.ExternalAuthDisabled)
 
- 	assert.False(t, updateUser.Filters.Hooks.CheckPasswordDisabled)
 
- 	assert.False(t, updateUser.Filters.DisableFsChecks)
 
- 	assert.True(t, updateUser.Filters.AllowAPIKeyAuth)
 
- 	// now check that a redacted password is not saved
 
- 	form.Set("s3_access_secret", redactedSecret)
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusSeeOther, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var lastUpdatedUser dataprovider.User
 
- 	err = render.DecodeJSON(rr.Body, &lastUpdatedUser)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, lastUpdatedUser.FsConfig.S3Config.AccessSecret.GetStatus())
 
- 	assert.Equal(t, updateUser.FsConfig.S3Config.AccessSecret.GetPayload(), lastUpdatedUser.FsConfig.S3Config.AccessSecret.GetPayload())
 
- 	assert.Empty(t, lastUpdatedUser.FsConfig.S3Config.AccessSecret.GetKey())
 
- 	assert.Empty(t, lastUpdatedUser.FsConfig.S3Config.AccessSecret.GetAdditionalData())
 
- 	// now clear credentials
 
- 	form.Set("s3_access_key", "")
 
- 	form.Set("s3_access_secret", "")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusSeeOther, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var userGet dataprovider.User
 
- 	err = render.DecodeJSON(rr.Body, &userGet)
 
- 	assert.NoError(t, err)
 
- 	assert.Nil(t, userGet.FsConfig.S3Config.AccessSecret)
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(userPath, user.Username), nil)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- }
 
- func TestWebUserGCSMock(t *testing.T) {
 
- 	webToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	apiToken, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath)
 
- 	assert.NoError(t, err)
 
- 	user := getTestUser()
 
- 	userAsJSON := getUserAsJSON(t, user)
 
- 	req, err := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	err = render.DecodeJSON(rr.Body, &user)
 
- 	assert.NoError(t, err)
 
- 	credentialsFilePath := filepath.Join(os.TempDir(), "gcs.json")
 
- 	err = createTestFile(credentialsFilePath, 0)
 
- 	assert.NoError(t, err)
 
- 	user.FsConfig.Provider = sdk.GCSFilesystemProvider
 
- 	user.FsConfig.GCSConfig.Bucket = "test"
 
- 	user.FsConfig.GCSConfig.KeyPrefix = "somedir/subdir/"
 
- 	user.FsConfig.GCSConfig.StorageClass = "standard"
 
- 	user.FsConfig.GCSConfig.ACL = "publicReadWrite"
 
- 	form := make(url.Values)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	form.Set("username", user.Username)
 
- 	form.Set("password", redactedSecret)
 
- 	form.Set("home_dir", user.HomeDir)
 
- 	form.Set("uid", "0")
 
- 	form.Set("gid", strconv.FormatInt(int64(user.GID), 10))
 
- 	form.Set("max_sessions", strconv.FormatInt(int64(user.MaxSessions), 10))
 
- 	form.Set("quota_size", strconv.FormatInt(user.QuotaSize, 10))
 
- 	form.Set("quota_files", strconv.FormatInt(int64(user.QuotaFiles), 10))
 
- 	form.Set("upload_bandwidth", "0")
 
- 	form.Set("download_bandwidth", "0")
 
- 	form.Set("upload_data_transfer", "0")
 
- 	form.Set("download_data_transfer", "0")
 
- 	form.Set("total_data_transfer", "0")
 
- 	form.Set("external_auth_cache_time", "0")
 
- 	form.Set("permissions", "*")
 
- 	form.Set("status", strconv.Itoa(user.Status))
 
- 	form.Set("expiration_date", "2020-01-01 00:00:00")
 
- 	form.Set("allowed_ip", "")
 
- 	form.Set("denied_ip", "")
 
- 	form.Set("fs_provider", "2")
 
- 	form.Set("gcs_bucket", user.FsConfig.GCSConfig.Bucket)
 
- 	form.Set("gcs_storage_class", user.FsConfig.GCSConfig.StorageClass)
 
- 	form.Set("gcs_acl", user.FsConfig.GCSConfig.ACL)
 
- 	form.Set("gcs_key_prefix", user.FsConfig.GCSConfig.KeyPrefix)
 
- 	form.Set("pattern_path0", "/dir1")
 
- 	form.Set("patterns0", "*.jpg,*.png")
 
- 	form.Set("pattern_type0", "allowed")
 
- 	form.Set("max_upload_file_size", "0")
 
- 	b, contentType, _ := getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	b, contentType, _ = getMultipartFormData(form, "gcs_credential_file", credentialsFilePath)
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	err = createTestFile(credentialsFilePath, 4096)
 
- 	assert.NoError(t, err)
 
- 	b, contentType, _ = getMultipartFormData(form, "gcs_credential_file", credentialsFilePath)
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusSeeOther, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var updateUser dataprovider.User
 
- 	err = render.DecodeJSON(rr.Body, &updateUser)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, int64(1577836800000), updateUser.ExpirationDate)
 
- 	assert.Equal(t, user.FsConfig.Provider, updateUser.FsConfig.Provider)
 
- 	assert.Equal(t, user.FsConfig.GCSConfig.Bucket, updateUser.FsConfig.GCSConfig.Bucket)
 
- 	assert.Equal(t, user.FsConfig.GCSConfig.StorageClass, updateUser.FsConfig.GCSConfig.StorageClass)
 
- 	assert.Equal(t, user.FsConfig.GCSConfig.ACL, updateUser.FsConfig.GCSConfig.ACL)
 
- 	assert.Equal(t, user.FsConfig.GCSConfig.KeyPrefix, updateUser.FsConfig.GCSConfig.KeyPrefix)
 
- 	if assert.Len(t, updateUser.Filters.FilePatterns, 1) {
 
- 		assert.Equal(t, "/dir1", updateUser.Filters.FilePatterns[0].Path)
 
- 		assert.Len(t, updateUser.Filters.FilePatterns[0].AllowedPatterns, 2)
 
- 		assert.Contains(t, updateUser.Filters.FilePatterns[0].AllowedPatterns, "*.png")
 
- 		assert.Contains(t, updateUser.Filters.FilePatterns[0].AllowedPatterns, "*.jpg")
 
- 	}
 
- 	form.Set("gcs_auto_credentials", "on")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusSeeOther, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	updateUser = dataprovider.User{}
 
- 	err = render.DecodeJSON(rr.Body, &updateUser)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, 1, updateUser.FsConfig.GCSConfig.AutomaticCredentials)
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(userPath, user.Username), nil)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	err = os.Remove(credentialsFilePath)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestWebUserAzureBlobMock(t *testing.T) {
 
- 	webToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	apiToken, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath)
 
- 	assert.NoError(t, err)
 
- 	user := getTestUser()
 
- 	userAsJSON := getUserAsJSON(t, user)
 
- 	req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
 
- 	setBearerForReq(req, apiToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	err = render.DecodeJSON(rr.Body, &user)
 
- 	assert.NoError(t, err)
 
- 	user.FsConfig.Provider = sdk.AzureBlobFilesystemProvider
 
- 	user.FsConfig.AzBlobConfig.Container = "container"
 
- 	user.FsConfig.AzBlobConfig.AccountName = "aname"
 
- 	user.FsConfig.AzBlobConfig.AccountKey = kms.NewPlainSecret("access-skey")
 
- 	user.FsConfig.AzBlobConfig.Endpoint = "http://127.0.0.1:9000/path?b=c"
 
- 	user.FsConfig.AzBlobConfig.KeyPrefix = "somedir/subdir/"
 
- 	user.FsConfig.AzBlobConfig.UploadPartSize = 5
 
- 	user.FsConfig.AzBlobConfig.UploadConcurrency = 4
 
- 	user.FsConfig.AzBlobConfig.DownloadPartSize = 3
 
- 	user.FsConfig.AzBlobConfig.DownloadConcurrency = 6
 
- 	user.FsConfig.AzBlobConfig.UseEmulator = true
 
- 	form := make(url.Values)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	form.Set("username", user.Username)
 
- 	form.Set("password", redactedSecret)
 
- 	form.Set("home_dir", user.HomeDir)
 
- 	form.Set("uid", "0")
 
- 	form.Set("gid", strconv.FormatInt(int64(user.GID), 10))
 
- 	form.Set("max_sessions", strconv.FormatInt(int64(user.MaxSessions), 10))
 
- 	form.Set("quota_size", strconv.FormatInt(user.QuotaSize, 10))
 
- 	form.Set("quota_files", strconv.FormatInt(int64(user.QuotaFiles), 10))
 
- 	form.Set("upload_bandwidth", "0")
 
- 	form.Set("download_bandwidth", "0")
 
- 	form.Set("upload_data_transfer", "0")
 
- 	form.Set("download_data_transfer", "0")
 
- 	form.Set("total_data_transfer", "0")
 
- 	form.Set("external_auth_cache_time", "0")
 
- 	form.Set("permissions", "*")
 
- 	form.Set("status", strconv.Itoa(user.Status))
 
- 	form.Set("expiration_date", "2020-01-01 00:00:00")
 
- 	form.Set("allowed_ip", "")
 
- 	form.Set("denied_ip", "")
 
- 	form.Set("fs_provider", "3")
 
- 	form.Set("az_container", user.FsConfig.AzBlobConfig.Container)
 
- 	form.Set("az_account_name", user.FsConfig.AzBlobConfig.AccountName)
 
- 	form.Set("az_account_key", user.FsConfig.AzBlobConfig.AccountKey.GetPayload())
 
- 	form.Set("az_endpoint", user.FsConfig.AzBlobConfig.Endpoint)
 
- 	form.Set("az_key_prefix", user.FsConfig.AzBlobConfig.KeyPrefix)
 
- 	form.Set("az_use_emulator", "checked")
 
- 	form.Set("pattern_path0", "/dir1")
 
- 	form.Set("patterns0", "*.jpg,*.png")
 
- 	form.Set("pattern_type0", "allowed")
 
- 	form.Set("pattern_path1", "/dir2")
 
- 	form.Set("patterns1", "*.zip")
 
- 	form.Set("pattern_type1", "denied")
 
- 	form.Set("max_upload_file_size", "0")
 
- 	// test invalid az_upload_part_size
 
- 	form.Set("az_upload_part_size", "a")
 
- 	b, contentType, _ := getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// test invalid az_upload_concurrency
 
- 	form.Set("az_upload_part_size", strconv.FormatInt(user.FsConfig.AzBlobConfig.UploadPartSize, 10))
 
- 	form.Set("az_upload_concurrency", "a")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// test invalid az_download_part_size
 
- 	form.Set("az_upload_concurrency", strconv.Itoa(user.FsConfig.AzBlobConfig.UploadConcurrency))
 
- 	form.Set("az_download_part_size", "a")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// test invalid az_download_concurrency
 
- 	form.Set("az_download_part_size", strconv.FormatInt(user.FsConfig.AzBlobConfig.DownloadPartSize, 10))
 
- 	form.Set("az_download_concurrency", "a")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// now add the user
 
- 	form.Set("az_download_concurrency", strconv.Itoa(user.FsConfig.AzBlobConfig.DownloadConcurrency))
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusSeeOther, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var updateUser dataprovider.User
 
- 	err = render.DecodeJSON(rr.Body, &updateUser)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, int64(1577836800000), updateUser.ExpirationDate)
 
- 	assert.Equal(t, updateUser.FsConfig.AzBlobConfig.Container, user.FsConfig.AzBlobConfig.Container)
 
- 	assert.Equal(t, updateUser.FsConfig.AzBlobConfig.AccountName, user.FsConfig.AzBlobConfig.AccountName)
 
- 	assert.Equal(t, updateUser.FsConfig.AzBlobConfig.Endpoint, user.FsConfig.AzBlobConfig.Endpoint)
 
- 	assert.Equal(t, updateUser.FsConfig.AzBlobConfig.KeyPrefix, user.FsConfig.AzBlobConfig.KeyPrefix)
 
- 	assert.Equal(t, updateUser.FsConfig.AzBlobConfig.UploadPartSize, user.FsConfig.AzBlobConfig.UploadPartSize)
 
- 	assert.Equal(t, updateUser.FsConfig.AzBlobConfig.UploadConcurrency, user.FsConfig.AzBlobConfig.UploadConcurrency)
 
- 	assert.Equal(t, updateUser.FsConfig.AzBlobConfig.DownloadPartSize, user.FsConfig.AzBlobConfig.DownloadPartSize)
 
- 	assert.Equal(t, updateUser.FsConfig.AzBlobConfig.DownloadConcurrency, user.FsConfig.AzBlobConfig.DownloadConcurrency)
 
- 	assert.Equal(t, 2, len(updateUser.Filters.FilePatterns))
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, updateUser.FsConfig.AzBlobConfig.AccountKey.GetStatus())
 
- 	assert.NotEmpty(t, updateUser.FsConfig.AzBlobConfig.AccountKey.GetPayload())
 
- 	assert.Empty(t, updateUser.FsConfig.AzBlobConfig.AccountKey.GetKey())
 
- 	assert.Empty(t, updateUser.FsConfig.AzBlobConfig.AccountKey.GetAdditionalData())
 
- 	// now check that a redacted password is not saved
 
- 	form.Set("az_account_key", redactedSecret+" ")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusSeeOther, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var lastUpdatedUser dataprovider.User
 
- 	err = render.DecodeJSON(rr.Body, &lastUpdatedUser)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, lastUpdatedUser.FsConfig.AzBlobConfig.AccountKey.GetStatus())
 
- 	assert.Equal(t, updateUser.FsConfig.AzBlobConfig.AccountKey.GetPayload(), lastUpdatedUser.FsConfig.AzBlobConfig.AccountKey.GetPayload())
 
- 	assert.Empty(t, lastUpdatedUser.FsConfig.AzBlobConfig.AccountKey.GetKey())
 
- 	assert.Empty(t, lastUpdatedUser.FsConfig.AzBlobConfig.AccountKey.GetAdditionalData())
 
- 	// test SAS url
 
- 	user.FsConfig.AzBlobConfig.SASURL = kms.NewPlainSecret("sasurl")
 
- 	form.Set("az_account_name", "")
 
- 	form.Set("az_account_key", "")
 
- 	form.Set("az_container", "")
 
- 	form.Set("az_sas_url", user.FsConfig.AzBlobConfig.SASURL.GetPayload())
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusSeeOther, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	updateUser = dataprovider.User{}
 
- 	err = render.DecodeJSON(rr.Body, &updateUser)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, updateUser.FsConfig.AzBlobConfig.SASURL.GetStatus())
 
- 	assert.NotEmpty(t, updateUser.FsConfig.AzBlobConfig.SASURL.GetPayload())
 
- 	assert.Empty(t, updateUser.FsConfig.AzBlobConfig.SASURL.GetKey())
 
- 	assert.Empty(t, updateUser.FsConfig.AzBlobConfig.SASURL.GetAdditionalData())
 
- 	// now check that a redacted sas url is not saved
 
- 	form.Set("az_sas_url", redactedSecret)
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusSeeOther, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	lastUpdatedUser = dataprovider.User{}
 
- 	err = render.DecodeJSON(rr.Body, &lastUpdatedUser)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, lastUpdatedUser.FsConfig.AzBlobConfig.SASURL.GetStatus())
 
- 	assert.Equal(t, updateUser.FsConfig.AzBlobConfig.SASURL.GetPayload(), lastUpdatedUser.FsConfig.AzBlobConfig.SASURL.GetPayload())
 
- 	assert.Empty(t, lastUpdatedUser.FsConfig.AzBlobConfig.SASURL.GetKey())
 
- 	assert.Empty(t, lastUpdatedUser.FsConfig.AzBlobConfig.SASURL.GetAdditionalData())
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(userPath, user.Username), nil)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- }
 
- func TestWebUserCryptMock(t *testing.T) {
 
- 	webToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	apiToken, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath)
 
- 	assert.NoError(t, err)
 
- 	user := getTestUser()
 
- 	userAsJSON := getUserAsJSON(t, user)
 
- 	req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
 
- 	setBearerForReq(req, apiToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	err = render.DecodeJSON(rr.Body, &user)
 
- 	assert.NoError(t, err)
 
- 	user.FsConfig.Provider = sdk.CryptedFilesystemProvider
 
- 	user.FsConfig.CryptConfig.Passphrase = kms.NewPlainSecret("crypted passphrase")
 
- 	form := make(url.Values)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	form.Set("username", user.Username)
 
- 	form.Set("password", redactedSecret)
 
- 	form.Set("home_dir", user.HomeDir)
 
- 	form.Set("uid", "0")
 
- 	form.Set("gid", strconv.FormatInt(int64(user.GID), 10))
 
- 	form.Set("max_sessions", strconv.FormatInt(int64(user.MaxSessions), 10))
 
- 	form.Set("quota_size", strconv.FormatInt(user.QuotaSize, 10))
 
- 	form.Set("quota_files", strconv.FormatInt(int64(user.QuotaFiles), 10))
 
- 	form.Set("upload_bandwidth", "0")
 
- 	form.Set("download_bandwidth", "0")
 
- 	form.Set("upload_data_transfer", "0")
 
- 	form.Set("download_data_transfer", "0")
 
- 	form.Set("total_data_transfer", "0")
 
- 	form.Set("external_auth_cache_time", "0")
 
- 	form.Set("permissions", "*")
 
- 	form.Set("status", strconv.Itoa(user.Status))
 
- 	form.Set("expiration_date", "2020-01-01 00:00:00")
 
- 	form.Set("allowed_ip", "")
 
- 	form.Set("denied_ip", "")
 
- 	form.Set("fs_provider", "4")
 
- 	form.Set("crypt_passphrase", "")
 
- 	form.Set("pattern_path0", "/dir1")
 
- 	form.Set("patterns0", "*.jpg,*.png")
 
- 	form.Set("pattern_type0", "allowed")
 
- 	form.Set("pattern_path1", "/dir2")
 
- 	form.Set("patterns1", "*.zip")
 
- 	form.Set("pattern_type1", "denied")
 
- 	form.Set("max_upload_file_size", "0")
 
- 	// passphrase cannot be empty
 
- 	b, contentType, _ := getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	form.Set("crypt_passphrase", user.FsConfig.CryptConfig.Passphrase.GetPayload())
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusSeeOther, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var updateUser dataprovider.User
 
- 	err = render.DecodeJSON(rr.Body, &updateUser)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, int64(1577836800000), updateUser.ExpirationDate)
 
- 	assert.Equal(t, 2, len(updateUser.Filters.FilePatterns))
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, updateUser.FsConfig.CryptConfig.Passphrase.GetStatus())
 
- 	assert.NotEmpty(t, updateUser.FsConfig.CryptConfig.Passphrase.GetPayload())
 
- 	assert.Empty(t, updateUser.FsConfig.CryptConfig.Passphrase.GetKey())
 
- 	assert.Empty(t, updateUser.FsConfig.CryptConfig.Passphrase.GetAdditionalData())
 
- 	// now check that a redacted password is not saved
 
- 	form.Set("crypt_passphrase", redactedSecret+" ")
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusSeeOther, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var lastUpdatedUser dataprovider.User
 
- 	err = render.DecodeJSON(rr.Body, &lastUpdatedUser)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, lastUpdatedUser.FsConfig.CryptConfig.Passphrase.GetStatus())
 
- 	assert.Equal(t, updateUser.FsConfig.CryptConfig.Passphrase.GetPayload(), lastUpdatedUser.FsConfig.CryptConfig.Passphrase.GetPayload())
 
- 	assert.Empty(t, lastUpdatedUser.FsConfig.CryptConfig.Passphrase.GetKey())
 
- 	assert.Empty(t, lastUpdatedUser.FsConfig.CryptConfig.Passphrase.GetAdditionalData())
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(userPath, user.Username), nil)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- }
 
- func TestWebUserSFTPFsMock(t *testing.T) {
 
- 	webToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	apiToken, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath)
 
- 	assert.NoError(t, err)
 
- 	user := getTestUser()
 
- 	userAsJSON := getUserAsJSON(t, user)
 
- 	req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
 
- 	setBearerForReq(req, apiToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusCreated, rr)
 
- 	err = render.DecodeJSON(rr.Body, &user)
 
- 	assert.NoError(t, err)
 
- 	user.FsConfig.Provider = sdk.SFTPFilesystemProvider
 
- 	user.FsConfig.SFTPConfig.Endpoint = "127.0.0.1:22"
 
- 	user.FsConfig.SFTPConfig.Username = "sftpuser"
 
- 	user.FsConfig.SFTPConfig.Password = kms.NewPlainSecret("pwd")
 
- 	user.FsConfig.SFTPConfig.PrivateKey = kms.NewPlainSecret(sftpPrivateKey)
 
- 	user.FsConfig.SFTPConfig.Fingerprints = []string{sftpPkeyFingerprint}
 
- 	user.FsConfig.SFTPConfig.Prefix = "/home/sftpuser"
 
- 	user.FsConfig.SFTPConfig.DisableCouncurrentReads = true
 
- 	user.FsConfig.SFTPConfig.BufferSize = 5
 
- 	form := make(url.Values)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	form.Set("username", user.Username)
 
- 	form.Set("password", redactedSecret)
 
- 	form.Set("home_dir", user.HomeDir)
 
- 	form.Set("uid", "0")
 
- 	form.Set("gid", strconv.FormatInt(int64(user.GID), 10))
 
- 	form.Set("max_sessions", strconv.FormatInt(int64(user.MaxSessions), 10))
 
- 	form.Set("quota_size", strconv.FormatInt(user.QuotaSize, 10))
 
- 	form.Set("quota_files", strconv.FormatInt(int64(user.QuotaFiles), 10))
 
- 	form.Set("upload_bandwidth", "0")
 
- 	form.Set("download_bandwidth", "0")
 
- 	form.Set("upload_data_transfer", "0")
 
- 	form.Set("download_data_transfer", "0")
 
- 	form.Set("total_data_transfer", "0")
 
- 	form.Set("external_auth_cache_time", "0")
 
- 	form.Set("permissions", "*")
 
- 	form.Set("status", strconv.Itoa(user.Status))
 
- 	form.Set("expiration_date", "2020-01-01 00:00:00")
 
- 	form.Set("allowed_ip", "")
 
- 	form.Set("denied_ip", "")
 
- 	form.Set("fs_provider", "5")
 
- 	form.Set("crypt_passphrase", "")
 
- 	form.Set("pattern_path0", "/dir1")
 
- 	form.Set("patterns0", "*.jpg,*.png")
 
- 	form.Set("pattern_type0", "allowed")
 
- 	form.Set("pattern_path1", "/dir2")
 
- 	form.Set("patterns1", "*.zip")
 
- 	form.Set("pattern_type1", "denied")
 
- 	form.Set("max_upload_file_size", "0")
 
- 	// empty sftpconfig
 
- 	b, contentType, _ := getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	form.Set("sftp_endpoint", user.FsConfig.SFTPConfig.Endpoint)
 
- 	form.Set("sftp_username", user.FsConfig.SFTPConfig.Username)
 
- 	form.Set("sftp_password", user.FsConfig.SFTPConfig.Password.GetPayload())
 
- 	form.Set("sftp_private_key", user.FsConfig.SFTPConfig.PrivateKey.GetPayload())
 
- 	form.Set("sftp_fingerprints", user.FsConfig.SFTPConfig.Fingerprints[0])
 
- 	form.Set("sftp_prefix", user.FsConfig.SFTPConfig.Prefix)
 
- 	form.Set("sftp_disable_concurrent_reads", "true")
 
- 	form.Set("sftp_buffer_size", strconv.FormatInt(user.FsConfig.SFTPConfig.BufferSize, 10))
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusSeeOther, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var updateUser dataprovider.User
 
- 	err = render.DecodeJSON(rr.Body, &updateUser)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, int64(1577836800000), updateUser.ExpirationDate)
 
- 	assert.Equal(t, 2, len(updateUser.Filters.FilePatterns))
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, updateUser.FsConfig.SFTPConfig.Password.GetStatus())
 
- 	assert.NotEmpty(t, updateUser.FsConfig.SFTPConfig.Password.GetPayload())
 
- 	assert.Empty(t, updateUser.FsConfig.SFTPConfig.Password.GetKey())
 
- 	assert.Empty(t, updateUser.FsConfig.SFTPConfig.Password.GetAdditionalData())
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, updateUser.FsConfig.SFTPConfig.PrivateKey.GetStatus())
 
- 	assert.NotEmpty(t, updateUser.FsConfig.SFTPConfig.PrivateKey.GetPayload())
 
- 	assert.Empty(t, updateUser.FsConfig.SFTPConfig.PrivateKey.GetKey())
 
- 	assert.Empty(t, updateUser.FsConfig.SFTPConfig.PrivateKey.GetAdditionalData())
 
- 	assert.Equal(t, updateUser.FsConfig.SFTPConfig.Prefix, user.FsConfig.SFTPConfig.Prefix)
 
- 	assert.Equal(t, updateUser.FsConfig.SFTPConfig.Username, user.FsConfig.SFTPConfig.Username)
 
- 	assert.Equal(t, updateUser.FsConfig.SFTPConfig.Endpoint, user.FsConfig.SFTPConfig.Endpoint)
 
- 	assert.True(t, updateUser.FsConfig.SFTPConfig.DisableCouncurrentReads)
 
- 	assert.Len(t, updateUser.FsConfig.SFTPConfig.Fingerprints, 1)
 
- 	assert.Equal(t, user.FsConfig.SFTPConfig.BufferSize, updateUser.FsConfig.SFTPConfig.BufferSize)
 
- 	assert.Contains(t, updateUser.FsConfig.SFTPConfig.Fingerprints, sftpPkeyFingerprint)
 
- 	// now check that a redacted credentials are not saved
 
- 	form.Set("sftp_password", redactedSecret+" ")
 
- 	form.Set("sftp_private_key", redactedSecret)
 
- 	b, contentType, _ = getMultipartFormData(form, "", "")
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusSeeOther, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var lastUpdatedUser dataprovider.User
 
- 	err = render.DecodeJSON(rr.Body, &lastUpdatedUser)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, lastUpdatedUser.FsConfig.SFTPConfig.Password.GetStatus())
 
- 	assert.Equal(t, updateUser.FsConfig.SFTPConfig.Password.GetPayload(), lastUpdatedUser.FsConfig.SFTPConfig.Password.GetPayload())
 
- 	assert.Empty(t, lastUpdatedUser.FsConfig.SFTPConfig.Password.GetKey())
 
- 	assert.Empty(t, lastUpdatedUser.FsConfig.SFTPConfig.Password.GetAdditionalData())
 
- 	assert.Equal(t, sdkkms.SecretStatusSecretBox, lastUpdatedUser.FsConfig.SFTPConfig.PrivateKey.GetStatus())
 
- 	assert.Equal(t, updateUser.FsConfig.SFTPConfig.PrivateKey.GetPayload(), lastUpdatedUser.FsConfig.SFTPConfig.PrivateKey.GetPayload())
 
- 	assert.Empty(t, lastUpdatedUser.FsConfig.SFTPConfig.PrivateKey.GetKey())
 
- 	assert.Empty(t, lastUpdatedUser.FsConfig.SFTPConfig.PrivateKey.GetAdditionalData())
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(userPath, user.Username), nil)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- }
 
- func TestAddWebFoldersMock(t *testing.T) {
 
- 	webToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	apiToken, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath)
 
- 	assert.NoError(t, err)
 
- 	mappedPath := filepath.Clean(os.TempDir())
 
- 	folderName := filepath.Base(mappedPath)
 
- 	folderDesc := "a simple desc"
 
- 	form := make(url.Values)
 
- 	form.Set("mapped_path", mappedPath)
 
- 	form.Set("name", folderName)
 
- 	form.Set("description", folderDesc)
 
- 	b, contentType, err := getMultipartFormData(form, "", "")
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodPost, webFolderPath, &b)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "unable to verify form token")
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	b, contentType, err = getMultipartFormData(form, "", "")
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, webFolderPath, &b)
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusSeeOther, rr)
 
- 	// adding the same folder will fail since the name must be unique
 
- 	b, contentType, err = getMultipartFormData(form, "", "")
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, webFolderPath, &b)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// invalid form
 
- 	req, err = http.NewRequest(http.MethodPost, webFolderPath, strings.NewReader(form.Encode()))
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", "text/plain; boundary=")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// now render the add folder page
 
- 	req, err = http.NewRequest(http.MethodGet, webFolderPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var folder vfs.BaseVirtualFolder
 
- 	req, _ = http.NewRequest(http.MethodGet, path.Join(folderPath, folderName), nil)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	err = render.DecodeJSON(rr.Body, &folder)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, mappedPath, folder.MappedPath)
 
- 	assert.Equal(t, folderName, folder.Name)
 
- 	assert.Equal(t, folderDesc, folder.Description)
 
- 	// cleanup
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(folderPath, folderName), nil)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- }
 
- func TestS3WebFolderMock(t *testing.T) {
 
- 	webToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	apiToken, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath)
 
- 	assert.NoError(t, err)
 
- 	mappedPath := filepath.Clean(os.TempDir())
 
- 	folderName := filepath.Base(mappedPath)
 
- 	folderDesc := "a simple desc"
 
- 	S3Bucket := "test"
 
- 	S3Region := "eu-west-1"
 
- 	S3AccessKey := "access-key"
 
- 	S3AccessSecret := kms.NewPlainSecret("folder-access-secret")
 
- 	S3SessionToken := "fake session token"
 
- 	S3RoleARN := "arn:aws:iam::123456789012:user/Development/product_1234/*"
 
- 	S3Endpoint := "http://127.0.0.1:9000/path?b=c"
 
- 	S3StorageClass := "Standard"
 
- 	S3ACL := "public-read-write"
 
- 	S3KeyPrefix := "somedir/subdir/"
 
- 	S3UploadPartSize := 5
 
- 	S3UploadConcurrency := 4
 
- 	S3MaxPartDownloadTime := 120
 
- 	S3MaxPartUploadTime := 60
 
- 	S3DownloadPartSize := 6
 
- 	S3DownloadConcurrency := 3
 
- 	form := make(url.Values)
 
- 	form.Set("mapped_path", mappedPath)
 
- 	form.Set("name", folderName)
 
- 	form.Set("description", folderDesc)
 
- 	form.Set("fs_provider", "1")
 
- 	form.Set("s3_bucket", S3Bucket)
 
- 	form.Set("s3_region", S3Region)
 
- 	form.Set("s3_access_key", S3AccessKey)
 
- 	form.Set("s3_access_secret", S3AccessSecret.GetPayload())
 
- 	form.Set("s3_session_token", S3SessionToken)
 
- 	form.Set("s3_role_arn", S3RoleARN)
 
- 	form.Set("s3_storage_class", S3StorageClass)
 
- 	form.Set("s3_acl", S3ACL)
 
- 	form.Set("s3_endpoint", S3Endpoint)
 
- 	form.Set("s3_key_prefix", S3KeyPrefix)
 
- 	form.Set("s3_upload_part_size", strconv.Itoa(S3UploadPartSize))
 
- 	form.Set("s3_download_part_max_time", strconv.Itoa(S3MaxPartDownloadTime))
 
- 	form.Set("s3_download_part_size", strconv.Itoa(S3DownloadPartSize))
 
- 	form.Set("s3_download_concurrency", strconv.Itoa(S3DownloadConcurrency))
 
- 	form.Set("s3_upload_part_max_time", strconv.Itoa(S3MaxPartUploadTime))
 
- 	form.Set("s3_upload_concurrency", "a")
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	b, contentType, err := getMultipartFormData(form, "", "")
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodPost, webFolderPath, &b)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	form.Set("s3_upload_concurrency", strconv.Itoa(S3UploadConcurrency))
 
- 	b, contentType, err = getMultipartFormData(form, "", "")
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, webFolderPath, &b)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusSeeOther, rr)
 
- 	var folder vfs.BaseVirtualFolder
 
- 	req, _ = http.NewRequest(http.MethodGet, path.Join(folderPath, folderName), nil)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	err = render.DecodeJSON(rr.Body, &folder)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, mappedPath, folder.MappedPath)
 
- 	assert.Equal(t, folderName, folder.Name)
 
- 	assert.Equal(t, folderDesc, folder.Description)
 
- 	assert.Equal(t, sdk.S3FilesystemProvider, folder.FsConfig.Provider)
 
- 	assert.Equal(t, S3Bucket, folder.FsConfig.S3Config.Bucket)
 
- 	assert.Equal(t, S3Region, folder.FsConfig.S3Config.Region)
 
- 	assert.Equal(t, S3AccessKey, folder.FsConfig.S3Config.AccessKey)
 
- 	assert.Equal(t, S3SessionToken, folder.FsConfig.S3Config.SessionToken)
 
- 	assert.NotEmpty(t, folder.FsConfig.S3Config.AccessSecret.GetPayload())
 
- 	assert.Equal(t, S3Endpoint, folder.FsConfig.S3Config.Endpoint)
 
- 	assert.Equal(t, S3StorageClass, folder.FsConfig.S3Config.StorageClass)
 
- 	assert.Equal(t, S3ACL, folder.FsConfig.S3Config.ACL)
 
- 	assert.Equal(t, S3KeyPrefix, folder.FsConfig.S3Config.KeyPrefix)
 
- 	assert.Equal(t, S3UploadConcurrency, folder.FsConfig.S3Config.UploadConcurrency)
 
- 	assert.Equal(t, int64(S3UploadPartSize), folder.FsConfig.S3Config.UploadPartSize)
 
- 	assert.Equal(t, S3MaxPartDownloadTime, folder.FsConfig.S3Config.DownloadPartMaxTime)
 
- 	assert.Equal(t, S3MaxPartUploadTime, folder.FsConfig.S3Config.UploadPartMaxTime)
 
- 	assert.Equal(t, S3DownloadConcurrency, folder.FsConfig.S3Config.DownloadConcurrency)
 
- 	assert.Equal(t, int64(S3DownloadPartSize), folder.FsConfig.S3Config.DownloadPartSize)
 
- 	assert.False(t, folder.FsConfig.S3Config.ForcePathStyle)
 
- 	// update
 
- 	S3UploadConcurrency = 10
 
- 	form.Set("s3_upload_concurrency", "b")
 
- 	b, contentType, err = getMultipartFormData(form, "", "")
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, path.Join(webFolderPath, folderName), &b)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	form.Set("s3_upload_concurrency", strconv.Itoa(S3UploadConcurrency))
 
- 	b, contentType, err = getMultipartFormData(form, "", "")
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, path.Join(webFolderPath, folderName), &b)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusSeeOther, rr)
 
- 	folder = vfs.BaseVirtualFolder{}
 
- 	req, _ = http.NewRequest(http.MethodGet, path.Join(folderPath, folderName), nil)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	err = render.DecodeJSON(rr.Body, &folder)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, mappedPath, folder.MappedPath)
 
- 	assert.Equal(t, folderName, folder.Name)
 
- 	assert.Equal(t, folderDesc, folder.Description)
 
- 	assert.Equal(t, sdk.S3FilesystemProvider, folder.FsConfig.Provider)
 
- 	assert.Equal(t, S3Bucket, folder.FsConfig.S3Config.Bucket)
 
- 	assert.Equal(t, S3Region, folder.FsConfig.S3Config.Region)
 
- 	assert.Equal(t, S3AccessKey, folder.FsConfig.S3Config.AccessKey)
 
- 	assert.Equal(t, S3SessionToken, folder.FsConfig.S3Config.SessionToken)
 
- 	assert.Equal(t, S3RoleARN, folder.FsConfig.S3Config.RoleARN)
 
- 	assert.NotEmpty(t, folder.FsConfig.S3Config.AccessSecret.GetPayload())
 
- 	assert.Equal(t, S3Endpoint, folder.FsConfig.S3Config.Endpoint)
 
- 	assert.Equal(t, S3StorageClass, folder.FsConfig.S3Config.StorageClass)
 
- 	assert.Equal(t, S3KeyPrefix, folder.FsConfig.S3Config.KeyPrefix)
 
- 	assert.Equal(t, S3UploadConcurrency, folder.FsConfig.S3Config.UploadConcurrency)
 
- 	assert.Equal(t, int64(S3UploadPartSize), folder.FsConfig.S3Config.UploadPartSize)
 
- 	// cleanup
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(folderPath, folderName), nil)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- }
 
- func TestUpdateWebFolderMock(t *testing.T) {
 
- 	webToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	apiToken, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath)
 
- 	assert.NoError(t, err)
 
- 	folderName := "vfolderupdate"
 
- 	folderDesc := "updated desc"
 
- 	folder := vfs.BaseVirtualFolder{
 
- 		Name:        folderName,
 
- 		MappedPath:  filepath.Join(os.TempDir(), "folderupdate"),
 
- 		Description: "dsc",
 
- 	}
 
- 	_, _, err = httpdtest.AddFolder(folder, http.StatusCreated)
 
- 	newMappedPath := folder.MappedPath + "1"
 
- 	assert.NoError(t, err)
 
- 	form := make(url.Values)
 
- 	form.Set("mapped_path", newMappedPath)
 
- 	form.Set("name", folderName)
 
- 	form.Set("description", folderDesc)
 
- 	form.Set(csrfFormToken, "")
 
- 	b, contentType, err := getMultipartFormData(form, "", "")
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodPost, path.Join(webFolderPath, folderName), &b)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "unable to verify form token")
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	b, contentType, err = getMultipartFormData(form, "", "")
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, path.Join(webFolderPath, folderName), &b)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusSeeOther, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, path.Join(folderPath, folderName), nil)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	err = render.DecodeJSON(rr.Body, &folder)
 
- 	assert.NoError(t, err)
 
- 	assert.Equal(t, newMappedPath, folder.MappedPath)
 
- 	assert.Equal(t, folderName, folder.Name)
 
- 	assert.Equal(t, folderDesc, folder.Description)
 
- 	// parse form error
 
- 	b, contentType, err = getMultipartFormData(form, "", "")
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, path.Join(webFolderPath, folderName)+"??a=a%B3%A2%G3", &b)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Contains(t, rr.Body.String(), "invalid URL escape")
 
- 	b, contentType, err = getMultipartFormData(form, "", "")
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, path.Join(webFolderPath, folderName+"1"), &b)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	form.Set("mapped_path", "arelative/path")
 
- 	b, contentType, err = getMultipartFormData(form, "", "")
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, path.Join(webFolderPath, folderName), &b)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	req.Header.Set("Content-Type", contentType)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// render update folder page
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(webFolderPath, folderName), nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, path.Join(webFolderPath, folderName+"1"), nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(webFolderPath, folderName), nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Invalid token")
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(webFolderPath, folderName), nil)
 
- 	setJWTCookieForReq(req, apiToken) // api token is not accepted
 
- 	setCSRFHeaderForReq(req, csrfToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusFound, rr)
 
- 	assert.Equal(t, webLoginPath, rr.Header().Get("Location"))
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(webFolderPath, folderName), nil)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	setCSRFHeaderForReq(req, csrfToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- }
 
- func TestWebFoldersMock(t *testing.T) {
 
- 	webToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	apiToken, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	mappedPath1 := filepath.Join(os.TempDir(), "vfolder1")
 
- 	mappedPath2 := filepath.Join(os.TempDir(), "vfolder2")
 
- 	folderName1 := filepath.Base(mappedPath1)
 
- 	folderName2 := filepath.Base(mappedPath2)
 
- 	folderDesc1 := "vfolder1 desc"
 
- 	folderDesc2 := "vfolder2 desc"
 
- 	folders := []vfs.BaseVirtualFolder{
 
- 		{
 
- 			Name:        folderName1,
 
- 			MappedPath:  mappedPath1,
 
- 			Description: folderDesc1,
 
- 		},
 
- 		{
 
- 			Name:        folderName2,
 
- 			MappedPath:  mappedPath2,
 
- 			Description: folderDesc2,
 
- 		},
 
- 	}
 
- 	for _, folder := range folders {
 
- 		folderAsJSON, err := json.Marshal(folder)
 
- 		assert.NoError(t, err)
 
- 		req, err := http.NewRequest(http.MethodPost, folderPath, bytes.NewBuffer(folderAsJSON))
 
- 		assert.NoError(t, err)
 
- 		setBearerForReq(req, apiToken)
 
- 		rr := executeRequest(req)
 
- 		checkResponseCode(t, http.StatusCreated, rr)
 
- 	}
 
- 	req, err := http.NewRequest(http.MethodGet, folderPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setBearerForReq(req, apiToken)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	var foldersGet []vfs.BaseVirtualFolder
 
- 	err = render.DecodeJSON(rr.Body, &foldersGet)
 
- 	assert.NoError(t, err)
 
- 	numFound := 0
 
- 	for _, f := range foldersGet {
 
- 		if f.Name == folderName1 {
 
- 			assert.Equal(t, mappedPath1, f.MappedPath)
 
- 			assert.Equal(t, folderDesc1, f.Description)
 
- 			numFound++
 
- 		}
 
- 		if f.Name == folderName2 {
 
- 			assert.Equal(t, mappedPath2, f.MappedPath)
 
- 			assert.Equal(t, folderDesc2, f.Description)
 
- 			numFound++
 
- 		}
 
- 	}
 
- 	assert.Equal(t, 2, numFound)
 
- 	req, err = http.NewRequest(http.MethodGet, webFoldersPath, nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, webFoldersPath+"?qlimit=a", nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, webFoldersPath+"?qlimit=1", nil)
 
- 	assert.NoError(t, err)
 
- 	setJWTCookieForReq(req, webToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	for _, folder := range folders {
 
- 		req, _ := http.NewRequest(http.MethodDelete, path.Join(folderPath, folder.Name), nil)
 
- 		setBearerForReq(req, apiToken)
 
- 		rr := executeRequest(req)
 
- 		checkResponseCode(t, http.StatusOK, rr)
 
- 	}
 
- }
 
- func TestAdminForgotPassword(t *testing.T) {
 
- 	smtpCfg := smtp.Config{
 
- 		Host:          "127.0.0.1",
 
- 		Port:          3525,
 
- 		TemplatesPath: "templates",
 
- 	}
 
- 	err := smtpCfg.Initialize("..")
 
- 	require.NoError(t, err)
 
- 	a := getTestAdmin()
 
- 	a.Username = altAdminUsername
 
- 	a.Password = altAdminPassword
 
- 	admin, _, err := httpdtest.AddAdmin(a, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodGet, webAdminForgotPwdPath, nil)
 
- 	assert.NoError(t, err)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, webAdminResetPwdPath, nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, webLoginPath, nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath)
 
- 	assert.NoError(t, err)
 
- 	form := make(url.Values)
 
- 	form.Set("username", "")
 
- 	// no csrf token
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminForgotPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusForbidden, rr.Code)
 
- 	// empty username
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminForgotPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "Username is mandatory")
 
- 	lastResetCode = ""
 
- 	form.Set("username", altAdminUsername)
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminForgotPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusFound, rr.Code)
 
- 	assert.GreaterOrEqual(t, len(lastResetCode), 20)
 
- 	form = make(url.Values)
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminResetPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusForbidden, rr.Code)
 
- 	// no password
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminResetPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "Please set a password")
 
- 	// no code
 
- 	form.Set("password", defaultPassword)
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminResetPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "Please set a confirmation code")
 
- 	// ok
 
- 	form.Set("code", lastResetCode)
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminResetPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusFound, rr.Code)
 
- 	form.Set("username", altAdminUsername)
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminForgotPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusFound, rr.Code)
 
- 	assert.GreaterOrEqual(t, len(lastResetCode), 20)
 
- 	// not working smtp server
 
- 	smtpCfg = smtp.Config{
 
- 		Host:          "127.0.0.1",
 
- 		Port:          3526,
 
- 		TemplatesPath: "templates",
 
- 	}
 
- 	err = smtpCfg.Initialize("..")
 
- 	require.NoError(t, err)
 
- 	form = make(url.Values)
 
- 	form.Set("username", altAdminUsername)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminForgotPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "Unable to send confirmation code via email")
 
- 	smtpCfg = smtp.Config{}
 
- 	err = smtpCfg.Initialize("..")
 
- 	require.NoError(t, err)
 
- 	form.Set("username", altAdminUsername)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	req, err = http.NewRequest(http.MethodPost, webAdminForgotPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "Unable to render password reset template")
 
- 	req, err = http.NewRequest(http.MethodGet, webAdminForgotPwdPath, nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, webAdminResetPwdPath, nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	_, err = httpdtest.RemoveAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestUserForgotPassword(t *testing.T) {
 
- 	smtpCfg := smtp.Config{
 
- 		Host:          "127.0.0.1",
 
- 		Port:          3525,
 
- 		TemplatesPath: "templates",
 
- 	}
 
- 	err := smtpCfg.Initialize("..")
 
- 	require.NoError(t, err)
 
- 	u := getTestUser()
 
- 	u.Email = "[email protected]"
 
- 	u.Filters.WebClient = []string{sdk.WebClientPasswordResetDisabled}
 
- 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	req, err := http.NewRequest(http.MethodGet, webClientForgotPwdPath, nil)
 
- 	assert.NoError(t, err)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, webClientResetPwdPath, nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, webClientLoginPath, nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	form := make(url.Values)
 
- 	form.Set("username", "")
 
- 	// no csrf token
 
- 	req, err = http.NewRequest(http.MethodPost, webClientForgotPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusForbidden, rr.Code)
 
- 	// empty username
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath)
 
- 	assert.NoError(t, err)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	req, err = http.NewRequest(http.MethodPost, webClientForgotPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "Username is mandatory")
 
- 	// user cannot reset the password
 
- 	form.Set("username", user.Username)
 
- 	req, err = http.NewRequest(http.MethodPost, webClientForgotPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "You are not allowed to reset your password")
 
- 	user.Filters.WebClient = []string{sdk.WebClientAPIKeyAuthChangeDisabled}
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	lastResetCode = ""
 
- 	req, err = http.NewRequest(http.MethodPost, webClientForgotPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusFound, rr.Code)
 
- 	assert.GreaterOrEqual(t, len(lastResetCode), 20)
 
- 	// no csrf token
 
- 	form = make(url.Values)
 
- 	req, err = http.NewRequest(http.MethodPost, webClientResetPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusForbidden, rr.Code)
 
- 	// no password
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	req, err = http.NewRequest(http.MethodPost, webClientResetPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "Please set a password")
 
- 	// no code
 
- 	form.Set("password", altAdminPassword)
 
- 	req, err = http.NewRequest(http.MethodPost, webClientResetPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "Please set a confirmation code")
 
- 	// ok
 
- 	form.Set("code", lastResetCode)
 
- 	req, err = http.NewRequest(http.MethodPost, webClientResetPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusFound, rr.Code)
 
- 	form = make(url.Values)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	form.Set("username", user.Username)
 
- 	lastResetCode = ""
 
- 	req, err = http.NewRequest(http.MethodPost, webClientForgotPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusFound, rr.Code)
 
- 	assert.GreaterOrEqual(t, len(lastResetCode), 20)
 
- 	smtpCfg = smtp.Config{}
 
- 	err = smtpCfg.Initialize("..")
 
- 	require.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodGet, webClientForgotPwdPath, nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, webClientResetPwdPath, nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- 	// user does not exist anymore
 
- 	form = make(url.Values)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	form.Set("code", lastResetCode)
 
- 	form.Set("password", "pwd")
 
- 	req, err = http.NewRequest(http.MethodPost, webClientResetPwdPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	assert.NoError(t, err)
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr = executeRequest(req)
 
- 	assert.Equal(t, http.StatusOK, rr.Code)
 
- 	assert.Contains(t, rr.Body.String(), "Unable to associate the confirmation code with an existing user")
 
- }
 
- func TestAPIForgotPassword(t *testing.T) {
 
- 	smtpCfg := smtp.Config{
 
- 		Host:          "127.0.0.1",
 
- 		Port:          3525,
 
- 		TemplatesPath: "templates",
 
- 	}
 
- 	err := smtpCfg.Initialize("..")
 
- 	require.NoError(t, err)
 
- 	a := getTestAdmin()
 
- 	a.Username = altAdminUsername
 
- 	a.Password = altAdminPassword
 
- 	a.Email = ""
 
- 	admin, _, err := httpdtest.AddAdmin(a, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	// no email, forgot pwd will not work
 
- 	lastResetCode = ""
 
- 	req, err := http.NewRequest(http.MethodPost, path.Join(adminPath, altAdminUsername, "/forgot-password"), nil)
 
- 	assert.NoError(t, err)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Your account does not have an email address")
 
- 	admin.Email = "[email protected]"
 
- 	admin, _, err = httpdtest.UpdateAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, path.Join(adminPath, altAdminUsername, "/forgot-password"), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.GreaterOrEqual(t, len(lastResetCode), 20)
 
- 	// invalid JSON
 
- 	req, err = http.NewRequest(http.MethodPost, path.Join(adminPath, altAdminUsername, "/reset-password"), bytes.NewBuffer([]byte(`{`)))
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	resetReq := make(map[string]string)
 
- 	resetReq["code"] = lastResetCode
 
- 	resetReq["password"] = defaultPassword
 
- 	asJSON, err := json.Marshal(resetReq)
 
- 	assert.NoError(t, err)
 
- 	// a user cannot use an admin code
 
- 	req, err = http.NewRequest(http.MethodPost, path.Join(userPath, defaultUsername, "/reset-password"), bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Invalid confirmation code")
 
- 	req, err = http.NewRequest(http.MethodPost, path.Join(adminPath, altAdminUsername, "/reset-password"), bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// the same code cannot be reused
 
- 	req, err = http.NewRequest(http.MethodPost, path.Join(adminPath, altAdminUsername, "/reset-password"), bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Confirmation code not found")
 
- 	admin, err = dataprovider.AdminExists(altAdminUsername)
 
- 	assert.NoError(t, err)
 
- 	match, err := admin.CheckPassword(defaultPassword)
 
- 	assert.NoError(t, err)
 
- 	assert.True(t, match)
 
- 	lastResetCode = ""
 
- 	// now the same for a user
 
- 	u := getTestUser()
 
- 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, path.Join(userPath, defaultUsername, "/forgot-password"), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Your account does not have an email address")
 
- 	user.Email = "[email protected]"
 
- 	user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, path.Join(userPath, defaultUsername, "/forgot-password"), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.GreaterOrEqual(t, len(lastResetCode), 20)
 
- 	// invalid JSON
 
- 	req, err = http.NewRequest(http.MethodPost, path.Join(userPath, defaultUsername, "/reset-password"), bytes.NewBuffer([]byte(`{`)))
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	// remove the reset password permission
 
- 	user.Filters.WebClient = []string{sdk.WebClientPasswordResetDisabled}
 
- 	_, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	resetReq["code"] = lastResetCode
 
- 	resetReq["password"] = altAdminPassword
 
- 	asJSON, err = json.Marshal(resetReq)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, path.Join(userPath, defaultUsername, "/reset-password"), bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "You are not allowed to reset your password")
 
- 	user.Filters.WebClient = []string{sdk.WebClientSharesDisabled}
 
- 	_, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, path.Join(userPath, defaultUsername, "/reset-password"), bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	// the same code cannot be reused
 
- 	req, err = http.NewRequest(http.MethodPost, path.Join(userPath, defaultUsername, "/reset-password"), bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Confirmation code not found")
 
- 	user, err = dataprovider.UserExists(defaultUsername)
 
- 	assert.NoError(t, err)
 
- 	err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(altAdminPassword))
 
- 	assert.NoError(t, err)
 
- 	lastResetCode = ""
 
- 	// a request for a missing admin/user will be silently ignored
 
- 	req, err = http.NewRequest(http.MethodPost, path.Join(adminPath, "missing-admin", "/forgot-password"), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Empty(t, lastResetCode)
 
- 	req, err = http.NewRequest(http.MethodPost, path.Join(userPath, "missing-user", "/forgot-password"), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.Empty(t, lastResetCode)
 
- 	lastResetCode = ""
 
- 	req, err = http.NewRequest(http.MethodPost, path.Join(adminPath, altAdminUsername, "/forgot-password"), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	assert.GreaterOrEqual(t, len(lastResetCode), 20)
 
- 	smtpCfg = smtp.Config{}
 
- 	err = smtpCfg.Initialize("..")
 
- 	require.NoError(t, err)
 
- 	// without an smtp configuration reset password is not available
 
- 	req, err = http.NewRequest(http.MethodPost, path.Join(adminPath, altAdminUsername, "/forgot-password"), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "No SMTP configuration")
 
- 	req, err = http.NewRequest(http.MethodPost, path.Join(userPath, defaultUsername, "/forgot-password"), nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "No SMTP configuration")
 
- 	_, err = httpdtest.RemoveAdmin(admin, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	// the admin does not exist anymore
 
- 	resetReq["code"] = lastResetCode
 
- 	resetReq["password"] = altAdminPassword
 
- 	asJSON, err = json.Marshal(resetReq)
 
- 	assert.NoError(t, err)
 
- 	req, err = http.NewRequest(http.MethodPost, path.Join(adminPath, altAdminUsername, "/reset-password"), bytes.NewBuffer(asJSON))
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusBadRequest, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Unable to associate the confirmation code with an existing admin")
 
- 	_, err = httpdtest.RemoveUser(user, http.StatusOK)
 
- 	assert.NoError(t, err)
 
- 	err = os.RemoveAll(user.GetHomeDir())
 
- 	assert.NoError(t, err)
 
- }
 
- func TestProviderClosedMock(t *testing.T) {
 
- 	token, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath)
 
- 	assert.NoError(t, err)
 
- 	dataprovider.Close()
 
- 	req, _ := http.NewRequest(http.MethodGet, webFoldersPath, nil)
 
- 	setJWTCookieForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusInternalServerError, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, webUsersPath, nil)
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusInternalServerError, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, webUserPath+"/0", nil)
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusInternalServerError, rr)
 
- 	form := make(url.Values)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	form.Set("username", "test")
 
- 	req, _ = http.NewRequest(http.MethodPost, webUserPath+"/0", strings.NewReader(form.Encode()))
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusInternalServerError, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, path.Join(webAdminPath, defaultTokenAuthUser), nil)
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusInternalServerError, rr)
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webAdminPath, defaultTokenAuthUser), strings.NewReader(form.Encode()))
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusInternalServerError, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, webAdminsPath, nil)
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusInternalServerError, rr)
 
- 	req, _ = http.NewRequest(http.MethodGet, path.Join(webFolderPath, defaultTokenAuthUser), nil)
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusInternalServerError, rr)
 
- 	req, _ = http.NewRequest(http.MethodPost, path.Join(webFolderPath, defaultTokenAuthUser), strings.NewReader(form.Encode()))
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusInternalServerError, rr)
 
- 	err = config.LoadConfig(configDir, "")
 
- 	assert.NoError(t, err)
 
- 	providerConf := config.GetProviderConf()
 
- 	providerConf.CredentialsPath = credentialsPath
 
- 	err = os.RemoveAll(credentialsPath)
 
- 	assert.NoError(t, err)
 
- 	err = dataprovider.Initialize(providerConf, configDir, true)
 
- 	assert.NoError(t, err)
 
- }
 
- func TestWebConnectionsMock(t *testing.T) {
 
- 	token, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodGet, webConnectionsPath, nil)
 
- 	setJWTCookieForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(webConnectionsPath, "id"), nil)
 
- 	setJWTCookieForReq(req, token)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Invalid token")
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(webConnectionsPath, "id"), nil)
 
- 	setJWTCookieForReq(req, token)
 
- 	setCSRFHeaderForReq(req, "csrfToken")
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusForbidden, rr)
 
- 	assert.Contains(t, rr.Body.String(), "Invalid token")
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath)
 
- 	assert.NoError(t, err)
 
- 	req, _ = http.NewRequest(http.MethodDelete, path.Join(webConnectionsPath, "id"), nil)
 
- 	setJWTCookieForReq(req, token)
 
- 	setCSRFHeaderForReq(req, csrfToken)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusNotFound, rr)
 
- }
 
- func TestGetWebStatusMock(t *testing.T) {
 
- 	token, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
 
- 	assert.NoError(t, err)
 
- 	req, _ := http.NewRequest(http.MethodGet, webStatusPath, nil)
 
- 	setJWTCookieForReq(req, token)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- }
 
- func TestStaticFilesMock(t *testing.T) {
 
- 	req, err := http.NewRequest(http.MethodGet, "/static/favicon.ico", nil)
 
- 	assert.NoError(t, err)
 
- 	rr := executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, "/openapi/openapi.yaml", nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, "/static", nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusMovedPermanently, rr)
 
- 	location := rr.Header().Get("Location")
 
- 	assert.Equal(t, "/static/", location)
 
- 	req, err = http.NewRequest(http.MethodGet, location, nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- 	req, err = http.NewRequest(http.MethodGet, "/openapi", nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusMovedPermanently, rr)
 
- 	location = rr.Header().Get("Location")
 
- 	assert.Equal(t, "/openapi/", location)
 
- 	req, err = http.NewRequest(http.MethodGet, location, nil)
 
- 	assert.NoError(t, err)
 
- 	rr = executeRequest(req)
 
- 	checkResponseCode(t, http.StatusOK, rr)
 
- }
 
- func startOIDCMockServer() {
 
- 	go func() {
 
- 		http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
 
- 			fmt.Fprintf(w, "OK\n")
 
- 		})
 
- 		http.HandleFunc("/auth/realms/sftpgo/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) {
 
- 			fmt.Fprintf(w, `{"issuer":"http://127.0.0.1:11111/auth/realms/sftpgo","authorization_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/auth","token_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/token","introspection_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/token/introspect","userinfo_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/userinfo","end_session_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/logout","frontchannel_logout_session_supported":true,"frontchannel_logout_supported":true,"jwks_uri":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/certs","check_session_iframe":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/login-status-iframe.html","grant_types_supported":["authorization_code","implicit","refresh_token","password","client_credentials","urn:ietf:params:oauth:grant-type:device_code","urn:openid:params:grant-type:ciba"],"response_types_supported":["code","none","id_token","token","id_token token","code id_token","code token","code id_token token"],"subject_types_supported":["public","pairwise"],"id_token_signing_alg_values_supported":["PS384","ES384","RS384","HS256","HS512","ES256","RS256","HS384","ES512","PS256","PS512","RS512"],"id_token_encryption_alg_values_supported":["RSA-OAEP","RSA-OAEP-256","RSA1_5"],"id_token_encryption_enc_values_supported":["A256GCM","A192GCM","A128GCM","A128CBC-HS256","A192CBC-HS384","A256CBC-HS512"],"userinfo_signing_alg_values_supported":["PS384","ES384","RS384","HS256","HS512","ES256","RS256","HS384","ES512","PS256","PS512","RS512","none"],"request_object_signing_alg_values_supported":["PS384","ES384","RS384","HS256","HS512","ES256","RS256","HS384","ES512","PS256","PS512","RS512","none"],"request_object_encryption_alg_values_supported":["RSA-OAEP","RSA-OAEP-256","RSA1_5"],"request_object_encryption_enc_values_supported":["A256GCM","A192GCM","A128GCM","A128CBC-HS256","A192CBC-HS384","A256CBC-HS512"],"response_modes_supported":["query","fragment","form_post","query.jwt","fragment.jwt","form_post.jwt","jwt"],"registration_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/clients-registrations/openid-connect","token_endpoint_auth_methods_supported":["private_key_jwt","client_secret_basic","client_secret_post","tls_client_auth","client_secret_jwt"],"token_endpoint_auth_signing_alg_values_supported":["PS384","ES384","RS384","HS256","HS512","ES256","RS256","HS384","ES512","PS256","PS512","RS512"],"introspection_endpoint_auth_methods_supported":["private_key_jwt","client_secret_basic","client_secret_post","tls_client_auth","client_secret_jwt"],"introspection_endpoint_auth_signing_alg_values_supported":["PS384","ES384","RS384","HS256","HS512","ES256","RS256","HS384","ES512","PS256","PS512","RS512"],"authorization_signing_alg_values_supported":["PS384","ES384","RS384","HS256","HS512","ES256","RS256","HS384","ES512","PS256","PS512","RS512"],"authorization_encryption_alg_values_supported":["RSA-OAEP","RSA-OAEP-256","RSA1_5"],"authorization_encryption_enc_values_supported":["A256GCM","A192GCM","A128GCM","A128CBC-HS256","A192CBC-HS384","A256CBC-HS512"],"claims_supported":["aud","sub","iss","auth_time","name","given_name","family_name","preferred_username","email","acr"],"claim_types_supported":["normal"],"claims_parameter_supported":true,"scopes_supported":["openid","phone","email","web-origins","offline_access","microprofile-jwt","profile","address","roles"],"request_parameter_supported":true,"request_uri_parameter_supported":true,"require_request_uri_registration":true,"code_challenge_methods_supported":["plain","S256"],"tls_client_certificate_bound_access_tokens":true,"revocation_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/revoke","revocation_endpoint_auth_methods_supported":["private_key_jwt","client_secret_basic","client_secret_post","tls_client_auth","client_secret_jwt"],"revocation_endpoint_auth_signing_alg_values_supported":["PS384","ES384","RS384","HS256","HS512","ES256","RS256","HS384","ES512","PS256","PS512","RS512"],"backchannel_logout_supported":true,"backchannel_logout_session_supported":true,"device_authorization_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/auth/device","backchannel_token_delivery_modes_supported":["poll","ping"],"backchannel_authentication_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/ext/ciba/auth","backchannel_authentication_request_signing_alg_values_supported":["PS384","ES384","RS384","ES256","RS256","ES512","PS256","PS512","RS512"],"require_pushed_authorization_requests":false,"pushed_authorization_request_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/ext/par/request","mtls_endpoint_aliases":{"token_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/token","revocation_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/revoke","introspection_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/token/introspect","device_authorization_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/auth/device","registration_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/clients-registrations/openid-connect","userinfo_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/userinfo","pushed_authorization_request_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/ext/par/request","backchannel_authentication_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/ext/ciba/auth"}}`)
 
- 		})
 
- 		http.HandleFunc("/404", func(w http.ResponseWriter, r *http.Request) {
 
- 			w.WriteHeader(http.StatusNotFound)
 
- 			fmt.Fprintf(w, "Not found\n")
 
- 		})
 
- 		if err := http.ListenAndServe(oidcMockAddr, nil); err != nil {
 
- 			logger.ErrorToConsole("could not start HTTP notification server: %v", err)
 
- 			os.Exit(1)
 
- 		}
 
- 	}()
 
- 	waitTCPListening(oidcMockAddr)
 
- }
 
- func waitForUsersQuotaScan(t *testing.T, token string) {
 
- 	for {
 
- 		var scans []common.ActiveQuotaScan
 
- 		req, _ := http.NewRequest(http.MethodGet, quotaScanPath, nil)
 
- 		setBearerForReq(req, token)
 
- 		rr := executeRequest(req)
 
- 		checkResponseCode(t, http.StatusOK, rr)
 
- 		err := render.DecodeJSON(rr.Body, &scans)
 
- 		if !assert.NoError(t, err, "Error getting active scans") {
 
- 			break
 
- 		}
 
- 		if len(scans) == 0 {
 
- 			break
 
- 		}
 
- 		time.Sleep(100 * time.Millisecond)
 
- 	}
 
- }
 
- func waitForFoldersQuotaScanPath(t *testing.T, token string) {
 
- 	var scans []common.ActiveVirtualFolderQuotaScan
 
- 	for {
 
- 		req, _ := http.NewRequest(http.MethodGet, quotaScanVFolderPath, nil)
 
- 		setBearerForReq(req, token)
 
- 		rr := executeRequest(req)
 
- 		checkResponseCode(t, http.StatusOK, rr)
 
- 		err := render.DecodeJSON(rr.Body, &scans)
 
- 		if !assert.NoError(t, err, "Error getting active folders scans") {
 
- 			break
 
- 		}
 
- 		if len(scans) == 0 {
 
- 			break
 
- 		}
 
- 		time.Sleep(100 * time.Millisecond)
 
- 	}
 
- }
 
- func waitTCPListening(address string) {
 
- 	for {
 
- 		conn, err := net.Dial("tcp", address)
 
- 		if err != nil {
 
- 			logger.WarnToConsole("tcp server %v not listening: %v", address, err)
 
- 			time.Sleep(100 * time.Millisecond)
 
- 			continue
 
- 		}
 
- 		logger.InfoToConsole("tcp server %v now listening", address)
 
- 		conn.Close()
 
- 		break
 
- 	}
 
- }
 
- func startSMTPServer() {
 
- 	go func() {
 
- 		if err := smtpd.ListenAndServe(smtpServerAddr, func(remoteAddr net.Addr, from string, to []string, data []byte) error {
 
- 			re := regexp.MustCompile(`code is ".*?"`)
 
- 			code := strings.TrimPrefix(string(re.Find(data)), "code is ")
 
- 			lastResetCode = strings.ReplaceAll(code, "\"", "")
 
- 			return nil
 
- 		}, "SFTPGo test", "localhost"); err != nil {
 
- 			logger.ErrorToConsole("could not start SMTP server: %v", err)
 
- 			os.Exit(1)
 
- 		}
 
- 	}()
 
- 	waitTCPListening(smtpServerAddr)
 
- }
 
- func getTestAdmin() dataprovider.Admin {
 
- 	return dataprovider.Admin{
 
- 		Username:    defaultTokenAuthUser,
 
- 		Password:    defaultTokenAuthPass,
 
- 		Status:      1,
 
- 		Permissions: []string{dataprovider.PermAdminAny},
 
- 		Email:       "[email protected]",
 
- 		Description: "test admin",
 
- 	}
 
- }
 
- func getTestUser() dataprovider.User {
 
- 	user := dataprovider.User{
 
- 		BaseUser: sdk.BaseUser{
 
- 			Username:    defaultUsername,
 
- 			Password:    defaultPassword,
 
- 			HomeDir:     filepath.Join(homeBasePath, defaultUsername),
 
- 			Status:      1,
 
- 			Description: "test user",
 
- 		},
 
- 	}
 
- 	user.Permissions = make(map[string][]string)
 
- 	user.Permissions["/"] = defaultPerms
 
- 	return user
 
- }
 
- func getTestSFTPUser() dataprovider.User {
 
- 	u := getTestUser()
 
- 	u.Username = u.Username + "_sftp"
 
- 	u.FsConfig.Provider = sdk.SFTPFilesystemProvider
 
- 	u.FsConfig.SFTPConfig.Endpoint = sftpServerAddr
 
- 	u.FsConfig.SFTPConfig.Username = defaultUsername
 
- 	u.FsConfig.SFTPConfig.Password = kms.NewPlainSecret(defaultPassword)
 
- 	return u
 
- }
 
- func getUserAsJSON(t *testing.T, user dataprovider.User) []byte {
 
- 	json, err := json.Marshal(user)
 
- 	assert.NoError(t, err)
 
- 	return json
 
- }
 
- func getCSRFToken(url string) (string, error) {
 
- 	req, err := http.NewRequest(http.MethodGet, url, nil)
 
- 	if err != nil {
 
- 		return "", err
 
- 	}
 
- 	resp, err := httpclient.GetHTTPClient().Do(req)
 
- 	if err != nil {
 
- 		return "", err
 
- 	}
 
- 	defer resp.Body.Close()
 
- 	doc, err := html.Parse(resp.Body)
 
- 	if err != nil {
 
- 		return "", err
 
- 	}
 
- 	var csrfToken string
 
- 	var f func(*html.Node)
 
- 	f = func(n *html.Node) {
 
- 		if n.Type == html.ElementNode && n.Data == "input" {
 
- 			var name, value string
 
- 			for _, attr := range n.Attr {
 
- 				if attr.Key == "value" {
 
- 					value = attr.Val
 
- 				}
 
- 				if attr.Key == "name" {
 
- 					name = attr.Val
 
- 				}
 
- 			}
 
- 			if name == csrfFormToken {
 
- 				csrfToken = value
 
- 				return
 
- 			}
 
- 		}
 
- 		for c := n.FirstChild; c != nil; c = c.NextSibling {
 
- 			f(c)
 
- 		}
 
- 	}
 
- 	f(doc)
 
- 	return csrfToken, nil
 
- }
 
- func getLoginForm(username, password, csrfToken string) url.Values {
 
- 	form := make(url.Values)
 
- 	form.Set("username", username)
 
- 	form.Set("password", password)
 
- 	form.Set(csrfFormToken, csrfToken)
 
- 	return form
 
- }
 
- func setCSRFHeaderForReq(req *http.Request, csrfToken string) {
 
- 	req.Header.Set("X-CSRF-TOKEN", csrfToken)
 
- }
 
- func setBearerForReq(req *http.Request, jwtToken string) {
 
- 	req.Header.Set("Authorization", fmt.Sprintf("Bearer %v", jwtToken))
 
- }
 
- func setAPIKeyForReq(req *http.Request, apiKey, username string) {
 
- 	if username != "" {
 
- 		apiKey += "." + username
 
- 	}
 
- 	req.Header.Set("X-SFTPGO-API-KEY", apiKey)
 
- }
 
- func setJWTCookieForReq(req *http.Request, jwtToken string) {
 
- 	req.Header.Set("Cookie", fmt.Sprintf("jwt=%v", jwtToken))
 
- }
 
- func getJWTAPITokenFromTestServer(username, password string) (string, error) {
 
- 	req, _ := http.NewRequest(http.MethodGet, tokenPath, nil)
 
- 	req.SetBasicAuth(username, password)
 
- 	rr := executeRequest(req)
 
- 	if rr.Code != http.StatusOK {
 
- 		return "", fmt.Errorf("unexpected  status code %v", rr.Code)
 
- 	}
 
- 	responseHolder := make(map[string]interface{})
 
- 	err := render.DecodeJSON(rr.Body, &responseHolder)
 
- 	if err != nil {
 
- 		return "", err
 
- 	}
 
- 	return responseHolder["access_token"].(string), nil
 
- }
 
- func getJWTAPIUserTokenFromTestServer(username, password string) (string, error) {
 
- 	req, _ := http.NewRequest(http.MethodGet, userTokenPath, nil)
 
- 	req.SetBasicAuth(username, password)
 
- 	rr := executeRequest(req)
 
- 	if rr.Code != http.StatusOK {
 
- 		return "", fmt.Errorf("unexpected  status code %v", rr.Code)
 
- 	}
 
- 	responseHolder := make(map[string]interface{})
 
- 	err := render.DecodeJSON(rr.Body, &responseHolder)
 
- 	if err != nil {
 
- 		return "", err
 
- 	}
 
- 	return responseHolder["access_token"].(string), nil
 
- }
 
- func getJWTWebToken(username, password string) (string, error) {
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath)
 
- 	if err != nil {
 
- 		return "", err
 
- 	}
 
- 	form := getLoginForm(username, password, csrfToken)
 
- 	req, _ := http.NewRequest(http.MethodPost, httpBaseURL+webLoginPath,
 
- 		bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	client := &http.Client{
 
- 		Timeout: 10 * time.Second,
 
- 		CheckRedirect: func(req *http.Request, via []*http.Request) error {
 
- 			return http.ErrUseLastResponse
 
- 		},
 
- 	}
 
- 	resp, err := client.Do(req)
 
- 	if err != nil {
 
- 		return "", err
 
- 	}
 
- 	defer resp.Body.Close()
 
- 	if resp.StatusCode != http.StatusFound {
 
- 		return "", fmt.Errorf("unexpected  status code %v", resp.StatusCode)
 
- 	}
 
- 	cookie := resp.Header.Get("Set-Cookie")
 
- 	if strings.HasPrefix(cookie, "jwt=") {
 
- 		return cookie[4:], nil
 
- 	}
 
- 	return "", errors.New("no cookie found")
 
- }
 
- func getJWTWebClientTokenFromTestServerWithAddr(username, password, remoteAddr string) (string, error) {
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webClientLoginPath)
 
- 	if err != nil {
 
- 		return "", err
 
- 	}
 
- 	form := getLoginForm(username, password, csrfToken)
 
- 	req, _ := http.NewRequest(http.MethodPost, webClientLoginPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.RemoteAddr = remoteAddr
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr := executeRequest(req)
 
- 	if rr.Code != http.StatusFound {
 
- 		return "", fmt.Errorf("unexpected  status code %v", rr)
 
- 	}
 
- 	return getCookieFromResponse(rr)
 
- }
 
- func getCookieFromResponse(rr *httptest.ResponseRecorder) (string, error) {
 
- 	cookie := strings.Split(rr.Header().Get("Set-Cookie"), ";")
 
- 	if strings.HasPrefix(cookie[0], "jwt=") {
 
- 		return cookie[0][4:], nil
 
- 	}
 
- 	return "", errors.New("no cookie found")
 
- }
 
- func getJWTWebClientTokenFromTestServer(username, password string) (string, error) {
 
- 	return getJWTWebClientTokenFromTestServerWithAddr(username, password, "")
 
- }
 
- func getJWTWebTokenFromTestServer(username, password string) (string, error) {
 
- 	csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath)
 
- 	if err != nil {
 
- 		return "", err
 
- 	}
 
- 	form := getLoginForm(username, password, csrfToken)
 
- 	req, _ := http.NewRequest(http.MethodPost, webLoginPath, bytes.NewBuffer([]byte(form.Encode())))
 
- 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
- 	rr := executeRequest(req)
 
- 	if rr.Code != http.StatusFound {
 
- 		return "", fmt.Errorf("unexpected  status code %v", rr)
 
- 	}
 
- 	return getCookieFromResponse(rr)
 
- }
 
- func executeRequest(req *http.Request) *httptest.ResponseRecorder {
 
- 	rr := httptest.NewRecorder()
 
- 	testServer.Config.Handler.ServeHTTP(rr, req)
 
- 	return rr
 
- }
 
- func checkResponseCode(t *testing.T, expected int, rr *httptest.ResponseRecorder) {
 
- 	assert.Equal(t, expected, rr.Code, rr.Body.String())
 
- }
 
- func createTestFile(path string, size int64) error {
 
- 	baseDir := filepath.Dir(path)
 
- 	if _, err := os.Stat(baseDir); os.IsNotExist(err) {
 
- 		err = os.MkdirAll(baseDir, os.ModePerm)
 
- 		if err != nil {
 
- 			return err
 
- 		}
 
- 	}
 
- 	content := make([]byte, size)
 
- 	if size > 0 {
 
- 		_, err := rand.Read(content)
 
- 		if err != nil {
 
- 			return err
 
- 		}
 
- 	}
 
- 	return os.WriteFile(path, content, os.ModePerm)
 
- }
 
- func getExitCodeScriptContent(exitCode int) []byte {
 
- 	content := []byte("#!/bin/sh\n\n")
 
- 	content = append(content, []byte(fmt.Sprintf("exit %v", exitCode))...)
 
- 	return content
 
- }
 
- func getMultipartFormData(values url.Values, fileFieldName, filePath string) (bytes.Buffer, string, error) {
 
- 	var b bytes.Buffer
 
- 	w := multipart.NewWriter(&b)
 
- 	for k, v := range values {
 
- 		for _, s := range v {
 
- 			if err := w.WriteField(k, s); err != nil {
 
- 				return b, "", err
 
- 			}
 
- 		}
 
- 	}
 
- 	if len(fileFieldName) > 0 && len(filePath) > 0 {
 
- 		fw, err := w.CreateFormFile(fileFieldName, filepath.Base(filePath))
 
- 		if err != nil {
 
- 			return b, "", err
 
- 		}
 
- 		f, err := os.Open(filePath)
 
- 		if err != nil {
 
- 			return b, "", err
 
- 		}
 
- 		defer f.Close()
 
- 		if _, err = io.Copy(fw, f); err != nil {
 
- 			return b, "", err
 
- 		}
 
- 	}
 
- 	err := w.Close()
 
- 	return b, w.FormDataContentType(), err
 
- }
 
- func generateTOTPPasscode(secret string) (string, error) {
 
- 	return totp.GenerateCodeCustom(secret, time.Now(), totp.ValidateOpts{
 
- 		Period:    30,
 
- 		Skew:      1,
 
- 		Digits:    otp.DigitsSix,
 
- 		Algorithm: otp.AlgorithmSHA1,
 
- 	})
 
- }
 
- func isDbDefenderSupported() bool {
 
- 	// SQLite shares the implementation with other SQL-based provider but it makes no sense
 
- 	// to use it outside test cases
 
- 	switch dataprovider.GetProviderStatus().Driver {
 
- 	case dataprovider.MySQLDataProviderName, dataprovider.PGSQLDataProviderName,
 
- 		dataprovider.CockroachDataProviderName, dataprovider.SQLiteDataProviderName:
 
- 		return true
 
- 	default:
 
- 		return false
 
- 	}
 
- }
 
- func BenchmarkSecretDecryption(b *testing.B) {
 
- 	s := kms.NewPlainSecret("test data")
 
- 	s.SetAdditionalData("username")
 
- 	err := s.Encrypt()
 
- 	require.NoError(b, err)
 
- 	for i := 0; i < b.N; i++ {
 
- 		err = s.Clone().Decrypt()
 
- 		require.NoError(b, err)
 
- 	}
 
- }
 
 
  |