router.go 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424
  1. package router
  2. import (
  3. "net/http"
  4. "os"
  5. "path"
  6. "strings"
  7. "time"
  8. "github.com/go-chi/chi"
  9. "github.com/go-chi/chi/middleware"
  10. "github.com/porter-dev/porter/internal/auth/token"
  11. "github.com/porter-dev/porter/server/api"
  12. "github.com/porter-dev/porter/server/requestlog"
  13. mw "github.com/porter-dev/porter/server/router/middleware"
  14. )
  15. // New creates a new Chi router instance and registers all routes supported by the
  16. // API
  17. func New(a *api.App) *chi.Mux {
  18. l := a.Logger
  19. r := chi.NewRouter()
  20. auth := mw.NewAuth(a.Store, a.ServerConf.CookieName, &token.TokenGeneratorConf{
  21. TokenSecret: a.ServerConf.TokenGeneratorSecret,
  22. }, a.Repo)
  23. r.Route("/api", func(r chi.Router) {
  24. r.Use(mw.ContentTypeJSON)
  25. // Group for default operations with 10s timeout
  26. r.Group(func(r chi.Router) {
  27. r.Use(middleware.Timeout(10 * time.Second))
  28. // health checks
  29. r.Method("GET", "/livez", http.HandlerFunc(a.HandleLive))
  30. r.Method("GET", "/readyz", http.HandlerFunc(a.HandleReady))
  31. // /api/users routes
  32. r.Method(
  33. "GET",
  34. "/users/{user_id}",
  35. auth.DoesUserIDMatch(
  36. requestlog.NewHandler(a.HandleReadUser, l),
  37. mw.URLParam,
  38. ),
  39. )
  40. r.Method(
  41. "GET",
  42. "/users/{user_id}/projects",
  43. auth.DoesUserIDMatch(
  44. requestlog.NewHandler(a.HandleListUserProjects, l),
  45. mw.URLParam,
  46. ),
  47. )
  48. r.Method(
  49. "POST",
  50. "/users",
  51. requestlog.NewHandler(a.HandleCreateUser, l),
  52. )
  53. r.Method(
  54. "DELETE",
  55. "/users/{user_id}",
  56. auth.DoesUserIDMatch(
  57. requestlog.NewHandler(a.HandleDeleteUser, l),
  58. mw.URLParam,
  59. ),
  60. )
  61. r.Method(
  62. "GET",
  63. "/cli/login",
  64. auth.BasicAuthenticateWithRedirect(
  65. requestlog.NewHandler(a.HandleCLILoginUser, l),
  66. ),
  67. )
  68. r.Method(
  69. "GET",
  70. "/cli/login/exchange",
  71. requestlog.NewHandler(a.HandleCLILoginExchangeToken, l),
  72. )
  73. r.Method(
  74. "POST",
  75. "/login",
  76. requestlog.NewHandler(a.HandleLoginUser, l),
  77. )
  78. r.Method(
  79. "GET",
  80. "/auth/check",
  81. auth.BasicAuthenticate(
  82. requestlog.NewHandler(a.HandleAuthCheck, l),
  83. ),
  84. )
  85. r.Method(
  86. "POST",
  87. "/logout",
  88. auth.BasicAuthenticate(
  89. requestlog.NewHandler(a.HandleLogoutUser, l),
  90. ),
  91. )
  92. r.Method(
  93. "POST",
  94. "/email/verify/initiate",
  95. auth.BasicAuthenticate(
  96. requestlog.NewHandler(a.InitiateEmailVerifyUser, l),
  97. ),
  98. )
  99. r.Method(
  100. "GET",
  101. "/email/verify/finalize",
  102. auth.BasicAuthenticateWithRedirect(
  103. requestlog.NewHandler(a.FinalizEmailVerifyUser, l),
  104. ),
  105. )
  106. r.Method(
  107. "POST",
  108. "/password/reset/initiate",
  109. requestlog.NewHandler(a.InitiatePWResetUser, l),
  110. )
  111. r.Method(
  112. "POST",
  113. "/password/reset/verify",
  114. requestlog.NewHandler(a.VerifyPWResetUser, l),
  115. )
  116. r.Method(
  117. "POST",
  118. "/password/reset/finalize",
  119. requestlog.NewHandler(a.FinalizPWResetUser, l),
  120. )
  121. // /api/integrations routes
  122. r.Method(
  123. "GET",
  124. "/integrations/cluster",
  125. auth.BasicAuthenticate(
  126. requestlog.NewHandler(a.HandleListClusterIntegrations, l),
  127. ),
  128. )
  129. r.Method(
  130. "GET",
  131. "/integrations/registry",
  132. auth.BasicAuthenticate(
  133. requestlog.NewHandler(a.HandleListRegistryIntegrations, l),
  134. ),
  135. )
  136. r.Method(
  137. "GET",
  138. "/integrations/helm",
  139. auth.BasicAuthenticate(
  140. requestlog.NewHandler(a.HandleListHelmRepoIntegrations, l),
  141. ),
  142. )
  143. r.Method(
  144. "GET",
  145. "/integrations/repo",
  146. auth.BasicAuthenticate(
  147. requestlog.NewHandler(a.HandleListRepoIntegrations, l),
  148. ),
  149. )
  150. // /api/templates routes
  151. r.Method(
  152. "GET",
  153. "/templates",
  154. auth.BasicAuthenticate(
  155. requestlog.NewHandler(a.HandleListTemplates, l),
  156. ),
  157. )
  158. r.Method(
  159. "GET",
  160. "/templates/{name}/{version}",
  161. auth.BasicAuthenticate(
  162. requestlog.NewHandler(a.HandleReadTemplate, l),
  163. ),
  164. )
  165. // /api/oauth routes
  166. r.Method(
  167. "GET",
  168. "/oauth/projects/{project_id}/github",
  169. auth.DoesUserHaveProjectAccess(
  170. requestlog.NewHandler(a.HandleGithubOAuthStartProject, l),
  171. mw.URLParam,
  172. mw.WriteAccess,
  173. ),
  174. )
  175. r.Method(
  176. "GET",
  177. "/oauth/login/github",
  178. requestlog.NewHandler(a.HandleGithubOAuthStartUser, l),
  179. )
  180. r.Method(
  181. "GET",
  182. "/oauth/github/callback",
  183. requestlog.NewHandler(a.HandleGithubOAuthCallback, l),
  184. )
  185. r.Method(
  186. "GET",
  187. "/oauth/projects/{project_id}/digitalocean",
  188. auth.DoesUserHaveProjectAccess(
  189. requestlog.NewHandler(a.HandleDOOAuthStartProject, l),
  190. mw.URLParam,
  191. mw.WriteAccess,
  192. ),
  193. )
  194. r.Method(
  195. "GET",
  196. "/oauth/digitalocean/callback",
  197. requestlog.NewHandler(a.HandleDOOAuthCallback, l),
  198. )
  199. // /api/projects routes
  200. r.Method(
  201. "GET",
  202. "/projects/{project_id}",
  203. auth.DoesUserHaveProjectAccess(
  204. requestlog.NewHandler(a.HandleReadProject, l),
  205. mw.URLParam,
  206. mw.ReadAccess,
  207. ),
  208. )
  209. r.Method(
  210. "POST",
  211. "/projects",
  212. auth.BasicAuthenticate(
  213. requestlog.NewHandler(a.HandleCreateProject, l),
  214. ),
  215. )
  216. r.Method(
  217. "DELETE",
  218. "/projects/{project_id}",
  219. auth.DoesUserHaveProjectAccess(
  220. requestlog.NewHandler(a.HandleDeleteProject, l),
  221. mw.URLParam,
  222. mw.WriteAccess,
  223. ),
  224. )
  225. // /api/projects/{project_id}/ci routes
  226. r.Method(
  227. "POST",
  228. "/projects/{project_id}/ci/actions",
  229. auth.DoesUserHaveProjectAccess(
  230. auth.DoesUserHaveClusterAccess(
  231. requestlog.NewHandler(a.HandleCreateGitAction, l),
  232. mw.URLParam,
  233. mw.QueryParam,
  234. ),
  235. mw.URLParam,
  236. mw.ReadAccess,
  237. ),
  238. )
  239. // /api/projects/{project_id}/invites routes
  240. r.Method(
  241. "POST",
  242. "/projects/{project_id}/invites",
  243. auth.DoesUserHaveProjectAccess(
  244. requestlog.NewHandler(a.HandleCreateInvite, l),
  245. mw.URLParam,
  246. mw.WriteAccess,
  247. ),
  248. )
  249. r.Method(
  250. "GET",
  251. "/projects/{project_id}/invites",
  252. auth.DoesUserHaveProjectAccess(
  253. requestlog.NewHandler(a.HandleListProjectInvites, l),
  254. mw.URLParam,
  255. mw.ReadAccess,
  256. ),
  257. )
  258. r.Method(
  259. "GET",
  260. "/projects/{project_id}/invites/{token}",
  261. auth.BasicAuthenticateWithRedirect(
  262. requestlog.NewHandler(a.HandleAcceptInvite, l),
  263. ),
  264. )
  265. r.Method(
  266. "DELETE",
  267. "/projects/{project_id}/invites/{invite_id}",
  268. auth.DoesUserHaveProjectAccess(
  269. auth.DoesUserHaveInviteAccess(
  270. requestlog.NewHandler(a.HandleDeleteProjectInvite, l),
  271. mw.URLParam,
  272. mw.URLParam,
  273. ),
  274. mw.URLParam,
  275. mw.WriteAccess,
  276. ),
  277. )
  278. // /api/projects/{project_id}/infra routes
  279. r.Method(
  280. "GET",
  281. "/projects/{project_id}/infra",
  282. auth.DoesUserHaveProjectAccess(
  283. requestlog.NewHandler(a.HandleListProjectInfra, l),
  284. mw.URLParam,
  285. mw.ReadAccess,
  286. ),
  287. )
  288. // /api/projects/{project_id}/provision routes
  289. r.Method(
  290. "POST",
  291. "/projects/{project_id}/provision/test",
  292. auth.DoesUserHaveProjectAccess(
  293. requestlog.NewHandler(a.HandleProvisionTestInfra, l),
  294. mw.URLParam,
  295. mw.ReadAccess,
  296. ),
  297. )
  298. r.Method(
  299. "POST",
  300. "/projects/{project_id}/provision/ecr",
  301. auth.DoesUserHaveProjectAccess(
  302. auth.DoesUserHaveAWSIntegrationAccess(
  303. requestlog.NewHandler(a.HandleProvisionAWSECRInfra, l),
  304. mw.URLParam,
  305. mw.BodyParam,
  306. false,
  307. ),
  308. mw.URLParam,
  309. mw.ReadAccess,
  310. ),
  311. )
  312. r.Method(
  313. "POST",
  314. "/projects/{project_id}/provision/eks",
  315. auth.DoesUserHaveProjectAccess(
  316. auth.DoesUserHaveAWSIntegrationAccess(
  317. requestlog.NewHandler(a.HandleProvisionAWSEKSInfra, l),
  318. mw.URLParam,
  319. mw.BodyParam,
  320. false,
  321. ),
  322. mw.URLParam,
  323. mw.ReadAccess,
  324. ),
  325. )
  326. r.Method(
  327. "POST",
  328. "/projects/{project_id}/provision/gcr",
  329. auth.DoesUserHaveProjectAccess(
  330. auth.DoesUserHaveGCPIntegrationAccess(
  331. requestlog.NewHandler(a.HandleProvisionGCPGCRInfra, l),
  332. mw.URLParam,
  333. mw.BodyParam,
  334. false,
  335. ),
  336. mw.URLParam,
  337. mw.ReadAccess,
  338. ),
  339. )
  340. r.Method(
  341. "POST",
  342. "/projects/{project_id}/provision/gke",
  343. auth.DoesUserHaveProjectAccess(
  344. auth.DoesUserHaveGCPIntegrationAccess(
  345. requestlog.NewHandler(a.HandleProvisionGCPGKEInfra, l),
  346. mw.URLParam,
  347. mw.BodyParam,
  348. false,
  349. ),
  350. mw.URLParam,
  351. mw.ReadAccess,
  352. ),
  353. )
  354. r.Method(
  355. "POST",
  356. "/projects/{project_id}/provision/docr",
  357. auth.DoesUserHaveProjectAccess(
  358. auth.DoesUserHaveDOIntegrationAccess(
  359. requestlog.NewHandler(a.HandleProvisionDODOCRInfra, l),
  360. mw.URLParam,
  361. mw.BodyParam,
  362. false,
  363. ),
  364. mw.URLParam,
  365. mw.ReadAccess,
  366. ),
  367. )
  368. r.Method(
  369. "POST",
  370. "/projects/{project_id}/provision/doks",
  371. auth.DoesUserHaveProjectAccess(
  372. auth.DoesUserHaveDOIntegrationAccess(
  373. requestlog.NewHandler(a.HandleProvisionDODOKSInfra, l),
  374. mw.URLParam,
  375. mw.BodyParam,
  376. false,
  377. ),
  378. mw.URLParam,
  379. mw.ReadAccess,
  380. ),
  381. )
  382. r.Method(
  383. "GET",
  384. "/projects/{project_id}/provision/{kind}/{infra_id}/logs",
  385. auth.DoesUserHaveProjectAccess(
  386. auth.DoesUserHaveInfraAccess(
  387. requestlog.NewHandler(a.HandleGetProvisioningLogs, l),
  388. mw.URLParam,
  389. mw.URLParam,
  390. ),
  391. mw.URLParam,
  392. mw.ReadAccess,
  393. ),
  394. )
  395. r.Method(
  396. "POST",
  397. "/projects/{project_id}/provision/{kind}/{infra_id}/logs",
  398. auth.DoesUserHaveProjectAccess(
  399. auth.DoesUserHaveInfraAccess(
  400. requestlog.NewHandler(a.HandleGetProvisioningLogs, l),
  401. mw.URLParam,
  402. mw.URLParam,
  403. ),
  404. mw.URLParam,
  405. mw.ReadAccess,
  406. ),
  407. )
  408. r.Method(
  409. "POST",
  410. "/projects/{project_id}/infra/{infra_id}/ecr/destroy",
  411. auth.DoesUserHaveProjectAccess(
  412. auth.DoesUserHaveInfraAccess(
  413. requestlog.NewHandler(a.HandleDestroyAWSECRInfra, l),
  414. mw.URLParam,
  415. mw.URLParam,
  416. ),
  417. mw.URLParam,
  418. mw.ReadAccess,
  419. ),
  420. )
  421. r.Method(
  422. "POST",
  423. "/projects/{project_id}/infra/{infra_id}/test/destroy",
  424. auth.DoesUserHaveProjectAccess(
  425. auth.DoesUserHaveInfraAccess(
  426. requestlog.NewHandler(a.HandleDestroyTestInfra, l),
  427. mw.URLParam,
  428. mw.URLParam,
  429. ),
  430. mw.URLParam,
  431. mw.ReadAccess,
  432. ),
  433. )
  434. r.Method(
  435. "POST",
  436. "/projects/{project_id}/infra/{infra_id}/eks/destroy",
  437. auth.DoesUserHaveProjectAccess(
  438. auth.DoesUserHaveInfraAccess(
  439. requestlog.NewHandler(a.HandleDestroyAWSEKSInfra, l),
  440. mw.URLParam,
  441. mw.URLParam,
  442. ),
  443. mw.URLParam,
  444. mw.ReadAccess,
  445. ),
  446. )
  447. r.Method(
  448. "POST",
  449. "/projects/{project_id}/infra/{infra_id}/gke/destroy",
  450. auth.DoesUserHaveProjectAccess(
  451. auth.DoesUserHaveInfraAccess(
  452. requestlog.NewHandler(a.HandleDestroyGCPGKEInfra, l),
  453. mw.URLParam,
  454. mw.URLParam,
  455. ),
  456. mw.URLParam,
  457. mw.ReadAccess,
  458. ),
  459. )
  460. r.Method(
  461. "POST",
  462. "/projects/{project_id}/infra/{infra_id}/docr/destroy",
  463. auth.DoesUserHaveProjectAccess(
  464. auth.DoesUserHaveInfraAccess(
  465. requestlog.NewHandler(a.HandleDestroyDODOCRInfra, l),
  466. mw.URLParam,
  467. mw.URLParam,
  468. ),
  469. mw.URLParam,
  470. mw.ReadAccess,
  471. ),
  472. )
  473. r.Method(
  474. "POST",
  475. "/projects/{project_id}/infra/{infra_id}/doks/destroy",
  476. auth.DoesUserHaveProjectAccess(
  477. auth.DoesUserHaveInfraAccess(
  478. requestlog.NewHandler(a.HandleDestroyDODOKSInfra, l),
  479. mw.URLParam,
  480. mw.URLParam,
  481. ),
  482. mw.URLParam,
  483. mw.ReadAccess,
  484. ),
  485. )
  486. // /api/projects/{project_id}/clusters routes
  487. r.Method(
  488. "GET",
  489. "/projects/{project_id}/clusters",
  490. auth.DoesUserHaveProjectAccess(
  491. requestlog.NewHandler(a.HandleListProjectClusters, l),
  492. mw.URLParam,
  493. mw.ReadAccess,
  494. ),
  495. )
  496. r.Method(
  497. "POST",
  498. "/projects/{project_id}/clusters",
  499. auth.DoesUserHaveProjectAccess(
  500. auth.DoesUserHaveAWSIntegrationAccess(
  501. auth.DoesUserHaveGCPIntegrationAccess(
  502. requestlog.NewHandler(a.HandleCreateProjectCluster, l),
  503. mw.URLParam,
  504. mw.BodyParam,
  505. true,
  506. ),
  507. mw.URLParam,
  508. mw.BodyParam,
  509. true,
  510. ),
  511. mw.URLParam,
  512. mw.WriteAccess,
  513. ),
  514. )
  515. r.Method(
  516. "GET",
  517. "/projects/{project_id}/clusters/{cluster_id}",
  518. auth.DoesUserHaveProjectAccess(
  519. auth.DoesUserHaveClusterAccess(
  520. requestlog.NewHandler(a.HandleReadProjectCluster, l),
  521. mw.URLParam,
  522. mw.URLParam,
  523. ),
  524. mw.URLParam,
  525. mw.ReadAccess,
  526. ),
  527. )
  528. r.Method(
  529. "POST",
  530. "/projects/{project_id}/clusters/{cluster_id}",
  531. auth.DoesUserHaveProjectAccess(
  532. auth.DoesUserHaveClusterAccess(
  533. requestlog.NewHandler(a.HandleUpdateProjectCluster, l),
  534. mw.URLParam,
  535. mw.URLParam,
  536. ),
  537. mw.URLParam,
  538. mw.WriteAccess,
  539. ),
  540. )
  541. r.Method(
  542. "DELETE",
  543. "/projects/{project_id}/clusters/{cluster_id}",
  544. auth.DoesUserHaveProjectAccess(
  545. auth.DoesUserHaveClusterAccess(
  546. requestlog.NewHandler(a.HandleDeleteProjectCluster, l),
  547. mw.URLParam,
  548. mw.URLParam,
  549. ),
  550. mw.URLParam,
  551. mw.WriteAccess,
  552. ),
  553. )
  554. // /api/projects/{project_id}/clusters/candidates routes
  555. r.Method(
  556. "POST",
  557. "/projects/{project_id}/clusters/candidates",
  558. auth.DoesUserHaveProjectAccess(
  559. requestlog.NewHandler(a.HandleCreateProjectClusterCandidates, l),
  560. mw.URLParam,
  561. mw.WriteAccess,
  562. ),
  563. )
  564. r.Method(
  565. "GET",
  566. "/projects/{project_id}/clusters/candidates",
  567. auth.DoesUserHaveProjectAccess(
  568. requestlog.NewHandler(a.HandleListProjectClusterCandidates, l),
  569. mw.URLParam,
  570. mw.WriteAccess,
  571. ),
  572. )
  573. r.Method(
  574. "POST",
  575. "/projects/{project_id}/clusters/candidates/{candidate_id}/resolve",
  576. auth.DoesUserHaveProjectAccess(
  577. requestlog.NewHandler(a.HandleResolveClusterCandidate, l),
  578. mw.URLParam,
  579. mw.WriteAccess,
  580. ),
  581. )
  582. // /api/projects/{project_id}/integrations routes
  583. r.Method(
  584. "POST",
  585. "/projects/{project_id}/integrations/gcp",
  586. auth.DoesUserHaveProjectAccess(
  587. requestlog.NewHandler(a.HandleCreateGCPIntegration, l),
  588. mw.URLParam,
  589. mw.WriteAccess,
  590. ),
  591. )
  592. r.Method(
  593. "POST",
  594. "/projects/{project_id}/integrations/aws",
  595. auth.DoesUserHaveProjectAccess(
  596. requestlog.NewHandler(a.HandleCreateAWSIntegration, l),
  597. mw.URLParam,
  598. mw.WriteAccess,
  599. ),
  600. )
  601. r.Method(
  602. "POST",
  603. "/projects/{project_id}/integrations/basic",
  604. auth.DoesUserHaveProjectAccess(
  605. requestlog.NewHandler(a.HandleCreateBasicAuthIntegration, l),
  606. mw.URLParam,
  607. mw.WriteAccess,
  608. ),
  609. )
  610. r.Method(
  611. "GET",
  612. "/projects/{project_id}/integrations/oauth",
  613. auth.DoesUserHaveProjectAccess(
  614. requestlog.NewHandler(a.HandleListProjectOAuthIntegrations, l),
  615. mw.URLParam,
  616. mw.WriteAccess,
  617. ),
  618. )
  619. // /api/projects/{project_id}/helmrepos routes
  620. r.Method(
  621. "POST",
  622. "/projects/{project_id}/helmrepos",
  623. auth.DoesUserHaveProjectAccess(
  624. auth.DoesUserHaveAWSIntegrationAccess(
  625. auth.DoesUserHaveGCPIntegrationAccess(
  626. requestlog.NewHandler(a.HandleCreateHelmRepo, l),
  627. mw.URLParam,
  628. mw.BodyParam,
  629. true,
  630. ),
  631. mw.URLParam,
  632. mw.BodyParam,
  633. true,
  634. ),
  635. mw.URLParam,
  636. mw.WriteAccess,
  637. ),
  638. )
  639. r.Method(
  640. "GET",
  641. "/projects/{project_id}/helmrepos",
  642. auth.DoesUserHaveProjectAccess(
  643. requestlog.NewHandler(a.HandleListProjectHelmRepos, l),
  644. mw.URLParam,
  645. mw.WriteAccess,
  646. ),
  647. )
  648. r.Method(
  649. "GET",
  650. "/projects/{project_id}/helmrepos/{helm_id}/charts",
  651. auth.DoesUserHaveProjectAccess(
  652. requestlog.NewHandler(a.HandleListHelmRepoCharts, l),
  653. mw.URLParam,
  654. mw.WriteAccess,
  655. ),
  656. )
  657. // /api/projects/{project_id}/registries routes
  658. r.Method(
  659. "POST",
  660. "/projects/{project_id}/registries",
  661. auth.DoesUserHaveProjectAccess(
  662. auth.DoesUserHaveAWSIntegrationAccess(
  663. auth.DoesUserHaveGCPIntegrationAccess(
  664. auth.DoesUserHaveDOIntegrationAccess(
  665. requestlog.NewHandler(a.HandleCreateRegistry, l),
  666. mw.URLParam,
  667. mw.BodyParam,
  668. true,
  669. ),
  670. mw.URLParam,
  671. mw.BodyParam,
  672. true,
  673. ),
  674. mw.URLParam,
  675. mw.BodyParam,
  676. true,
  677. ),
  678. mw.URLParam,
  679. mw.WriteAccess,
  680. ),
  681. )
  682. r.Method(
  683. "GET",
  684. "/projects/{project_id}/registries",
  685. auth.DoesUserHaveProjectAccess(
  686. requestlog.NewHandler(a.HandleListProjectRegistries, l),
  687. mw.URLParam,
  688. mw.WriteAccess,
  689. ),
  690. )
  691. r.Method(
  692. "POST",
  693. "/projects/{project_id}/registries/{registry_id}",
  694. auth.DoesUserHaveProjectAccess(
  695. auth.DoesUserHaveRegistryAccess(
  696. requestlog.NewHandler(a.HandleUpdateProjectRegistry, l),
  697. mw.URLParam,
  698. mw.URLParam,
  699. ),
  700. mw.URLParam,
  701. mw.WriteAccess,
  702. ),
  703. )
  704. r.Method(
  705. "GET",
  706. "/projects/{project_id}/registries/ecr/{region}/token",
  707. auth.DoesUserHaveProjectAccess(
  708. requestlog.NewHandler(a.HandleGetProjectRegistryECRToken, l),
  709. mw.URLParam,
  710. mw.WriteAccess,
  711. ),
  712. )
  713. r.Method(
  714. "GET",
  715. "/projects/{project_id}/registries/gcr/token",
  716. auth.DoesUserHaveProjectAccess(
  717. requestlog.NewHandler(a.HandleGetProjectRegistryGCRToken, l),
  718. mw.URLParam,
  719. mw.WriteAccess,
  720. ),
  721. )
  722. r.Method(
  723. "GET",
  724. "/projects/{project_id}/registries/dockerhub/token",
  725. auth.DoesUserHaveProjectAccess(
  726. requestlog.NewHandler(a.HandleGetProjectRegistryDockerhubToken, l),
  727. mw.URLParam,
  728. mw.WriteAccess,
  729. ),
  730. )
  731. r.Method(
  732. "GET",
  733. "/projects/{project_id}/registries/docr/token",
  734. auth.DoesUserHaveProjectAccess(
  735. requestlog.NewHandler(a.HandleGetProjectRegistryDOCRToken, l),
  736. mw.URLParam,
  737. mw.WriteAccess,
  738. ),
  739. )
  740. r.Method(
  741. "DELETE",
  742. "/projects/{project_id}/registries/{registry_id}",
  743. auth.DoesUserHaveProjectAccess(
  744. auth.DoesUserHaveRegistryAccess(
  745. requestlog.NewHandler(a.HandleDeleteProjectRegistry, l),
  746. mw.URLParam,
  747. mw.URLParam,
  748. ),
  749. mw.URLParam,
  750. mw.WriteAccess,
  751. ),
  752. )
  753. // /api/projects/{project_id}/registries/{registry_id}/repositories routes
  754. r.Method(
  755. "GET",
  756. "/projects/{project_id}/registries/{registry_id}/repositories",
  757. auth.DoesUserHaveProjectAccess(
  758. auth.DoesUserHaveRegistryAccess(
  759. requestlog.NewHandler(a.HandleListRepositories, l),
  760. mw.URLParam,
  761. mw.URLParam,
  762. ),
  763. mw.URLParam,
  764. mw.WriteAccess,
  765. ),
  766. )
  767. r.Method(
  768. "GET",
  769. // * is the repo name, which can itself be nested
  770. // for example, for GCR this is project-id/repo
  771. // need to use wildcard, see https://github.com/go-chi/chi/issues/243
  772. "/projects/{project_id}/registries/{registry_id}/repositories/*",
  773. auth.DoesUserHaveProjectAccess(
  774. auth.DoesUserHaveRegistryAccess(
  775. requestlog.NewHandler(a.HandleListImages, l),
  776. mw.URLParam,
  777. mw.URLParam,
  778. ),
  779. mw.URLParam,
  780. mw.WriteAccess,
  781. ),
  782. )
  783. // /api/projects/{project_id}/releases routes
  784. r.Method(
  785. "GET",
  786. "/projects/{project_id}/releases",
  787. auth.DoesUserHaveProjectAccess(
  788. auth.DoesUserHaveClusterAccess(
  789. requestlog.NewHandler(a.HandleListReleases, l),
  790. mw.URLParam,
  791. mw.QueryParam,
  792. ),
  793. mw.URLParam,
  794. mw.ReadAccess,
  795. ),
  796. )
  797. r.Method(
  798. "GET",
  799. "/projects/{project_id}/releases/{name}/{revision}/components",
  800. auth.DoesUserHaveProjectAccess(
  801. auth.DoesUserHaveClusterAccess(
  802. requestlog.NewHandler(a.HandleGetReleaseComponents, l),
  803. mw.URLParam,
  804. mw.QueryParam,
  805. ),
  806. mw.URLParam,
  807. mw.ReadAccess,
  808. ),
  809. )
  810. r.Method(
  811. "GET",
  812. "/projects/{project_id}/releases/{name}/{revision}/controllers",
  813. auth.DoesUserHaveProjectAccess(
  814. auth.DoesUserHaveClusterAccess(
  815. requestlog.NewHandler(a.HandleGetReleaseControllers, l),
  816. mw.URLParam,
  817. mw.QueryParam,
  818. ),
  819. mw.URLParam,
  820. mw.ReadAccess,
  821. ),
  822. )
  823. r.Method(
  824. "GET",
  825. "/projects/{project_id}/releases/{name}/{revision}/pods/all",
  826. auth.DoesUserHaveProjectAccess(
  827. auth.DoesUserHaveClusterAccess(
  828. requestlog.NewHandler(a.HandleGetReleaseAllPods, l),
  829. mw.URLParam,
  830. mw.QueryParam,
  831. ),
  832. mw.URLParam,
  833. mw.ReadAccess,
  834. ),
  835. )
  836. r.Method(
  837. "GET",
  838. "/projects/{project_id}/releases/{name}/history",
  839. auth.DoesUserHaveProjectAccess(
  840. auth.DoesUserHaveClusterAccess(
  841. requestlog.NewHandler(a.HandleListReleaseHistory, l),
  842. mw.URLParam,
  843. mw.QueryParam,
  844. ),
  845. mw.URLParam,
  846. mw.ReadAccess,
  847. ),
  848. )
  849. r.Method(
  850. "GET",
  851. "/projects/{project_id}/releases/{name}/webhook_token",
  852. auth.DoesUserHaveProjectAccess(
  853. auth.DoesUserHaveClusterAccess(
  854. requestlog.NewHandler(a.HandleGetReleaseToken, l),
  855. mw.URLParam,
  856. mw.QueryParam,
  857. ),
  858. mw.URLParam,
  859. mw.ReadAccess,
  860. ),
  861. )
  862. r.Method(
  863. "GET",
  864. "/projects/{project_id}/releases/{name}/{revision}",
  865. auth.DoesUserHaveProjectAccess(
  866. auth.DoesUserHaveClusterAccess(
  867. requestlog.NewHandler(a.HandleGetRelease, l),
  868. mw.URLParam,
  869. mw.QueryParam,
  870. ),
  871. mw.URLParam,
  872. mw.ReadAccess,
  873. ),
  874. )
  875. // /api/projects/{project_id}/gitrepos routes
  876. r.Method(
  877. "GET",
  878. "/projects/{project_id}/gitrepos",
  879. auth.DoesUserHaveProjectAccess(
  880. requestlog.NewHandler(a.HandleListProjectGitRepos, l),
  881. mw.URLParam,
  882. mw.ReadAccess,
  883. ),
  884. )
  885. r.Method(
  886. "DELETE",
  887. "/projects/{project_id}/gitrepos/{git_repo_id}",
  888. auth.DoesUserHaveProjectAccess(
  889. auth.DoesUserHaveGitRepoAccess(
  890. requestlog.NewHandler(a.HandleDeleteProjectGitRepo, l),
  891. mw.URLParam,
  892. mw.URLParam,
  893. ),
  894. mw.URLParam,
  895. mw.WriteAccess,
  896. ),
  897. )
  898. r.Method(
  899. "GET",
  900. "/projects/{project_id}/gitrepos/{git_repo_id}/repos",
  901. auth.DoesUserHaveProjectAccess(
  902. auth.DoesUserHaveGitRepoAccess(
  903. requestlog.NewHandler(a.HandleListRepos, l),
  904. mw.URLParam,
  905. mw.URLParam,
  906. ),
  907. mw.URLParam,
  908. mw.ReadAccess,
  909. ),
  910. )
  911. r.Method(
  912. "GET",
  913. "/projects/{project_id}/gitrepos/{git_repo_id}/repos/{kind}/{owner}/{name}/branches",
  914. auth.DoesUserHaveProjectAccess(
  915. auth.DoesUserHaveGitRepoAccess(
  916. requestlog.NewHandler(a.HandleGetBranches, l),
  917. mw.URLParam,
  918. mw.URLParam,
  919. ),
  920. mw.URLParam,
  921. mw.ReadAccess,
  922. ),
  923. )
  924. r.Method(
  925. "GET",
  926. "/projects/{project_id}/gitrepos/{git_repo_id}/repos/{kind}/{owner}/{name}/{branch}/contents",
  927. auth.DoesUserHaveProjectAccess(
  928. auth.DoesUserHaveGitRepoAccess(
  929. requestlog.NewHandler(a.HandleGetBranchContents, l),
  930. mw.URLParam,
  931. mw.URLParam,
  932. ),
  933. mw.URLParam,
  934. mw.ReadAccess,
  935. ),
  936. )
  937. r.Method(
  938. "GET",
  939. "/projects/{project_id}/gitrepos/{git_repo_id}/repos/{kind}/{owner}/{name}/{branch}/procfile",
  940. auth.DoesUserHaveProjectAccess(
  941. auth.DoesUserHaveGitRepoAccess(
  942. requestlog.NewHandler(a.HandleGetProcfileContents, l),
  943. mw.URLParam,
  944. mw.URLParam,
  945. ),
  946. mw.URLParam,
  947. mw.ReadAccess,
  948. ),
  949. )
  950. // /api/projects/{project_id}/k8s routes
  951. r.Method(
  952. "GET",
  953. "/projects/{project_id}/k8s/namespaces",
  954. auth.DoesUserHaveProjectAccess(
  955. auth.DoesUserHaveClusterAccess(
  956. requestlog.NewHandler(a.HandleListNamespaces, l),
  957. mw.URLParam,
  958. mw.QueryParam,
  959. ),
  960. mw.URLParam,
  961. mw.ReadAccess,
  962. ),
  963. )
  964. r.Method(
  965. "GET",
  966. "/projects/{project_id}/k8s/kubeconfig",
  967. auth.DoesUserHaveProjectAccess(
  968. auth.DoesUserHaveClusterAccess(
  969. requestlog.NewHandler(a.HandleGetTemporaryKubeconfig, l),
  970. mw.URLParam,
  971. mw.QueryParam,
  972. ),
  973. mw.URLParam,
  974. mw.WriteAccess,
  975. ),
  976. )
  977. r.Method(
  978. "GET",
  979. "/projects/{project_id}/k8s/prometheus/detect",
  980. auth.DoesUserHaveProjectAccess(
  981. auth.DoesUserHaveClusterAccess(
  982. requestlog.NewHandler(a.HandleDetectPrometheusInstalled, l),
  983. mw.URLParam,
  984. mw.QueryParam,
  985. ),
  986. mw.URLParam,
  987. mw.ReadAccess,
  988. ),
  989. )
  990. r.Method(
  991. "GET",
  992. "/projects/{project_id}/k8s/prometheus/ingresses",
  993. auth.DoesUserHaveProjectAccess(
  994. auth.DoesUserHaveClusterAccess(
  995. requestlog.NewHandler(a.HandleListNGINXIngresses, l),
  996. mw.URLParam,
  997. mw.QueryParam,
  998. ),
  999. mw.URLParam,
  1000. mw.ReadAccess,
  1001. ),
  1002. )
  1003. r.Method(
  1004. "GET",
  1005. "/projects/{project_id}/k8s/metrics",
  1006. auth.DoesUserHaveProjectAccess(
  1007. auth.DoesUserHaveClusterAccess(
  1008. requestlog.NewHandler(a.HandleGetPodMetrics, l),
  1009. mw.URLParam,
  1010. mw.QueryParam,
  1011. ),
  1012. mw.URLParam,
  1013. mw.ReadAccess,
  1014. ),
  1015. )
  1016. r.Method(
  1017. "GET",
  1018. "/projects/{project_id}/k8s/{namespace}/pod/{name}/logs",
  1019. auth.DoesUserHaveProjectAccess(
  1020. auth.DoesUserHaveClusterAccess(
  1021. requestlog.NewHandler(a.HandleGetPodLogs, l),
  1022. mw.URLParam,
  1023. mw.QueryParam,
  1024. ),
  1025. mw.URLParam,
  1026. mw.ReadAccess,
  1027. ),
  1028. )
  1029. r.Method(
  1030. "GET",
  1031. "/projects/{project_id}/k8s/{namespace}/{chart}/{release_name}/jobs",
  1032. auth.DoesUserHaveProjectAccess(
  1033. auth.DoesUserHaveClusterAccess(
  1034. requestlog.NewHandler(a.HandleListJobsByChart, l),
  1035. mw.URLParam,
  1036. mw.QueryParam,
  1037. ),
  1038. mw.URLParam,
  1039. mw.ReadAccess,
  1040. ),
  1041. )
  1042. r.Method(
  1043. "GET",
  1044. "/projects/{project_id}/k8s/jobs/{namespace}/{name}/pods",
  1045. auth.DoesUserHaveProjectAccess(
  1046. auth.DoesUserHaveClusterAccess(
  1047. requestlog.NewHandler(a.HandleListJobPods, l),
  1048. mw.URLParam,
  1049. mw.QueryParam,
  1050. ),
  1051. mw.URLParam,
  1052. mw.ReadAccess,
  1053. ),
  1054. )
  1055. r.Method(
  1056. "GET",
  1057. "/projects/{project_id}/k8s/{namespace}/ingress/{name}",
  1058. auth.DoesUserHaveProjectAccess(
  1059. auth.DoesUserHaveClusterAccess(
  1060. requestlog.NewHandler(a.HandleGetIngress, l),
  1061. mw.URLParam,
  1062. mw.QueryParam,
  1063. ),
  1064. mw.URLParam,
  1065. mw.ReadAccess,
  1066. ),
  1067. )
  1068. r.Method(
  1069. "GET",
  1070. "/projects/{project_id}/k8s/{kind}/status",
  1071. auth.DoesUserHaveProjectAccess(
  1072. auth.DoesUserHaveClusterAccess(
  1073. requestlog.NewHandler(a.HandleStreamControllerStatus, l),
  1074. mw.URLParam,
  1075. mw.QueryParam,
  1076. ),
  1077. mw.URLParam,
  1078. mw.ReadAccess,
  1079. ),
  1080. )
  1081. r.Method(
  1082. "GET",
  1083. "/projects/{project_id}/k8s/pods",
  1084. auth.DoesUserHaveProjectAccess(
  1085. auth.DoesUserHaveClusterAccess(
  1086. requestlog.NewHandler(a.HandleListPods, l),
  1087. mw.URLParam,
  1088. mw.QueryParam,
  1089. ),
  1090. mw.URLParam,
  1091. mw.ReadAccess,
  1092. ),
  1093. )
  1094. r.Method(
  1095. "DELETE",
  1096. "/projects/{project_id}/k8s/pods/{namespace}/{name}",
  1097. auth.DoesUserHaveProjectAccess(
  1098. auth.DoesUserHaveClusterAccess(
  1099. requestlog.NewHandler(a.HandleDeletePod, l),
  1100. mw.URLParam,
  1101. mw.QueryParam,
  1102. ),
  1103. mw.URLParam,
  1104. mw.ReadAccess,
  1105. ),
  1106. )
  1107. r.Method(
  1108. "GET",
  1109. "/projects/{project_id}/k8s/pods/{namespace}/{name}/events/list",
  1110. auth.DoesUserHaveProjectAccess(
  1111. auth.DoesUserHaveClusterAccess(
  1112. requestlog.NewHandler(a.HandleListPodEvents, l),
  1113. mw.URLParam,
  1114. mw.QueryParam,
  1115. ),
  1116. mw.URLParam,
  1117. mw.ReadAccess,
  1118. ),
  1119. )
  1120. r.Method(
  1121. "POST",
  1122. "/projects/{project_id}/k8s/configmap/create",
  1123. auth.DoesUserHaveProjectAccess(
  1124. auth.DoesUserHaveClusterAccess(
  1125. requestlog.NewHandler(a.HandleCreateConfigMap, l),
  1126. mw.URLParam,
  1127. mw.QueryParam,
  1128. ),
  1129. mw.URLParam,
  1130. mw.ReadAccess,
  1131. ),
  1132. )
  1133. r.Method(
  1134. "DELETE",
  1135. "/projects/{project_id}/k8s/configmap/delete",
  1136. auth.DoesUserHaveProjectAccess(
  1137. auth.DoesUserHaveClusterAccess(
  1138. requestlog.NewHandler(a.HandleDeleteConfigMap, l),
  1139. mw.URLParam,
  1140. mw.QueryParam,
  1141. ),
  1142. mw.URLParam,
  1143. mw.ReadAccess,
  1144. ),
  1145. )
  1146. r.Method(
  1147. "GET",
  1148. "/projects/{project_id}/k8s/configmap",
  1149. auth.DoesUserHaveProjectAccess(
  1150. auth.DoesUserHaveClusterAccess(
  1151. requestlog.NewHandler(a.HandleGetConfigMap, l),
  1152. mw.URLParam,
  1153. mw.QueryParam,
  1154. ),
  1155. mw.URLParam,
  1156. mw.ReadAccess,
  1157. ),
  1158. )
  1159. r.Method(
  1160. "GET",
  1161. "/projects/{project_id}/k8s/configmap/list",
  1162. auth.DoesUserHaveProjectAccess(
  1163. auth.DoesUserHaveClusterAccess(
  1164. requestlog.NewHandler(a.HandleListConfigMaps, l),
  1165. mw.URLParam,
  1166. mw.QueryParam,
  1167. ),
  1168. mw.URLParam,
  1169. mw.ReadAccess,
  1170. ),
  1171. )
  1172. r.Method(
  1173. "POST",
  1174. "/projects/{project_id}/k8s/configmap/update",
  1175. auth.DoesUserHaveProjectAccess(
  1176. auth.DoesUserHaveClusterAccess(
  1177. requestlog.NewHandler(a.HandleUpdateConfigMap, l),
  1178. mw.URLParam,
  1179. mw.QueryParam,
  1180. ),
  1181. mw.URLParam,
  1182. mw.ReadAccess,
  1183. ),
  1184. )
  1185. r.Method(
  1186. "POST",
  1187. "/projects/{project_id}/k8s/jobs/{namespace}/{name}/stop",
  1188. auth.DoesUserHaveProjectAccess(
  1189. auth.DoesUserHaveClusterAccess(
  1190. requestlog.NewHandler(a.HandleStopJob, l),
  1191. mw.URLParam,
  1192. mw.QueryParam,
  1193. ),
  1194. mw.URLParam,
  1195. mw.ReadAccess,
  1196. ),
  1197. )
  1198. // /api/projects/{project_id}/subdomain routes
  1199. r.Method(
  1200. "POST",
  1201. "/projects/{project_id}/k8s/subdomain",
  1202. auth.DoesUserHaveProjectAccess(
  1203. auth.DoesUserHaveClusterAccess(
  1204. requestlog.NewHandler(a.HandleCreateDNSRecord, l),
  1205. mw.URLParam,
  1206. mw.QueryParam,
  1207. ),
  1208. mw.URLParam,
  1209. mw.ReadAccess,
  1210. ),
  1211. )
  1212. // capabilities
  1213. r.Method(
  1214. "GET",
  1215. "/capabilities",
  1216. http.HandlerFunc(a.HandleGetCapabilities),
  1217. )
  1218. // /api/projects/{project_id}/deploy routes
  1219. r.Method(
  1220. "POST",
  1221. "/projects/{project_id}/deploy/{name}/{version}",
  1222. auth.DoesUserHaveProjectAccess(
  1223. auth.DoesUserHaveClusterAccess(
  1224. requestlog.NewHandler(a.HandleDeployTemplate, l),
  1225. mw.URLParam,
  1226. mw.QueryParam,
  1227. ),
  1228. mw.URLParam,
  1229. mw.ReadAccess,
  1230. ),
  1231. )
  1232. })
  1233. // Create group for long-running Helm operations
  1234. r.Group(func(r chi.Router) {
  1235. r.Use(middleware.Timeout(300 * time.Second))
  1236. r.Method(
  1237. "POST",
  1238. "/projects/{project_id}/releases/{name}/rollback",
  1239. auth.DoesUserHaveProjectAccess(
  1240. auth.DoesUserHaveClusterAccess(
  1241. requestlog.NewHandler(a.HandleRollbackRelease, l),
  1242. mw.URLParam,
  1243. mw.QueryParam,
  1244. ),
  1245. mw.URLParam,
  1246. mw.ReadAccess,
  1247. ),
  1248. )
  1249. r.Method(
  1250. "POST",
  1251. "/webhooks/deploy/{token}",
  1252. requestlog.NewHandler(a.HandleReleaseDeployWebhook, l),
  1253. )
  1254. r.Method(
  1255. "POST",
  1256. "/projects/{project_id}/delete/{name}",
  1257. auth.DoesUserHaveProjectAccess(
  1258. auth.DoesUserHaveClusterAccess(
  1259. requestlog.NewHandler(a.HandleUninstallTemplate, l),
  1260. mw.URLParam,
  1261. mw.QueryParam,
  1262. ),
  1263. mw.URLParam,
  1264. mw.ReadAccess,
  1265. ),
  1266. )
  1267. r.Method(
  1268. "POST",
  1269. "/projects/{project_id}/releases/{name}/upgrade",
  1270. auth.DoesUserHaveProjectAccess(
  1271. auth.DoesUserHaveClusterAccess(
  1272. requestlog.NewHandler(a.HandleUpgradeRelease, l),
  1273. mw.URLParam,
  1274. mw.QueryParam,
  1275. ),
  1276. mw.URLParam,
  1277. mw.ReadAccess,
  1278. ),
  1279. )
  1280. })
  1281. })
  1282. staticFilePath := a.ServerConf.StaticFilePath
  1283. fs := http.FileServer(http.Dir(staticFilePath))
  1284. r.Get("/*", func(w http.ResponseWriter, r *http.Request) {
  1285. if _, err := os.Stat(staticFilePath + r.RequestURI); os.IsNotExist(err) {
  1286. w.Header().Set("Cache-Control", "no-cache")
  1287. http.StripPrefix(r.URL.Path, fs).ServeHTTP(w, r)
  1288. } else {
  1289. // Set static files involving html, js, or empty cache to "no-cache", which means they must be validated
  1290. // for changes before the browser uses the cache
  1291. if base := path.Base(r.URL.Path); strings.Contains(base, "html") || strings.Contains(base, "js") || base == "." || base == "/" {
  1292. w.Header().Set("Cache-Control", "no-cache")
  1293. }
  1294. fs.ServeHTTP(w, r)
  1295. }
  1296. })
  1297. return r
  1298. }