From d6f620bc0d6ae3094ad49d64705c435518a8b756 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Fri, 18 Nov 2022 15:38:50 +0100 Subject: [PATCH 1/5] ui: Use $lib in imports --- ui/src/{ => lib}/components/AuthButton.svelte | 0 ui/src/{ => lib}/components/BuildState.svelte | 0 ui/src/{ => lib}/components/Correction.svelte | 0 .../components/CorrectionPieChart.svelte | 0 .../components/CorrectionReference.svelte | 2 +- .../CorrectionResponseFooter.svelte | 4 ++-- .../components/CorrectionResponses.svelte | 4 ++-- ui/src/{ => lib}/components/DateFormat.svelte | 0 .../{ => lib}/components/DateTimeInput.svelte | 0 ui/src/{ => lib}/components/ListInput.svelte | 0 .../components/ListInputResponses.svelte | 0 .../{ => lib}/components/QuestionForm.svelte | 2 +- .../components/QuestionHeader.svelte | 2 +- .../components/QuestionProposals.svelte | 2 +- .../components/ResponseCorrected.svelte | 4 ++-- .../components/StartStopLiveSurvey.svelte | 0 .../{ => lib}/components/StudentGrades.svelte | 4 ++-- .../components/SubmissionStatus.svelte | 4 ++-- .../{ => lib}/components/SurveyAdmin.svelte | 4 ++-- .../{ => lib}/components/SurveyBadge.svelte | 0 ui/src/{ => lib}/components/SurveyList.svelte | 12 +++++------ .../components/SurveyQuestions.svelte | 8 ++++---- ui/src/{ => lib}/components/Toaster.svelte | 2 +- ui/src/{ => lib}/components/UserKeys.svelte | 2 +- .../{ => lib}/components/UserSurveys.svelte | 4 ++-- .../components/ValidateSubmissions.svelte | 4 ++-- ui/src/{ => lib}/components/WorkAdmin.svelte | 2 +- .../components/WorkRepository.svelte | 8 ++++---- ui/src/{ => lib}/stores/toasts.js | 0 ui/src/{ => lib}/stores/user.js | 0 ui/src/routes/__layout.svelte | 6 +++--- ui/src/routes/auth.svelte | 6 +++--- ui/src/routes/grades/[promo].svelte | 2 +- ui/src/routes/grades/index.svelte | 2 +- ui/src/routes/help.svelte | 4 ++-- ui/src/routes/index.svelte | 10 +++++----- ui/src/routes/keys.svelte | 6 +++--- ui/src/routes/surveys/[sid]/__layout.svelte | 2 +- ui/src/routes/surveys/[sid]/admin.svelte | 20 +++++++++---------- ui/src/routes/surveys/[sid]/index.svelte | 12 +++++------ ui/src/routes/surveys/[sid]/live.svelte | 10 +++++----- .../surveys/[sid]/responses/[rid].svelte | 16 +++++++-------- .../surveys/[sid]/responses/index.svelte | 16 +++++++-------- ui/src/routes/surveys/index.svelte | 4 ++-- ui/src/routes/surveys/new.svelte | 8 ++++---- ui/src/routes/users/[uid]/index.svelte | 10 +++++----- .../routes/users/[uid]/surveys/[sid].svelte | 10 +++++----- .../routes/users/[uid]/surveys/index.svelte | 8 ++++---- ui/src/routes/users/index.svelte | 6 +++--- ui/src/routes/works/[wid]/__layout.svelte | 2 +- ui/src/routes/works/[wid]/index.svelte | 16 +++++++-------- ui/src/routes/works/[wid]/rendus.svelte | 20 +++++++++---------- ui/src/routes/works/index.svelte | 14 ++++++------- ui/src/routes/works/new.svelte | 8 ++++---- 54 files changed, 146 insertions(+), 146 deletions(-) rename ui/src/{ => lib}/components/AuthButton.svelte (100%) rename ui/src/{ => lib}/components/BuildState.svelte (100%) rename ui/src/{ => lib}/components/Correction.svelte (100%) rename ui/src/{ => lib}/components/CorrectionPieChart.svelte (100%) rename ui/src/{ => lib}/components/CorrectionReference.svelte (98%) rename ui/src/{ => lib}/components/CorrectionResponseFooter.svelte (97%) rename ui/src/{ => lib}/components/CorrectionResponses.svelte (98%) rename ui/src/{ => lib}/components/DateFormat.svelte (100%) rename ui/src/{ => lib}/components/DateTimeInput.svelte (100%) rename ui/src/{ => lib}/components/ListInput.svelte (100%) rename ui/src/{ => lib}/components/ListInputResponses.svelte (100%) rename ui/src/{ => lib}/components/QuestionForm.svelte (99%) rename ui/src/{ => lib}/components/QuestionHeader.svelte (97%) rename ui/src/{ => lib}/components/QuestionProposals.svelte (98%) rename ui/src/{ => lib}/components/ResponseCorrected.svelte (98%) rename ui/src/{ => lib}/components/StartStopLiveSurvey.svelte (100%) rename ui/src/{ => lib}/components/StudentGrades.svelte (96%) rename ui/src/{ => lib}/components/SubmissionStatus.svelte (94%) rename ui/src/{ => lib}/components/SurveyAdmin.svelte (98%) rename ui/src/{ => lib}/components/SurveyBadge.svelte (100%) rename ui/src/{ => lib}/components/SurveyList.svelte (92%) rename ui/src/{ => lib}/components/SurveyQuestions.svelte (94%) rename ui/src/{ => lib}/components/Toaster.svelte (92%) rename ui/src/{ => lib}/components/UserKeys.svelte (97%) rename ui/src/{ => lib}/components/UserSurveys.svelte (94%) rename ui/src/{ => lib}/components/ValidateSubmissions.svelte (94%) rename ui/src/{ => lib}/components/WorkAdmin.svelte (99%) rename ui/src/{ => lib}/components/WorkRepository.svelte (97%) rename ui/src/{ => lib}/stores/toasts.js (100%) rename ui/src/{ => lib}/stores/user.js (100%) diff --git a/ui/src/components/AuthButton.svelte b/ui/src/lib/components/AuthButton.svelte similarity index 100% rename from ui/src/components/AuthButton.svelte rename to ui/src/lib/components/AuthButton.svelte diff --git a/ui/src/components/BuildState.svelte b/ui/src/lib/components/BuildState.svelte similarity index 100% rename from ui/src/components/BuildState.svelte rename to ui/src/lib/components/BuildState.svelte diff --git a/ui/src/components/Correction.svelte b/ui/src/lib/components/Correction.svelte similarity index 100% rename from ui/src/components/Correction.svelte rename to ui/src/lib/components/Correction.svelte diff --git a/ui/src/components/CorrectionPieChart.svelte b/ui/src/lib/components/CorrectionPieChart.svelte similarity index 100% rename from ui/src/components/CorrectionPieChart.svelte rename to ui/src/lib/components/CorrectionPieChart.svelte diff --git a/ui/src/components/CorrectionReference.svelte b/ui/src/lib/components/CorrectionReference.svelte similarity index 98% rename from ui/src/components/CorrectionReference.svelte rename to ui/src/lib/components/CorrectionReference.svelte index f1c51e1..110f6f9 100644 --- a/ui/src/components/CorrectionReference.svelte +++ b/ui/src/lib/components/CorrectionReference.svelte @@ -1,5 +1,5 @@ diff --git a/ui/src/components/SubmissionStatus.svelte b/ui/src/lib/components/SubmissionStatus.svelte similarity index 94% rename from ui/src/components/SubmissionStatus.svelte rename to ui/src/lib/components/SubmissionStatus.svelte index b7ad14a..5af55c9 100644 --- a/ui/src/components/SubmissionStatus.svelte +++ b/ui/src/lib/components/SubmissionStatus.svelte @@ -1,8 +1,8 @@
diff --git a/ui/src/components/UserKeys.svelte b/ui/src/lib/components/UserKeys.svelte similarity index 97% rename from ui/src/components/UserKeys.svelte rename to ui/src/lib/components/UserKeys.svelte index 7f383cb..f616b8e 100644 --- a/ui/src/components/UserKeys.svelte +++ b/ui/src/lib/components/UserKeys.svelte @@ -1,5 +1,5 @@ diff --git a/ui/src/components/UserSurveys.svelte b/ui/src/lib/components/UserSurveys.svelte similarity index 94% rename from ui/src/components/UserSurveys.svelte rename to ui/src/lib/components/UserSurveys.svelte index dad0bb3..5d9a8ed 100644 --- a/ui/src/components/UserSurveys.svelte +++ b/ui/src/lib/components/UserSurveys.svelte @@ -1,8 +1,8 @@ diff --git a/ui/src/routes/grades/index.svelte b/ui/src/routes/grades/index.svelte index 026f5ce..b016fbb 100644 --- a/ui/src/routes/grades/index.svelte +++ b/ui/src/routes/grades/index.svelte @@ -1,5 +1,5 @@ diff --git a/ui/src/routes/help.svelte b/ui/src/routes/help.svelte index 6b4a8c8..e87598a 100644 --- a/ui/src/routes/help.svelte +++ b/ui/src/routes/help.svelte @@ -1,6 +1,6 @@
diff --git a/ui/src/routes/surveys/new.svelte b/ui/src/routes/surveys/new.svelte index 2a4f626..9aaf369 100644 --- a/ui/src/routes/surveys/new.svelte +++ b/ui/src/routes/surveys/new.svelte @@ -1,10 +1,10 @@ diff --git a/ui/src/routes/users/[uid]/index.svelte b/ui/src/routes/users/[uid]/index.svelte index f6fbaee..d5c9e99 100644 --- a/ui/src/routes/users/[uid]/index.svelte +++ b/ui/src/routes/users/[uid]/index.svelte @@ -9,11 +9,11 @@ diff --git a/ui/src/routes/works/new.svelte b/ui/src/routes/works/new.svelte index efbcfd0..3a635fb 100644 --- a/ui/src/routes/works/new.svelte +++ b/ui/src/routes/works/new.svelte @@ -1,10 +1,10 @@ From d7f679ce8443de51f5f639283d2ff12cb3843374 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Fri, 18 Nov 2022 16:11:24 +0100 Subject: [PATCH 2/5] Display survey mean to admin --- surveys.go | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/surveys.go b/surveys.go index 48df3eb..ad44b0a 100644 --- a/surveys.go +++ b/surveys.go @@ -77,11 +77,12 @@ func declareAPIAuthSurveysRoutes(router *gin.RouterGroup) { surveysRoutes.Use(surveyHandler) surveysRoutes.GET("/score", func(c *gin.Context) { + loggedUser := c.MustGet("LoggedUser").(*User) var u *User if user, ok := c.Get("user"); ok { u = user.(*User) } else { - u = c.MustGet("LoggedUser").(*User) + u = loggedUser } s := c.MustGet("survey").(*Survey) @@ -93,10 +94,29 @@ func declareAPIAuthSurveysRoutes(router *gin.RouterGroup) { return } - if score == nil { - c.JSON(http.StatusOK, map[string]string{"score": "N/A"}) - } else { + if score != nil { c.JSON(http.StatusOK, map[string]float64{"score": *score}) + } else if _, ok := c.Get("user"); !ok && loggedUser.IsAdmin { + // Admin retrieve mean score + scores, err := s.GetGrades() + if err != nil { + log.Printf("Unable to GetGrades(sid=%d): %s", s.Id, err.Error()) + c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs when trying to retrieve grades."}) + return + } + + *score = 0 + nbGrades := 0 + for _, s := range scores { + *score += *s + nbGrades += 1 + } + + *score /= float64(nbGrades) + + c.JSON(http.StatusOK, map[string]float64{"score": *score}) + } else { + c.JSON(http.StatusOK, map[string]string{"score": "N/A"}) } } else { c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"errmsg": "Not accessible"}) From bf5b0e88dd2a0d1ccfd3e492894cf1a7bc415ecb Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Fri, 18 Nov 2022 16:14:56 +0100 Subject: [PATCH 3/5] Fix correction template mess --- ui/src/routes/surveys/[sid]/responses/[rid].svelte | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/src/routes/surveys/[sid]/responses/[rid].svelte b/ui/src/routes/surveys/[sid]/responses/[rid].svelte index 2198212..56d71aa 100644 --- a/ui/src/routes/surveys/[sid]/responses/[rid].svelte +++ b/ui/src/routes/surveys/[sid]/responses/[rid].svelte @@ -85,7 +85,7 @@
-
+
+
From f675047ce8f6636aa45336b56c069172330b050f Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Sat, 19 Nov 2022 11:41:35 +0100 Subject: [PATCH 4/5] Refactor permissions checks to avoid questions/works leaks between promotions/groups/start-availability MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thanks-To François Dautrême --- questions.go | 41 ++++++++++++++++++++++------------------- surveys.go | 23 ++++++++++------------- works.go | 46 +++++++++++++++++++++++++--------------------- 3 files changed, 57 insertions(+), 53 deletions(-) diff --git a/questions.go b/questions.go index 19a4a25..d742e1b 100644 --- a/questions.go +++ b/questions.go @@ -39,7 +39,7 @@ func declareAPIAuthQuestionsRoutes(router *gin.RouterGroup) { c.JSON(http.StatusOK, questions) } } else { - if (!s.Shown || s.Direct != nil) && !u.IsAdmin { + if s.Direct != nil && !u.IsAdmin { c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"errmsg": "Not accessible"}) return } @@ -62,24 +62,7 @@ func declareAPIAuthQuestionsRoutes(router *gin.RouterGroup) { questionsRoutes.Use(questionHandler) questionsRoutes.GET("", func(c *gin.Context) { - q := c.MustGet("question").(*Question) - u := c.MustGet("LoggedUser").(*User) - - if !u.IsAdmin { - s, err := getSurvey(int(q.IdSurvey)) - if err != nil { - log.Println("Unable to getSurvey:", err) - c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs during survey retrieval. Please try again later."}) - return - } - - if !s.Shown || (s.Direct != nil && *s.Direct != q.Id) { - c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"errmsg": "Not authorized"}) - return - } - } - - c.JSON(http.StatusOK, q) + c.JSON(http.StatusOK, c.MustGet("question").(*Question)) }) declareAPIAuthProposalsRoutes(questionsRoutes) @@ -171,6 +154,8 @@ func declareAPIAdminUserQuestionsRoutes(router *gin.RouterGroup) { } func questionHandler(c *gin.Context) { + u := c.MustGet("LoggedUser").(*User) + var survey *Survey if s, ok := c.Get("survey"); ok { survey = s.(*Survey) @@ -190,6 +175,15 @@ func questionHandler(c *gin.Context) { c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "Question not found"}) return } + + s, err := getSurvey(int(question.IdSurvey)) + if err != nil { + log.Println("Unable to getSurvey:", err) + c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs during survey retrieval. Please try again later."}) + return + } + + survey = s } else { question, err = survey.GetQuestion(qid) if err != nil { @@ -198,6 +192,15 @@ func questionHandler(c *gin.Context) { } } + if !u.IsAdmin && (!survey.checkUserAccessToSurvey(u) || (survey.Direct != nil && *survey.Direct != question.Id)) { + c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"errmsg": "Not authorized"}) + return + } + if !u.IsAdmin && survey.StartAvailability.After(time.Now()) { + c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"errmsg": "Not accessible yet"}) + return + } + c.Set("question", question) c.Next() diff --git a/surveys.go b/surveys.go index ad44b0a..81a0185 100644 --- a/surveys.go +++ b/surveys.go @@ -62,19 +62,14 @@ func declareAPISurveysRoutes(router *gin.RouterGroup) { return } - s := c.MustGet("survey").(*Survey) - - if (s.Promo == u.Promo && (s.Group == "" || strings.Contains(u.Groups, ","+s.Group+",") && s.Shown)) || u.IsAdmin { - c.JSON(http.StatusOK, s) - } else { - c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"errmsg": "Not accessible"}) - } + c.JSON(http.StatusOK, c.MustGet("survey").(*Survey)) }) } func declareAPIAuthSurveysRoutes(router *gin.RouterGroup) { surveysRoutes := router.Group("/surveys/:sid") surveysRoutes.Use(surveyHandler) + surveysRoutes.Use(surveyUserAccessHandler) surveysRoutes.GET("/score", func(c *gin.Context) { loggedUser := c.MustGet("LoggedUser").(*User) @@ -219,18 +214,20 @@ func surveyHandler(c *gin.Context) { } } +func (s *Survey) checkUserAccessToSurvey(u *User) bool { + return u.IsAdmin || (u.Promo == s.Promo && s.Shown && (s.Group == "" || strings.Contains(u.Groups, ","+s.Group+","))) +} + func surveyUserAccessHandler(c *gin.Context) { u := c.MustGet("LoggedUser").(*User) - w := c.MustGet("survey").(*Survey) + s := c.MustGet("survey").(*Survey) - if u.IsAdmin { - c.Next() - } else if w.Shown && (w.Group == "" || strings.Contains(u.Groups, ","+w.Group+",")) { - c.Next() - } else { + if !s.checkUserAccessToSurvey(u) { c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "Survey not found."}) return } + + c.Next() } type Survey struct { diff --git a/works.go b/works.go index 3b0a106..2ca25ee 100644 --- a/works.go +++ b/works.go @@ -43,7 +43,11 @@ func declareAPIWorksRoutes(router *gin.RouterGroup) { } else { for _, w := range works { if w.Group == "" || strings.Contains(u.Groups, ","+w.Group+",") { + // Remove informations not needed on front page for students + w.Promo = 0 w.Group = "" + w.DescriptionRaw = "" + response = append(response, w) } } @@ -79,7 +83,10 @@ func declareAPIWorksRoutes(router *gin.RouterGroup) { } else { for _, w := range works { if w.Group == "" || strings.Contains(u.Groups, ","+w.Group+",") { + // Remove informations not needed on front page for students + w.Promo = 0 w.Group = "" + response = append(response, w) } } @@ -193,16 +200,7 @@ func declareAPIAuthWorksRoutes(router *gin.RouterGroup) { worksRoutes.Use(workUserAccessHandler) worksRoutes.GET("", func(c *gin.Context) { - u := c.MustGet("LoggedUser").(*User) - w := c.MustGet("work").(*Work) - - if u.IsAdmin { - c.JSON(http.StatusOK, w) - } else if w.Shown && w.StartAvailability.Before(time.Now()) && (w.Group == "" || strings.Contains(u.Groups, ","+w.Group+",")) { - c.JSON(http.StatusOK, w) - } else { - c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"errmsg": "Permission denied"}) - } + c.JSON(http.StatusOK, c.MustGet("work").(*Work)) }) // Grades related to works @@ -239,18 +237,24 @@ func workHandler(c *gin.Context) { } } +func (w *Work) checkUserAccessToWork(u *User) bool { + return u.IsAdmin || (u.Promo == w.Promo && w.Shown && (w.Group == "" || strings.Contains(u.Groups, ","+w.Group+","))) +} + func workUserAccessHandler(c *gin.Context) { u := c.MustGet("LoggedUser").(*User) w := c.MustGet("work").(*Work) - if u.IsAdmin { - c.Next() - } else if w.Shown && (w.Group == "" || strings.Contains(u.Groups, ","+w.Group+",")) { - c.Next() - } else { + if !w.checkUserAccessToWork(u) { c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "Work not found."}) return } + if !u.IsAdmin && w.StartAvailability.After(time.Now()) { + c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"errmsg": "Not accessible yet"}) + return + } + + c.Next() } type OneWork struct { @@ -291,14 +295,14 @@ func allWorks(cnd string, param ...interface{}) (items []*OneWork, err error) { type Work struct { Id int64 `json:"id"` Title string `json:"title"` - Promo uint `json:"promo"` - Group string `json:"group"` + Promo uint `json:"promo,omitempty"` + Group string `json:"group,omitempty"` Shown bool `json:"shown"` - Description string `json:"description"` + Description string `json:"description,omitempty"` DescriptionRaw string `json:"descr_raw,omitempty"` - Tag string `json:"tag"` - SubmissionURL *string `json:"submission_url"` - Corrected bool `json:"corrected"` + Tag string `json:"tag,omitempty"` + SubmissionURL *string `json:"submission_url,omitempty"` + Corrected bool `json:"corrected,omitempty"` StartAvailability time.Time `json:"start_availability"` EndAvailability time.Time `json:"end_availability"` } From c21df9d93f6958f22b9c7f9a17b8516944f619fa Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Sat, 19 Nov 2022 11:43:26 +0100 Subject: [PATCH 5/5] =?UTF-8?q?Credit=20Fran=C3=A7ois=20on=20bounty=20page?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ui/src/routes/bug-bounty.svelte | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ui/src/routes/bug-bounty.svelte b/ui/src/routes/bug-bounty.svelte index 38c4d50..c5a29f3 100644 --- a/ui/src/routes/bug-bounty.svelte +++ b/ui/src/routes/bug-bounty.svelte @@ -65,6 +65,22 @@

Hall of Fame

+
+
+ L'accès aux questionnaires n'était pas filtré selon les groupes ou les promos. + +2 pts +
+
+
+ francois.dautreme +
+

+ Divulguée et corrigée le 19 novembre 2022. + Commit +

+
+
+
Il était toujours possible de répondre aux questionnaires après l'heure de clôture.