github.com/quickfeed/quickfeed@v0.0.0-20240507093252-ed8ca812a09c/web/webserver.go (about) 1 package web 2 3 import ( 4 "net/http" 5 "time" 6 7 "connectrpc.com/connect" 8 "github.com/quickfeed/quickfeed/internal/rand" 9 "github.com/quickfeed/quickfeed/qf/qfconnect" 10 "github.com/quickfeed/quickfeed/web/auth" 11 "github.com/quickfeed/quickfeed/web/hooks" 12 "github.com/quickfeed/quickfeed/web/interceptor" 13 "golang.org/x/oauth2" 14 ) 15 16 const ( 17 // streamTimeout is the timeout for the submission stream. 18 streamTimeout = 15 * time.Minute 19 ) 20 21 func (s *QuickFeedService) NewQuickFeedHandler(tm *auth.TokenManager) (string, http.Handler) { 22 interceptors := connect.WithInterceptors( 23 interceptor.NewMetricsInterceptor(), 24 interceptor.NewValidationInterceptor(s.logger), 25 interceptor.NewTokenAuthInterceptor(s.logger, tm, s.db), 26 interceptor.NewUserInterceptor(s.logger, tm), 27 interceptor.NewAccessControlInterceptor(tm), 28 interceptor.NewTokenInterceptor(tm), 29 ) 30 return qfconnect.NewQuickFeedServiceHandler(s, interceptors) 31 } 32 33 // RegisterRouter registers http endpoints for authentication API and scm provider webhooks. 34 func (s *QuickFeedService) RegisterRouter(tm *auth.TokenManager, authConfig *oauth2.Config, public string) *http.ServeMux { 35 // Serve static files. 36 router := http.NewServeMux() 37 assets := http.FileServer(http.Dir(public + "/assets")) // skipcq: GO-S1034 38 dist := http.FileServer(http.Dir(public + "/dist")) // skipcq: GO-S1034 39 40 router.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 41 http.ServeFile(w, r, public+"/assets/index.html") 42 })) 43 paths, handler := s.NewQuickFeedHandler(tm) 44 router.Handle(paths, controller(handler, streamTimeout)) 45 46 router.Handle(auth.Assets, http.StripPrefix(auth.Assets, assets)) 47 router.Handle(auth.Static, http.StripPrefix(auth.Static, dist)) 48 // Register auth endpoints. 49 callbackSecret := rand.String() 50 router.HandleFunc(auth.Auth, auth.OAuth2Login(s.logger, authConfig, callbackSecret)) 51 router.HandleFunc(auth.Callback, auth.OAuth2Callback(s.logger, s.db, tm, authConfig, callbackSecret)) 52 router.HandleFunc(auth.Logout, auth.OAuth2Logout()) 53 54 // Register hooks. 55 ghHook := hooks.NewGitHubWebHook(s.logger, s.db, s.scmMgr, s.runner, s.bh.Secret, s.streams, tm) 56 router.HandleFunc(auth.Hook, ghHook.Handle()) 57 58 return router 59 } 60 61 // controller is a wrapper for the QuickFeedService handler that sets a write deadline for the submission stream. 62 // TODO: Remove this when connect-go finally supports deadlines. 63 // TODO: https://github.com/connectrpc/connect-go/issues/604 64 func controller(h http.Handler, timeout time.Duration) http.Handler { 65 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 66 if r.URL.Path == qfconnect.QuickFeedServiceSubmissionStreamProcedure { 67 control := http.NewResponseController(w) 68 _ = control.SetWriteDeadline(time.Now().Add(timeout)) 69 } 70 h.ServeHTTP(w, r) 71 }) 72 }