Compare commits

..

65 commits

Author SHA1 Message Date
821efbe41c chore(deps): update dependency svelte to v5
Some checks failed
continuous-integration/drone/push Build is failing
2025-03-28 14:07:37 +00:00
cb0e0e2c24 chore(deps): update module golang.org/x/oauth2 to v0.28.0
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-03-28 10:07:14 +00:00
6100f33e7c chore(deps): update module golang.org/x/image to v0.25.0
All checks were successful
continuous-integration/drone/push Build is passing
2025-03-28 08:26:08 +00:00
47f2004a4c chore(deps): update dependency eslint-plugin-svelte to v3
Some checks are pending
continuous-integration/drone/push Build is running
2025-03-28 08:25:55 +00:00
faf74ec808 chore(deps): update module github.com/go-git/go-git/v5 to v5.14.0
Some checks are pending
continuous-integration/drone/push Build is running
2025-03-27 22:22:56 +00:00
e42545416f chore(deps): update module golang.org/x/crypto to v0.36.0
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-03-27 16:08:13 +00:00
3f5d6bb04b chore(deps): update module github.com/burntsushi/toml to v1.5.0
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-03-27 12:06:30 +00:00
99c436ba9a Keep repochecker on 3.19 (needed for grammalecte)
All checks were successful
continuous-integration/drone/push Build is passing
2025-03-27 12:28:48 +01:00
a7d521fbdd admin: Can change capture_regexp along with key 2025-03-27 12:28:16 +01:00
0c53372618 admin: Implement .gz file download test 2025-03-27 12:28:16 +01:00
84be750ce6 admin: circle animation no more block click on refresh button 2025-03-27 12:28:16 +01:00
3881385c9e admin: List all existing association between users and teams 2025-03-27 12:28:16 +01:00
e44cac32ac admin: New button to refine teams colors 2025-03-27 12:28:16 +01:00
485e6b0173 admin: Able to import Cyberrange teams from interface 2025-03-27 12:28:16 +01:00
f1ada8ce99 admin: Use logo from challengeinfo in ui template 2025-03-27 12:28:16 +01:00
7e301b8ecb admin: Replace PKI page by authentication settings, refactor 2025-03-27 12:28:16 +01:00
4dcf1218d8 chore(deps): update module github.com/asticode/go-astisub to v0.34.0
Some checks are pending
continuous-integration/drone/push Build is running
2025-03-27 11:27:30 +00:00
3f5b7b9ed7 chore(deps): update alpine docker tag to v3.21
Some checks are pending
continuous-integration/drone/push Build is running
2025-03-27 11:27:16 +00:00
bc0570c2c7 chore(deps): update dependency eslint-config-prettier to v10.1.1
Some checks are pending
continuous-integration/drone/push Build is running
2025-03-27 11:27:00 +00:00
cd50a4b9d3 chore(deps): update dependency vite to v5.4.15
Some checks are pending
continuous-integration/drone/push Build is running
2025-03-27 11:26:33 +00:00
4734a8f047 chore(deps): update dependency sass-loader to v16.0.5
Some checks are pending
continuous-integration/drone/push Build is running
2025-03-27 11:26:18 +00:00
dadb84e8f9 admin: Dex config contains challenge name instead of hardcoded name
All checks were successful
continuous-integration/drone/push Build is passing
2025-03-26 12:04:43 +01:00
801042e5cf fickit: Update linuxkit images 2025-03-26 11:55:36 +01:00
fca27b07fe admin: Also import team members from CyberRange 2025-03-26 11:25:06 +01:00
3fc765ccfa admin: Export logos present in challenge.json 2025-03-26 11:13:09 +01:00
590a55c395 libfic: Create a color randomization function 2025-03-25 18:54:36 +01:00
b62369f89f admin: New route to import teams from CyberRange format 2025-03-25 18:19:22 +01:00
cb4ceecbf5 challenge-sync-airbus: Refactor and prefer calling it cyberrange 2025-03-25 18:02:11 +01:00
98d9f2daf3 Keep repochecker on 3.19 (needed for grammalecte) 2025-03-25 12:04:09 +01:00
db1e2603fc chore(deps): update alpine docker tag to v3.21 2025-03-25 12:04:09 +01:00
0730a22daa chore(deps): update dependency @sveltejs/kit to v2.20.2 2025-03-25 12:04:09 +01:00
3467ca6db5 chore(deps): update dependency sass to v1.86.0 2025-03-25 12:04:09 +01:00
910adb123a chore(deps): update dependency prettier to v3.5.3 2025-03-25 12:04:09 +01:00
1551c11a00 chore(deps): update dependency eslint to v9.23.0 2025-03-25 12:04:09 +01:00
ed3e6b66de chore(deps): update dependency @sveltestrap/sveltestrap to v7.1.0 2025-03-25 12:04:09 +01:00
c21fd098a0 Remove useless file 2025-03-25 12:04:09 +01:00
7df675346c challenge-sync-airbus: 2025 API ready
All checks were successful
continuous-integration/drone/push Build is passing
2025-03-24 19:31:59 +01:00
526d693ffd chore(deps): update module golang.org/x/crypto to v0.33.0
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-02-11 16:18:38 +00:00
df8a759134 chore(deps): update dependency sass to v1.84.0
All checks were successful
continuous-integration/drone/push Build is passing
2025-02-11 12:56:59 +00:00
03e48b749c chore(deps): update dependency @sveltejs/kit to v2.17.1
Some checks are pending
continuous-integration/drone/push Build is pending
2025-02-11 12:56:55 +00:00
97f7e3fa59 chore(deps): update dependency @sveltestrap/sveltestrap to v7
Some checks are pending
continuous-integration/drone/push Build is pending
2025-02-11 12:56:18 +00:00
e421c91ac2 chore(deps): update module github.com/go-git/go-git/v5 to v5.13.2
Some checks are pending
continuous-integration/drone/push Build is pending
2025-02-11 12:56:05 +00:00
baccc54d02 chore(deps): update module golang.org/x/oauth2 to v0.26.0
All checks were successful
continuous-integration/drone/push Build is passing
2025-02-05 02:55:02 +00:00
e8e87c9958 chore(deps): update module golang.org/x/image to v0.24.0
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-02-05 00:42:32 +00:00
08a31898df admin: New button to delete tries for a flag
All checks were successful
continuous-integration/drone/push Build is passing
2025-02-04 19:08:44 +01:00
b409fa6806 admin: Retrieve stats on exercices 2025-02-04 19:08:44 +01:00
63b4cdc622 admin: Use non-breakable whitespaces 2025-02-04 19:08:44 +01:00
650f933993 admin: duration change impact the expected end 2025-02-04 19:08:44 +01:00
603b226955 fickit: Prepare team registration through checker 2025-02-04 19:08:44 +01:00
55e829fa64 fickit: Allow admin to remove submissions 2025-02-04 19:08:44 +01:00
45a0504c44 chore(deps): lock file maintenance
All checks were successful
continuous-integration/drone/push Build is passing
2025-01-27 02:27:27 +00:00
ad7489e558 admin: Start compute flag stats
All checks were successful
continuous-integration/drone/push Build is passing
2025-01-25 14:46:47 +01:00
57c3cd8fd6 admin: Fix mcq entry update 2025-01-24 23:49:37 +01:00
24686a6a24 admin: Fix check file on disk for compressed files 2025-01-24 23:49:37 +01:00
407b67f4c2 sync: Ensure placeholder and raw are not the same 2025-01-24 23:49:37 +01:00
c28d974105 fickit: Update images 2025-01-24 23:49:37 +01:00
ffb69663b6 fickit: Initiate sshd config with keys on first run 2025-01-24 23:49:37 +01:00
4ec4f47951 fickit: keep last metadata iso when dm-crypt key change 2025-01-24 23:49:37 +01:00
96707e3a29 configs: Detect mkisofs 2025-01-24 23:49:37 +01:00
a4001759f6 ui: Fix file disclaimer not showing 2025-01-24 23:49:37 +01:00
f15cd29f78 chore(deps): update dependency @sveltestrap/sveltestrap to v6.2.8
All checks were successful
continuous-integration/drone/push Build is passing
2025-01-23 18:41:07 +00:00
7e41ddd664 chore(deps): update dependency eslint-config-prettier to v10
Some checks are pending
continuous-integration/drone/push Build is running
2025-01-23 18:40:58 +00:00
89b7710544 chore(deps): update dependency @sveltejs/kit to v2.16.1
Some checks are pending
continuous-integration/drone/push Build is running
2025-01-23 18:40:43 +00:00
79ec20d11c chore(deps): update dependency sass to v1.83.4
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-01-21 14:57:58 +00:00
09206df20a chore(deps): update module golang.org/x/crypto to v0.32.0
All checks were successful
continuous-integration/drone/push Build is passing
2025-01-18 12:40:53 +00:00
58 changed files with 1612 additions and 1000 deletions

View file

@ -20,7 +20,7 @@ RUN go get -d -v ./admin && \
go build -v -buildmode=plugin -o repochecker/videos-rules.so ./repochecker/videos go build -v -buildmode=plugin -o repochecker/videos-rules.so ./repochecker/videos
FROM alpine:3.20 FROM alpine:3.21
RUN apk add --no-cache \ RUN apk add --no-cache \
ca-certificates \ ca-certificates \

View file

@ -13,7 +13,7 @@ RUN go get -d -v ./checker && \
go build -v -buildvcs=false -o checker/checker ./checker go build -v -buildvcs=false -o checker/checker ./checker
FROM alpine:3.20 FROM alpine:3.21
WORKDIR /srv WORKDIR /srv

View file

@ -13,7 +13,7 @@ RUN go get -d -v ./dashboard && \
go build -v -buildvcs=false -o dashboard/dashboard ./dashboard go build -v -buildvcs=false -o dashboard/dashboard ./dashboard
FROM alpine:3.20 FROM alpine:3.21
EXPOSE 8082 EXPOSE 8082

View file

@ -1,4 +1,4 @@
FROM alpine:3.20 FROM alpine:3.21
EXPOSE 67/udp EXPOSE 67/udp
EXPOSE 69/udp EXPOSE 69/udp

View file

@ -12,7 +12,7 @@ RUN go get -d -v ./evdist && \
go build -v -buildvcs=false -o evdist/evdist ./evdist go build -v -buildvcs=false -o evdist/evdist ./evdist
FROM alpine:3.20 FROM alpine:3.21
WORKDIR /srv WORKDIR /srv

View file

@ -13,7 +13,7 @@ RUN go get -d -v ./generator && \
go build -v -buildvcs=false -o generator/generator ./generator go build -v -buildvcs=false -o generator/generator ./generator
FROM alpine:3.20 FROM alpine:3.21
WORKDIR /srv WORKDIR /srv

View file

@ -15,7 +15,7 @@ RUN go get -d -v ./admin && \
go build -v -o get-remote-files ./admin/get-remote-files go build -v -o get-remote-files ./admin/get-remote-files
FROM alpine:3.20 FROM alpine:3.21
RUN apk add --no-cache \ RUN apk add --no-cache \
ca-certificates ca-certificates

View file

@ -25,7 +25,7 @@ RUN go get -d -v ./qa && \
go build -v -buildvcs=false -o qa/qa ./qa go build -v -buildvcs=false -o qa/qa ./qa
FROM alpine:3.20 FROM alpine:3.21
EXPOSE 8083 EXPOSE 8083

View file

@ -13,7 +13,7 @@ RUN go get -d -v ./receiver && \
go build -v -buildvcs=false -o ./receiver/receiver ./receiver go build -v -buildvcs=false -o ./receiver/receiver ./receiver
FROM alpine:3.20 FROM alpine:3.21
EXPOSE 8080 EXPOSE 8080

View file

@ -13,7 +13,7 @@ RUN go get -d -v ./remote/challenge-sync-airbus && \
go build -v -buildvcs=false -o ./challenge-sync-airbus ./remote/challenge-sync-airbus go build -v -buildvcs=false -o ./challenge-sync-airbus ./remote/challenge-sync-airbus
FROM alpine:3.20 FROM alpine:3.21
RUN apk add --no-cache openssl ca-certificates RUN apk add --no-cache openssl ca-certificates

View file

@ -13,7 +13,7 @@ RUN go get -d -v ./remote/scores-sync-zqds && \
go build -v -buildvcs=false -o ./scores-sync-zqds ./remote/scores-sync-zqds go build -v -buildvcs=false -o ./scores-sync-zqds ./remote/scores-sync-zqds
FROM alpine:3.20 FROM alpine:3.21
RUN apk add --no-cache openssl ca-certificates RUN apk add --no-cache openssl ca-certificates

View file

@ -62,6 +62,8 @@ func declareExercicesRoutes(router *gin.RouterGroup) {
apiFlagsRoutes.POST("/try", tryExerciceFlag) apiFlagsRoutes.POST("/try", tryExerciceFlag)
apiFlagsRoutes.DELETE("/", deleteExerciceFlag) apiFlagsRoutes.DELETE("/", deleteExerciceFlag)
apiFlagsRoutes.GET("/dependancies", showExerciceFlagDeps) apiFlagsRoutes.GET("/dependancies", showExerciceFlagDeps)
apiFlagsRoutes.GET("/statistics", showExerciceFlagStats)
apiFlagsRoutes.DELETE("/tries", deleteExerciceFlagTries)
apiFlagsRoutes.GET("/choices/", listFlagChoices) apiFlagsRoutes.GET("/choices/", listFlagChoices)
apiFlagsChoicesRoutes := apiExercicesRoutes.Group("/choices/:cid") apiFlagsChoicesRoutes := apiExercicesRoutes.Group("/choices/:cid")
apiFlagsChoicesRoutes.Use(FlagChoiceHandler) apiFlagsChoicesRoutes.Use(FlagChoiceHandler)
@ -77,6 +79,8 @@ func declareExercicesRoutes(router *gin.RouterGroup) {
apiQuizRoutes.PUT("", updateExerciceQuiz) apiQuizRoutes.PUT("", updateExerciceQuiz)
apiQuizRoutes.DELETE("", deleteExerciceQuiz) apiQuizRoutes.DELETE("", deleteExerciceQuiz)
apiQuizRoutes.GET("/dependancies", showExerciceQuizDeps) apiQuizRoutes.GET("/dependancies", showExerciceQuizDeps)
apiQuizRoutes.GET("/statistics", showExerciceQuizStats)
apiQuizRoutes.DELETE("/tries", deleteExerciceQuizTries)
apiExercicesRoutes.GET("/tags", listExerciceTags) apiExercicesRoutes.GET("/tags", listExerciceTags)
apiExercicesRoutes.POST("/tags", addExerciceTag) apiExercicesRoutes.POST("/tags", addExerciceTag)
@ -852,6 +856,60 @@ func showExerciceFlagDeps(c *gin.Context) {
c.JSON(http.StatusOK, deps) c.JSON(http.StatusOK, deps)
} }
func showExerciceFlagStats(c *gin.Context) {
exercice := c.MustGet("exercice").(*fic.Exercice)
flag := c.MustGet("flag-key").(*fic.FlagKey)
history, err := exercice.GetHistory()
if err != nil {
log.Println("Unable to getExerciceHistory:", err.Error())
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs when retrieving exercice history"})
return
}
var completed int64
for _, hline := range history {
if hline["kind"].(string) == "flag_found" {
if *hline["secondary"].(*int) == flag.Id {
completed += 1
}
}
}
tries, err := flag.NbTries()
if err != nil {
log.Println("Unable to nbTries:", err.Error())
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs when retrieving flag tries"})
return
}
teams, err := flag.TeamsOnIt()
if err != nil {
log.Println("Unable to teamsOnIt:", err.Error())
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs when retrieving flag related teams"})
return
}
c.JSON(http.StatusOK, gin.H{
"completed": completed,
"tries": tries,
"teams": teams,
})
}
func deleteExerciceFlagTries(c *gin.Context) {
flag := c.MustGet("flag-key").(*fic.FlagKey)
err := flag.DeleteTries()
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
return
}
c.AbortWithStatusJSON(http.StatusOK, true)
}
func tryExerciceFlag(c *gin.Context) { func tryExerciceFlag(c *gin.Context) {
flag := c.MustGet("flag-key").(*fic.FlagKey) flag := c.MustGet("flag-key").(*fic.FlagKey)
@ -895,6 +953,23 @@ func updateExerciceFlag(c *gin.Context) {
flag.Help = uk.Help flag.Help = uk.Help
flag.IgnoreCase = uk.IgnoreCase flag.IgnoreCase = uk.IgnoreCase
flag.Multiline = uk.Multiline flag.Multiline = uk.Multiline
flag.ChoicesCost = uk.ChoicesCost
flag.BonusGain = uk.BonusGain
if uk.CaptureRe != nil && len(*uk.CaptureRe) > 0 {
if flag.CaptureRegexp != uk.CaptureRe && uk.Flag == "" {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "Pour changer la capture_regexp, vous devez rentrer la réponse attendue à nouveau, car le flag doit être recalculé."})
return
}
flag.CaptureRegexp = uk.CaptureRe
} else {
if flag.CaptureRegexp != nil && uk.Flag == "" {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "Pour changer la capture_regexp, vous devez rentrer la réponse attendue à nouveau, car le flag doit être recalculé."})
return
}
flag.CaptureRegexp = nil
}
if len(uk.Flag) > 0 { if len(uk.Flag) > 0 {
var err error var err error
flag.Checksum, err = flag.ComputeChecksum([]byte(uk.Flag)) flag.Checksum, err = flag.ComputeChecksum([]byte(uk.Flag))
@ -906,14 +981,6 @@ func updateExerciceFlag(c *gin.Context) {
} else { } else {
flag.Checksum = uk.Value flag.Checksum = uk.Value
} }
flag.ChoicesCost = uk.ChoicesCost
flag.BonusGain = uk.BonusGain
if uk.CaptureRe != nil && len(*uk.CaptureRe) > 0 {
flag.CaptureRegexp = uk.CaptureRe
} else {
flag.CaptureRegexp = nil
}
if _, err := flag.Update(); err != nil { if _, err := flag.Update(); err != nil {
log.Println("Unable to updateExerciceFlag:", err.Error()) log.Println("Unable to updateExerciceFlag:", err.Error())
@ -1022,6 +1089,60 @@ func showExerciceQuizDeps(c *gin.Context) {
c.JSON(http.StatusOK, deps) c.JSON(http.StatusOK, deps)
} }
func showExerciceQuizStats(c *gin.Context) {
exercice := c.MustGet("exercice").(*fic.Exercice)
quiz := c.MustGet("flag-quiz").(*fic.MCQ)
history, err := exercice.GetHistory()
if err != nil {
log.Println("Unable to getExerciceHistory:", err.Error())
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs when retrieving exercice history"})
return
}
var completed int64
for _, hline := range history {
if hline["kind"].(string) == "mcq_found" {
if *hline["secondary"].(*int) == quiz.Id {
completed += 1
}
}
}
tries, err := quiz.NbTries()
if err != nil {
log.Println("Unable to nbTries:", err.Error())
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs when retrieving flag tries"})
return
}
teams, err := quiz.TeamsOnIt()
if err != nil {
log.Println("Unable to teamsOnIt:", err.Error())
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs when retrieving flag related teams"})
return
}
c.JSON(http.StatusOK, gin.H{
"completed": completed,
"tries": tries,
"teams": teams,
})
}
func deleteExerciceQuizTries(c *gin.Context) {
quiz := c.MustGet("flag-quiz").(*fic.MCQ)
err := quiz.DeleteTries()
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
return
}
c.AbortWithStatusJSON(http.StatusOK, true)
}
func updateExerciceQuiz(c *gin.Context) { func updateExerciceQuiz(c *gin.Context) {
quiz := c.MustGet("flag-quiz").(*fic.MCQ) quiz := c.MustGet("flag-quiz").(*fic.MCQ)

View file

@ -3,9 +3,12 @@ package api
import ( import (
"archive/zip" "archive/zip"
"encoding/json" "encoding/json"
"io"
"log"
"net/http" "net/http"
"path" "path"
"srs.epita.fr/fic-server/admin/sync"
"srs.epita.fr/fic-server/libfic" "srs.epita.fr/fic-server/libfic"
"srs.epita.fr/fic-server/settings" "srs.epita.fr/fic-server/settings"
@ -59,6 +62,41 @@ func declareExportRoutes(router *gin.RouterGroup) {
json.NewEncoder(f).Encode(challengeinfo) json.NewEncoder(f).Encode(challengeinfo)
} }
// Include partners' logos from challenge.json
if sync.GlobalImporter != nil {
if len(challengeinfo.MainLogo) > 0 {
for _, logo := range challengeinfo.MainLogo {
fd, closer, err := sync.OpenOrGetFile(sync.GlobalImporter, logo)
if err != nil {
log.Printf("Unable to archive main logo %q: %s", logo, err.Error())
continue
}
f, err := w.Create(path.Join("logo", path.Base(logo)))
if err == nil {
io.Copy(f, fd)
}
closer()
}
}
if len(challengeinfo.Partners) > 0 {
for _, partner := range challengeinfo.Partners {
fd, closer, err := sync.OpenOrGetFile(sync.GlobalImporter, partner.Src)
if err != nil {
log.Printf("Unable to archive partner logo %q: %s", partner.Src, err.Error())
continue
}
f, err := w.Create(path.Join("partner", path.Base(partner.Src)))
if err == nil {
io.Copy(f, fd)
}
closer()
}
}
}
// my.json // my.json
f, err = w.Create("my.json") f, err = w.Create("my.json")
if err == nil { if err == nil {

View file

@ -34,6 +34,11 @@ func declarePasswordRoutes(router *gin.RouterGroup) {
c.JSON(http.StatusOK, gin.H{"password": passwd}) c.JSON(http.StatusOK, gin.H{"password": passwd})
}) })
router.GET("/oauth-status", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"secret_defined": OidcSecret != "",
})
})
router.GET("/dex.yaml", func(c *gin.Context) { router.GET("/dex.yaml", func(c *gin.Context) {
cfg, err := genDexConfig() cfg, err := genDexConfig()
if err != nil { if err != nil {
@ -136,7 +141,7 @@ storage:
web: web:
http: 0.0.0.0:5556 http: 0.0.0.0:5556
frontend: frontend:
issuer: Challenge forensic issuer: {{ .Name }}
logoURL: {{ .LogoPath }} logoURL: {{ .LogoPath }}
dir: /srv/dex/web/ dir: /srv/dex/web/
oauth2: oauth2:

View file

@ -1,9 +1,9 @@
package api package api
import ( import (
"encoding/json"
"fmt" "fmt"
"log" "log"
"math/rand"
"net/http" "net/http"
"strconv" "strconv"
"strings" "strings"
@ -186,6 +186,9 @@ func declareTeamsRoutes(router *gin.RouterGroup) {
declareTeamsPasswordRoutes(apiTeamsRoutes) declareTeamsPasswordRoutes(apiTeamsRoutes)
declareTeamClaimsRoutes(apiTeamsRoutes) declareTeamClaimsRoutes(apiTeamsRoutes)
declareTeamCertificateRoutes(apiTeamsRoutes) declareTeamCertificateRoutes(apiTeamsRoutes)
// Import teams from cyberrange
router.POST("/cyberrange-teams.json", importTeamsFromCyberrange)
} }
func TeamHandler(c *gin.Context) { func TeamHandler(c *gin.Context) {
@ -292,6 +295,11 @@ func bindingTeams(c *gin.Context) {
c.String(http.StatusOK, ret) c.String(http.StatusOK, ret)
} }
type teamAssociation struct {
Association string `json:"association"`
TeamId int64 `json:"team_id"`
}
func allAssociations(c *gin.Context) { func allAssociations(c *gin.Context) {
teams, err := fic.GetTeams() teams, err := fic.GetTeams()
if err != nil { if err != nil {
@ -300,7 +308,7 @@ func allAssociations(c *gin.Context) {
return return
} }
var ret []string var ret []teamAssociation
for _, team := range teams { for _, team := range teams {
assocs, err := pki.GetTeamAssociations(TeamsDir, team.Id) assocs, err := pki.GetTeamAssociations(TeamsDir, team.Id)
@ -310,13 +318,84 @@ func allAssociations(c *gin.Context) {
} }
for _, a := range assocs { for _, a := range assocs {
ret = append(ret, a) ret = append(ret, teamAssociation{a, team.Id})
} }
} }
c.JSON(http.StatusOK, ret) c.JSON(http.StatusOK, ret)
} }
func importTeamsFromCyberrange(c *gin.Context) {
file, err := c.FormFile("file")
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"errmsg": "Failed to get file: " + err.Error()})
return
}
src, err := file.Open()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"errmsg": "Failed to open file: " + err.Error()})
return
}
defer src.Close()
var ut []fic.CyberrangeTeam
err = json.NewDecoder(src).Decode(&fic.CyberrangeAPIResponse{Data: &ut})
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
return
}
teams, err := fic.GetTeams()
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": fmt.Sprintf("Impossible de récupérer la liste des équipes actuelles: %s", err.Error())})
return
}
for _, crteam := range ut {
var exist_team *fic.Team
for _, team := range teams {
if team.Name == crteam.Name && team.ExternalId == crteam.UUID {
exist_team = team
break
}
}
if exist_team != nil {
exist_team.Name = crteam.Name
exist_team.ExternalId = crteam.UUID
_, err = exist_team.Update()
} else {
exist_team, err = fic.CreateTeam(crteam.Name, fic.RandomColor().ToRGB(), crteam.UUID)
}
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": fmt.Sprintf("Impossible d'ajouter/de modifier l'équipe %v: %s", crteam, err.Error())})
return
}
// Import members
if c.DefaultQuery("nomembers", "0") != "" && len(crteam.Members) > 0 {
exist_team.ClearMembers()
for _, member := range crteam.Members {
_, err = exist_team.AddMember(member.Name, "", member.Nickname, exist_team.Name)
if err != nil {
log.Printf("Unable to add member %q to team %s (tid=%d): %s", member.UUID, exist_team.Name, exist_team.Id, err.Error())
}
}
}
}
teams, err = fic.GetTeams()
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": fmt.Sprintf("Impossible de récupérer la liste des équipes après import: %s", err.Error())})
return
}
c.JSON(http.StatusOK, teams)
}
func createTeam(c *gin.Context) { func createTeam(c *gin.Context) {
var ut fic.Team var ut fic.Team
err := c.ShouldBindJSON(&ut) err := c.ShouldBindJSON(&ut)
@ -326,11 +405,7 @@ func createTeam(c *gin.Context) {
} }
if ut.Color == 0 { if ut.Color == 0 {
ut.Color = fic.HSL{ ut.Color = fic.RandomColor().ToRGB()
H: rand.Float64(),
S: 1,
L: 0.5,
}.ToRGB()
} }
team, err := fic.CreateTeam(strings.TrimSpace(ut.Name), ut.Color, ut.ExternalId) team, err := fic.CreateTeam(strings.TrimSpace(ut.Name), ut.Color, ut.ExternalId)

View file

@ -4,7 +4,7 @@ const indextpl = `<!DOCTYPE html>
<html ng-app="FICApp"> <html ng-app="FICApp">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Challenge Forensic - Administration</title> <title>{{ .title }} - Administration</title>
<link href="{{.urlbase}}css/bootstrap.min.css" type="text/css" rel="stylesheet"> <link href="{{.urlbase}}css/bootstrap.min.css" type="text/css" rel="stylesheet">
<link href="{{.urlbase}}css/glyphicon.css" type="text/css" rel="stylesheet" media="screen"> <link href="{{.urlbase}}css/glyphicon.css" type="text/css" rel="stylesheet" media="screen">
<style> <style>
@ -86,7 +86,7 @@ const indextpl = `<!DOCTYPE html>
<body class="bg-light text-dark"> <body class="bg-light text-dark">
<nav class="navbar sticky-top navbar-expand-lg navbar-dark text-light" ng-class="{'bg-dark': settings.wip, 'bg-danger': !settings.wip}"> <nav class="navbar sticky-top navbar-expand-lg navbar-dark text-light" ng-class="{'bg-dark': settings.wip, 'bg-danger': !settings.wip}">
<a class="navbar-brand" href="."> <a class="navbar-brand" href=".">
<img alt="FIC" src="img/fic.png" style="height: 30px"> <img alt="{{ .title }}" src="{{ .logo }}" style="height: 30px">
</a> </a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#adminMenu" aria-controls="adminMenu" aria-expanded="false" aria-label="Toggle navigation"> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#adminMenu" aria-controls="adminMenu" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span> <span class="navbar-toggler-icon"></span>
@ -95,7 +95,7 @@ const indextpl = `<!DOCTYPE html>
<div class="collapse navbar-collapse" id="adminMenu"> <div class="collapse navbar-collapse" id="adminMenu">
<ul class="navbar-nav mr-auto"> <ul class="navbar-nav mr-auto">
<li class="nav-item" ng-class="{'active': $location.path().startsWith('/teams')}"><a class="nav-link" href="teams">&Eacute;quipes</a></li> <li class="nav-item" ng-class="{'active': $location.path().startsWith('/teams')}"><a class="nav-link" href="teams">&Eacute;quipes</a></li>
<li class="nav-item" ng-class="{'active': $location.path().startsWith('/pki')}"><a class="nav-link" href="pki">PKI</a></li> <li class="nav-item" ng-class="{'active': $location.path().startsWith('/auth')}"><a class="nav-link" href="auth">Authentification</a></li>
<li class="nav-item" ng-class="{'active': $location.path().startsWith('/themes')}"><a class="nav-link" href="themes">Thèmes</a></li> <li class="nav-item" ng-class="{'active': $location.path().startsWith('/themes')}"><a class="nav-link" href="themes">Thèmes</a></li>
<li class="nav-item" ng-class="{'active': $location.path().startsWith('/exercices')}"><a class="nav-link" href="exercices">Exercices</a></li> <li class="nav-item" ng-class="{'active': $location.path().startsWith('/exercices')}"><a class="nav-link" href="exercices">Exercices</a></li>
<li class="nav-item" ng-class="{'active': $location.path().startsWith('/public')}"><a class="nav-link" href="public/0">Public</a></li> <li class="nav-item" ng-class="{'active': $location.path().startsWith('/public')}"><a class="nav-link" href="public/0">Public</a></li>
@ -124,7 +124,7 @@ const indextpl = `<!DOCTYPE html>
</div> </div>
<span id="clock" class="navbar-text" ng-controller="CountdownController" ng-cloak> <span id="clock" class="navbar-text" ng-controller="CountdownController" ng-cloak>
<div style="position: absolute;"> <div style="pointer-events: none; position: absolute;">
<div style="position: absolute;" id="circle1" class="circle-anim border-danger"></div> <div style="position: absolute;" id="circle1" class="circle-anim border-danger"></div>
<div style="position: absolute;" id="circle2" class="circle-anim border-info"></div> <div style="position: absolute;" id="circle2" class="circle-anim border-info"></div>
</div> </div>

View file

@ -6,6 +6,7 @@ import (
"errors" "errors"
"log" "log"
"net/http" "net/http"
"os"
"path" "path"
"strings" "strings"
"text/template" "text/template"
@ -25,10 +26,24 @@ var assets embed.FS
var indexPage []byte var indexPage []byte
func genIndex(baseURL string) { func genIndex(baseURL string) {
tplcfg := map[string]string{
"logo": "img/logo.png",
"title": "Challenge",
"urlbase": path.Clean(path.Join(baseURL+"/", "nuke"))[:len(path.Clean(path.Join(baseURL+"/", "nuke")))-4],
}
ci, err := api.GetChallengeInfo()
if err == nil && ci != nil {
tplcfg["title"] = ci.Title
if len(ci.MainLogo) > 0 {
tplcfg["logo"] = "/files/logo/" + path.Base(ci.MainLogo[0])
}
}
b := bytes.NewBufferString("") b := bytes.NewBufferString("")
if indexTmpl, err := template.New("index").Parse(indextpl); err != nil { if indexTmpl, err := template.New("index").Parse(indextpl); err != nil {
log.Fatal("Cannot create template:", err) log.Fatal("Cannot create template:", err)
} else if err = indexTmpl.Execute(b, map[string]string{"urlbase": path.Clean(path.Join(baseURL+"/", "nuke"))[:len(path.Clean(path.Join(baseURL+"/", "nuke")))-4]}); err != nil { } else if err = indexTmpl.Execute(b, tplcfg); err != nil {
log.Fatal("An error occurs during template execution:", err) log.Fatal("An error occurs during template execution:", err)
} else { } else {
indexPage = b.Bytes() indexPage = b.Bytes()
@ -50,6 +65,9 @@ func declareStaticRoutes(router *gin.RouterGroup, cfg *settings.Settings, baseUR
router.GET("/", func(c *gin.Context) { router.GET("/", func(c *gin.Context) {
serveIndex(c) serveIndex(c)
}) })
router.GET("/auth/*_", func(c *gin.Context) {
serveIndex(c)
})
router.GET("/claims/*_", func(c *gin.Context) { router.GET("/claims/*_", func(c *gin.Context) {
serveIndex(c) serveIndex(c)
}) })
@ -104,8 +122,22 @@ func declareStaticRoutes(router *gin.RouterGroup, cfg *settings.Settings, baseUR
}) })
router.GET("/files/*_", func(c *gin.Context) { router.GET("/files/*_", func(c *gin.Context) {
// TODO: handle .gz file here filepath := path.Join(fic.FilesDir, strings.TrimPrefix(strings.TrimPrefix(c.Request.URL.Path, baseURL), "/files"))
http.ServeFile(c.Writer, c.Request, path.Join(fic.FilesDir, strings.TrimPrefix(c.Request.URL.Path, path.Join(baseURL, "files"))))
if st, err := os.Stat(filepath); os.IsNotExist(err) || st.Size() == 0 {
if st, err := os.Stat(filepath + ".gz"); err == nil {
if fd, err := os.Open(filepath + ".gz"); err == nil {
log.Println(filepath + ".gz")
c.DataFromReader(http.StatusOK, st.Size(), "application/octet-stream", fd, map[string]string{
"Content-Encoding": "gzip",
})
return
}
}
}
log.Println(filepath)
c.File(filepath)
}) })
router.GET("/submissions/*_", func(c *gin.Context) { router.GET("/submissions/*_", func(c *gin.Context) {
http.ServeFile(c.Writer, c.Request, path.Join(api.TimestampCheck, strings.TrimPrefix(c.Request.URL.Path, path.Join(baseURL, "submissions")))) http.ServeFile(c.Writer, c.Request, path.Join(api.TimestampCheck, strings.TrimPrefix(c.Request.URL.Path, path.Join(baseURL, "submissions"))))

View file

@ -25,6 +25,10 @@ angular.module("FICApp", ["ngRoute", "ngResource", "ngSanitize"])
controller: "SettingsController", controller: "SettingsController",
templateUrl: "views/settings.html" templateUrl: "views/settings.html"
}) })
.when("/auth", {
controller: "AuthController",
templateUrl: "views/auth.html"
})
.when("/pki", { .when("/pki", {
controller: "PKIController", controller: "PKIController",
templateUrl: "views/pki.html" templateUrl: "views/pki.html"
@ -348,6 +352,9 @@ angular.module("FICApp")
.factory("ExerciceFlagDeps", function ($resource) { .factory("ExerciceFlagDeps", function ($resource) {
return $resource("api/exercices/:exerciceId/flags/:flagId/dependancies", { exerciceId: '@idExercice', flagId: '@id' }) return $resource("api/exercices/:exerciceId/flags/:flagId/dependancies", { exerciceId: '@idExercice', flagId: '@id' })
}) })
.factory("ExerciceFlagStats", function ($resource) {
return $resource("api/exercices/:exerciceId/flags/:flagId/statistics", { exerciceId: '@idExercice', flagId: '@id' })
})
.factory("ExerciceMCQFlag", function ($resource) { .factory("ExerciceMCQFlag", function ($resource) {
return $resource("api/exercices/:exerciceId/quiz/:mcqId", { exerciceId: '@idExercice', mcqId: '@id' }, { return $resource("api/exercices/:exerciceId/quiz/:mcqId", { exerciceId: '@idExercice', mcqId: '@id' }, {
update: { method: 'PUT' } update: { method: 'PUT' }
@ -355,6 +362,9 @@ angular.module("FICApp")
}) })
.factory("ExerciceMCQDeps", function ($resource) { .factory("ExerciceMCQDeps", function ($resource) {
return $resource("api/exercices/:exerciceId/quiz/:mcqId/dependancies", { exerciceId: '@idExercice', mcqId: '@id' }) return $resource("api/exercices/:exerciceId/quiz/:mcqId/dependancies", { exerciceId: '@idExercice', mcqId: '@id' })
})
.factory("ExerciceMCQStats", function ($resource) {
return $resource("api/exercices/:exerciceId/quiz/:mcqId/statistics", { exerciceId: '@idExercice', mcqId: '@id' })
}); });
angular.module("FICApp") angular.module("FICApp")
@ -611,9 +621,18 @@ angular.module("FICApp")
response.enableExerciceDepend = response.unlockedChallengeDepth >= 0; response.enableExerciceDepend = response.unlockedChallengeDepth >= 0;
response.disabledsubmitbutton = response.disablesubmitbutton && response.disablesubmitbutton.length > 0; response.disabledsubmitbutton = response.disablesubmitbutton && response.disablesubmitbutton.length > 0;
if (response.end) {
$scope.duration = (response.end - response.start)/60000;
}
}) })
$scope.challenge = SettingsChallenge.get(); $scope.challenge = SettingsChallenge.get();
$scope.duration = 360; $scope.duration = 360;
$scope.durationChange = function(endChanged) {
if (endChanged)
$scope.duration = (new Date($scope.config.end).getTime() - new Date($scope.config.start).getTime())/60000;
else
$scope.config.end = new Date(new Date($scope.config.start).getTime() + $scope.duration * 60000);
}
$scope.activateTime = ""; $scope.activateTime = "";
$scope.challenge.$promise.then(function (c) { $scope.challenge.$promise.then(function (c) {
if (c.duration) if (c.duration)
@ -648,7 +667,7 @@ angular.module("FICApp")
$scope.saveChallengeInfo = function () { $scope.saveChallengeInfo = function () {
this.challenge.duration = $scope.duration; this.challenge.duration = $scope.duration;
this.challenge.$update(function (response) { this.challenge.$update(function (response) {
$scope.addToast('success', 'Infos du challenge mises à jour avec succès !'); $scope.addToast('success', 'Infos du challenge mises à jour avec succès!');
}, function (response) { }, function (response) {
$scope.addToast('danger', 'An error occurs when saving challenge info:', response.data.errmsg); $scope.addToast('danger', 'An error occurs when saving challenge info:', response.data.errmsg);
}); });
@ -722,9 +741,9 @@ angular.module("FICApp")
"teams": "En validant, vous supprimerez l'ensemble des équipes enregistreées.", "teams": "En validant, vous supprimerez l'ensemble des équipes enregistreées.",
"game": "En validant, vous supprimerez toutes les tentatives, les validations, ... faites par les équipes.", "game": "En validant, vous supprimerez toutes les tentatives, les validations, ... faites par les équipes.",
} }
$scope.addToast('warning', txts[type], 'Êtes-vous sûr de vouloir continuer ?', $scope.addToast('warning', txts[type], 'Êtes-vous sûr de vouloir continuer?',
function () { function () {
if (confirm("Êtes-vous vraiment sûr ?\n" + txts[type])) { if (confirm("Êtes-vous vraiment sûr?\n" + txts[type])) {
$http.post("api/reset", { "type": type }).then(function (time) { $http.post("api/reset", { "type": type }).then(function (time) {
$scope.addToast('success', type + 'reseted'); $scope.addToast('success', type + 'reseted');
$location.url("/"); $location.url("/");
@ -736,7 +755,7 @@ angular.module("FICApp")
}); });
}; };
$scope.switchToProd = function () { $scope.switchToProd = function () {
$scope.addToast('warning', "Activer le mode challenge ?", "L'activation du mode challenge est temporaire (vous devriez plutôt relancer le daemon avec l'option `-4real`). Ce mode permet d'éviter les mauvaises manipulations et désactive le hook git de synchronisation automatique. Êtes-vous sûr de vouloir continuer ?", $scope.addToast('warning', "Activer le mode challenge?", "L'activation du mode challenge est temporaire (vous devriez plutôt relancer le daemon avec l'option `-4real`). Ce mode permet d'éviter les mauvaises manipulations et désactive le hook git de synchronisation automatique. Êtes-vous sûr de vouloir continuer?",
function () { function () {
$http.put("api/prod", true).then(function (time) { $http.put("api/prod", true).then(function (time) {
$rootScope.refreshSettings() $rootScope.refreshSettings()
@ -759,6 +778,20 @@ angular.module("FICApp")
}); });
}; };
}) })
.component('teamLink', {
bindings: {
idTeam: '=',
},
controller: function (Team) {
var ctrl = this;
ctrl.team = {};
ctrl.$onInit = function () {
ctrl.team = Team.get({teamId: ctrl.idTeam});
};
},
template: `<a href="/teams/{{ $ctrl.idTeam }}">{{ $ctrl.team.name }}</a> `
})
.component('repositoryUptodate', { .component('repositoryUptodate', {
bindings: { bindings: {
repository: '<', repository: '<',
@ -820,10 +853,10 @@ angular.module("FICApp")
$scope.deepSync = function (theme) { $scope.deepSync = function (theme) {
if (theme) { if (theme) {
question = 'Faire une synchronisation intégrale du thème ' + theme.name + ' ?' question = 'Faire une synchronisation intégrale du thème ' + theme.name + '?'
url = "api/sync/deep/" + theme.id url = "api/sync/deep/" + theme.id
} else { } else {
question = 'Faire une synchronisation intégrale ?' question = 'Faire une synchronisation intégrale?'
url = "api/sync/deep" url = "api/sync/deep"
} }
$scope.addToast('warning', question, '', $scope.addToast('warning', question, '',
@ -839,7 +872,7 @@ angular.module("FICApp")
}); });
}; };
$scope.speedyDeepSync = function () { $scope.speedyDeepSync = function () {
$scope.addToast('warning', 'Faire une synchronisation profonde rapide, sans s\'occuper des fichiers ?', '', $scope.addToast('warning', 'Faire une synchronisation profonde rapide, sans s\'occuper des fichiers?', '',
function () { function () {
$scope.deepSyncInProgress = true; $scope.deepSyncInProgress = true;
$http.post("api/sync/speed").then(function () { $http.post("api/sync/speed").then(function () {
@ -852,7 +885,7 @@ angular.module("FICApp")
}); });
}; };
$scope.baseSync = function () { $scope.baseSync = function () {
$scope.addToast('warning', 'Tirer les mises à jour du dépôt ?', '', $scope.addToast('warning', 'Tirer les mises à jour du dépôt?', '',
function () { function () {
$scope.deepSyncInProgress = true; $scope.deepSyncInProgress = true;
$http.post("api/sync/base").then(function () { $http.post("api/sync/base").then(function () {
@ -865,7 +898,7 @@ angular.module("FICApp")
}); });
}; };
$scope.syncVideos = function () { $scope.syncVideos = function () {
$scope.addToast('warning', 'Synchroniser les vidéos de résolution ?', 'ATTENTION il ne faut pas lancer cette synchronisation durant le challenge. Seulement une fois le challenge terminé, cela permet de rendre les vidéos accessibles dans l\'interface joueurs.', $scope.addToast('warning', 'Synchroniser les vidéos de résolution?', 'ATTENTION il ne faut pas lancer cette synchronisation durant le challenge. Seulement une fois le challenge terminé, cela permet de rendre les vidéos accessibles dans l\'interface joueurs.',
function () { function () {
$scope.deepSyncInProgress = true; $scope.deepSyncInProgress = true;
$http.post("api/sync/videos").then(function () { $http.post("api/sync/videos").then(function () {
@ -892,6 +925,49 @@ angular.module("FICApp")
}; };
}) })
.controller("AuthController", function ($scope, $http) {
$scope.generateHtpasswd = function () {
$http.post("api/htpasswd").then(function () {
$scope.addToast('success', 'Fichier htpasswd généré avec succès');
}, function (response) {
$scope.addToast('danger', 'An error occurs when generating htpasswd file:', response.data.errmsg);
});
};
$scope.removeHtpasswd = function () {
$http.delete("api/htpasswd").then(function () {
$scope.addToast('success', 'Fichier htpasswd supprimé avec succès');
}, function (response) {
$scope.addToast('danger', 'An error occurs when deleting htpasswd file:', response.data.errmsg);
});
};
})
.controller("OAuthController", function ($scope, $http) {
$scope.refreshOAuthStatus = function () {
$http.get("api/oauth-status").then(function (res) {
$scope.oauth_status = response.data;
});
};
$scope.genDexCfg = function () {
$http.post("api/dex.yaml").then(function () {
$http.post("api/dex-password.tpl").then(function () {
$scope.addToast('success', 'Dex config refreshed.', "Don't forget to reload/reboot frontend host.");
}, function (response) {
$scope.addToast('danger', 'An error occurs when generating dex password tpl:', response.data.errmsg);
});
}, function (response) {
$scope.addToast('danger', 'An error occurs when generating dex config:', response.data.errmsg);
});
$http.post("api/vouch-proxy.yaml").then(function () {
$scope.addToast('success', 'VouchProxy config refreshed.', "Don't forget to reload/reboot frontend host.");
}, function (response) {
$scope.addToast('danger', 'An error occurs when generating VouchProxy config:', response.data.errmsg);
});
}
})
.controller("PKIController", function ($scope, $rootScope, Certificate, CACertificate, Team, $location, $http) { .controller("PKIController", function ($scope, $rootScope, Certificate, CACertificate, Team, $location, $http) {
var ts = Date.now() - Date.now() % 86400000; var ts = Date.now() - Date.now() % 86400000;
var d = new Date(ts); var d = new Date(ts);
@ -976,20 +1052,6 @@ angular.module("FICApp")
$scope.addToast('danger', 'An error occurs when generating certificate:', response.data.errmsg); $scope.addToast('danger', 'An error occurs when generating certificate:', response.data.errmsg);
}); });
}; };
$scope.generateHtpasswd = function () {
$http.post("api/htpasswd").then(function () {
$scope.addToast('success', 'Fichier htpasswd généré avec succès');
}, function (response) {
$scope.addToast('danger', 'An error occurs when generating htpasswd file:', response.data.errmsg);
});
};
$scope.removeHtpasswd = function () {
$http.delete("api/htpasswd").then(function () {
$scope.addToast('success', 'Fichier htpasswd supprimé avec succès');
}, function (response) {
$scope.addToast('danger', 'An error occurs when deleting htpasswd file:', response.data.errmsg);
});
};
}) })
.controller("PublicController", function ($scope, $rootScope, $routeParams, $location, Scene, Theme, Teams, Exercice) { .controller("PublicController", function ($scope, $rootScope, $routeParams, $location, Scene, Theme, Teams, Exercice) {
@ -1110,7 +1172,7 @@ angular.module("FICApp")
}, },
{ {
type: "countdown", type: "countdown",
params: { color: "success", end: null, lead: "Go, go, go !", title: "Le challenge forensic va bientôt commencer !" }, params: { color: "success", end: null, lead: "Go, go, go!", title: "Le challenge forensic va bientôt commencer!" },
}, },
]; ];
$scope.display.side = [ $scope.display.side = [
@ -1229,8 +1291,8 @@ angular.module("FICApp")
show: true, show: true,
shadow: "#E8CF5C", shadow: "#E8CF5C",
end: new Date($rootScope.getSrvTime().getTime() + 1802000).toISOString(), end: new Date($rootScope.getSrvTime().getTime() + 1802000).toISOString(),
before: "Heure joyeuse : chaque résolution compte double !", before: "Heure joyeuse: chaque résolution compte double!",
after: "Heure joyeuse terminée !", after: "Heure joyeuse terminée!",
} }
} }
else if (scene == "freehintquarter") { else if (scene == "freehintquarter") {
@ -1238,8 +1300,8 @@ angular.module("FICApp")
show: true, show: true,
shadow: "#3DD28F", shadow: "#3DD28F",
end: new Date($rootScope.getSrvTime().getTime() + 902000).toISOString(), end: new Date($rootScope.getSrvTime().getTime() + 902000).toISOString(),
before: "Quart d'heure facile : indices dévoilés !", before: "Quart d'heure facile: indices dévoilés!",
after: "Quart d'heure facile terminée !", after: "Quart d'heure facile terminée!",
} }
} }
}; };
@ -1368,7 +1430,7 @@ angular.module("FICApp")
}); });
}; };
$scope.clearFilesDir = function () { $scope.clearFilesDir = function () {
$scope.addToast('warning', 'Êtes-vous sûr de vouloir continuer ?', "Ceci va supprimer tout le contenu du dossier FILES. Il s'agit des fichiers ci-dessous, il faudra refaire une synchronisation ensuite.", $scope.addToast('warning', 'Êtes-vous sûr de vouloir continuer?', "Ceci va supprimer tout le contenu du dossier FILES. Il s'agit des fichiers ci-dessous, il faudra refaire une synchronisation ensuite.",
function () { function () {
$scope.clearFilesWIP = true; $scope.clearFilesWIP = true;
$http({ $http({
@ -2255,9 +2317,9 @@ angular.module("FICApp")
} }
$scope.saveFlag = function () { $scope.saveFlag = function () {
if (this.flag.id) { if (this.flag.id) {
this.flag.$update(); this.flag.$update().then(function() {}, function(error) { $scope.addToast('danger', 'Impossible de mettre à jour le flag :', error.data.errmsg); });
} else { } else {
this.flag.$save({ exerciceId: $routeParams.exerciceId }); this.flag.$save({ exerciceId: $routeParams.exerciceId }).then(function() {}, function(error) { $scope.addToast('danger', 'Impossible de créer le flag :', error.data.errmsg); });
} }
$rootScope.staticFilesNeedUpdate++; $rootScope.staticFilesNeedUpdate++;
} }
@ -2276,7 +2338,7 @@ angular.module("FICApp")
method: "POST" method: "POST"
}).then(function (response) { }).then(function (response) {
flag.test_str = ""; flag.test_str = "";
$scope.addToast('success', "Flag Ok !"); $scope.addToast('success', "Flag Ok!");
}, function (response) { }, function (response) {
flag.test_str = ""; flag.test_str = "";
$scope.addToast('danger', 'An error occurs: ', response.data.errmsg); $scope.addToast('danger', 'An error occurs: ', response.data.errmsg);
@ -2345,6 +2407,18 @@ angular.module("FICApp")
} }
}) })
.controller("ExerciceFlagStatsController", function ($scope, $routeParams, ExerciceFlagStats, $http) {
$scope.init = function (flag) {
$scope.flag_id = flag.id;
$scope.stats = ExerciceFlagStats.get({ exerciceId: $routeParams.exerciceId, flagId: flag.id });
}
$scope.deleteTries = function () {
$http.delete(`/api/exercices/${$routeParams.exerciceId}/flags/${$scope.flag_id}/tries`).then(function () {
$scope.stats = ExerciceFlagStats.get({ exerciceId: $routeParams.exerciceId, flagId: $scope.flag_id });
});
}
})
.controller("ExerciceMCQFlagsController", function ($scope, ExerciceMCQFlag, $routeParams, $rootScope) { .controller("ExerciceMCQFlagsController", function ($scope, ExerciceMCQFlag, $routeParams, $rootScope) {
$scope.quiz = ExerciceMCQFlag.query({ exerciceId: $routeParams.exerciceId }); $scope.quiz = ExerciceMCQFlag.query({ exerciceId: $routeParams.exerciceId });
@ -2382,6 +2456,18 @@ angular.module("FICApp")
} }
}) })
.controller("ExerciceMCQStatsController", function ($scope, $routeParams, ExerciceMCQStats, $http) {
$scope.init = function (mcq) {
$scope.mcq_id = mcq.id;
$scope.stats = ExerciceMCQStats.get({ exerciceId: $routeParams.exerciceId, mcqId: mcq.id });
}
$scope.deleteTries = function () {
$http.delete(`/api/exercices/${$routeParams.exerciceId}/quiz/${$scope.mcq_id}/tries`).then(function () {
$scope.stats = ExerciceMCQStats.get({ exerciceId: $routeParams.exerciceId, mcqId: $scope.mcq_id });
});
}
})
.controller("TeamsListController", function ($scope, $rootScope, Team, $location, $http) { .controller("TeamsListController", function ($scope, $rootScope, Team, $location, $http) {
$scope.teams = Team.query(); $scope.teams = Team.query();
$scope.fields = ["id", "name"]; $scope.fields = ["id", "name"];
@ -2408,22 +2494,6 @@ angular.module("FICApp")
} }
}; };
$scope.genDexCfg = function () {
$http.post("api/dex.yaml").then(function () {
$http.post("api/dex-password.tpl").then(function () {
$scope.addToast('success', 'Dex config refreshed.', "Don't forget to reload/reboot frontend host.");
}, function (response) {
$scope.addToast('danger', 'An error occurs when generating dex password tpl:', response.data.errmsg);
});
}, function (response) {
$scope.addToast('danger', 'An error occurs when generating dex config:', response.data.errmsg);
});
$http.post("api/vouch-proxy.yaml").then(function () {
$scope.addToast('success', 'VouchProxy config refreshed.', "Don't forget to reload/reboot frontend host.");
}, function (response) {
$scope.addToast('danger', 'An error occurs when generating VouchProxy config:', response.data.errmsg);
});
}
$scope.desactiveTeams = function () { $scope.desactiveTeams = function () {
$http.post("api/disableinactiveteams").then(function () { $http.post("api/disableinactiveteams").then(function () {
$scope.teams = Team.query(); $scope.teams = Team.query();
@ -2431,9 +2501,34 @@ angular.module("FICApp")
$scope.addToast('danger', 'An error occurs when disabling inactive teams:', response.data.errmsg); $scope.addToast('danger', 'An error occurs when disabling inactive teams:', response.data.errmsg);
}); });
} }
$scope.refineTeamsColors = function () {
$http.post("api/refine_colors").then(function () {
$scope.teams = Team.query();
}, function (response) {
$scope.addToast('danger', 'An error occurs when updating teams:', response.data.errmsg);
});
}
$scope.show = function (id) { $scope.show = function (id) {
$location.url("/teams/" + id); $location.url("/teams/" + id);
}; };
$scope.triggerTeamsImport = function() {
document.getElementById('crTeamsInput').click();
};
$scope.uploadFile = function() {
var formData = new FormData();
formData.append('file', $scope.selectedFile);
$http.post('api/cyberrange-teams.json', formData, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined},
}).then(function(response) {
$scope.teams = response.data;
$scope.addToast('success', 'Import des équipes', "L'import a été réalisé avec succès !");
}, function(error) {
console.log(error);
$scope.addToast('danger', 'Import des équipes', error.data.errmsg);
});
};
}) })
.controller("TeamMembersController", function ($scope, TeamMember) { .controller("TeamMembersController", function ($scope, TeamMember) {
$scope.fields = ["firstname", "lastname", "nickname", "company"]; $scope.fields = ["firstname", "lastname", "nickname", "company"];

View file

@ -81,6 +81,22 @@ angular.module("FICApp")
}); });
} }
} }
}])
.directive('fileModel', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function($scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
element.bind('change', function(){
$scope.$apply(function(){
modelSetter($scope, element[0].files[0]);
$scope.uploadFile();
});
});
}
};
}]); }]);
angular.module("FICApp") angular.module("FICApp")

View file

@ -0,0 +1,86 @@
<div class="d-flex justify-content-between align-items-center">
<h2>
Authentification
</h2>
<div>
<div class="btn-group mr-1" role="group">
<button type="button" ng-click="generateHtpasswd()" class="btn btn-sm btn-secondary"><span class="glyphicon glyphicon-save-file" aria-hidden="true"></span> Générer <code>fichtpasswd</code></button>
<button type="button" ng-click="removeHtpasswd()" class="btn btn-sm btn-danger"><span class="glyphicon glyphicon-trash" aria-hidden="true"></span></button>
</div>
</div>
</div>
<div ng-controller="OAuthController">
<div class="d-flex justify-content-between align-items-center">
<h3>
OAuth 2
<span class="badge badge-success" ng-if="oauth_status.secret_defined">Actif</span>
<span class="badge badge-danger" ng-if="!oauth_status.secret_defined">Non configuré</span>
</h3>
<div>
<button type="button" ng-click="genDexCfg()" class="btn btn-success mr-2"><span class="glyphicon glyphicon-refresh" aria-hidden="true"></span> DexIdP</button>
</div>
</div>
</div>
<hr>
<div ng-controller="PKIController">
<div class="d-flex justify-content-between align-items-center">
<h3>
Autorité de certification
<span class="badge badge-success" ng-if="ca.version">Générée</span>
<span class="badge badge-danger" ng-if="!ca.version">Introuvable</span>
</h3>
<div>
<a
class="btn btn-primary"
href="/pki"
>
<span class="glyphicon glyphicon-certificate" aria-hidden="true"></span>
Gérer la PKI
</a>
</div>
</div>
<div class="alert alert-info" ng-if="!ca.version">
<strong>Aucune CA n'a été générée pour le moment.</strong>
</div>
<dl ng-if="ca.version">
<ng-repeat ng-repeat="(k, v) in ca" class="row">
<dt class="col-3 text-right">{{ k }}</dt>
<dd class="col-9" ng-if="v.CommonName">/CN={{ v.CommonName }}/OU={{ v.OrganizationalUnit }}/O={{ v.Organization }}/L={{ v.Locality }}/P={{ v.Province }}/C={{ v.Country }}/</dd>
<dd class="col-9" ng-if="!v.CommonName">{{ v }}</dd>
</ng-repeat>
</dl>
</div>
<hr>
<div class="mb-4" ng-controller="AllTeamAssociationsController">
<div class="d-flex justify-content-between align-items-center">
<h3>
Association utilisateurs et équipes
</h3>
<div>
</div>
</div>
<table class="table table-sm table-hover" ng-controller="TeamsListController" >
<tr>
<th class="text-right">Utilisateur</th>
<th></th>
<th>Équipe</th>
</tr>
<tr ng-repeat="association in allAssociations">
<td class="text-right">{{ association.association }}</td>
<td class="text-center">&#11020;</td>
<td ng-repeat="team in teams" ng-if="team.id == association.team_id">
<a ng-href="teams/{{ team.id }}">
{{ team.name }}
</a>
</td>
</tr>
</table>
</div>

View file

@ -73,12 +73,28 @@
</div> </div>
<div class="col-4"> <div class="col-4">
<div ng-controller="ExerciceFlagDepsController" ng-init="init(flag)"> <div ng-controller="ExerciceFlagDepsController" ng-init="init(flag)">
Dépendances&nbsp;: <strong>Dépendances&nbsp;:</strong>
<ul ng-if="deps.length > 0"> <ul ng-if="deps.length > 0">
<dependancy ng-repeat="dep in deps" dep="dep"></dependancy> <dependancy ng-repeat="dep in deps" dep="dep"></dependancy>
</ul> </ul>
<span ng-if="deps.length == 0"> sans</span> <span ng-if="deps.length == 0"> sans</span>
</div> </div>
<hr>
<div ng-controller="ExerciceFlagStatsController" ng-init="init(flag)">
<strong>Statistiques</strong>
<ul>
<li>Validés: {{ stats["completed"] }}</li>
<li>
Tentés: {{ stats["tries"] }}
<button type="button" ng-click="deleteTries()" class="btn btn-sm btn-danger" ng-if="stats['tries'] > 0"><span class="glyphicon glyphicon-trash" aria-hidden="true"></span></button>
</li>
<li>
Équipes:
<span ng-if="stats['teams'].length == 0">aucune</span>
<team-link ng-repeat="team in stats['teams']" id-team="team"></team-link>
</li>
</ul>
</div>
</div> </div>
<div class="col-4" ng-controller="ExerciceFlagChoicesController"> <div class="col-4" ng-controller="ExerciceFlagChoicesController">
<div class="btn-toolbar justify-content-end mb-2" role="toolbar"> <div class="btn-toolbar justify-content-end mb-2" role="toolbar">
@ -168,6 +184,22 @@
<dependancy ng-repeat="dep in deps" dep="dep"></dependancy> <dependancy ng-repeat="dep in deps" dep="dep"></dependancy>
</ul> </ul>
<span ng-if="deps.length == 0"> sans</span> <span ng-if="deps.length == 0"> sans</span>
<hr>
<div ng-controller="ExerciceMCQStatsController" ng-init="init(q)">
<strong>Statistiques</strong>
<ul>
<li>Validés: {{ stats["completed"] }}</li>
<li>
Tentés: {{ stats["tries"] }}
<button type="button" ng-click="deleteTries()" class="btn btn-sm btn-danger" ng-if="stats['tries'] > 0"><span class="glyphicon glyphicon-trash" aria-hidden="true"></span></button>
</li>
<li>
Équipes:
<span ng-if="stats['teams'].length == 0">aucune</span>
<team-link ng-repeat="team in stats['teams']" id-team="team"></team-link>
</li>
</ul>
</div>
</div> </div>
</form> </form>
</div> </div>

View file

@ -100,7 +100,7 @@
<form ng-submit="saveFile()" class="list-group-item bg-light text-dark" ng-repeat="file in files"> <form ng-submit="saveFile()" class="list-group-item bg-light text-dark" ng-repeat="file in files">
<div class="row form-group"> <div class="row form-group">
<input type="text" ng-model="file.name" class="col form-control form-control-sm" placeholder="Nom de fichier"> <input type="text" ng-model="file.name" class="col form-control form-control-sm" placeholder="Nom de fichier">
<a href="../files{{file.path}}" class="btn btn-sm btn-secondary col-auto"><span class="glyphicon glyphicon-download" aria-hidden="true"></span></a> <a href="../files{{file.path}}" target="_self" class="btn btn-sm btn-secondary col-auto"><span class="glyphicon glyphicon-download" aria-hidden="true"></span></a>
<button type="submit" class="btn btn-sm btn-success col-auto"><span class="glyphicon glyphicon-ok" aria-hidden="true"></span></button><br> <button type="submit" class="btn btn-sm btn-success col-auto"><span class="glyphicon glyphicon-ok" aria-hidden="true"></span></button><br>
<button type="button" ng-click="deleteFile()" class="btn btn-sm btn-danger col-auto"><span class="glyphicon glyphicon-remove" aria-hidden="true"></span></button> <button type="button" ng-click="deleteFile()" class="btn btn-sm btn-danger col-auto"><span class="glyphicon glyphicon-remove" aria-hidden="true"></span></button>
</div> </div>

View file

@ -30,13 +30,13 @@
<div class="spinner-border spinner-border-sm" role="status" ng-if="file.gunzipWIP"></div> <div class="spinner-border spinner-border-sm" role="status" ng-if="file.gunzipWIP"></div>
</button> </button>
</td> </td>
<td ng-repeat="field in fields"> <td ng-repeat="field in fields" class="text-truncate" style="max-width: 30vw" title="{{ file[field] }}">
{{ file[field] }} {{ file[field] }}
<span ng-if="field == 'id' && file.err !== undefined && file.err !== true" title="{{ file.err }}" class="glyphicon glyphicon-exclamation-sign"></span> <span ng-if="field == 'id' && file.err !== undefined && file.err !== true" title="{{ file.err }}" class="glyphicon glyphicon-exclamation-sign"></span>
</td> </td>
<td> <td style="max-width: 100px">
{{ file.checksum | bto16 }} <div class="text-truncate" title="{{ file.checksum | bto16 }}">{{ file.checksum | bto16 }}</div>
<div ng-if="file.checksum_shown">{{ file.checksum_shown | bto16 }}</div> <div class="text-truncate" ng-if="file.checksum_shown" title="{{ file.checksum_shown | bto16 }}">{{ file.checksum_shown | bto16 }}</div>
</td> </td>
</tr> </tr>
</tbody> </tbody>

View file

@ -35,7 +35,7 @@
<label for="startTime" class="col-sm-3 col-form-label col-form-label-sm" ng-class="{'text-primary font-weight-bold': config.start != dist_config.start}">Début du challenge</label> <label for="startTime" class="col-sm-3 col-form-label col-form-label-sm" ng-class="{'text-primary font-weight-bold': config.start != dist_config.start}">Début du challenge</label>
<div class="col-sm-9"> <div class="col-sm-9">
<div class="input-group"> <div class="input-group">
<input type="datetime-local" class="form-control form-control-sm" id="startTime" ng-model="config.start" ng-class="{'border-primary': config.start != dist_config.start}"> <input type="datetime-local" class="form-control form-control-sm" id="startTime" ng-model="config.start" ng-change="durationChange()" ng-class="{'border-primary': config.start != dist_config.start}">
<div class="input-group-append"> <div class="input-group-append">
<button ng-click="launchChallenge()" class="btn btn-sm btn-secondary" type="button"><span class="glyphicon glyphicon-play" aria-hidden="true"></span> Lancer le challenge</button> <button ng-click="launchChallenge()" class="btn btn-sm btn-secondary" type="button"><span class="glyphicon glyphicon-play" aria-hidden="true"></span> Lancer le challenge</button>
</div> </div>
@ -46,14 +46,14 @@
<div class="form-group row"> <div class="form-group row">
<label for="endTime" class="col-sm-3 col-form-label col-form-label-sm" ng-class="{'text-primary font-weight-bold': config.end != dist_config.end}">Fin du challenge</label> <label for="endTime" class="col-sm-3 col-form-label col-form-label-sm" ng-class="{'text-primary font-weight-bold': config.end != dist_config.end}">Fin du challenge</label>
<div class="col-sm-6"> <div class="col-sm-6">
<input type="datetime-local" class="form-control form-control-sm" id="endTime" ng-model="config.end" ng-class="{'border-primary': config.end != dist_config.end}"> <input type="datetime-local" class="form-control form-control-sm" id="endTime" ng-model="config.end" ng-change="durationChange(true)" ng-class="{'border-primary': config.end != dist_config.end}">
</div> </div>
<div class="col-sm-1 text-right"> <div class="col-sm-1 text-right">
<label for="duration" class="col-form-label col-form-label-sm">Durée</label> <label for="duration" class="col-form-label col-form-label-sm">Durée</label>
</div> </div>
<div class="col-sm-2"> <div class="col-sm-2">
<div class="input-group input-group-sm"> <div class="input-group input-group-sm">
<input type="text" class="form-control form-control-sm" id="duration" ng-model="duration" integer> <input type="number" class="form-control form-control-sm" id="duration" ng-model="duration" ng-change="durationChange()" integer>
<div class="input-group-append"> <div class="input-group-append">
<span class="input-group-text">min</span> <span class="input-group-text">min</span>
</div> </div>
@ -323,7 +323,7 @@
<form class="row" ng-controller="AllTeamAssociationsController" ng-submit="addDelegatedQA()"> <form class="row" ng-controller="AllTeamAssociationsController" ng-submit="addDelegatedQA()">
<div class="col"> <div class="col">
<select class="form-control form-control-sm" ng-model="newdqa"> <select class="form-control form-control-sm" ng-model="newdqa">
<option ng-selected="newdqa == m" ng-repeat="(i,m) in allAssociations" ng-value="m">{{ m }}</option> <option ng-selected="newdqa == m.association" ng-repeat="(i,m) in allAssociations" ng-value="m.association">{{ m.association }}</option>
</select> </select>
</div> </div>
<div class="col input-group"> <div class="col input-group">

View file

@ -1,11 +1,19 @@
<h2> <div class="d-flex justify-content-between align-items-center">
&Eacute;quipes <h2>
<button type="button" ng-click="show('new')" class="float-right btn btn-sm btn-primary"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Ajouter une équipe</button> &Eacute;quipes
<button type="button" ng-click="show('print')" class="float-right btn btn-sm btn-secondary mr-2"><span class="glyphicon glyphicon-print" aria-hidden="true"></span> Imprimer les équipes</button> </h2>
<button type="button" ng-click="show('export')" class="float-right btn btn-sm btn-secondary mr-2"><span class="glyphicon glyphicon-export" aria-hidden="true"></span> Statistiques générales</button> <div>
<button type="button" ng-click="desactiveTeams()" class="float-right btn btn-sm btn-danger mr-2" title="Cliquer pour marquer les équipes sans certificat comme inactives (et ainsi éviter que ses fichiers ne soient générés)"><span class="glyphicon glyphicon-leaf" aria-hidden="true"></span> Désactiver les équipes inactives</button> <button type="button" ng-click="show('new')" class="btn btn-sm btn-primary ml-1"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Ajouter une équipe</button>
<button type="button" ng-click="genDexCfg()" class="float-right btn btn-sm btn-success mr-2"><span class="glyphicon glyphicon-refresh" aria-hidden="true"></span> DexIdP</button> <form class="d-inline">
</h2> <input id="crTeamsInput" type="file" file-model="selectedFile" class="d-none" />
<button type="button" ng-click="triggerTeamsImport()" class="btn btn-sm btn-secondary ml-1"><span class="glyphicon glyphicon-import" aria-hidden="true"></span> Import Cyberrange</button>
</form>
<button type="button" ng-click="show('print')" class="btn btn-sm btn-secondary ml-1" title="Imprimer les équipes et leurs membres"><span class="glyphicon glyphicon-print" aria-hidden="true"></span></button>
<button type="button" ng-click="refineTeamsColors()" class="btn btn-sm btn-secondary ml-1" title="Réarranger automatiquement les couleurs des équipes pour maximiser le spectre utilisé"><span class="glyphicon glyphicon-adjust" aria-hidden="true"></span></button>
<button type="button" ng-click="show('export')" class="btn btn-sm btn-secondary ml-1"><span class="glyphicon glyphicon-export" aria-hidden="true"></span> Statistiques générales</button>
<button type="button" ng-click="desactiveTeams()" class="btn btn-sm btn-danger ml-1" title="Cliquer pour marquer les équipes sans certificat comme inactives (et ainsi éviter que ses fichiers ne soient générés)"><span class="glyphicon glyphicon-leaf" aria-hidden="true"></span> Désactiver les équipes inactives</button>
</div>
</div>
<p><input type="search" class="form-control" placeholder="Search" ng-model="query" ng-keypress="validateSearch($event)" autofocus></p> <p><input type="search" class="form-control" placeholder="Search" ng-model="query" ng-keypress="validateSearch($event)" autofocus></p>
<table class="table table-hover table-bordered table-striped table-sm"> <table class="table table-hover table-bordered table-striped table-sm">

View file

@ -279,6 +279,7 @@ func buildKeyFlag(exercice *fic.Exercice, flag ExerciceFlag, flagline int, defau
} }
type importFlag struct { type importFlag struct {
origin ExerciceFlag
Line int Line int
Flag fic.Flag Flag fic.Flag
JustifyOf *fic.MCQ_entry JustifyOf *fic.MCQ_entry
@ -392,8 +393,9 @@ func buildExerciceFlag(i Importer, exercice *fic.Exercice, flag ExerciceFlag, nl
errs = multierr.Append(errs, berrs) errs = multierr.Append(errs, berrs)
if addedFlag != nil { if addedFlag != nil {
ret = append(ret, importFlag{ ret = append(ret, importFlag{
Line: nline + 1, origin: flag,
Flag: addedFlag, Line: nline + 1,
Flag: addedFlag,
}) })
} }
} else if flag.Type == "key" || strings.HasPrefix(flag.Type, "number") || flag.Type == "text" || flag.Type == "ucq" || flag.Type == "radio" || flag.Type == "vector" { } else if flag.Type == "key" || strings.HasPrefix(flag.Type, "number") || flag.Type == "text" || flag.Type == "ucq" || flag.Type == "radio" || flag.Type == "vector" {
@ -401,6 +403,7 @@ func buildExerciceFlag(i Importer, exercice *fic.Exercice, flag ExerciceFlag, nl
errs = multierr.Append(errs, berrs) errs = multierr.Append(errs, berrs)
if addedFlag != nil { if addedFlag != nil {
ret = append(ret, importFlag{ ret = append(ret, importFlag{
origin: flag,
Line: nline + 1, Line: nline + 1,
Flag: *addedFlag, Flag: *addedFlag,
Choices: choices, Choices: choices,
@ -462,6 +465,7 @@ func buildExerciceFlag(i Importer, exercice *fic.Exercice, flag ExerciceFlag, nl
errs = multierr.Append(errs, berrs) errs = multierr.Append(errs, berrs)
if addedFlag != nil { if addedFlag != nil {
ret = append(ret, importFlag{ ret = append(ret, importFlag{
origin: flag,
Line: nline + 1, Line: nline + 1,
Flag: *addedFlag, Flag: *addedFlag,
JustifyOf: entry, JustifyOf: entry,
@ -479,8 +483,9 @@ func buildExerciceFlag(i Importer, exercice *fic.Exercice, flag ExerciceFlag, nl
} }
ret = append([]importFlag{importFlag{ ret = append([]importFlag{importFlag{
Line: nline + 1, origin: flag,
Flag: &addedFlag, Line: nline + 1,
Flag: &addedFlag,
}}, ret...) }}, ret...)
} }
return return
@ -570,6 +575,10 @@ func CheckExerciceFlags(i Importer, exercice *fic.Exercice, files []string, exce
if int64(fk.ChoicesCost) >= exercice.Gain { if int64(fk.ChoicesCost) >= exercice.Gain {
errs = multierr.Append(errs, NewFlagError(exercice, nil, flag.Line, fmt.Errorf("flag's choice_cost is higher than exercice gain"))) errs = multierr.Append(errs, NewFlagError(exercice, nil, flag.Line, fmt.Errorf("flag's choice_cost is higher than exercice gain")))
} }
if raw, ok := flag.origin.Raw.(string); ok && raw == fk.Placeholder {
errs = multierr.Append(errs, NewFlagError(exercice, nil, flag.Line, fmt.Errorf("flag's placeholder and raw are identical")))
}
} }
// Check dependency loop // Check dependency loop

View file

@ -238,3 +238,21 @@ func WriteFileContent(i Importer, URI string, content []byte) error {
return fmt.Errorf("%t is not capable of writing", i) return fmt.Errorf("%t is not capable of writing", i)
} }
} }
func OpenOrGetFile(i Importer, URI string) (fd io.Reader, closer func() error, err error) {
if strings.HasPrefix(URI, "$FILES$") {
var fdc io.ReadCloser
fdc, err = os.Open(path.Join(fic.FilesDir, strings.TrimPrefix(URI, "$FILES$/")))
fd = fdc
closer = fdc.Close
} else {
fd, err = GlobalImporter.GetFile(URI)
if fdcloser, ok := fd.(io.ReadCloser); ok {
closer = fdcloser.Close
} else {
closer = func() error { return nil }
}
}
return
}

View file

@ -20,6 +20,8 @@ escape_newline () {
sed 's/$/\\n/g' | tr -d '\n' sed 's/$/\\n/g' | tr -d '\n'
} }
which mkisofs > /dev/null 2> /dev/null || { echo "Please install genisoimage (Debian/Ubuntu) or cdrkit (Alpine)" >&2; exit 1; }
if [ $# -gt 0 ] if [ $# -gt 0 ]
then then
which jq > /dev/null 2> /dev/null || { echo "Please install jq" >&2; exit 1; } which jq > /dev/null 2> /dev/null || { echo "Please install jq" >&2; exit 1; }

View file

@ -21,6 +21,8 @@ OLD_KEY=$(cat /run/config/dm-crypt/key)
[ "${NEW_KEY}" != "${OLD_KEY}" ] && { [ "${NEW_KEY}" != "${OLD_KEY}" ] && {
read -p "DM-CRYPT key changed in metadata, are you sure you want to erase it? (y/N) " V read -p "DM-CRYPT key changed in metadata, are you sure you want to erase it? (y/N) " V
[ "$V" != "y" ] && [ "$V" != "Y" ] && while true; do [ "$V" != "y" ] && [ "$V" != "Y" ] && while true; do
mv /boot/imgs/fickit-metadata.iso /boot/imgs/fickit-metadata.iso.skipped
cp /boot/imgs/fickit-metadata.iso.bak /boot/imgs/fickit-metadata.iso
echo echo
echo "Metadata drive not erased" echo "Metadata drive not erased"
echo echo

View file

@ -1,54 +1,54 @@
kernel: kernel:
#image: nemunaire/kernel:5.10.62-0b705d955f5e283f62583c4e227d64a7924c138f-amd64 #image: nemunaire/kernel:5.10.62-0b705d955f5e283f62583c4e227d64a7924c138f-amd64
image: linuxkit/kernel:6.6.13 image: linuxkit/kernel:6.6.71
cmdline: "console=ttyS0 console=tty0" cmdline: "console=ttyS0 console=tty0"
init: init:
- linuxkit/init:7135424f6836ee166d1199e88cfb95ee88efaf91 - linuxkit/init:8eea386739975a43af558eec757a7dcb3a3d2e7b
- linuxkit/runc:efcece75889aec4e2de0d95ba27ccc46438522b3 - linuxkit/runc:667e7ea2c426a2460ca21e3da065a57dbb3369c9
- linuxkit/containerd:ce79d5d4ab9c46f4763735c6e4ab5c51c3feb5d8 - linuxkit/containerd:a988a1a8bcbacc2c0390ca0c08f949e2b4b5915d
- linuxkit/ca-certificates:d4cc1b82c73d272e94d0e71ea375fe56b0c0626a - linuxkit/ca-certificates:7b32a26ca9c275d3ef32b11fe2a83dbd2aee2fdb
- linuxkit/getty:bae9e3d4861173bacf78f14a4fe44997a430d13b - linuxkit/getty:05eca453695984a69617f1f1f0bcdae7f7032967
- nemunaire/mdadm:04814350d71ba9417e1f861be1685de26adf7a67 - nemunaire/mdadm:04814350d71ba9417e1f861be1685de26adf7a67
- nemunaire/kexec:839b4eedfce02a56c581dec2383dc6faff120855 - nemunaire/kexec:839b4eedfce02a56c581dec2383dc6faff120855
onboot: onboot:
- name: mod - name: mod
image: linuxkit/modprobe:e3de97ac10970edee33faa78d9780117174bd1ac image: linuxkit/modprobe:773ee174006ecbb412830e48889795bae40b62f9
command: ["/bin/sh", "-c", "modprobe xhci_pci ahci intel_lpss_pci i2c_i801 megaraid_sas tg3 bnxt_en"] command: ["/bin/sh", "-c", "modprobe xhci_pci ahci intel_lpss_pci i2c_i801 megaraid_sas tg3 bnxt_en"]
- name: sysctl - name: sysctl
image: linuxkit/sysctl:c5f4b4895844b993dce4e8b35fd8263a6b557807 image: linuxkit/sysctl:5f56434b81004b50b47ed629b222619168c2bcdf
binds: binds:
- /etc/sysctl.d/01-fic.conf:/etc/sysctl.d/01-fic.conf:ro - /etc/sysctl.d/01-fic.conf:/etc/sysctl.d/01-fic.conf:ro
# Metadata # Metadata
- name: metadata - name: metadata
image: linuxkit/metadata:f35b5aafc7d19bb6a44a900840727902dad78e44 image: linuxkit/metadata:4f81c0c3a2b245567fd7d32d799018c9614a9907
command: ["/usr/bin/metadata", "-v", "cdrom"] command: ["/usr/bin/metadata", "-v", "cdrom"]
# Filesystem # Filesystem
- name: swap - name: swap
image: linuxkit/swap:8a1fd15d56b6ddf67d6d8ce25361178e1f36128b image: linuxkit/swap:f4b8ffef87c8c72165bd8a92b790ac252ccf1821
command: ["/sbin/swapon", "/dev/sda3"] command: ["/sbin/swapon", "/dev/sda3"]
- name: dm-crypt - name: dm-crypt
image: linuxkit/dm-crypt:19fa6affe9da03afc91694e36d72a4924c65a0e0 image: linuxkit/dm-crypt:981fde241bb84616a5ba94c04cdefa1489431a25
command: ["/usr/bin/crypto", "-l", "crypt_fic", "/dev/sda4"] command: ["/usr/bin/crypto", "-l", "crypt_fic", "/dev/sda4"]
binds: binds:
- /dev:/dev - /dev:/dev
- /run/config/dm-crypt:/etc/dm-crypt - /run/config/dm-crypt:/etc/dm-crypt
- name: mount - name: mount
image: linuxkit/mount:4413ebd50bfbe026058e4a60463259cece2b8bb5 image: linuxkit/mount:cb8caa72248f7082fc2074ce843d53cdc15df04a
command: ["/usr/bin/mountie", "-device", "/dev/mapper/crypt_fic", "/var/lib/fic" ] command: ["/usr/bin/mountie", "-device", "/dev/mapper/crypt_fic", "/var/lib/fic" ]
# Network # Network
# - name: dhcpcd # - name: dhcpcd
# image: linuxkit/dhcpcd:330839488cd122db3c44738e265c035c9729a963 # image: linuxkit/dhcpcd:157df9ef45a035f1542ec2270e374f18efef98a5
# command: ["/sbin/dhcpcd", "--nobackground", "-f", "/dhcpcd.conf", "-1"] # command: ["/sbin/dhcpcd", "--nobackground", "-f", "/dhcpcd.conf", "-1"]
# - name: ntp # - name: ntp
# image: linuxkit/openntpd:da26954c2f98a274091e5ed0bbdd2079a77a47c1 # image: linuxkit/openntpd:f99c4117763480815553b72022b426639a13ce86
- name: synchro-ip-setup - name: synchro-ip-setup
image: linuxkit/ip:af77c3f93143ff352a07ad5233d25a665012bcce image: linuxkit/ip:9696394a7d57b384ae919662ae162c9152029156
command: ["/bin/sh", "-c", "ip a add 10.10.10.1/29 dev eth2; ip link set eth2 up;" ] command: ["/bin/sh", "-c", "ip a add 10.10.10.1/29 dev eth2; ip link set eth2 up;" ]
net: new net: new
runtime: runtime:
@ -57,7 +57,7 @@ onboot:
bindNS: bindNS:
net: /run/netns/synchro net: /run/netns/synchro
- name: qa-ip-setup - name: qa-ip-setup
image: linuxkit/ip:af77c3f93143ff352a07ad5233d25a665012bcce image: linuxkit/ip:9696394a7d57b384ae919662ae162c9152029156
command: ["/bin/sh", "-c", "ip link show eth1 2> /dev/null && { ip a add 10.10.10.1/29 dev eth1; ip link set eth1 up; }; ip a add 172.17.0.6/24 dev vethin-qa; ip link set vethin-qa up" ] command: ["/bin/sh", "-c", "ip link show eth1 2> /dev/null && { ip a add 10.10.10.1/29 dev eth1; ip link set eth1 up; }; ip a add 172.17.0.6/24 dev vethin-qa; ip link set vethin-qa up" ]
net: new net: new
runtime: runtime:
@ -69,7 +69,7 @@ onboot:
bindNS: bindNS:
net: /run/netns/fic-qa net: /run/netns/fic-qa
- name: admin-ip-setup - name: admin-ip-setup
image: linuxkit/ip:af77c3f93143ff352a07ad5233d25a665012bcce image: linuxkit/ip:9696394a7d57b384ae919662ae162c9152029156
#command: ["/bin/sh", "-c", "ip link add link eth3 name adminiface type vlan id 99; ip a add 172.16.99.219/24 dev adminiface; ip link set eth3 up; ip link set adminiface up; ip r add default via 172.16.99.1; ip a add 172.17.0.2/24 dev vethin-admin; ip link set vethin-admin up; ping -W 10 -c 1 172.16.99.1;" ] #command: ["/bin/sh", "-c", "ip link add link eth3 name adminiface type vlan id 99; ip a add 172.16.99.219/24 dev adminiface; ip link set eth3 up; ip link set adminiface up; ip r add default via 172.16.99.1; ip a add 172.17.0.2/24 dev vethin-admin; ip link set vethin-admin up; ping -W 10 -c 1 172.16.99.1;" ]
command: ["/bin/sh", "-c", "ip link set eth3 up; while read IP; do ip a add ${IP} dev eth3; done < /run/config/ip_config/backend-admin; ip r add default via $(cat /run/config/ip_config/backend-router); ip a add 172.17.0.2/24 dev vethin-admin; ip link set vethin-admin up; echo 'Waiting for' $(cat /run/config/ip_config/backend-router); ping -W 10 -c 1 $(cat /run/config/ip_config/backend-router); ip link show eth1 2> /dev/null && { ip a add 10.0.0.1/24 dev eth1; ip link set eth1 up; };" ] command: ["/bin/sh", "-c", "ip link set eth3 up; while read IP; do ip a add ${IP} dev eth3; done < /run/config/ip_config/backend-admin; ip r add default via $(cat /run/config/ip_config/backend-router); ip a add 172.17.0.2/24 dev vethin-admin; ip link set vethin-admin up; echo 'Waiting for' $(cat /run/config/ip_config/backend-router); ping -W 10 -c 1 $(cat /run/config/ip_config/backend-router); ip link show eth1 2> /dev/null && { ip a add 10.0.0.1/24 dev eth1; ip link set eth1 up; };" ]
net: new net: new
@ -85,7 +85,7 @@ onboot:
bindNS: bindNS:
net: /run/netns/fic-admin net: /run/netns/fic-admin
- name: checker-ip-setup - name: checker-ip-setup
image: linuxkit/ip:af77c3f93143ff352a07ad5233d25a665012bcce image: linuxkit/ip:9696394a7d57b384ae919662ae162c9152029156
command: ["/bin/sh", "-c", "ip a add 172.17.0.3/24 dev vethin-checker; ip link set vethin-checker up;" ] command: ["/bin/sh", "-c", "ip a add 172.17.0.3/24 dev vethin-checker; ip link set vethin-checker up;" ]
net: new net: new
runtime: runtime:
@ -96,7 +96,7 @@ onboot:
bindNS: bindNS:
net: /run/netns/fic-checker net: /run/netns/fic-checker
- name: generator-ip-setup - name: generator-ip-setup
image: linuxkit/ip:af77c3f93143ff352a07ad5233d25a665012bcce image: linuxkit/ip:9696394a7d57b384ae919662ae162c9152029156
command: ["/bin/sh", "-c", "ip a add 172.17.0.5/24 dev vethin-generat; ip link set vethin-generat up;" ] command: ["/bin/sh", "-c", "ip a add 172.17.0.5/24 dev vethin-generat; ip link set vethin-generat up;" ]
net: new net: new
runtime: runtime:
@ -107,7 +107,7 @@ onboot:
bindNS: bindNS:
net: /run/netns/fic-generator net: /run/netns/fic-generator
- name: mysql-ip-setup - name: mysql-ip-setup
image: linuxkit/ip:af77c3f93143ff352a07ad5233d25a665012bcce image: linuxkit/ip:9696394a7d57b384ae919662ae162c9152029156
command: ["/bin/sh", "-c", "ip a add 172.17.0.4/24 dev vethin-db; ip link set vethin-db up;" ] command: ["/bin/sh", "-c", "ip a add 172.17.0.4/24 dev vethin-db; ip link set vethin-db up;" ]
net: new net: new
runtime: runtime:
@ -118,7 +118,7 @@ onboot:
bindNS: bindNS:
net: /run/netns/db net: /run/netns/db
- name: bridge-setup - name: bridge-setup
image: linuxkit/ip:af77c3f93143ff352a07ad5233d25a665012bcce image: linuxkit/ip:9696394a7d57b384ae919662ae162c9152029156
command: ["/bin/sh", "-c", "ip a add 172.17.0.1/24 dev br0; ip link set veth-admin master br0; ip link set veth-checker master br0; ip link set veth-generator master br0; ip link set veth-db master br0; ip link set veth-qa master br0; ip link set br0 up; ip link set veth-admin up; ip link set veth-checker up; ip link set veth-generator up; ip link set veth-db up; ip link set veth-qa up;" ] command: ["/bin/sh", "-c", "ip a add 172.17.0.1/24 dev br0; ip link set veth-admin master br0; ip link set veth-checker master br0; ip link set veth-generator master br0; ip link set veth-db master br0; ip link set veth-qa master br0; ip link set br0 up; ip link set veth-admin up; ip link set veth-checker up; ip link set veth-generator up; ip link set veth-db up; ip link set veth-qa up;" ]
runtime: runtime:
interfaces: interfaces:
@ -126,7 +126,7 @@ onboot:
add: bridge add: bridge
- name: firewall-synchro - name: firewall-synchro
image: linuxkit/ip:af77c3f93143ff352a07ad5233d25a665012bcce image: linuxkit/ip:9696394a7d57b384ae919662ae162c9152029156
command: ["/bin/bash", "-c", "/sbin/iptables-restore < /etc/iptables/rules-synchro.v4; /sbin/ip6tables-restore < /etc/iptables/rules.v6" ] command: ["/bin/bash", "-c", "/sbin/iptables-restore < /etc/iptables/rules-synchro.v4; /sbin/ip6tables-restore < /etc/iptables/rules.v6" ]
binds: binds:
- /etc/iptables/rules-synchro.v4:/etc/iptables/rules-synchro.v4:ro - /etc/iptables/rules-synchro.v4:/etc/iptables/rules-synchro.v4:ro
@ -136,7 +136,7 @@ onboot:
mkdir: mkdir:
- /var/lib/fic/teams - /var/lib/fic/teams
- name: firewall-admin - name: firewall-admin
image: linuxkit/ip:af77c3f93143ff352a07ad5233d25a665012bcce image: linuxkit/ip:9696394a7d57b384ae919662ae162c9152029156
command: ["/bin/bash", "-c", "/sbin/iptables-restore < /etc/iptables/rules-admin.v4; /sbin/ip6tables-restore < /etc/iptables/rules.v6" ] command: ["/bin/bash", "-c", "/sbin/iptables-restore < /etc/iptables/rules-admin.v4; /sbin/ip6tables-restore < /etc/iptables/rules.v6" ]
binds: binds:
- /etc/iptables/rules-admin.v4:/etc/iptables/rules-admin.v4:ro - /etc/iptables/rules-admin.v4:/etc/iptables/rules-admin.v4:ro
@ -153,17 +153,26 @@ onboot:
mkdir: mkdir:
- /var/lib/fic/secrets - /var/lib/fic/secrets
- name: create-ssh-keys
image: nemunaire/rsync:a3d76b2dd0a9ad73be44dc77ad765b20d96a3285
command: ["/bin/sh", "-c", "touch /etc/ssh/sshd_config && ssh-keygen -A"]
binds:
- /var/lib/fic/ssh:/etc/ssh
runtime:
mkdir:
- /var/lib/fic/ssh
services: services:
# - name: getty # - name: getty
# image: linuxkit/getty:bae9e3d4861173bacf78f14a4fe44997a430d13b # image: linuxkit/getty:05eca453695984a69617f1f1f0bcdae7f7032967
# env: # env:
# - INSECURE=true # - INSECURE=true
# Enable acpi to shutdown on power events # Enable acpi to shutdown on power events
- name: acpid - name: acpid
image: linuxkit/acpid:6379700e2f3341250432e37a4cac36e35c7caac8 image: linuxkit/acpid:6cb5575e487a8fcbd4c3eb6721c23299e6ea452f
- name: rngd - name: rngd
image: linuxkit/rngd:814d1a3a76e84eae01a94575c038fd22652f94e3 image: linuxkit/rngd:1a18f2149e42a0a1cb9e7d37608a494342c26032
- name: db - name: db
image: mariadb:11 image: mariadb:11
command: ["/bin/bash", "/usr/local/bin/docker-entrypoint.sh", "mariadbd"] command: ["/bin/bash", "/usr/local/bin/docker-entrypoint.sh", "mariadbd"]
@ -228,7 +237,7 @@ services:
- /var/lib/fic/generator:/srv/GENERATOR:ro - /var/lib/fic/generator:/srv/GENERATOR:ro
- /var/lib/fic/pki:/srv/PKI - /var/lib/fic/pki:/srv/PKI
- /var/lib/fic/settings:/srv/SETTINGS - /var/lib/fic/settings:/srv/SETTINGS
- /var/lib/fic/submissions:/srv/submissions:ro - /var/lib/fic/submissions:/srv/submissions
- /var/lib/fic/sync:/srv/SYNC - /var/lib/fic/sync:/srv/SYNC
- /var/lib/fic/teams:/srv/TEAMS - /var/lib/fic/teams:/srv/TEAMS
net: /run/netns/fic-admin net: /run/netns/fic-admin
@ -269,7 +278,10 @@ services:
binds: binds:
- /etc/hosts:/etc/hosts:ro - /etc/hosts:/etc/hosts:ro
- /var/lib/fic/generator:/srv/GENERATOR:ro - /var/lib/fic/generator:/srv/GENERATOR:ro
# Uncomment this to disallow registrations
- /var/lib/fic/teams:/srv/TEAMS:ro - /var/lib/fic/teams:/srv/TEAMS:ro
# Uncomment this to allow registrations
#- /var/lib/fic/teams:/srv/TEAMS
- /var/lib/fic/secrets/mysql_password:/run/secrets/mysql_password:ro - /var/lib/fic/secrets/mysql_password:/run/secrets/mysql_password:ro
- /var/lib/fic/settingsdist:/srv/SETTINGSDIST:ro - /var/lib/fic/settingsdist:/srv/SETTINGSDIST:ro
- /var/lib/fic/submissions:/srv/submissions - /var/lib/fic/submissions:/srv/submissions
@ -361,7 +373,6 @@ services:
- /var/lib/fic/files - /var/lib/fic/files
- /var/lib/fic/pki/shared - /var/lib/fic/pki/shared
- /var/lib/fic/settingsdist - /var/lib/fic/settingsdist
- /var/lib/fic/ssh
- /var/lib/fic/submissions - /var/lib/fic/submissions
- /var/lib/fic/teams - /var/lib/fic/teams
- /var/log/frontend - /var/log/frontend

View file

@ -1,6 +1,6 @@
kernel: kernel:
#image: nemunaire/kernel:5.10.62-0b705d955f5e283f62583c4e227d64a7924c138f-amd64 #image: nemunaire/kernel:5.10.62-0b705d955f5e283f62583c4e227d64a7924c138f-amd64
image: linuxkit/kernel:6.6.13 image: linuxkit/kernel:6.6.71
cmdline: "console=ttyS0 console=tty0" cmdline: "console=ttyS0 console=tty0"
init: init:

View file

@ -1,50 +1,50 @@
kernel: kernel:
#image: nemunaire/kernel:5.10.62-0b705d955f5e283f62583c4e227d64a7924c138f-amd64 #image: nemunaire/kernel:5.10.62-0b705d955f5e283f62583c4e227d64a7924c138f-amd64
image: linuxkit/kernel:6.6.13 image: linuxkit/kernel:6.6.71
cmdline: "console=ttyS0 console=tty0" cmdline: "console=ttyS0 console=tty0"
init: init:
- linuxkit/init:7135424f6836ee166d1199e88cfb95ee88efaf91 - linuxkit/init:8eea386739975a43af558eec757a7dcb3a3d2e7b
- linuxkit/runc:efcece75889aec4e2de0d95ba27ccc46438522b3 - linuxkit/runc:667e7ea2c426a2460ca21e3da065a57dbb3369c9
- linuxkit/containerd:ce79d5d4ab9c46f4763735c6e4ab5c51c3feb5d8 - linuxkit/containerd:a988a1a8bcbacc2c0390ca0c08f949e2b4b5915d
- linuxkit/ca-certificates:d4cc1b82c73d272e94d0e71ea375fe56b0c0626a - linuxkit/ca-certificates:7b32a26ca9c275d3ef32b11fe2a83dbd2aee2fdb
- linuxkit/getty:bae9e3d4861173bacf78f14a4fe44997a430d13b - linuxkit/getty:05eca453695984a69617f1f1f0bcdae7f7032967
- nemunaire/mdadm:04814350d71ba9417e1f861be1685de26adf7a67 - nemunaire/mdadm:04814350d71ba9417e1f861be1685de26adf7a67
- nemunaire/kexec:839b4eedfce02a56c581dec2383dc6faff120855 - nemunaire/kexec:839b4eedfce02a56c581dec2383dc6faff120855
- nemunaire/fic-frontend-ui:latest - nemunaire/fic-frontend-ui:latest
onboot: onboot:
- name: mod - name: mod
image: linuxkit/modprobe:e3de97ac10970edee33faa78d9780117174bd1ac image: linuxkit/modprobe:773ee174006ecbb412830e48889795bae40b62f9
command: ["/bin/sh", "-c", "modprobe xhci_pci ahci intel_lpss_pci i2c_i801 megaraid_sas tg3 bnxt_en"] command: ["/bin/sh", "-c", "modprobe xhci_pci ahci intel_lpss_pci i2c_i801 megaraid_sas tg3 bnxt_en"]
- name: sysctl - name: sysctl
image: linuxkit/sysctl:c5f4b4895844b993dce4e8b35fd8263a6b557807 image: linuxkit/sysctl:5f56434b81004b50b47ed629b222619168c2bcdf
# Metadata # Metadata
- name: metadata - name: metadata
image: linuxkit/metadata:f35b5aafc7d19bb6a44a900840727902dad78e44 image: linuxkit/metadata:4f81c0c3a2b245567fd7d32d799018c9614a9907
command: ["/usr/bin/metadata", "-v", "cdrom"] command: ["/usr/bin/metadata", "-v", "cdrom"]
# Filesystem # Filesystem
- name: swap - name: swap
image: linuxkit/swap:8a1fd15d56b6ddf67d6d8ce25361178e1f36128b image: linuxkit/swap:f4b8ffef87c8c72165bd8a92b790ac252ccf1821
command: ["/sbin/swapon", "/dev/sda3"] command: ["/sbin/swapon", "/dev/sda3"]
- name: dm-crypt - name: dm-crypt
image: linuxkit/dm-crypt:19fa6affe9da03afc91694e36d72a4924c65a0e0 image: linuxkit/dm-crypt:981fde241bb84616a5ba94c04cdefa1489431a25
command: ["/usr/bin/crypto", "-l", "crypt_fic", "/dev/sda4"] command: ["/usr/bin/crypto", "-l", "crypt_fic", "/dev/sda4"]
binds: binds:
- /dev:/dev - /dev:/dev
- /run/config/dm-crypt:/etc/dm-crypt - /run/config/dm-crypt:/etc/dm-crypt
- name: mount - name: mount
image: linuxkit/mount:4413ebd50bfbe026058e4a60463259cece2b8bb5 image: linuxkit/mount:cb8caa72248f7082fc2074ce843d53cdc15df04a
command: ["/usr/bin/mountie", "-device", "/dev/mapper/crypt_fic", "/var/lib/fic" ] command: ["/usr/bin/mountie", "-device", "/dev/mapper/crypt_fic", "/var/lib/fic" ]
# Network # Network
# - name: ntp # - name: ntp
# image: linuxkit/openntpd:da26954c2f98a274091e5ed0bbdd2079a77a47c1 # image: linuxkit/openntpd:f99c4117763480815553b72022b426639a13ce86
- name: nginx-ip-setup - name: nginx-ip-setup
image: linuxkit/ip:af77c3f93143ff352a07ad5233d25a665012bcce image: linuxkit/ip:9696394a7d57b384ae919662ae162c9152029156
command: ["/bin/sh", "-c", "ip a add 172.17.1.2/24 dev vethin-nginx; ip link set vethin-nginx up;" ] command: ["/bin/sh", "-c", "ip a add 172.17.1.2/24 dev vethin-nginx; ip link set vethin-nginx up;" ]
net: new net: new
runtime: runtime:
@ -55,7 +55,7 @@ onboot:
bindNS: bindNS:
net: /run/netns/nginx net: /run/netns/nginx
- name: frontal-ip-setup # without bonding - name: frontal-ip-setup # without bonding
image: linuxkit/ip:af77c3f93143ff352a07ad5233d25a665012bcce image: linuxkit/ip:9696394a7d57b384ae919662ae162c9152029156
command: ["/bin/sh", "-c", "ip link set name bond-frontal eth3; ip link set bond-frontal up; while read IP; do ip a add ${IP} dev bond-frontal; done < /run/config/ip_config/frontend-players; ip r add default via $(cat /run/config/ip_config/frontend-router); ip link add link bond-frontal name internet type vlan id 4; ip a add 10.10.10.2/29 dev internet; ip link set internet up;" ] command: ["/bin/sh", "-c", "ip link set name bond-frontal eth3; ip link set bond-frontal up; while read IP; do ip a add ${IP} dev bond-frontal; done < /run/config/ip_config/frontend-players; ip r add default via $(cat /run/config/ip_config/frontend-router); ip link add link bond-frontal name internet type vlan id 4; ip a add 10.10.10.2/29 dev internet; ip link set internet up;" ]
net: /run/netns/nginx net: /run/netns/nginx
binds: binds:
@ -67,7 +67,7 @@ onboot:
- name: eth3 - name: eth3
# - name: eth4 # - name: eth4
# - name: frontal-ip-setup # with bonding # - name: frontal-ip-setup # with bonding
# image: linuxkit/ip:af77c3f93143ff352a07ad5233d25a665012bcce # image: linuxkit/ip:9696394a7d57b384ae919662ae162c9152029156
# command: ["/bin/sh", "-c", "ip link set dev bond-frontal type bond mode balance-alb; ip link set bond-frontal up; ifenslave bond-frontal eth1 eth2 eth3 eth4; while read IP; do ip a add ${IP} dev bond-frontal; done < /run/config/ip_config/frontend-players; ip r add default via $(cat /run/config/ip_config/frontend-router); ip link add link bond-frontal name internet type vlan id 4; ip link set internet up; sysctl -w net.ipv4.ip_forward=1;" ] # command: ["/bin/sh", "-c", "ip link set dev bond-frontal type bond mode balance-alb; ip link set bond-frontal up; ifenslave bond-frontal eth1 eth2 eth3 eth4; while read IP; do ip a add ${IP} dev bond-frontal; done < /run/config/ip_config/frontend-players; ip r add default via $(cat /run/config/ip_config/frontend-router); ip link add link bond-frontal name internet type vlan id 4; ip link set internet up; sysctl -w net.ipv4.ip_forward=1;" ]
# net: /run/netns/nginx # net: /run/netns/nginx
# binds: # binds:
@ -81,7 +81,7 @@ onboot:
# - name: bond-frontal # - name: bond-frontal
# add: bond # add: bond
- name: receiver-ip-setup - name: receiver-ip-setup
image: linuxkit/ip:af77c3f93143ff352a07ad5233d25a665012bcce image: linuxkit/ip:9696394a7d57b384ae919662ae162c9152029156
command: ["/bin/sh", "-c", "ip a add 172.17.1.3/24 dev vethin-receiver; ip link set vethin-receiver up;" ] command: ["/bin/sh", "-c", "ip a add 172.17.1.3/24 dev vethin-receiver; ip link set vethin-receiver up;" ]
net: new net: new
runtime: runtime:
@ -92,7 +92,7 @@ onboot:
bindNS: bindNS:
net: /run/netns/fic-receiver net: /run/netns/fic-receiver
- name: sshd-ip-setup - name: sshd-ip-setup
image: linuxkit/ip:af77c3f93143ff352a07ad5233d25a665012bcce image: linuxkit/ip:9696394a7d57b384ae919662ae162c9152029156
command: ["/bin/sh", "-c", "ip a add 10.10.10.2/29 dev eth2; ip link set eth2 up;" ] command: ["/bin/sh", "-c", "ip a add 10.10.10.2/29 dev eth2; ip link set eth2 up;" ]
net: new net: new
runtime: runtime:
@ -101,7 +101,7 @@ onboot:
bindNS: bindNS:
net: /run/netns/sshd net: /run/netns/sshd
- name: auth-ip-setup - name: auth-ip-setup
image: linuxkit/ip:af77c3f93143ff352a07ad5233d25a665012bcce image: linuxkit/ip:9696394a7d57b384ae919662ae162c9152029156
command: ["/bin/sh", "-c", "ip a add 172.17.1.4/24 dev vethin-auth; ip link set vethin-auth up;" ] command: ["/bin/sh", "-c", "ip a add 172.17.1.4/24 dev vethin-auth; ip link set vethin-auth up;" ]
net: new net: new
runtime: runtime:
@ -112,7 +112,7 @@ onboot:
bindNS: bindNS:
net: /run/netns/auth net: /run/netns/auth
- name: bridge-setup - name: bridge-setup
image: linuxkit/ip:af77c3f93143ff352a07ad5233d25a665012bcce image: linuxkit/ip:9696394a7d57b384ae919662ae162c9152029156
command: ["/bin/sh", "-c", "ip a add 172.17.1.1/24 dev br0; ip link set veth-nginx master br0; ip link set veth-receiver master br0; ip link set veth-auth master br0; ip link set br0 up; ip link set veth-nginx up; ip link set veth-receiver up; ip link set veth-auth up;" ] command: ["/bin/sh", "-c", "ip a add 172.17.1.1/24 dev br0; ip link set veth-nginx master br0; ip link set veth-receiver master br0; ip link set veth-auth master br0; ip link set br0 up; ip link set veth-nginx up; ip link set veth-receiver up; ip link set veth-auth up;" ]
runtime: runtime:
interfaces: interfaces:
@ -120,7 +120,7 @@ onboot:
add: bridge add: bridge
- name: firewall-frontal - name: firewall-frontal
image: linuxkit/ip:af77c3f93143ff352a07ad5233d25a665012bcce image: linuxkit/ip:9696394a7d57b384ae919662ae162c9152029156
command: ["/bin/bash", "-c", "/sbin/iptables-restore < /etc/iptables/rules-frontal.v4; /sbin/ip6tables-restore < /etc/iptables/rules.v6; [ -f /run/config/remote_sync/destination ] && /sbin/iptables -I OUTPUT 7 -o bond-frontal -d $(cat /run/config/remote_sync/destination | tr -d '\n') -p tcp -m tcp --dport https -j ACCEPT;" ] command: ["/bin/bash", "-c", "/sbin/iptables-restore < /etc/iptables/rules-frontal.v4; /sbin/ip6tables-restore < /etc/iptables/rules.v6; [ -f /run/config/remote_sync/destination ] && /sbin/iptables -I OUTPUT 7 -o bond-frontal -d $(cat /run/config/remote_sync/destination | tr -d '\n') -p tcp -m tcp --dport https -j ACCEPT;" ]
binds: binds:
- /etc/iptables/rules-frontal.v4:/etc/iptables/rules-frontal.v4:ro - /etc/iptables/rules-frontal.v4:/etc/iptables/rules-frontal.v4:ro
@ -129,26 +129,35 @@ onboot:
- /run/config/remote_sync/:/run/config/remote_sync/:ro - /run/config/remote_sync/:/run/config/remote_sync/:ro
net: /run/netns/nginx net: /run/netns/nginx
- name: firewall-sshd - name: firewall-sshd
image: linuxkit/ip:af77c3f93143ff352a07ad5233d25a665012bcce image: linuxkit/ip:9696394a7d57b384ae919662ae162c9152029156
command: ["/bin/bash", "-c", "/sbin/iptables-restore < /etc/iptables/rules-sshd.v4; /sbin/ip6tables-restore < /etc/iptables/rules.v6" ] command: ["/bin/bash", "-c", "/sbin/iptables-restore < /etc/iptables/rules-sshd.v4; /sbin/ip6tables-restore < /etc/iptables/rules.v6" ]
binds: binds:
- /etc/iptables/rules-sshd.v4:/etc/iptables/rules-sshd.v4:ro - /etc/iptables/rules-sshd.v4:/etc/iptables/rules-sshd.v4:ro
- /etc/iptables/rules.v6:/etc/iptables/rules.v6:ro - /etc/iptables/rules.v6:/etc/iptables/rules.v6:ro
net: /run/netns/sshd net: /run/netns/sshd
- name: create-ssh-keys
image: nemunaire/rsync:a3d76b2dd0a9ad73be44dc77ad765b20d96a3285
command: ["/bin/sh", "-c", "touch /etc/ssh/sshd_config && ssh-keygen -A"]
binds:
- /var/lib/fic/ssh:/etc/ssh
runtime:
mkdir:
- /var/lib/fic/ssh
services: services:
# - name: getty # - name: getty
# image: linuxkit/getty:bae9e3d4861173bacf78f14a4fe44997a430d13b # image: linuxkit/getty:05eca453695984a69617f1f1f0bcdae7f7032967
# env: # env:
# - INSECURE=true # - INSECURE=true
# Enable acpi to shutdown on power events # Enable acpi to shutdown on power events
- name: acpid - name: acpid
image: linuxkit/acpid:6379700e2f3341250432e37a4cac36e35c7caac8 image: linuxkit/acpid:6cb5575e487a8fcbd4c3eb6721c23299e6ea452f
- name: rngd - name: rngd
image: linuxkit/rngd:814d1a3a76e84eae01a94575c038fd22652f94e3 image: linuxkit/rngd:1a18f2149e42a0a1cb9e7d37608a494342c26032
- name: dhcpcd - name: dhcpcd
image: linuxkit/dhcpcd:330839488cd122db3c44738e265c035c9729a963 image: linuxkit/dhcpcd:157df9ef45a035f1542ec2270e374f18efef98a5
net: /run/netns/nginx net: /run/netns/nginx
binds: binds:
- /etc/dhcpcd.conf:/dhcpcd.conf:ro - /etc/dhcpcd.conf:/dhcpcd.conf:ro
@ -257,7 +266,6 @@ services:
- /var/lib/fic/files - /var/lib/fic/files
- /var/lib/fic/pki - /var/lib/fic/pki
- /var/lib/fic/settingsdist - /var/lib/fic/settingsdist
- /var/lib/fic/ssh
- /var/lib/fic/submissions - /var/lib/fic/submissions
- /var/lib/fic/teams - /var/lib/fic/teams
@ -280,7 +288,7 @@ services:
# net: /run/netns/nginx # net: /run/netns/nginx
- name: dexidp - name: dexidp
image: ghcr.io/dexidp/dex:v2.41.1 image: ghcr.io/dexidp/dex:v2.42.0
net: /run/netns/auth net: /run/netns/auth
binds: binds:
- /etc/hosts:/etc/hosts:ro - /etc/hosts:/etc/hosts:ro
@ -294,7 +302,7 @@ services:
mkdir: mkdir:
- /var/lib/fic/dex - /var/lib/fic/dex
- name: vouch-proxy - name: vouch-proxy
image: quay.io/vouch/vouch-proxy:alpine-0.39 image: quay.io/vouch/vouch-proxy:alpine-0.41
env: env:
- VOUCH_CONFIG=/etc/vouch/config.yml - VOUCH_CONFIG=/etc/vouch/config.yml
net: /run/netns/auth net: /run/netns/auth

View file

@ -1,15 +1,15 @@
kernel: kernel:
#image: nemunaire/kernel:5.10.62-0b705d955f5e283f62583c4e227d64a7924c138f-amd64 #image: nemunaire/kernel:5.10.62-0b705d955f5e283f62583c4e227d64a7924c138f-amd64
image: linuxkit/kernel:6.6.13 image: linuxkit/kernel:6.6.71
cmdline: "console=ttyS0 console=tty0" cmdline: "console=ttyS0 console=tty0"
init: init:
- nemunaire/mdadm:04814350d71ba9417e1f861be1685de26adf7a67 - nemunaire/mdadm:04814350d71ba9417e1f861be1685de26adf7a67
- nemunaire/syslinux:086f221f281d577d300949aa1094fb20c5cd90dc - nemunaire/syslinux:086f221f281d577d300949aa1094fb20c5cd90dc
- linuxkit/format:3c858f0cf42a2b14441bfb5c266b78f14d2b75a4 - linuxkit/format:3fb088f60ed73ba4a15be41e44654b74112fd3f9
- linuxkit/dm-crypt:19fa6affe9da03afc91694e36d72a4924c65a0e0 - linuxkit/dm-crypt:981fde241bb84616a5ba94c04cdefa1489431a25
- linuxkit/metadata:f35b5aafc7d19bb6a44a900840727902dad78e44 - linuxkit/metadata:4f81c0c3a2b245567fd7d32d799018c9614a9907
- alpine:latest - alpine:latest
files: files:

View file

@ -1,12 +1,12 @@
kernel: kernel:
#image: nemunaire/kernel:5.10.62-0b705d955f5e283f62583c4e227d64a7924c138f-amd64 #image: nemunaire/kernel:5.10.62-0b705d955f5e283f62583c4e227d64a7924c138f-amd64
image: linuxkit/kernel:6.6.13 image: linuxkit/kernel:6.6.71
cmdline: "console=ttyS0 console=tty0" cmdline: "console=ttyS0 console=tty0"
init: init:
- nemunaire/mdadm:04814350d71ba9417e1f861be1685de26adf7a67 - nemunaire/mdadm:04814350d71ba9417e1f861be1685de26adf7a67
- linuxkit/metadata:f35b5aafc7d19bb6a44a900840727902dad78e44 - linuxkit/metadata:4f81c0c3a2b245567fd7d32d799018c9614a9907
- alpine:latest - alpine:latest

File diff suppressed because it is too large Load diff

View file

@ -12,10 +12,10 @@
"@sveltejs/adapter-static": "^3.0.0", "@sveltejs/adapter-static": "^3.0.0",
"@sveltejs/kit": "^2.0.0", "@sveltejs/kit": "^2.0.0",
"@sveltejs/vite-plugin-svelte": "^3.0.0", "@sveltejs/vite-plugin-svelte": "^3.0.0",
"@sveltestrap/sveltestrap": "^6.2.1", "@sveltestrap/sveltestrap": "^7.0.0",
"eslint": "^9.0.0", "eslint": "^9.0.0",
"eslint-config-prettier": "^9.0.0", "eslint-config-prettier": "^10.0.0",
"eslint-plugin-svelte": "^2.35.1", "eslint-plugin-svelte": "^3.0.0",
"prettier": "^3.0.0", "prettier": "^3.0.0",
"prettier-plugin-svelte": "^3.1.2", "prettier-plugin-svelte": "^3.1.2",
"sass": "^1.51.0", "sass": "^1.51.0",

View file

@ -33,9 +33,9 @@
</h1> </h1>
<div style="min-width: 0"> <div style="min-width: 0">
<h4 class="fw-bold"><samp>{file.name}</samp></h4> <h4 class="fw-bold"><samp>{file.name}</samp></h4>
{#if file.disclamer} {#if file.disclaimer}
<div class="file-disclamer text-warning"> <div class="file-disclaimer text-warning">
{file.disclamer} {file.disclaimer}
</div> </div>
{/if} {/if}
<nobr> <nobr>
@ -61,10 +61,10 @@
{/if} {/if}
<style> <style>
.file-disclamer { .file-disclaimer {
display: none; display: none;
} }
:global(.list-group-item:hover .file-disclamer) { :global(.list-group-item:hover .file-disclaimer) {
display: block; display: block;
} }
</style> </style>

42
go.mod
View file

@ -1,16 +1,16 @@
module srs.epita.fr/fic-server module srs.epita.fr/fic-server
go 1.21 go 1.23.0
toolchain go1.23.4 toolchain go1.24.1
require ( require (
github.com/BurntSushi/toml v1.4.0 github.com/BurntSushi/toml v1.5.0
github.com/asticode/go-astisub v0.32.0 github.com/asticode/go-astisub v0.34.0
github.com/cenkalti/dominantcolor v1.0.3 github.com/cenkalti/dominantcolor v1.0.3
github.com/gin-contrib/sessions v1.0.2 github.com/gin-contrib/sessions v1.0.2
github.com/gin-gonic/gin v1.10.0 github.com/gin-gonic/gin v1.10.0
github.com/go-git/go-git/v5 v5.13.1 github.com/go-git/go-git/v5 v5.14.0
github.com/go-sql-driver/mysql v1.8.1 github.com/go-sql-driver/mysql v1.8.1
github.com/google/gopacket v1.1.19 github.com/google/gopacket v1.1.19
github.com/studio-b12/gowebdav v0.10.0 github.com/studio-b12/gowebdav v0.10.0
@ -18,17 +18,17 @@ require (
github.com/yuin/goldmark v1.7.8 github.com/yuin/goldmark v1.7.8
gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b
go.uber.org/multierr v1.11.0 go.uber.org/multierr v1.11.0
golang.org/x/crypto v0.31.0 golang.org/x/crypto v0.36.0
golang.org/x/image v0.23.0 golang.org/x/image v0.25.0
golang.org/x/oauth2 v0.25.0 golang.org/x/oauth2 v0.28.0
gopkg.in/fsnotify.v1 v1.4.7 gopkg.in/fsnotify.v1 v1.4.7
) )
require ( require (
dario.cat/mergo v1.0.0 // indirect dario.cat/mergo v1.0.0 // indirect
filippo.io/edwards25519 v1.1.0 // indirect filippo.io/edwards25519 v1.1.0 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/ProtonMail/go-crypto v1.1.3 // indirect github.com/ProtonMail/go-crypto v1.1.5 // indirect
github.com/acomagu/bufpipe v1.0.4 // indirect github.com/acomagu/bufpipe v1.0.4 // indirect
github.com/asticode/go-astikit v0.20.0 // indirect github.com/asticode/go-astikit v0.20.0 // indirect
github.com/asticode/go-astits v1.8.0 // indirect github.com/asticode/go-astits v1.8.0 // indirect
@ -37,23 +37,23 @@ require (
github.com/bytedance/sonic/loader v0.1.1 // indirect github.com/bytedance/sonic/loader v0.1.1 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
github.com/chenzhuoyu/iasm v0.9.1 // indirect github.com/chenzhuoyu/iasm v0.9.1 // indirect
github.com/cloudflare/circl v1.3.7 // indirect github.com/cloudflare/circl v1.6.0 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect github.com/cloudwego/iasm v0.2.0 // indirect
github.com/cyphar/filepath-securejoin v0.3.6 // indirect github.com/cyphar/filepath-securejoin v0.4.1 // indirect
github.com/disintegration/imaging v1.6.2 // indirect github.com/disintegration/imaging v1.6.2 // indirect
github.com/emirpasic/gods v1.18.1 // indirect github.com/emirpasic/gods v1.18.1 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-git/go-billy/v5 v5.6.1 // indirect github.com/go-git/go-billy/v5 v5.6.2 // indirect
github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.20.0 // indirect github.com/go-playground/validator/v10 v10.20.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect github.com/goccy/go-json v0.10.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/golang/protobuf v1.5.3 // indirect github.com/golang/protobuf v1.5.4 // indirect
github.com/gorilla/context v1.1.2 // indirect github.com/gorilla/context v1.1.2 // indirect
github.com/gorilla/securecookie v1.1.2 // indirect github.com/gorilla/securecookie v1.1.2 // indirect
github.com/gorilla/sessions v1.2.2 // indirect github.com/gorilla/sessions v1.2.2 // indirect
@ -69,20 +69,20 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/pjbgf/sha1cd v0.3.2 // indirect
github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b // indirect github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b // indirect
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
github.com/skeema/knownhosts v1.3.0 // indirect github.com/skeema/knownhosts v1.3.1 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/u2takey/go-utils v0.3.1 // indirect github.com/u2takey/go-utils v0.3.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect github.com/ugorji/go/codec v1.2.12 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect
golang.org/x/arch v0.8.0 // indirect golang.org/x/arch v0.8.0 // indirect
golang.org/x/mod v0.17.0 // indirect golang.org/x/mod v0.17.0 // indirect
golang.org/x/net v0.33.0 // indirect golang.org/x/net v0.35.0 // indirect
golang.org/x/sync v0.10.0 // indirect golang.org/x/sync v0.12.0 // indirect
golang.org/x/sys v0.28.0 // indirect golang.org/x/sys v0.31.0 // indirect
golang.org/x/text v0.21.0 // indirect golang.org/x/text v0.23.0 // indirect
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
google.golang.org/appengine v1.6.7 // indirect google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.34.1 // indirect google.golang.org/protobuf v1.34.1 // indirect

57
go.sum
View file

@ -10,6 +10,8 @@ github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk= github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk=
github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
@ -17,6 +19,8 @@ github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VM
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 h1:YoJbenK9C67SkzkDfmQuVln04ygHj3vjZfd9FL+GmQQ= github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 h1:YoJbenK9C67SkzkDfmQuVln04ygHj3vjZfd9FL+GmQQ=
github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4 h1:ra2OtmuW0AE5csawV4YXMNGNQQXvLRps3z2Z59OPO+I= github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4 h1:ra2OtmuW0AE5csawV4YXMNGNQQXvLRps3z2Z59OPO+I=
@ -33,6 +37,8 @@ github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0k
github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
github.com/ProtonMail/go-crypto v1.1.3 h1:nRBOetoydLeUb4nHajyO2bKqMLfWQ/ZPwkXqXxPxCFk= github.com/ProtonMail/go-crypto v1.1.3 h1:nRBOetoydLeUb4nHajyO2bKqMLfWQ/ZPwkXqXxPxCFk=
github.com/ProtonMail/go-crypto v1.1.3/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= github.com/ProtonMail/go-crypto v1.1.3/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
github.com/ProtonMail/go-crypto v1.1.5 h1:eoAQfK2dwL+tFSFpr7TbOaPNUbPiJj4fLYwwGE1FQO4=
github.com/ProtonMail/go-crypto v1.1.5/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk= github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk=
github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ= github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ=
@ -68,6 +74,8 @@ github.com/asticode/go-astisub v0.30.0 h1:z4k2Y+V+rlCE8qk3uw/nie56KXxJaL1/GwTP+9
github.com/asticode/go-astisub v0.30.0/go.mod h1:WTkuSzFB+Bp7wezuSf2Oxulj5A8zu2zLRVFf6bIFQK8= github.com/asticode/go-astisub v0.30.0/go.mod h1:WTkuSzFB+Bp7wezuSf2Oxulj5A8zu2zLRVFf6bIFQK8=
github.com/asticode/go-astisub v0.32.0 h1:i1RHVQyTxSAuX0X3YC5zIyWruVZorS3cDXxqxYa0qss= github.com/asticode/go-astisub v0.32.0 h1:i1RHVQyTxSAuX0X3YC5zIyWruVZorS3cDXxqxYa0qss=
github.com/asticode/go-astisub v0.32.0/go.mod h1:WTkuSzFB+Bp7wezuSf2Oxulj5A8zu2zLRVFf6bIFQK8= github.com/asticode/go-astisub v0.32.0/go.mod h1:WTkuSzFB+Bp7wezuSf2Oxulj5A8zu2zLRVFf6bIFQK8=
github.com/asticode/go-astisub v0.34.0 h1:owKNj0A9pc7YVW/rNy2MJZ1mf0L8DTdklZVfyZDhTWI=
github.com/asticode/go-astisub v0.34.0/go.mod h1:WTkuSzFB+Bp7wezuSf2Oxulj5A8zu2zLRVFf6bIFQK8=
github.com/asticode/go-astits v1.8.0 h1:rf6aiiGn/QhlFjNON1n5plqF3Fs025XLUwiQ0NB6oZg= github.com/asticode/go-astits v1.8.0 h1:rf6aiiGn/QhlFjNON1n5plqF3Fs025XLUwiQ0NB6oZg=
github.com/asticode/go-astits v1.8.0/go.mod h1:DkOWmBNQpnr9mv24KfZjq4JawCFX1FCqjLVGvO0DygQ= github.com/asticode/go-astits v1.8.0/go.mod h1:DkOWmBNQpnr9mv24KfZjq4JawCFX1FCqjLVGvO0DygQ=
github.com/aws/aws-sdk-go v1.38.20 h1:QbzNx/tdfATbdKfubBpkt84OM6oBkxQZRw6+bW2GyeA= github.com/aws/aws-sdk-go v1.38.20 h1:QbzNx/tdfATbdKfubBpkt84OM6oBkxQZRw6+bW2GyeA=
@ -104,6 +112,8 @@ github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEM
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
github.com/cloudflare/circl v1.6.0 h1:cr5JKic4HI+LkINy2lg3W2jF8sHCVTBncJr5gIIq7qk=
github.com/cloudflare/circl v1.6.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
@ -113,6 +123,8 @@ github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53E
github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
github.com/cyphar/filepath-securejoin v0.3.6 h1:4d9N5ykBnSp5Xn2JkhocYDkOpURL/18CYMpo6xB9uWM= github.com/cyphar/filepath-securejoin v0.3.6 h1:4d9N5ykBnSp5Xn2JkhocYDkOpURL/18CYMpo6xB9uWM=
github.com/cyphar/filepath-securejoin v0.3.6/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= github.com/cyphar/filepath-securejoin v0.3.6/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -168,6 +180,8 @@ github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+
github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
github.com/go-git/go-billy/v5 v5.6.1 h1:u+dcrgaguSSkbjzHwelEjc0Yj300NUevrrPphk/SoRA= github.com/go-git/go-billy/v5 v5.6.1 h1:u+dcrgaguSSkbjzHwelEjc0Yj300NUevrrPphk/SoRA=
github.com/go-git/go-billy/v5 v5.6.1/go.mod h1:0AsLr1z2+Uksi4NlElmMblP5rPcDZNRCD8ujZCRR2BE= github.com/go-git/go-billy/v5 v5.6.1/go.mod h1:0AsLr1z2+Uksi4NlElmMblP5rPcDZNRCD8ujZCRR2BE=
github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM=
github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
github.com/go-git/go-git-fixtures/v4 v4.2.1 h1:n9gGL1Ct/yIw+nfsfr8s4+sbhT+Ncu2SubfXjIWgci8= github.com/go-git/go-git-fixtures/v4 v4.2.1 h1:n9gGL1Ct/yIw+nfsfr8s4+sbhT+Ncu2SubfXjIWgci8=
github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0= github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0=
github.com/go-git/go-git-fixtures/v4 v4.3.1/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo= github.com/go-git/go-git-fixtures/v4 v4.3.1/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo=
@ -199,6 +213,10 @@ github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZt
github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY= github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY=
github.com/go-git/go-git/v5 v5.13.1 h1:DAQ9APonnlvSWpvolXWIuV6Q6zXy2wHbN4cVlNR5Q+M= github.com/go-git/go-git/v5 v5.13.1 h1:DAQ9APonnlvSWpvolXWIuV6Q6zXy2wHbN4cVlNR5Q+M=
github.com/go-git/go-git/v5 v5.13.1/go.mod h1:qryJB4cSBoq3FRoBRf5A77joojuBcmPJ0qu3XXXVixc= github.com/go-git/go-git/v5 v5.13.1/go.mod h1:qryJB4cSBoq3FRoBRf5A77joojuBcmPJ0qu3XXXVixc=
github.com/go-git/go-git/v5 v5.13.2 h1:7O7xvsK7K+rZPKW6AQR1YyNhfywkv7B8/FsP3ki6Zv0=
github.com/go-git/go-git/v5 v5.13.2/go.mod h1:hWdW5P4YZRjmpGHwRH2v3zkWcNl6HeXaXQEMGb3NJ9A=
github.com/go-git/go-git/v5 v5.14.0 h1:/MD3lCrGjCen5WfEAzKg00MJJffKhC8gzS80ycmCi60=
github.com/go-git/go-git/v5 v5.14.0/go.mod h1:Z5Xhoia5PcWA3NF8vRLURn9E5FRhSl7dGj9ItW3Wk5k=
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
@ -243,12 +261,15 @@ github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MG
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
@ -352,6 +373,8 @@ github.com/pjbgf/sha1cd v0.2.3 h1:uKQP/7QOzNtKYH7UTohZLcjF5/55EnTw0jO/Ru4jZwI=
github.com/pjbgf/sha1cd v0.2.3/go.mod h1:HOK9QrgzdHpbc2Kzip0Q1yi3M2MFGPADtR6HjG65m5M= github.com/pjbgf/sha1cd v0.2.3/go.mod h1:HOK9QrgzdHpbc2Kzip0Q1yi3M2MFGPADtR6HjG65m5M=
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4=
github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@ -382,6 +405,8 @@ github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L
github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo=
github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY= github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY=
github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M= github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M=
github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8=
github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@ -542,6 +567,12 @@ golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY=
golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.1.0 h1:r8Oj8ZA2Xy12/b5KZYj3tuv7NG/fBz3TwQVvpJ9l8Rk= golang.org/x/image v0.1.0 h1:r8Oj8ZA2Xy12/b5KZYj3tuv7NG/fBz3TwQVvpJ9l8Rk=
golang.org/x/image v0.1.0/go.mod h1:iyPr49SD/G/TBxYVB/9RRtGUT5eNbo2u4NamWeQcD5c= golang.org/x/image v0.1.0/go.mod h1:iyPr49SD/G/TBxYVB/9RRtGUT5eNbo2u4NamWeQcD5c=
@ -589,6 +620,10 @@ golang.org/x/image v0.22.0 h1:UtK5yLUzilVrkjMAZAZ34DXGpASN8i8pj8g+O+yd10g=
golang.org/x/image v0.22.0/go.mod h1:9hPFhljd4zZ1GNSIZJ49sqbp45GKK9t6w+iXvGqZUz4= golang.org/x/image v0.22.0/go.mod h1:9hPFhljd4zZ1GNSIZJ49sqbp45GKK9t6w+iXvGqZUz4=
golang.org/x/image v0.23.0 h1:HseQ7c2OpPKTPVzNjG5fwJsOTCiiwS4QdsYi5XU6H68= golang.org/x/image v0.23.0 h1:HseQ7c2OpPKTPVzNjG5fwJsOTCiiwS4QdsYi5XU6H68=
golang.org/x/image v0.23.0/go.mod h1:wJJBTdLfCCf3tiHa1fNxpZmUI4mmoZvwMCPP0ddoNKY= golang.org/x/image v0.23.0/go.mod h1:wJJBTdLfCCf3tiHa1fNxpZmUI4mmoZvwMCPP0ddoNKY=
golang.org/x/image v0.24.0 h1:AN7zRgVsbvmTfNyqIbbOraYL8mSwcKncEj8ofjgzcMQ=
golang.org/x/image v0.24.0/go.mod h1:4b/ITuLfqYq1hqZcjofwctIhi7sZh2WaCjvsBNjjya8=
golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ=
golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
@ -657,6 +692,10 @@ golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
golang.org/x/oauth2 v0.1.0 h1:isLCZuhj4v+tYv7eskaN4v/TM+A1begWWgyVJDdl1+Y= golang.org/x/oauth2 v0.1.0 h1:isLCZuhj4v+tYv7eskaN4v/TM+A1begWWgyVJDdl1+Y=
golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A= golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A=
golang.org/x/oauth2 v0.2.0 h1:GtQkldQ9m7yvzCL1V+LrYow3Khe0eJH0w7RbX/VbaIU= golang.org/x/oauth2 v0.2.0 h1:GtQkldQ9m7yvzCL1V+LrYow3Khe0eJH0w7RbX/VbaIU=
@ -707,6 +746,10 @@ golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE=
golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/oauth2 v0.25.0 h1:CY4y7XT9v0cRI9oupztF8AgiIu99L/ksR/Xp/6jrZ70= golang.org/x/oauth2 v0.25.0 h1:CY4y7XT9v0cRI9oupztF8AgiIu99L/ksR/Xp/6jrZ70=
golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/oauth2 v0.26.0 h1:afQXWNNaeC4nvZ0Ed9XvCCzXM6UHJG7iCg0W4fPqSBE=
golang.org/x/oauth2 v0.26.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc=
golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -718,6 +761,10 @@ golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -798,6 +845,12 @@ golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@ -847,6 +900,10 @@ golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

26
libfic/cyberrange.go Normal file
View file

@ -0,0 +1,26 @@
package fic
import ()
type CyberrangeAPIResponse struct {
Data interface{}
CurrentPage int `json:"current_page"`
PerPage int `json:"per_page"`
LastPage int `json:"last_page"`
Total int `json:"total"`
}
type CyberrangeTeam struct {
UUID string `json:"session_uuid"`
Members []CyberrangeTeamMember `json:"members"`
Name string `json:"name"`
Score int64 `json:"score"`
Rank int `json:"rank"`
}
type CyberrangeTeamMember struct {
UUID string `json:"session_uuid"`
Name string `json:"name"`
Nickname string `json:"nickname"`
EMail string `json:"email"`
}

View file

@ -414,6 +414,7 @@ CREATE TABLE IF NOT EXISTS exercice_solved(
} }
if _, err := db.Exec(` if _, err := db.Exec(`
CREATE TABLE IF NOT EXISTS exercice_tries( CREATE TABLE IF NOT EXISTS exercice_tries(
id_try INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
id_exercice INTEGER NOT NULL, id_exercice INTEGER NOT NULL,
id_team INTEGER NOT NULL, id_team INTEGER NOT NULL,
time TIMESTAMP NOT NULL, time TIMESTAMP NOT NULL,
@ -423,6 +424,26 @@ CREATE TABLE IF NOT EXISTS exercice_tries(
FOREIGN KEY(id_exercice) REFERENCES exercices(id_exercice), FOREIGN KEY(id_exercice) REFERENCES exercices(id_exercice),
FOREIGN KEY(id_team) REFERENCES teams(id_team) FOREIGN KEY(id_team) REFERENCES teams(id_team)
) DEFAULT CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; ) DEFAULT CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
`); err != nil {
return err
}
if _, err := db.Exec(`
CREATE TABLE IF NOT EXISTS exercice_tries_flags(
id_try INTEGER NOT NULL,
id_flag INTEGER NOT NULL,
FOREIGN KEY(id_try) REFERENCES exercice_tries(id_try) ON DELETE CASCADE,
FOREIGN KEY(id_flag) REFERENCES exercice_flags(id_flag) ON DELETE CASCADE
) DEFAULT CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
`); err != nil {
return err
}
if _, err := db.Exec(`
CREATE TABLE IF NOT EXISTS exercice_tries_mcq(
id_try INTEGER NOT NULL,
id_mcq INTEGER NOT NULL,
FOREIGN KEY(id_try) REFERENCES exercice_tries(id_try) ON DELETE CASCADE,
FOREIGN KEY(id_mcq) REFERENCES exercice_mcq(id_mcq) ON DELETE CASCADE
) DEFAULT CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
`); err != nil { `); err != nil {
return err return err
} }

View file

@ -3,6 +3,7 @@ package fic
import ( import (
"errors" "errors"
"fmt" "fmt"
"log"
"math" "math"
"time" "time"
) )
@ -444,11 +445,25 @@ func (e *Exercice) GetOrdinal() (int, error) {
} }
// NewTry registers a solving attempt for the given Team. // NewTry registers a solving attempt for the given Team.
func (e *Exercice) NewTry(t *Team, cksum []byte) error { func (e *Exercice) NewTry(t *Team, cksum []byte, flags ...Flag) (int64, error) {
if _, err := DBExec("INSERT INTO exercice_tries (id_exercice, id_team, time, cksum) VALUES (?, ?, ?, ?)", e.Id, t.Id, time.Now(), cksum); err != nil { if res, err := DBExec("INSERT INTO exercice_tries (id_exercice, id_team, time, cksum) VALUES (?, ?, ?, ?)", e.Id, t.Id, time.Now(), cksum); err != nil {
return err return 0, err
} else { } else {
return nil return res.LastInsertId()
}
}
func (e *Exercice) NewTryFlag(tryid int64, flags ...Flag) {
for _, flag := range flags {
if fk, ok := flag.(*FlagKey); ok {
if _, err := DBExec("INSERT INTO exercice_tries_flags (id_try, id_flag) VALUES (?, ?)", tryid, fk.Id); err != nil {
log.Println("Unable to add detailed try: ", err.Error())
}
} else if fm, ok := flag.(*MCQ); ok {
if _, err := DBExec("INSERT INTO exercice_tries_mcq (id_try, id_mcq) VALUES (?, ?)", tryid, fm.Id); err != nil {
log.Println("Unable to add detailed try: ", err.Error())
}
}
} }
} }
@ -550,7 +565,7 @@ func (e *Exercice) MCQSolved() (res []int64) {
// CheckResponse, given both flags and MCQ responses, figures out if thoses are correct (or if they are previously solved). // CheckResponse, given both flags and MCQ responses, figures out if thoses are correct (or if they are previously solved).
// In the meanwhile, CheckResponse registers good answers given (but it does not mark the challenge as solved at the end). // In the meanwhile, CheckResponse registers good answers given (but it does not mark the challenge as solved at the end).
func (e *Exercice) CheckResponse(cksum []byte, respflags map[int]string, respmcq map[int]bool, t *Team) (bool, error) { func (e *Exercice) CheckResponse(cksum []byte, respflags map[int]string, respmcq map[int]bool, t *Team) (bool, error) {
if err := e.NewTry(t, cksum); err != nil { if tryId, err := e.NewTry(t, cksum); err != nil {
return false, err return false, err
} else if flags, err := e.GetFlagKeys(); err != nil { } else if flags, err := e.GetFlagKeys(); err != nil {
return false, err return false, err
@ -565,6 +580,10 @@ func (e *Exercice) CheckResponse(cksum []byte, respflags map[int]string, respmcq
// Check MCQs // Check MCQs
for _, mcq := range mcqs { for _, mcq := range mcqs {
if mcq.HasOneEntry(respmcq) {
e.NewTryFlag(tryId, mcq)
}
if d := mcq.Check(respmcq); d > 0 { if d := mcq.Check(respmcq); d > 0 {
if !PartialValidation || t.HasPartiallySolved(mcq) == nil { if !PartialValidation || t.HasPartiallySolved(mcq) == nil {
valid = false valid = false
@ -589,15 +608,21 @@ func (e *Exercice) CheckResponse(cksum []byte, respflags map[int]string, respmcq
for _, flag := range flags { for _, flag := range flags {
if res, ok := respflags[flag.Id]; !ok && (!PartialValidation || t.HasPartiallySolved(flag) == nil) { if res, ok := respflags[flag.Id]; !ok && (!PartialValidation || t.HasPartiallySolved(flag) == nil) {
valid = valid && flag.IsOptionnal() valid = valid && flag.IsOptionnal()
} else if flag.Check([]byte(res)) != 0 { } else if ok {
if !PartialValidation || t.HasPartiallySolved(flag) == nil { if len(res) > 0 {
valid = valid && flag.IsOptionnal() e.NewTryFlag(tryId, flag)
} }
} else {
err := flag.FoundBy(t) if flag.Check([]byte(res)) != 0 {
if err == nil { if !PartialValidation || t.HasPartiallySolved(flag) == nil {
// err is unicity issue, probably flag already found valid = valid && flag.IsOptionnal()
goodResponses += 1 }
} else {
err := flag.FoundBy(t)
if err == nil {
// err is unicity issue, probably flag already found
goodResponses += 1
}
} }
} }
} }

View file

@ -68,7 +68,8 @@ func (e *Exercice) AppendHistoryItem(tId int64, kind string, secondary *int64) e
if kind == "tries" { if kind == "tries" {
bid := make([]byte, 5) bid := make([]byte, 5)
binary.LittleEndian.PutUint32(bid, rand.Uint32()) binary.LittleEndian.PutUint32(bid, rand.Uint32())
return (&Exercice{Id: e.Id}).NewTry(team, bid) _, err = (&Exercice{Id: e.Id}).NewTry(team, bid)
return err
} else if kind == "hint" && secondary != nil { } else if kind == "hint" && secondary != nil {
return team.OpenHint(&EHint{Id: *secondary}) return team.OpenHint(&EHint{Id: *secondary})
} else if kind == "wchoices" && secondary != nil { } else if kind == "wchoices" && secondary != nil {

View file

@ -392,7 +392,12 @@ func (f *EFile) GetDepends() ([]Flag, error) {
// CheckFileOnDisk recalculates the hash of the file on disk. // CheckFileOnDisk recalculates the hash of the file on disk.
func (f *EFile) CheckFileOnDisk() error { func (f *EFile) CheckFileOnDisk() error {
if _, size, err := checkFileHash(path.Join(FilesDir, f.Path), f.Checksum); err != nil { firstChecksum := f.Checksum
if len(f.ChecksumShown) > 0 {
firstChecksum = f.ChecksumShown
}
if _, size, err := checkFileHash(path.Join(FilesDir, f.Path), firstChecksum); size > 0 && err != nil {
return err return err
} else if size == 0 { } else if size == 0 {
if _, _, err := checkFileHash(path.Join(FilesDir, f.Path+".gz"), f.Checksum); err != nil { if _, _, err := checkFileHash(path.Join(FilesDir, f.Path+".gz"), f.Checksum); err != nil {
@ -400,9 +405,17 @@ func (f *EFile) CheckFileOnDisk() error {
} else { } else {
return nil return nil
} }
} else { } else if err != nil {
return nil return err
} }
if _, err := os.Stat(path.Join(FilesDir, f.Path+".gz")); !os.IsNotExist(err) {
if _, _, err = checkFileHash(path.Join(FilesDir, f.Path+".gz"), f.Checksum); err != nil {
return err
}
}
return nil
} }
// GunzipFileOnDisk gunzip a compressed file. // GunzipFileOnDisk gunzip a compressed file.

View file

@ -14,6 +14,9 @@ type Flag interface {
Check(val interface{}) int Check(val interface{}) int
IsOptionnal() bool IsOptionnal() bool
FoundBy(t *Team) error FoundBy(t *Team) error
NbTries() (int64, error)
TeamsOnIt() ([]int64, error)
DeleteTries() error
} }
// GetFlag returns a list of flags comming with the challenge. // GetFlag returns a list of flags comming with the challenge.

View file

@ -230,6 +230,54 @@ func (k *FlagKey) RecoverId() (Flag, error) {
} }
} }
// NbTries returns the flag resolution statistics.
func (k *FlagKey) NbTries() (tries int64, err error) {
err = DBQueryRow("SELECT COUNT(*) AS tries FROM exercice_tries_flags WHERE id_flag = ?", k.Id).Scan(&tries)
return
}
func (k *FlagKey) TeamsOnIt() ([]int64, error) {
if rows, err := DBQuery("SELECT DISTINCT M.id_team FROM exercice_tries_flags F INNER JOIN exercice_tries T ON T.id_try = F.id_try INNER JOIN teams M ON M.id_team = T.id_team WHERE id_flag = ?", k.Id); err != nil {
return nil, err
} else {
defer rows.Close()
teams := []int64{}
for rows.Next() {
var idteam int64
if err := rows.Scan(&idteam); err != nil {
return nil, err
}
teams = append(teams, idteam)
}
return teams, nil
}
}
func (k *FlagKey) DeleteTries() error {
if rows, err := DBQuery("SELECT id_try FROM exercice_tries_flags WHERE id_flag = ?", k.Id); err != nil {
return err
} else {
defer rows.Close()
for rows.Next() {
var idtry int64
err = rows.Scan(&idtry)
if err != nil {
return err
}
_, err = DBExec("DELETE FROM exercice_tries WHERE id_try = ?", idtry)
if err != nil {
return err
}
}
return nil
}
}
// AddFlagKey creates and fills a new struct Flag, from a hashed flag, and registers it into the database. // AddFlagKey creates and fills a new struct Flag, from a hashed flag, and registers it into the database.
func (k *FlagKey) Create(e *Exercice) (Flag, error) { func (k *FlagKey) Create(e *Exercice) (Flag, error) {
// Check the regexp compile // Check the regexp compile

View file

@ -71,6 +71,18 @@ func (k *FlagLabel) RecoverId() (Flag, error) {
} }
} }
func (k *FlagLabel) NbTries() (int64, error) {
return 0, nil
}
func (k *FlagLabel) TeamsOnIt() ([]int64, error) {
return nil, nil
}
func (k *FlagLabel) DeleteTries() error {
return nil
}
// AddFlagLabel creates and fills a new struct Flag and registers it into the database. // AddFlagLabel creates and fills a new struct Flag and registers it into the database.
func (k *FlagLabel) Create(e *Exercice) (Flag, error) { func (k *FlagLabel) Create(e *Exercice) (Flag, error) {
if res, err := DBExec("INSERT INTO exercice_flag_labels (id_exercice, ordre, label, variant) VALUES (?, ?, ?, ?)", e.Id, k.Order, k.Label, k.Variant); err != nil { if res, err := DBExec("INSERT INTO exercice_flag_labels (id_exercice, ordre, label, variant) VALUES (?, ?, ?, ?)", e.Id, k.Order, k.Label, k.Variant); err != nil {

View file

@ -136,6 +136,54 @@ func (m *MCQ) RecoverId() (Flag, error) {
} }
} }
// NbTries returns the MCQ resolution statistics.
func (m *MCQ) NbTries() (tries int64, err error) {
err = DBQueryRow("SELECT COUNT(*) AS tries FROM exercice_tries_mcq WHERE id_mcq = ?", m.Id).Scan(&tries)
return
}
func (m *MCQ) TeamsOnIt() ([]int64, error) {
if rows, err := DBQuery("SELECT DISTINCT M.id_team FROM exercice_tries_mcq F INNER JOIN exercice_tries T ON T.id_try = F.id_try INNER JOIN teams M ON M.id_team = T.id_team WHERE id_mcq = ?", m.Id); err != nil {
return nil, err
} else {
defer rows.Close()
teams := []int64{}
for rows.Next() {
var idteam int64
if err := rows.Scan(&idteam); err != nil {
return nil, err
}
teams = append(teams, idteam)
}
return teams, nil
}
}
func (m *MCQ) DeleteTries() error {
if rows, err := DBQuery("SELECT id_try FROM exercice_tries_mcq WHERE id_mcq = ?", m.Id); err != nil {
return err
} else {
defer rows.Close()
for rows.Next() {
var idtry int64
err = rows.Scan(&idtry)
if err != nil {
return err
}
_, err = DBExec("DELETE FROM exercice_tries WHERE id_try = ?", idtry)
if err != nil {
return err
}
}
return nil
}
}
// Create registers a MCQ into the database and recursively add its entries. // Create registers a MCQ into the database and recursively add its entries.
func (m *MCQ) Create(e *Exercice) (Flag, error) { func (m *MCQ) Create(e *Exercice) (Flag, error) {
if res, err := DBExec("INSERT INTO exercice_mcq (id_exercice, ordre, title) VALUES (?, ?, ?)", e.Id, m.Order, m.Title); err != nil { if res, err := DBExec("INSERT INTO exercice_mcq (id_exercice, ordre, title) VALUES (?, ?, ?)", e.Id, m.Order, m.Title); err != nil {
@ -207,7 +255,7 @@ func (m *MCQ) AddEntry(e *MCQ_entry) (*MCQ_entry, error) {
// Update applies modifications back to the database. // Update applies modifications back to the database.
func (n *MCQ_entry) Update() (int64, error) { func (n *MCQ_entry) Update() (int64, error) {
if res, err := DBExec("UPDATE mcq_entries SET label = ?, response = ? WHERE id_mcq = ?", n.Label, n.Response, n.Id); err != nil { if res, err := DBExec("UPDATE mcq_entries SET label = ?, response = ? WHERE id_mcq_entry = ?", n.Label, n.Response, n.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {
return 0, err return 0, err
@ -319,6 +367,24 @@ func (m *MCQ) IsOptionnal() bool {
return false return false
} }
// Check if the given vals contains at least a response for the given MCQ.
func (m *MCQ) HasOneEntry(v interface{}) bool {
var vals map[int]bool
if va, ok := v.(map[int]bool); !ok {
return false
} else {
vals = va
}
for _, n := range m.Entries {
if _, ok := vals[n.Id]; ok {
return true
}
}
return false
}
// Check if the given vals are the expected ones to validate this flag. // Check if the given vals are the expected ones to validate this flag.
func (m *MCQ) Check(v interface{}) int { func (m *MCQ) Check(v interface{}) int {
var vals map[int]bool var vals map[int]bool

View file

@ -3,6 +3,7 @@ package fic
import ( import (
"bytes" "bytes"
"crypto/md5" "crypto/md5"
"math/rand"
"regexp" "regexp"
"strings" "strings"
) )
@ -187,3 +188,11 @@ func (c HSL) ToRGB() (rgb uint32) {
return r*65536 + g*256 + b return r*65536 + g*256 + b
} }
func RandomColor() HSL {
return HSL{
H: rand.Float64(),
S: 1,
L: 0.5,
}
}

480
qa/ui/package-lock.json generated
View file

@ -8,7 +8,7 @@
"name": "qa", "name": "qa",
"version": "0.0.1", "version": "0.0.1",
"dependencies": { "dependencies": {
"@sveltestrap/sveltestrap": "^6.2.1", "@sveltestrap/sveltestrap": "^7.0.0",
"bootstrap": "^5.2.2", "bootstrap": "^5.2.2",
"bootstrap-icons": "^1.9.1" "bootstrap-icons": "^1.9.1"
}, },
@ -17,8 +17,8 @@
"@sveltejs/kit": "^2.0.0", "@sveltejs/kit": "^2.0.0",
"@sveltejs/vite-plugin-svelte": "^3.0.0", "@sveltejs/vite-plugin-svelte": "^3.0.0",
"eslint": "^9.0.0", "eslint": "^9.0.0",
"eslint-config-prettier": "^9.0.0", "eslint-config-prettier": "^10.0.0",
"eslint-plugin-svelte": "^2.35.1", "eslint-plugin-svelte": "^3.0.0",
"prettier": "^3.0.0", "prettier": "^3.0.0",
"prettier-plugin-svelte": "^3.1.2", "prettier-plugin-svelte": "^3.1.2",
"svelte": "^5.0.0", "svelte": "^5.0.0",
@ -472,13 +472,13 @@
} }
}, },
"node_modules/@eslint/config-array": { "node_modules/@eslint/config-array": {
"version": "0.19.1", "version": "0.19.2",
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.1.tgz", "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.2.tgz",
"integrity": "sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA==", "integrity": "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@eslint/object-schema": "^2.1.5", "@eslint/object-schema": "^2.1.6",
"debug": "^4.3.1", "debug": "^4.3.1",
"minimatch": "^3.1.2" "minimatch": "^3.1.2"
}, },
@ -486,10 +486,20 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
} }
}, },
"node_modules/@eslint/config-helpers": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.0.tgz",
"integrity": "sha512-yJLLmLexii32mGrhW29qvU3QBVTu0GUmEf/J4XsBtVhp4JkIUFN/BjWqTF63yRvGApIDpZm5fa97LtYtINmfeQ==",
"dev": true,
"license": "Apache-2.0",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/@eslint/core": { "node_modules/@eslint/core": {
"version": "0.10.0", "version": "0.12.0",
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.10.0.tgz", "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.12.0.tgz",
"integrity": "sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw==", "integrity": "sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
@ -500,9 +510,9 @@
} }
}, },
"node_modules/@eslint/eslintrc": { "node_modules/@eslint/eslintrc": {
"version": "3.2.0", "version": "3.3.1",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz",
"integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -524,9 +534,9 @@
} }
}, },
"node_modules/@eslint/js": { "node_modules/@eslint/js": {
"version": "9.18.0", "version": "9.23.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.18.0.tgz", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.23.0.tgz",
"integrity": "sha512-fK6L7rxcq6/z+AaQMtiFTkvbHkBLNlwyRxHpKawP0x3u9+NC6MQTnFW+AdpwC6gfHTW0051cokQgtTN2FqlxQA==", "integrity": "sha512-35MJ8vCPU0ZMxo7zfev2pypqTwWTofFZO6m4KAtdoFhRpLJUpHTZZ+KB3C7Hb1d7bULYwO4lJXGCi5Se+8OMbw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@ -534,9 +544,9 @@
} }
}, },
"node_modules/@eslint/object-schema": { "node_modules/@eslint/object-schema": {
"version": "2.1.5", "version": "2.1.6",
"resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.5.tgz", "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz",
"integrity": "sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ==", "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"engines": { "engines": {
@ -544,13 +554,13 @@
} }
}, },
"node_modules/@eslint/plugin-kit": { "node_modules/@eslint/plugin-kit": {
"version": "0.2.5", "version": "0.2.7",
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.5.tgz", "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.7.tgz",
"integrity": "sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A==", "integrity": "sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@eslint/core": "^0.10.0", "@eslint/core": "^0.12.0",
"levn": "^0.4.1" "levn": "^0.4.1"
}, },
"engines": { "engines": {
@ -610,9 +620,9 @@
} }
}, },
"node_modules/@humanwhocodes/retry": { "node_modules/@humanwhocodes/retry": {
"version": "0.4.1", "version": "0.4.2",
"resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz", "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz",
"integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"engines": { "engines": {
@ -689,9 +699,9 @@
} }
}, },
"node_modules/@rollup/rollup-android-arm-eabi": { "node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.30.1", "version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.32.0.tgz",
"integrity": "sha512-pSWY+EVt3rJ9fQ3IqlrEUtXh3cGqGtPDH1FQlNZehO2yYxCHEX1SPsz1M//NXwYfbTlcKr9WObLnJX9FsS9K1Q==", "integrity": "sha512-G2fUQQANtBPsNwiVFg4zKiPQyjVKZCUdQUol53R8E71J7AsheRMV/Yv/nB8giOcOVqP7//eB5xPqieBYZe9bGg==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@ -703,9 +713,9 @@
] ]
}, },
"node_modules/@rollup/rollup-android-arm64": { "node_modules/@rollup/rollup-android-arm64": {
"version": "4.30.1", "version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.32.0.tgz",
"integrity": "sha512-/NA2qXxE3D/BRjOJM8wQblmArQq1YoBVJjrjoTSBS09jgUisq7bqxNHJ8kjCHeV21W/9WDGwJEWSN0KQ2mtD/w==", "integrity": "sha512-qhFwQ+ljoymC+j5lXRv8DlaJYY/+8vyvYmVx074zrLsu5ZGWYsJNLjPPVJJjhZQpyAKUGPydOq9hRLLNvh1s3A==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -717,9 +727,9 @@
] ]
}, },
"node_modules/@rollup/rollup-darwin-arm64": { "node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.30.1", "version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.32.0.tgz",
"integrity": "sha512-r7FQIXD7gB0WJ5mokTUgUWPl0eYIH0wnxqeSAhuIwvnnpjdVB8cRRClyKLQr7lgzjctkbp5KmswWszlwYln03Q==", "integrity": "sha512-44n/X3lAlWsEY6vF8CzgCx+LQaoqWGN7TzUfbJDiTIOjJm4+L2Yq+r5a8ytQRGyPqgJDs3Rgyo8eVL7n9iW6AQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -731,9 +741,9 @@
] ]
}, },
"node_modules/@rollup/rollup-darwin-x64": { "node_modules/@rollup/rollup-darwin-x64": {
"version": "4.30.1", "version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.32.0.tgz",
"integrity": "sha512-x78BavIwSH6sqfP2xeI1hd1GpHL8J4W2BXcVM/5KYKoAD3nNsfitQhvWSw+TFtQTLZ9OmlF+FEInEHyubut2OA==", "integrity": "sha512-F9ct0+ZX5Np6+ZDztxiGCIvlCaW87HBdHcozUfsHnj1WCUTBUubAoanhHUfnUHZABlElyRikI0mgcw/qdEm2VQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -745,9 +755,9 @@
] ]
}, },
"node_modules/@rollup/rollup-freebsd-arm64": { "node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.30.1", "version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.32.0.tgz",
"integrity": "sha512-HYTlUAjbO1z8ywxsDFWADfTRfTIIy/oUlfIDmlHYmjUP2QRDTzBuWXc9O4CXM+bo9qfiCclmHk1x4ogBjOUpUQ==", "integrity": "sha512-JpsGxLBB2EFXBsTLHfkZDsXSpSmKD3VxXCgBQtlPcuAqB8TlqtLcbeMhxXQkCDv1avgwNjF8uEIbq5p+Cee0PA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -759,9 +769,9 @@
] ]
}, },
"node_modules/@rollup/rollup-freebsd-x64": { "node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.30.1", "version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.32.0.tgz",
"integrity": "sha512-1MEdGqogQLccphhX5myCJqeGNYTNcmTyaic9S7CG3JhwuIByJ7J05vGbZxsizQthP1xpVx7kd3o31eOogfEirw==", "integrity": "sha512-wegiyBT6rawdpvnD9lmbOpx5Sph+yVZKHbhnSP9MqUEDX08G4UzMU+D87jrazGE7lRSyTRs6NEYHtzfkJ3FjjQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -773,9 +783,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm-gnueabihf": { "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.30.1", "version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.32.0.tgz",
"integrity": "sha512-PaMRNBSqCx7K3Wc9QZkFx5+CX27WFpAMxJNiYGAXfmMIKC7jstlr32UhTgK6T07OtqR+wYlWm9IxzennjnvdJg==", "integrity": "sha512-3pA7xecItbgOs1A5H58dDvOUEboG5UfpTq3WzAdF54acBbUM+olDJAPkgj1GRJ4ZqE12DZ9/hNS2QZk166v92A==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@ -787,9 +797,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm-musleabihf": { "node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.30.1", "version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.32.0.tgz",
"integrity": "sha512-B8Rcyj9AV7ZlEFqvB5BubG5iO6ANDsRKlhIxySXcF1axXYUyqwBok+XZPgIYGBgs7LDXfWfifxhw0Ik57T0Yug==", "integrity": "sha512-Y7XUZEVISGyge51QbYyYAEHwpGgmRrAxQXO3siyYo2kmaj72USSG8LtlQQgAtlGfxYiOwu+2BdbPjzEpcOpRmQ==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@ -801,9 +811,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm64-gnu": { "node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.30.1", "version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.32.0.tgz",
"integrity": "sha512-hqVyueGxAj3cBKrAI4aFHLV+h0Lv5VgWZs9CUGqr1z0fZtlADVV1YPOij6AhcK5An33EXaxnDLmJdQikcn5NEw==", "integrity": "sha512-r7/OTF5MqeBrZo5omPXcTnjvv1GsrdH8a8RerARvDFiDwFpDVDnJyByYM/nX+mvks8XXsgPUxkwe/ltaX2VH7w==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -815,9 +825,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm64-musl": { "node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.30.1", "version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.32.0.tgz",
"integrity": "sha512-i4Ab2vnvS1AE1PyOIGp2kXni69gU2DAUVt6FSXeIqUCPIR3ZlheMW3oP2JkukDfu3PsexYRbOiJrY+yVNSk9oA==", "integrity": "sha512-HJbifC9vex9NqnlodV2BHVFNuzKL5OnsV2dvTw6e1dpZKkNjPG6WUq+nhEYV6Hv2Bv++BXkwcyoGlXnPrjAKXw==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -829,9 +839,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-loongarch64-gnu": { "node_modules/@rollup/rollup-linux-loongarch64-gnu": {
"version": "4.30.1", "version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.32.0.tgz",
"integrity": "sha512-fARcF5g296snX0oLGkVxPmysetwUk2zmHcca+e9ObOovBR++9ZPOhqFUM61UUZ2EYpXVPN1redgqVoBB34nTpQ==", "integrity": "sha512-VAEzZTD63YglFlWwRj3taofmkV1V3xhebDXffon7msNz4b14xKsz7utO6F8F4cqt8K/ktTl9rm88yryvDpsfOw==",
"cpu": [ "cpu": [
"loong64" "loong64"
], ],
@ -843,9 +853,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": { "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
"version": "4.30.1", "version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.32.0.tgz",
"integrity": "sha512-GLrZraoO3wVT4uFXh67ElpwQY0DIygxdv0BNW9Hkm3X34wu+BkqrDrkcsIapAY+N2ATEbvak0XQ9gxZtCIA5Rw==", "integrity": "sha512-Sts5DST1jXAc9YH/iik1C9QRsLcCoOScf3dfbY5i4kH9RJpKxiTBXqm7qU5O6zTXBTEZry69bGszr3SMgYmMcQ==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
@ -857,9 +867,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-riscv64-gnu": { "node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.30.1", "version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.32.0.tgz",
"integrity": "sha512-0WKLaAUUHKBtll0wvOmh6yh3S0wSU9+yas923JIChfxOaaBarmb/lBKPF0w/+jTVozFnOXJeRGZ8NvOxvk/jcw==", "integrity": "sha512-qhlXeV9AqxIyY9/R1h1hBD6eMvQCO34ZmdYvry/K+/MBs6d1nRFLm6BOiITLVI+nFAAB9kUB6sdJRKyVHXnqZw==",
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
@ -871,9 +881,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-s390x-gnu": { "node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.30.1", "version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.32.0.tgz",
"integrity": "sha512-GWFs97Ruxo5Bt+cvVTQkOJ6TIx0xJDD/bMAOXWJg8TCSTEK8RnFeOeiFTxKniTc4vMIaWvCplMAFBt9miGxgkA==", "integrity": "sha512-8ZGN7ExnV0qjXa155Rsfi6H8M4iBBwNLBM9lcVS+4NcSzOFaNqmt7djlox8pN1lWrRPMRRQ8NeDlozIGx3Omsw==",
"cpu": [ "cpu": [
"s390x" "s390x"
], ],
@ -885,9 +895,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-x64-gnu": { "node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.30.1", "version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.32.0.tgz",
"integrity": "sha512-UtgGb7QGgXDIO+tqqJ5oZRGHsDLO8SlpE4MhqpY9Llpzi5rJMvrK6ZGhsRCST2abZdBqIBeXW6WPD5fGK5SDwg==", "integrity": "sha512-VDzNHtLLI5s7xd/VubyS10mq6TxvZBp+4NRWoW+Hi3tgV05RtVm4qK99+dClwTN1McA6PHwob6DEJ6PlXbY83A==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -899,9 +909,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-x64-musl": { "node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.30.1", "version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.32.0.tgz",
"integrity": "sha512-V9U8Ey2UqmQsBT+xTOeMzPzwDzyXmnAoO4edZhL7INkwQcaW1Ckv3WJX3qrrp/VHaDkEWIBWhRwP47r8cdrOow==", "integrity": "sha512-qcb9qYDlkxz9DxJo7SDhWxTWV1gFuwznjbTiov289pASxlfGbaOD54mgbs9+z94VwrXtKTu+2RqwlSTbiOqxGg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -913,9 +923,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-arm64-msvc": { "node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.30.1", "version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.32.0.tgz",
"integrity": "sha512-WabtHWiPaFF47W3PkHnjbmWawnX/aE57K47ZDT1BXTS5GgrBUEpvOzq0FI0V/UYzQJgdb8XlhVNH8/fwV8xDjw==", "integrity": "sha512-pFDdotFDMXW2AXVbfdUEfidPAk/OtwE/Hd4eYMTNVVaCQ6Yl8et0meDaKNL63L44Haxv4UExpv9ydSf3aSayDg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -927,9 +937,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-ia32-msvc": { "node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.30.1", "version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.32.0.tgz",
"integrity": "sha512-pxHAU+Zv39hLUTdQQHUVHf4P+0C47y/ZloorHpzs2SXMRqeAWmGghzAhfOlzFHHwjvgokdFAhC4V+6kC1lRRfw==", "integrity": "sha512-/TG7WfrCAjeRNDvI4+0AAMoHxea/USWhAzf9PVDFHbcqrQ7hMMKp4jZIy4VEjk72AAfN5k4TiSMRXRKf/0akSw==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@ -941,9 +951,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-x64-msvc": { "node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.30.1", "version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.32.0.tgz",
"integrity": "sha512-D6qjsXGcvhTjv0kI4fU8tUuBDF/Ueee4SVX79VfNDXZa64TfCW1Slkb6Z7O1p7vflqZjcmOVdZlqf8gvJxc6og==", "integrity": "sha512-5hqO5S3PTEO2E5VjCePxv40gIgyS2KvO7E7/vvC/NbIW4SIRamkMr1hqj+5Y67fbBWv/bQLB6KelBQmXlyCjWA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -954,6 +964,15 @@
"win32" "win32"
] ]
}, },
"node_modules/@sveltejs/acorn-typescript": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.5.tgz",
"integrity": "sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ==",
"license": "MIT",
"peerDependencies": {
"acorn": "^8.9.0"
}
},
"node_modules/@sveltejs/adapter-static": { "node_modules/@sveltejs/adapter-static": {
"version": "3.0.8", "version": "3.0.8",
"resolved": "https://registry.npmjs.org/@sveltejs/adapter-static/-/adapter-static-3.0.8.tgz", "resolved": "https://registry.npmjs.org/@sveltejs/adapter-static/-/adapter-static-3.0.8.tgz",
@ -965,25 +984,23 @@
} }
}, },
"node_modules/@sveltejs/kit": { "node_modules/@sveltejs/kit": {
"version": "2.15.2", "version": "2.20.2",
"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.15.2.tgz", "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.20.2.tgz",
"integrity": "sha512-p208T1kdM6zd8k4YXIUM60pLWQ8dZqehXSiqn4NulXHyHibX53uIAL2xtNL8GjxX2IVPqPRT978MwVYhCKExdQ==", "integrity": "sha512-Dv8TOAZC9vyfcAB9TMsvUEJsRbklRTeNfcYBPaeH6KnABJ99i3CvCB2eNx8fiiliIqe+9GIchBg4RodRH5p1BQ==",
"dev": true, "dev": true,
"hasInstallScript": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@types/cookie": "^0.6.0", "@types/cookie": "^0.6.0",
"cookie": "^0.6.0", "cookie": "^0.6.0",
"devalue": "^5.1.0", "devalue": "^5.1.0",
"esm-env": "^1.2.1", "esm-env": "^1.2.2",
"import-meta-resolve": "^4.1.0", "import-meta-resolve": "^4.1.0",
"kleur": "^4.1.5", "kleur": "^4.1.5",
"magic-string": "^0.30.5", "magic-string": "^0.30.5",
"mrmime": "^2.0.0", "mrmime": "^2.0.0",
"sade": "^1.8.1", "sade": "^1.8.1",
"set-cookie-parser": "^2.6.0", "set-cookie-parser": "^2.6.0",
"sirv": "^3.0.0", "sirv": "^3.0.0"
"tiny-glob": "^0.2.9"
}, },
"bin": { "bin": {
"svelte-kit": "svelte-kit.js" "svelte-kit": "svelte-kit.js"
@ -1039,9 +1056,9 @@
} }
}, },
"node_modules/@sveltestrap/sveltestrap": { "node_modules/@sveltestrap/sveltestrap": {
"version": "6.2.7", "version": "7.1.0",
"resolved": "https://registry.npmjs.org/@sveltestrap/sveltestrap/-/sveltestrap-6.2.7.tgz", "resolved": "https://registry.npmjs.org/@sveltestrap/sveltestrap/-/sveltestrap-7.1.0.tgz",
"integrity": "sha512-WwLLfAFUb42BGuRrf3Vbct30bQMzlEMMipN/MfxhjuLTmLQeW9muVJfPyvjtWS+mY+RjkSCoHvAp/ZobP1NLlQ==", "integrity": "sha512-TpIx25kqLV+z+VD3yfqYayOI1IaCeWFbT0uqM6NfA4vQgDs9PjFwmjkU4YEAlV/ngs9e7xPmaRWE7lkrg4Miow==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@popperjs/core": "^2.11.8" "@popperjs/core": "^2.11.8"
@ -1092,15 +1109,6 @@
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
} }
}, },
"node_modules/acorn-typescript": {
"version": "1.4.13",
"resolved": "https://registry.npmjs.org/acorn-typescript/-/acorn-typescript-1.4.13.tgz",
"integrity": "sha512-xsc9Xv0xlVfwp2o7sQ+GCQ1PgbkdcpWdTzrwXxO3xDMTAywVS3oXVOcOHuRjAPkS4P9b+yc/qNF15460v+jp4Q==",
"license": "MIT",
"peerDependencies": {
"acorn": ">=8.9.0"
}
},
"node_modules/ajv": { "node_modules/ajv": {
"version": "6.12.6", "version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@ -1408,22 +1416,23 @@
} }
}, },
"node_modules/eslint": { "node_modules/eslint": {
"version": "9.18.0", "version": "9.23.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.18.0.tgz", "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.23.0.tgz",
"integrity": "sha512-+waTfRWQlSbpt3KWE+CjrPPYnbq9kfZIYUqapc0uBXyjTp8aYXZDsUH16m39Ryq3NjAVP4tjuF7KaukeqoCoaA==", "integrity": "sha512-jV7AbNoFPAY1EkFYpLq5bslU9NLNO8xnEeQXwErNibVryjk67wHVmddTBilc5srIttJDBrB0eMHKZBFbSIABCw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.12.1", "@eslint-community/regexpp": "^4.12.1",
"@eslint/config-array": "^0.19.0", "@eslint/config-array": "^0.19.2",
"@eslint/core": "^0.10.0", "@eslint/config-helpers": "^0.2.0",
"@eslint/eslintrc": "^3.2.0", "@eslint/core": "^0.12.0",
"@eslint/js": "9.18.0", "@eslint/eslintrc": "^3.3.1",
"@eslint/plugin-kit": "^0.2.5", "@eslint/js": "9.23.0",
"@eslint/plugin-kit": "^0.2.7",
"@humanfs/node": "^0.16.6", "@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/module-importer": "^1.0.1",
"@humanwhocodes/retry": "^0.4.1", "@humanwhocodes/retry": "^0.4.2",
"@types/estree": "^1.0.6", "@types/estree": "^1.0.6",
"@types/json-schema": "^7.0.15", "@types/json-schema": "^7.0.15",
"ajv": "^6.12.4", "ajv": "^6.12.4",
@ -1431,7 +1440,7 @@
"cross-spawn": "^7.0.6", "cross-spawn": "^7.0.6",
"debug": "^4.3.2", "debug": "^4.3.2",
"escape-string-regexp": "^4.0.0", "escape-string-regexp": "^4.0.0",
"eslint-scope": "^8.2.0", "eslint-scope": "^8.3.0",
"eslint-visitor-keys": "^4.2.0", "eslint-visitor-keys": "^4.2.0",
"espree": "^10.3.0", "espree": "^10.3.0",
"esquery": "^1.5.0", "esquery": "^1.5.0",
@ -1468,9 +1477,9 @@
} }
}, },
"node_modules/eslint-compat-utils": { "node_modules/eslint-compat-utils": {
"version": "0.5.1", "version": "0.6.4",
"resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz", "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.6.4.tgz",
"integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==", "integrity": "sha512-/u+GQt8NMfXO8w17QendT4gvO5acfxQsAKirAt0LVxDnr2N8YLCVbregaNc/Yhp7NM128DwCaRvr8PLDfeNkQw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -1484,9 +1493,9 @@
} }
}, },
"node_modules/eslint-config-prettier": { "node_modules/eslint-config-prettier": {
"version": "9.1.0", "version": "10.1.1",
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.1.tgz",
"integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", "integrity": "sha512-4EQQr6wXwS+ZJSzaR5ZCrYgLxqvUjdXctaEtBqHcbkW944B1NQyO4qpdHQbXBONfwxXdkAY81HH4+LUfrg+zPw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"bin": { "bin": {
@ -1497,32 +1506,31 @@
} }
}, },
"node_modules/eslint-plugin-svelte": { "node_modules/eslint-plugin-svelte": {
"version": "2.46.1", "version": "3.3.3",
"resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-2.46.1.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-3.3.3.tgz",
"integrity": "sha512-7xYr2o4NID/f9OEYMqxsEQsCsj4KaMy4q5sANaKkAb6/QeCjYFxRmDm2S3YC3A3pl1kyPZ/syOx/i7LcWYSbIw==", "integrity": "sha512-imzGqIgWbfsb/CR14d3k3M8MiVNGet+l9mjPhvo1Rm0Nxi0rNn4/eELqyR8FWlgKBMlGkOp2kshRJm0xpxNfHQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.4.0", "@eslint-community/eslint-utils": "^4.4.1",
"@jridgewell/sourcemap-codec": "^1.4.15", "@jridgewell/sourcemap-codec": "^1.5.0",
"eslint-compat-utils": "^0.5.1", "eslint-compat-utils": "^0.6.4",
"esutils": "^2.0.3", "esutils": "^2.0.3",
"known-css-properties": "^0.35.0", "known-css-properties": "^0.35.0",
"postcss": "^8.4.38", "postcss": "^8.4.49",
"postcss-load-config": "^3.1.4", "postcss-load-config": "^3.1.4",
"postcss-safe-parser": "^6.0.0", "postcss-safe-parser": "^7.0.0",
"postcss-selector-parser": "^6.1.0", "semver": "^7.6.3",
"semver": "^7.6.2", "svelte-eslint-parser": "^1.0.1"
"svelte-eslint-parser": "^0.43.0"
}, },
"engines": { "engines": {
"node": "^14.17.0 || >=16.0.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}, },
"funding": { "funding": {
"url": "https://github.com/sponsors/ota-meshi" "url": "https://github.com/sponsors/ota-meshi"
}, },
"peerDependencies": { "peerDependencies": {
"eslint": "^7.0.0 || ^8.0.0-0 || ^9.0.0-0", "eslint": "^8.57.1 || ^9.0.0",
"svelte": "^3.37.0 || ^4.0.0 || ^5.0.0" "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
@ -1532,9 +1540,9 @@
} }
}, },
"node_modules/eslint-scope": { "node_modules/eslint-scope": {
"version": "8.2.0", "version": "8.3.0",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz",
"integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==",
"dev": true, "dev": true,
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"dependencies": { "dependencies": {
@ -1599,9 +1607,9 @@
} }
}, },
"node_modules/esrap": { "node_modules/esrap": {
"version": "1.4.3", "version": "1.4.5",
"resolved": "https://registry.npmjs.org/esrap/-/esrap-1.4.3.tgz", "resolved": "https://registry.npmjs.org/esrap/-/esrap-1.4.5.tgz",
"integrity": "sha512-Xddc1RsoFJ4z9nR7W7BFaEPIp4UXoeQ0+077UdWLxbafMQFyU79sQJMk7kxNgRwQ9/aVgaKacCHC2pUACGwmYw==", "integrity": "sha512-CjNMjkBWWZeHn+VX+gS8YvFwJ5+NDhg8aWZBSFJPR8qQduDNjbJodA2WcwCm7uQa5Rjqj+nZvVmceg1RbHFB9g==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@jridgewell/sourcemap-codec": "^1.4.15" "@jridgewell/sourcemap-codec": "^1.4.15"
@ -1753,20 +1761,6 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/globalyzer": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz",
"integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==",
"dev": true,
"license": "MIT"
},
"node_modules/globrex": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz",
"integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==",
"dev": true,
"license": "MIT"
},
"node_modules/has-flag": { "node_modules/has-flag": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@ -2144,9 +2138,9 @@
"license": "ISC" "license": "ISC"
}, },
"node_modules/postcss": { "node_modules/postcss": {
"version": "8.4.49", "version": "8.5.1",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz",
"integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", "integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==",
"dev": true, "dev": true,
"funding": [ "funding": [
{ {
@ -2164,7 +2158,7 @@
], ],
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"nanoid": "^3.3.7", "nanoid": "^3.3.8",
"picocolors": "^1.1.1", "picocolors": "^1.1.1",
"source-map-js": "^1.2.1" "source-map-js": "^1.2.1"
}, },
@ -2203,20 +2197,30 @@
} }
}, },
"node_modules/postcss-safe-parser": { "node_modules/postcss-safe-parser": {
"version": "6.0.0", "version": "7.0.1",
"resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz", "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz",
"integrity": "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==", "integrity": "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==",
"dev": true, "dev": true,
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/postcss-safe-parser"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=12.0" "node": ">=18.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
}, },
"peerDependencies": { "peerDependencies": {
"postcss": "^8.3.3" "postcss": "^8.4.31"
} }
}, },
"node_modules/postcss-scss": { "node_modules/postcss-scss": {
@ -2247,9 +2251,9 @@
} }
}, },
"node_modules/postcss-selector-parser": { "node_modules/postcss-selector-parser": {
"version": "6.1.2", "version": "7.1.0",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz",
"integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -2271,9 +2275,9 @@
} }
}, },
"node_modules/prettier": { "node_modules/prettier": {
"version": "3.4.2", "version": "3.5.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
"integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"bin": { "bin": {
@ -2318,9 +2322,9 @@
} }
}, },
"node_modules/rollup": { "node_modules/rollup": {
"version": "4.30.1", "version": "4.32.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.30.1.tgz", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.32.0.tgz",
"integrity": "sha512-mlJ4glW020fPuLi7DkM/lN97mYEZGWeqBnrljzN0gs7GLctqX3lNWxKQ7Gl712UAX+6fog/L3jh4gb7R6aVi3w==", "integrity": "sha512-JmrhfQR31Q4AuNBjjAX4s+a/Pu/Q8Q9iwjWBsjRH1q52SPFE2NqRMK6fUZKKnvKO6id+h7JIRf0oYsph53eATg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -2334,25 +2338,25 @@
"npm": ">=8.0.0" "npm": ">=8.0.0"
}, },
"optionalDependencies": { "optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.30.1", "@rollup/rollup-android-arm-eabi": "4.32.0",
"@rollup/rollup-android-arm64": "4.30.1", "@rollup/rollup-android-arm64": "4.32.0",
"@rollup/rollup-darwin-arm64": "4.30.1", "@rollup/rollup-darwin-arm64": "4.32.0",
"@rollup/rollup-darwin-x64": "4.30.1", "@rollup/rollup-darwin-x64": "4.32.0",
"@rollup/rollup-freebsd-arm64": "4.30.1", "@rollup/rollup-freebsd-arm64": "4.32.0",
"@rollup/rollup-freebsd-x64": "4.30.1", "@rollup/rollup-freebsd-x64": "4.32.0",
"@rollup/rollup-linux-arm-gnueabihf": "4.30.1", "@rollup/rollup-linux-arm-gnueabihf": "4.32.0",
"@rollup/rollup-linux-arm-musleabihf": "4.30.1", "@rollup/rollup-linux-arm-musleabihf": "4.32.0",
"@rollup/rollup-linux-arm64-gnu": "4.30.1", "@rollup/rollup-linux-arm64-gnu": "4.32.0",
"@rollup/rollup-linux-arm64-musl": "4.30.1", "@rollup/rollup-linux-arm64-musl": "4.32.0",
"@rollup/rollup-linux-loongarch64-gnu": "4.30.1", "@rollup/rollup-linux-loongarch64-gnu": "4.32.0",
"@rollup/rollup-linux-powerpc64le-gnu": "4.30.1", "@rollup/rollup-linux-powerpc64le-gnu": "4.32.0",
"@rollup/rollup-linux-riscv64-gnu": "4.30.1", "@rollup/rollup-linux-riscv64-gnu": "4.32.0",
"@rollup/rollup-linux-s390x-gnu": "4.30.1", "@rollup/rollup-linux-s390x-gnu": "4.32.0",
"@rollup/rollup-linux-x64-gnu": "4.30.1", "@rollup/rollup-linux-x64-gnu": "4.32.0",
"@rollup/rollup-linux-x64-musl": "4.30.1", "@rollup/rollup-linux-x64-musl": "4.32.0",
"@rollup/rollup-win32-arm64-msvc": "4.30.1", "@rollup/rollup-win32-arm64-msvc": "4.32.0",
"@rollup/rollup-win32-ia32-msvc": "4.30.1", "@rollup/rollup-win32-ia32-msvc": "4.32.0",
"@rollup/rollup-win32-x64-msvc": "4.30.1", "@rollup/rollup-win32-x64-msvc": "4.32.0",
"fsevents": "~2.3.2" "fsevents": "~2.3.2"
} }
}, },
@ -2464,16 +2468,16 @@
} }
}, },
"node_modules/svelte": { "node_modules/svelte": {
"version": "5.19.0", "version": "5.25.3",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-5.19.0.tgz", "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.25.3.tgz",
"integrity": "sha512-qvd2GvvYnJxS/MteQKFSMyq8cQrAAut28QZ39ySv9k3ggmhw4Au4Rfcsqva74i0xMys//OhbhVCNfXPrDzL/Bg==", "integrity": "sha512-J9rcZ/xVJonAoESqVGHHZhrNdVbrCfkdB41BP6eiwHMoFShD9it3yZXApVYMHdGfCshBsZCKsajwJeBbS/M1zg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@ampproject/remapping": "^2.3.0", "@ampproject/remapping": "^2.3.0",
"@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/sourcemap-codec": "^1.5.0",
"@sveltejs/acorn-typescript": "^1.0.5",
"@types/estree": "^1.0.5", "@types/estree": "^1.0.5",
"acorn": "^8.12.1", "acorn": "^8.12.1",
"acorn-typescript": "^1.4.13",
"aria-query": "^5.3.1", "aria-query": "^5.3.1",
"axobject-query": "^4.1.0", "axobject-query": "^4.1.0",
"clsx": "^2.1.1", "clsx": "^2.1.1",
@ -2489,20 +2493,21 @@
} }
}, },
"node_modules/svelte-eslint-parser": { "node_modules/svelte-eslint-parser": {
"version": "0.43.0", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-0.43.0.tgz", "resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-1.1.1.tgz",
"integrity": "sha512-GpU52uPKKcVnh8tKN5P4UZpJ/fUDndmq7wfsvoVXsyP+aY0anol7Yqo01fyrlaWGMFfm4av5DyrjlaXdLRJvGA==", "integrity": "sha512-QLVGPIMDettl30qRHXU2VrPvVJKG8GsGstye7n8rFbEiu3gEARksuQg9Xu4GzubNxhGNM8stfBZkhyMbBQmjFA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"eslint-scope": "^7.2.2", "eslint-scope": "^8.2.0",
"eslint-visitor-keys": "^3.4.3", "eslint-visitor-keys": "^4.0.0",
"espree": "^9.6.1", "espree": "^10.0.0",
"postcss": "^8.4.39", "postcss": "^8.4.49",
"postcss-scss": "^4.0.9" "postcss-scss": "^4.0.9",
"postcss-selector-parser": "^7.0.0"
}, },
"engines": { "engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}, },
"funding": { "funding": {
"url": "https://github.com/sponsors/ota-meshi" "url": "https://github.com/sponsors/ota-meshi"
@ -2516,54 +2521,6 @@
} }
} }
}, },
"node_modules/svelte-eslint-parser/node_modules/eslint-scope": {
"version": "7.2.2",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
"integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"esrecurse": "^4.3.0",
"estraverse": "^5.2.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/svelte-eslint-parser/node_modules/eslint-visitor-keys": {
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
"dev": true,
"license": "Apache-2.0",
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/svelte-eslint-parser/node_modules/espree": {
"version": "9.6.1",
"resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
"integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"acorn": "^8.9.0",
"acorn-jsx": "^5.3.2",
"eslint-visitor-keys": "^3.4.1"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/svelte-hmr": { "node_modules/svelte-hmr": {
"version": "0.16.0", "version": "0.16.0",
"resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.16.0.tgz", "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.16.0.tgz",
@ -2577,17 +2534,6 @@
"svelte": "^3.19.0 || ^4.0.0" "svelte": "^3.19.0 || ^4.0.0"
} }
}, },
"node_modules/tiny-glob": {
"version": "0.2.9",
"resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz",
"integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==",
"dev": true,
"license": "MIT",
"dependencies": {
"globalyzer": "0.1.0",
"globrex": "^0.1.2"
}
},
"node_modules/totalist": { "node_modules/totalist": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
@ -2629,9 +2575,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/vite": { "node_modules/vite": {
"version": "5.4.11", "version": "5.4.15",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz", "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.15.tgz",
"integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==", "integrity": "sha512-6ANcZRivqL/4WtwPGTKNaosuNJr5tWiftOC7liM7G9+rMb8+oeJeyzymDu4rTN93seySBmbjSfsS3Vzr19KNtA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {

View file

@ -14,8 +14,8 @@
"@sveltejs/kit": "^2.0.0", "@sveltejs/kit": "^2.0.0",
"@sveltejs/vite-plugin-svelte": "^3.0.0", "@sveltejs/vite-plugin-svelte": "^3.0.0",
"eslint": "^9.0.0", "eslint": "^9.0.0",
"eslint-config-prettier": "^9.0.0", "eslint-config-prettier": "^10.0.0",
"eslint-plugin-svelte": "^2.35.1", "eslint-plugin-svelte": "^3.0.0",
"prettier": "^3.0.0", "prettier": "^3.0.0",
"prettier-plugin-svelte": "^3.1.2", "prettier-plugin-svelte": "^3.1.2",
"svelte": "^5.0.0", "svelte": "^5.0.0",
@ -25,6 +25,6 @@
"dependencies": { "dependencies": {
"bootstrap": "^5.2.2", "bootstrap": "^5.2.2",
"bootstrap-icons": "^1.9.1", "bootstrap-icons": "^1.9.1",
"@sveltestrap/sveltestrap": "^6.2.1" "@sveltestrap/sveltestrap": "^7.0.0"
} }
} }

View file

@ -9,12 +9,14 @@ import (
"log" "log"
"net/http" "net/http"
"strconv" "strconv"
"srs.epita.fr/fic-server/libfic"
) )
type AirbusAPI struct { type AirbusAPI struct {
BaseURL string BaseURL string
Token string Token string
SessionID int64 SessionUUID string
InsecureSkipVerify bool InsecureSkipVerify bool
} }
@ -51,7 +53,7 @@ func (a *AirbusAPI) request(method, endpoint string, data io.Reader, out interfa
if out != nil { if out != nil {
jdec := json.NewDecoder(resp.Body) jdec := json.NewDecoder(resp.Body)
if err := jdec.Decode(out); err != nil { if err := jdec.Decode(&fic.CyberrangeAPIResponse{Data: out}); err != nil {
return fmt.Errorf("an error occurs when trying to decode response: %w", err) return fmt.Errorf("an error occurs when trying to decode response: %w", err)
} }
} }
@ -87,7 +89,7 @@ type AirbusUser struct {
} }
func (a *AirbusAPI) GetUsers() (users AirbusUserData, err error) { func (a *AirbusAPI) GetUsers() (users AirbusUserData, err error) {
err = a.request("GET", fmt.Sprintf("/sessions/%d/users", a.SessionID), nil, &users) err = a.request("GET", fmt.Sprintf("/sessions/%s/users", a.SessionUUID), nil, &users)
return return
} }
@ -137,7 +139,7 @@ type AirbusChallenge struct {
} }
func (a *AirbusAPI) GetChallenges() (challenges AirbusChallengeData, err error) { func (a *AirbusAPI) GetChallenges() (challenges AirbusChallengeData, err error) {
err = a.request("GET", fmt.Sprintf("/v1/sessions/%d/challenges", a.SessionID), nil, &challenges) err = a.request("GET", fmt.Sprintf("/v1/sessions/%s/challenges", a.SessionUUID), nil, &challenges)
return return
} }
@ -156,25 +158,23 @@ func (a *AirbusAPI) GetChallengeFromName(name string) (*AirbusChallenge, error)
return nil, fmt.Errorf("unable to find challenge %q", name) return nil, fmt.Errorf("unable to find challenge %q", name)
} }
func (a *AirbusAPI) ValidateChallengeFromUser(team *AirbusTeam, challengeId AirbusChallengeId) (err error) { func (a *AirbusAPI) ValidateChallengeFromUser(team *fic.CyberrangeTeam, challengeId AirbusChallengeId) (err error) {
log.Printf("ValidateChallenge: %d, %s, %d", a.SessionID, challengeId.String(), team.Members[0].ID) log.Printf("ValidateChallenge: %s, %s, %s", a.SessionUUID, challengeId.String(), team.Members[0].UUID)
if dryRun { if dryRun {
return return
} }
err = a.request("GET", fmt.Sprintf("/v1/sessions/%d/%s/%d/validate", a.SessionID, challengeId.String(), team.Members[0].ID), nil, nil) err = a.request("GET", fmt.Sprintf("/v1/sessions/%s/%s/%s/validate", a.SessionUUID, challengeId.String(), team.Members[0].UUID), nil, nil)
return return
} }
type AirbusUserAwards struct { type AirbusUserAwards struct {
UserId int64 `json:"gaming_user_id"`
Message string `json:"name"` Message string `json:"name"`
Value int64 `json:"value"` Value int64 `json:"value"`
} }
func (a *AirbusAPI) AwardUser(team *AirbusTeam, value int64, message string) (err error) { func (a *AirbusAPI) AwardUser(team *fic.CyberrangeTeam, value int64, message string) (err error) {
awards := AirbusUserAwards{ awards := AirbusUserAwards{
UserId: team.Members[0].ID,
Message: message, Message: message,
Value: value, Value: value,
} }
@ -190,7 +190,7 @@ func (a *AirbusAPI) AwardUser(team *AirbusTeam, value int64, message string) (er
return return
} }
err = a.request("POST", fmt.Sprintf("/v1/sessions/%d/awards", a.SessionID), bytes.NewReader(marshalled), nil) err = a.request("POST", fmt.Sprintf("/v1/sessions/%s/%s/awards", a.SessionUUID, team.Members[0].UUID), bytes.NewReader(marshalled), nil)
if err != nil { if err != nil {
return err return err
} }

View file

@ -16,6 +16,8 @@ import (
"time" "time"
"gopkg.in/fsnotify.v1" "gopkg.in/fsnotify.v1"
"srs.epita.fr/fic-server/libfic"
) )
var ( var (
@ -77,12 +79,8 @@ func main() {
fd.Close() fd.Close()
} }
if v, exists := os.LookupEnv("AIRBUS_SESSIONID"); exists { if v, exists := os.LookupEnv("AIRBUS_SESSION_UUID"); exists {
var err error api.SessionUUID = v
api.SessionID, err = strconv.ParseInt(v, 10, 64)
if err != nil {
log.Fatal("AIRBUS_SESSIONID is invalid: ", err.Error())
}
} else if v, exists := os.LookupEnv("AIRBUS_SESSION_NAME_FILE"); exists { } else if v, exists := os.LookupEnv("AIRBUS_SESSION_NAME_FILE"); exists {
fd, err := os.Open(v) fd, err := os.Open(v)
if err != nil { if err != nil {
@ -101,15 +99,15 @@ func main() {
for _, session := range sessions { for _, session := range sessions {
if session.Name == v { if session.Name == v {
api.SessionID = session.ID api.SessionUUID = session.UUID
break break
} }
} }
if api.SessionID == 0 { if api.SessionUUID == "" {
log.Fatal("Session ID not found") log.Fatal("Session ID not found")
} else { } else {
log.Println("Session ID discovered: ", api.SessionID) log.Println("Session ID discovered: ", api.SessionUUID)
} }
} else if v, exists := os.LookupEnv("AIRBUS_SESSION_NAME"); exists { } else if v, exists := os.LookupEnv("AIRBUS_SESSION_NAME"); exists {
sessions, err := api.GetSessions() sessions, err := api.GetSessions()
@ -117,17 +115,19 @@ func main() {
log.Fatal("Unable to retrieve session: ", err) log.Fatal("Unable to retrieve session: ", err)
} }
found := false
for _, session := range sessions { for _, session := range sessions {
if session.Name == v { if session.Name == v {
api.SessionID = session.ID api.SessionUUID = session.UUID
found = true
break break
} }
} }
if api.SessionID == 0 { if !found {
log.Fatal("Session ID not found") log.Fatal("Session ID not found")
} else { } else {
log.Println("Session ID discovered: ", api.SessionID) log.Println("Session ID discovered: ", api.SessionUUID)
} }
} else { } else {
sessions, err := api.GetSessions() sessions, err := api.GetSessions()
@ -138,7 +138,7 @@ func main() {
log.Println("Please define your AIRBUS_SESSIONID or AIRBUS_SESSION_NAME.") log.Println("Please define your AIRBUS_SESSIONID or AIRBUS_SESSION_NAME.")
log.Println("Existing sessions are:") log.Println("Existing sessions are:")
for _, session := range sessions { for _, session := range sessions {
log.Printf(" - %d: %q", session.ID, session.Name) log.Printf(" - %s: %q", session.UUID, session.Name)
} }
os.Exit(1) os.Exit(1)
} }
@ -156,11 +156,11 @@ func main() {
} }
fmt.Println("## Airbus' registered teams:") fmt.Println("## Airbus' registered teams:")
fmt.Println("-------------------------------------------") fmt.Println("----------------------------------------------------------------------------------")
fmt.Println(" ID | Name | Nb. | Score | Rank") fmt.Println(" UUID | Name | Nb. | Score | Rank")
fmt.Println("-------------------------------------------") fmt.Println("----------------------------------------------------------------------------------")
for _, team := range teams { for _, team := range teams {
fmt.Printf("% 2d | % 15s | % 3d | % 5d | % 3d\n", team.ID, team.Name, len(team.Members), team.Score, team.Rank) fmt.Printf(" %s | % 20s | % 3d | % 5d | % 3d\n", team.UUID, team.Name, len(team.Members), team.Score, team.Rank)
} }
case "rank": case "rank":
teams, err := api.GetTeams() teams, err := api.GetTeams()
@ -169,7 +169,7 @@ func main() {
os.Exit(1) os.Exit(1)
} }
ranking := []*AirbusTeam{} ranking := []*fic.CyberrangeTeam{}
for _, team := range teams { for _, team := range teams {
tmp := team tmp := team
ranking = append(ranking, &tmp) ranking = append(ranking, &tmp)
@ -178,11 +178,11 @@ func main() {
sort.Sort(sort.Reverse(ByScore(ranking))) sort.Sort(sort.Reverse(ByScore(ranking)))
fmt.Println("## Airbus' ranking:") fmt.Println("## Airbus' ranking:")
fmt.Println("-------------------------------------") fmt.Println("----------------------------------------------------------------------------")
fmt.Println(" Rank | Name | ID | Score") fmt.Println(" Rank | Name | UUID | Score")
fmt.Println("-------------------------------------") fmt.Println("----------------------------------------------------------------------------")
for _, team := range ranking { for _, team := range ranking {
fmt.Printf("% 5d | % 15s |% 3d | % 5d\n", team.Rank, team.Name, team.ID, team.Score) fmt.Printf("% 5d | % 20s | %s | % 5d\n", team.Rank, team.Name, team.UUID, team.Score)
} }
case "get": case "get":
teams, err := api.GetTeams() teams, err := api.GetTeams()
@ -191,22 +191,18 @@ func main() {
os.Exit(1) os.Exit(1)
} }
teamid, err := strconv.ParseInt(args[1], 10, 64) teamid := args[1]
if err != nil {
log.Println(err)
os.Exit(1)
}
for _, team := range teams { for _, team := range teams {
if team.ID == teamid { if team.UUID == teamid {
fmt.Printf("## Airbus' registered team %d:\n\nID: %d\nName: %s\nScore: %d\nRank: %d\nMembers:\n", teamid, team.ID, team.Name, team.Score, team.Rank) fmt.Printf("## Airbus' registered team %s:\n\nUUID: %s\nName: %s\nScore: %d\nRank: %d\nMembers:\n", teamid, team.UUID, team.Name, team.Score, team.Rank)
for _, member := range team.Members { for _, member := range team.Members {
fmt.Printf(" - ID: %d\n Name: %s\n Nickname: %s\n E-mail: %s\n", member.ID, member.Name, member.Nickname, member.EMail) fmt.Printf(" - UUID: %s\n Name: %s\n Nickname: %s\n E-mail: %s\n", member.UUID, member.Name, member.Nickname, member.EMail)
} }
os.Exit(0) os.Exit(0)
} }
} }
fmt.Printf("Team %d not found. Use 'list' to view all existing teams\n", teamid) fmt.Printf("Team %s not found. Use 'list' to view all existing teams\n", teamid)
case "award": case "award":
if len(args) < 3 { if len(args) < 3 {
fmt.Println("award <TEAM_ID> <VALUE> <MESSAGE>") fmt.Println("award <TEAM_ID> <VALUE> <MESSAGE>")
@ -219,11 +215,7 @@ func main() {
os.Exit(1) os.Exit(1)
} }
teamid, err := strconv.ParseInt(args[1], 10, 64) teamid := args[1]
if err != nil {
log.Println("Invalid team id", err)
os.Exit(1)
}
value, err := strconv.ParseInt(args[2], 10, 64) value, err := strconv.ParseInt(args[2], 10, 64)
if err != nil { if err != nil {
@ -232,7 +224,7 @@ func main() {
} }
for _, team := range teams { for _, team := range teams {
if team.ID == teamid { if team.UUID == teamid {
err = api.AwardUser(&team, value, strings.Join(args[3:], " ")) err = api.AwardUser(&team, value, strings.Join(args[3:], " "))
if err != nil { if err != nil {
log.Println("Unable to award team:", err) log.Println("Unable to award team:", err)
@ -243,7 +235,7 @@ func main() {
os.Exit(0) os.Exit(0)
} }
} }
fmt.Printf("Team %d not found. Use 'list' to view all existing teams\n", teamid) fmt.Printf("Team %s not found. Use 'list' to view all existing teams\n", teamid)
} }
os.Exit(0) os.Exit(0)

View file

@ -1,12 +1,18 @@
package main package main
import () import (
"time"
)
type Session struct { type Session struct {
Name string `json:"name"` Name string `json:"name"`
Status string `json:"status"` QuestionValidation string `json:"question_validation"`
ID int64 `json:"id"` Status string `json:"status"`
Mode string `json:"mode"` UUID string `json:"uuid"`
Mode string `json:"mode"`
Difficulty int `json:"difficulty"`
StartedAt time.Time `json:"start_at"`
FinishAt time.Time `json:"finish_at"`
} }
func (a *AirbusAPI) GetSessions() (ret []Session, err error) { func (a *AirbusAPI) GetSessions() (ret []Session, err error) {

View file

@ -2,44 +2,27 @@ package main
import ( import (
"fmt" "fmt"
"srs.epita.fr/fic-server/libfic"
) )
type AirbusTeam struct { func (a *AirbusAPI) GetTeams() ([]fic.CyberrangeTeam, error) {
ID int64 `json:"id"` var data []fic.CyberrangeTeam
Members []TeamMember `json:"members"` err := a.request("GET", fmt.Sprintf("/v1/sessions/%s/teams", a.SessionUUID), nil, &data)
Name string `json:"name"`
Score int64 `json:"score"`
Rank int `json:"rank"`
}
type TeamMember struct {
ID int64 `json:"id"`
Name string `json:"name"`
Nickname string `json:"nickname"`
EMail string `json:"email"`
}
type airbusDataTeam struct {
Data []AirbusTeam `json:"data"`
}
func (a *AirbusAPI) GetTeams() ([]AirbusTeam, error) {
var data airbusDataTeam
err := a.request("GET", fmt.Sprintf("/v1/sessions/%d/teams", a.SessionID), nil, &data)
if err != nil { if err != nil {
return nil, err return nil, err
} else { } else {
return data.Data, nil return data, nil
} }
} }
type ByRank []*AirbusTeam type ByRank []*fic.CyberrangeTeam
func (a ByRank) Len() int { return len(a) } func (a ByRank) Len() int { return len(a) }
func (a ByRank) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func (a ByRank) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByRank) Less(i, j int) bool { return a[i].Rank < a[j].Rank } func (a ByRank) Less(i, j int) bool { return a[i].Rank < a[j].Rank }
type ByScore []*AirbusTeam type ByScore []*fic.CyberrangeTeam
func (a ByScore) Len() int { return len(a) } func (a ByScore) Len() int { return len(a) }
func (a ByScore) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func (a ByScore) Swap(i, j int) { a[i], a[j] = a[j], a[i] }

View file

@ -1,102 +0,0 @@
[
{
"name": "#D\u00e9fendonsEnsemble",
"score": 0
},
{
"name": "Les Pires Hat",
"score": 0
},
{
"name": "Esnarcotrafiquants",
"score": 0
},
{
"name": "Quarkslab",
"score": 0
},
{
"name": "HackademINT",
"score": 0
},
{
"name": "Phreaks 2600",
"score": 0
},
{
"name": "Rhackgondins",
"score": 0
},
{
"name": "Team France",
"score": 0
},
{
"name": "Hack UTT",
"score": 0
},
{
"name": "HDRF",
"score": 0
},
{
"name": "#199",
"score": 0
},
{
"name": "Hackday",
"score": 0
},
{
"name": "GCC",
"score": 0
},
{
"name": "Apeltek",
"score": 0
},
{
"name": "Hackvengers",
"score": 0
},
{
"name": "Guardia Cyber Squad",
"score": 0
},
{
"name": "F0r3nS0C",
"score": 0
},
{
"name": "Oteriack",
"score": 0
},
{
"name": "Cervelles de Canuts",
"score": 0
},
{
"name": "Next'H4ck",
"score": 0
},
{
"name": "Overflowl",
"score": 0
},
{
"name": "Capgemini Aces of Spades",
"score": 0
},
{
"name": "DLS",
"score": 0
},
{
"name": "ESGI",
"score": 0
},
{
"name": "0xECE",
"score": 0
}
]

View file

@ -5,6 +5,8 @@ import (
"log" "log"
"os" "os"
"time" "time"
"srs.epita.fr/fic-server/libfic"
) )
type TSValue struct { type TSValue struct {
@ -32,7 +34,7 @@ func loadTS(tspath string) (timestamp map[string]*TSValue, err error) {
} }
} }
func loadTSFromAPI(teams map[string]*AirbusTeam) (timestamp map[string]*TSValue, err error) { func loadTSFromAPI(teams map[string]*fic.CyberrangeTeam) (timestamp map[string]*TSValue, err error) {
now := time.Now() now := time.Now()
timestamp = map[string]*TSValue{} timestamp = map[string]*TSValue{}

View file

@ -23,7 +23,7 @@ type Walker struct {
Exercices AirbusExercicesBindings Exercices AirbusExercicesBindings
Teams map[string]fic.ExportedTeam Teams map[string]fic.ExportedTeam
RevTeams map[string]string RevTeams map[string]string
TeamBindings map[string]*AirbusTeam TeamBindings map[string]*fic.CyberrangeTeam
API AirbusAPI API AirbusAPI
Coeff float64 Coeff float64
} }
@ -35,11 +35,11 @@ func (w *Walker) fetchTeams() error {
} }
w.RevTeams = map[string]string{} w.RevTeams = map[string]string{}
w.TeamBindings = map[string]*AirbusTeam{} w.TeamBindings = map[string]*fic.CyberrangeTeam{}
for tid, team := range w.Teams { for tid, team := range w.Teams {
for i, t := range teams { for i, t := range teams {
if team.Name == t.Name || team.ExternalId == t.Name { if team.Name == t.Name || team.ExternalId == t.Name || team.ExternalId == t.UUID {
w.TeamBindings[tid] = &teams[i] w.TeamBindings[tid] = &teams[i]
break break
} }
@ -143,7 +143,7 @@ func (w *Walker) WalkScore(path string, d os.DirEntry, err error) error {
return nil return nil
} }
func (w *Walker) TreatScoreGrid(path string, airbusTeam *AirbusTeam) error { func (w *Walker) TreatScoreGrid(path string, airbusTeam *fic.CyberrangeTeam) error {
// Read score grid // Read score grid
fdscores, err := os.Open(path) fdscores, err := os.Open(path)
if err != nil { if err != nil {