Compare commits

..

18 Commits

Author SHA1 Message Date
5a670d99ca chore(deps): update module github.com/go-git/go-git/v5 to v5.13.2 2025-02-05 02:53:38 +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
24 changed files with 724 additions and 300 deletions

View File

@ -62,6 +62,8 @@ func declareExercicesRoutes(router *gin.RouterGroup) {
apiFlagsRoutes.POST("/try", tryExerciceFlag)
apiFlagsRoutes.DELETE("/", deleteExerciceFlag)
apiFlagsRoutes.GET("/dependancies", showExerciceFlagDeps)
apiFlagsRoutes.GET("/statistics", showExerciceFlagStats)
apiFlagsRoutes.DELETE("/tries", deleteExerciceFlagTries)
apiFlagsRoutes.GET("/choices/", listFlagChoices)
apiFlagsChoicesRoutes := apiExercicesRoutes.Group("/choices/:cid")
apiFlagsChoicesRoutes.Use(FlagChoiceHandler)
@ -77,6 +79,8 @@ func declareExercicesRoutes(router *gin.RouterGroup) {
apiQuizRoutes.PUT("", updateExerciceQuiz)
apiQuizRoutes.DELETE("", deleteExerciceQuiz)
apiQuizRoutes.GET("/dependancies", showExerciceQuizDeps)
apiQuizRoutes.GET("/statistics", showExerciceQuizStats)
apiQuizRoutes.DELETE("/tries", deleteExerciceQuizTries)
apiExercicesRoutes.GET("/tags", listExerciceTags)
apiExercicesRoutes.POST("/tags", addExerciceTag)
@ -852,6 +856,60 @@ func showExerciceFlagDeps(c *gin.Context) {
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) {
flag := c.MustGet("flag-key").(*fic.FlagKey)
@ -1022,6 +1080,60 @@ func showExerciceQuizDeps(c *gin.Context) {
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) {
quiz := c.MustGet("flag-quiz").(*fic.MCQ)

View File

@ -348,6 +348,9 @@ angular.module("FICApp")
.factory("ExerciceFlagDeps", function ($resource) {
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) {
return $resource("api/exercices/:exerciceId/quiz/:mcqId", { exerciceId: '@idExercice', mcqId: '@id' }, {
update: { method: 'PUT' }
@ -355,6 +358,9 @@ angular.module("FICApp")
})
.factory("ExerciceMCQDeps", function ($resource) {
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")
@ -611,9 +617,18 @@ angular.module("FICApp")
response.enableExerciceDepend = response.unlockedChallengeDepth >= 0;
response.disabledsubmitbutton = response.disablesubmitbutton && response.disablesubmitbutton.length > 0;
if (response.end) {
$scope.duration = (response.end - response.start)/60000;
}
})
$scope.challenge = SettingsChallenge.get();
$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.challenge.$promise.then(function (c) {
if (c.duration)
@ -648,7 +663,7 @@ angular.module("FICApp")
$scope.saveChallengeInfo = function () {
this.challenge.duration = $scope.duration;
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) {
$scope.addToast('danger', 'An error occurs when saving challenge info:', response.data.errmsg);
});
@ -722,9 +737,9 @@ angular.module("FICApp")
"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.",
}
$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 () {
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) {
$scope.addToast('success', type + 'reseted');
$location.url("/");
@ -736,7 +751,7 @@ angular.module("FICApp")
});
};
$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 () {
$http.put("api/prod", true).then(function (time) {
$rootScope.refreshSettings()
@ -759,6 +774,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', {
bindings: {
repository: '<',
@ -820,10 +849,10 @@ angular.module("FICApp")
$scope.deepSync = function (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
} else {
question = 'Faire une synchronisation intégrale ?'
question = 'Faire une synchronisation intégrale?'
url = "api/sync/deep"
}
$scope.addToast('warning', question, '',
@ -839,7 +868,7 @@ angular.module("FICApp")
});
};
$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 () {
$scope.deepSyncInProgress = true;
$http.post("api/sync/speed").then(function () {
@ -852,7 +881,7 @@ angular.module("FICApp")
});
};
$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 () {
$scope.deepSyncInProgress = true;
$http.post("api/sync/base").then(function () {
@ -865,7 +894,7 @@ angular.module("FICApp")
});
};
$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 () {
$scope.deepSyncInProgress = true;
$http.post("api/sync/videos").then(function () {
@ -1110,7 +1139,7 @@ angular.module("FICApp")
},
{
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 = [
@ -1229,8 +1258,8 @@ angular.module("FICApp")
show: true,
shadow: "#E8CF5C",
end: new Date($rootScope.getSrvTime().getTime() + 1802000).toISOString(),
before: "Heure joyeuse : chaque résolution compte double !",
after: "Heure joyeuse terminée !",
before: "Heure joyeuse: chaque résolution compte double!",
after: "Heure joyeuse terminée!",
}
}
else if (scene == "freehintquarter") {
@ -1238,8 +1267,8 @@ angular.module("FICApp")
show: true,
shadow: "#3DD28F",
end: new Date($rootScope.getSrvTime().getTime() + 902000).toISOString(),
before: "Quart d'heure facile : indices dévoilés !",
after: "Quart d'heure facile terminée !",
before: "Quart d'heure facile: indices dévoilés!",
after: "Quart d'heure facile terminée!",
}
}
};
@ -1368,7 +1397,7 @@ angular.module("FICApp")
});
};
$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 () {
$scope.clearFilesWIP = true;
$http({
@ -2276,7 +2305,7 @@ angular.module("FICApp")
method: "POST"
}).then(function (response) {
flag.test_str = "";
$scope.addToast('success', "Flag Ok !");
$scope.addToast('success', "Flag Ok!");
}, function (response) {
flag.test_str = "";
$scope.addToast('danger', 'An error occurs: ', response.data.errmsg);
@ -2345,6 +2374,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) {
$scope.quiz = ExerciceMCQFlag.query({ exerciceId: $routeParams.exerciceId });
@ -2382,6 +2423,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) {
$scope.teams = Team.query();
$scope.fields = ["id", "name"];

View File

@ -73,12 +73,28 @@
</div>
<div class="col-4">
<div ng-controller="ExerciceFlagDepsController" ng-init="init(flag)">
Dépendances&nbsp;:
<strong>Dépendances&nbsp;:</strong>
<ul ng-if="deps.length > 0">
<dependancy ng-repeat="dep in deps" dep="dep"></dependancy>
</ul>
<span ng-if="deps.length == 0"> sans</span>
</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 class="col-4" ng-controller="ExerciceFlagChoicesController">
<div class="btn-toolbar justify-content-end mb-2" role="toolbar">
@ -168,6 +184,22 @@
<dependancy ng-repeat="dep in deps" dep="dep"></dependancy>
</ul>
<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>
</form>
</div>

View File

@ -30,13 +30,13 @@
<div class="spinner-border spinner-border-sm" role="status" ng-if="file.gunzipWIP"></div>
</button>
</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] }}
<span ng-if="field == 'id' && file.err !== undefined && file.err !== true" title="{{ file.err }}" class="glyphicon glyphicon-exclamation-sign"></span>
</td>
<td>
{{ file.checksum | bto16 }}
<div ng-if="file.checksum_shown">{{ file.checksum_shown | bto16 }}</div>
<td style="max-width: 100px">
<div class="text-truncate" title="{{ file.checksum | bto16 }}">{{ file.checksum | bto16 }}</div>
<div class="text-truncate" ng-if="file.checksum_shown" title="{{ file.checksum_shown | bto16 }}">{{ file.checksum_shown | bto16 }}</div>
</td>
</tr>
</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>
<div class="col-sm-9">
<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">
<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>
@ -46,14 +46,14 @@
<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>
<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 class="col-sm-1 text-right">
<label for="duration" class="col-form-label col-form-label-sm">Durée</label>
</div>
<div class="col-sm-2">
<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">
<span class="input-group-text">min</span>
</div>

View File

@ -279,6 +279,7 @@ func buildKeyFlag(exercice *fic.Exercice, flag ExerciceFlag, flagline int, defau
}
type importFlag struct {
origin ExerciceFlag
Line int
Flag fic.Flag
JustifyOf *fic.MCQ_entry
@ -392,8 +393,9 @@ func buildExerciceFlag(i Importer, exercice *fic.Exercice, flag ExerciceFlag, nl
errs = multierr.Append(errs, berrs)
if addedFlag != nil {
ret = append(ret, importFlag{
Line: nline + 1,
Flag: addedFlag,
origin: flag,
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" {
@ -401,6 +403,7 @@ func buildExerciceFlag(i Importer, exercice *fic.Exercice, flag ExerciceFlag, nl
errs = multierr.Append(errs, berrs)
if addedFlag != nil {
ret = append(ret, importFlag{
origin: flag,
Line: nline + 1,
Flag: *addedFlag,
Choices: choices,
@ -462,6 +465,7 @@ func buildExerciceFlag(i Importer, exercice *fic.Exercice, flag ExerciceFlag, nl
errs = multierr.Append(errs, berrs)
if addedFlag != nil {
ret = append(ret, importFlag{
origin: flag,
Line: nline + 1,
Flag: *addedFlag,
JustifyOf: entry,
@ -479,8 +483,9 @@ func buildExerciceFlag(i Importer, exercice *fic.Exercice, flag ExerciceFlag, nl
}
ret = append([]importFlag{importFlag{
Line: nline + 1,
Flag: &addedFlag,
origin: flag,
Line: nline + 1,
Flag: &addedFlag,
}}, ret...)
}
return
@ -570,6 +575,10 @@ func CheckExerciceFlags(i Importer, exercice *fic.Exercice, files []string, exce
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")))
}
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

View File

@ -20,6 +20,8 @@ escape_newline () {
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 ]
then
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}" ] && {
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
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 "Metadata drive not erased"
echo

View File

@ -153,6 +153,15 @@ onboot:
mkdir:
- /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:
# - name: getty
# image: linuxkit/getty:bae9e3d4861173bacf78f14a4fe44997a430d13b
@ -228,7 +237,7 @@ services:
- /var/lib/fic/generator:/srv/GENERATOR:ro
- /var/lib/fic/pki:/srv/PKI
- /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/teams:/srv/TEAMS
net: /run/netns/fic-admin
@ -269,7 +278,10 @@ services:
binds:
- /etc/hosts:/etc/hosts:ro
- /var/lib/fic/generator:/srv/GENERATOR:ro
# Uncomment this to disallow registrations
- /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/settingsdist:/srv/SETTINGSDIST:ro
- /var/lib/fic/submissions:/srv/submissions
@ -361,7 +373,6 @@ services:
- /var/lib/fic/files
- /var/lib/fic/pki/shared
- /var/lib/fic/settingsdist
- /var/lib/fic/ssh
- /var/lib/fic/submissions
- /var/lib/fic/teams
- /var/log/frontend

View File

@ -136,6 +136,15 @@ onboot:
- /etc/iptables/rules.v6:/etc/iptables/rules.v6:ro
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:
# - name: getty
# image: linuxkit/getty:bae9e3d4861173bacf78f14a4fe44997a430d13b
@ -257,7 +266,6 @@ services:
- /var/lib/fic/files
- /var/lib/fic/pki
- /var/lib/fic/settingsdist
- /var/lib/fic/ssh
- /var/lib/fic/submissions
- /var/lib/fic/teams

View File

@ -7,9 +7,9 @@ kernel:
init:
- nemunaire/mdadm:04814350d71ba9417e1f861be1685de26adf7a67
- nemunaire/syslinux:086f221f281d577d300949aa1094fb20c5cd90dc
- linuxkit/format:3c858f0cf42a2b14441bfb5c266b78f14d2b75a4
- linuxkit/dm-crypt:19fa6affe9da03afc91694e36d72a4924c65a0e0
- linuxkit/metadata:f35b5aafc7d19bb6a44a900840727902dad78e44
- linuxkit/format:8f487d728959192289e0783784fc2b185eadbc82
- linuxkit/dm-crypt:ad2a05dcffa28ef809a61aa27ba230c82f02f603
- linuxkit/metadata:83cda7b43112b201613084ea8b7fab585b6e5549
- alpine:latest
files:

View File

@ -533,9 +533,9 @@
}
},
"node_modules/@eslint/js": {
"version": "9.18.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.18.0.tgz",
"integrity": "sha512-fK6L7rxcq6/z+AaQMtiFTkvbHkBLNlwyRxHpKawP0x3u9+NC6MQTnFW+AdpwC6gfHTW0051cokQgtTN2FqlxQA==",
"version": "9.19.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.19.0.tgz",
"integrity": "sha512-rbq9/g38qjfqFLOVPvwjIvFFdNziEC5S65jmjPw5r6A//QH+W91akh9irMwjDN8zKUTak6W9EsAv4m/7Wnw0UQ==",
"dev": true,
"license": "MIT",
"engines": {
@ -681,9 +681,9 @@
}
},
"node_modules/@parcel/watcher": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.0.tgz",
"integrity": "sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ==",
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz",
"integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
@ -702,25 +702,25 @@
"url": "https://opencollective.com/parcel"
},
"optionalDependencies": {
"@parcel/watcher-android-arm64": "2.5.0",
"@parcel/watcher-darwin-arm64": "2.5.0",
"@parcel/watcher-darwin-x64": "2.5.0",
"@parcel/watcher-freebsd-x64": "2.5.0",
"@parcel/watcher-linux-arm-glibc": "2.5.0",
"@parcel/watcher-linux-arm-musl": "2.5.0",
"@parcel/watcher-linux-arm64-glibc": "2.5.0",
"@parcel/watcher-linux-arm64-musl": "2.5.0",
"@parcel/watcher-linux-x64-glibc": "2.5.0",
"@parcel/watcher-linux-x64-musl": "2.5.0",
"@parcel/watcher-win32-arm64": "2.5.0",
"@parcel/watcher-win32-ia32": "2.5.0",
"@parcel/watcher-win32-x64": "2.5.0"
"@parcel/watcher-android-arm64": "2.5.1",
"@parcel/watcher-darwin-arm64": "2.5.1",
"@parcel/watcher-darwin-x64": "2.5.1",
"@parcel/watcher-freebsd-x64": "2.5.1",
"@parcel/watcher-linux-arm-glibc": "2.5.1",
"@parcel/watcher-linux-arm-musl": "2.5.1",
"@parcel/watcher-linux-arm64-glibc": "2.5.1",
"@parcel/watcher-linux-arm64-musl": "2.5.1",
"@parcel/watcher-linux-x64-glibc": "2.5.1",
"@parcel/watcher-linux-x64-musl": "2.5.1",
"@parcel/watcher-win32-arm64": "2.5.1",
"@parcel/watcher-win32-ia32": "2.5.1",
"@parcel/watcher-win32-x64": "2.5.1"
}
},
"node_modules/@parcel/watcher-android-arm64": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.0.tgz",
"integrity": "sha512-qlX4eS28bUcQCdribHkg/herLe+0A9RyYC+mm2PXpncit8z5b3nSqGVzMNR3CmtAOgRutiZ02eIJJgP/b1iEFQ==",
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz",
"integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==",
"cpu": [
"arm64"
],
@ -739,9 +739,9 @@
}
},
"node_modules/@parcel/watcher-darwin-arm64": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.0.tgz",
"integrity": "sha512-hyZ3TANnzGfLpRA2s/4U1kbw2ZI4qGxaRJbBH2DCSREFfubMswheh8TeiC1sGZ3z2jUf3s37P0BBlrD3sjVTUw==",
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz",
"integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==",
"cpu": [
"arm64"
],
@ -760,9 +760,9 @@
}
},
"node_modules/@parcel/watcher-darwin-x64": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.0.tgz",
"integrity": "sha512-9rhlwd78saKf18fT869/poydQK8YqlU26TMiNg7AIu7eBp9adqbJZqmdFOsbZ5cnLp5XvRo9wcFmNHgHdWaGYA==",
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz",
"integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==",
"cpu": [
"x64"
],
@ -781,9 +781,9 @@
}
},
"node_modules/@parcel/watcher-freebsd-x64": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.0.tgz",
"integrity": "sha512-syvfhZzyM8kErg3VF0xpV8dixJ+RzbUaaGaeb7uDuz0D3FK97/mZ5AJQ3XNnDsXX7KkFNtyQyFrXZzQIcN49Tw==",
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz",
"integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==",
"cpu": [
"x64"
],
@ -802,9 +802,9 @@
}
},
"node_modules/@parcel/watcher-linux-arm-glibc": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.0.tgz",
"integrity": "sha512-0VQY1K35DQET3dVYWpOaPFecqOT9dbuCfzjxoQyif1Wc574t3kOSkKevULddcR9znz1TcklCE7Ht6NIxjvTqLA==",
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz",
"integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==",
"cpu": [
"arm"
],
@ -823,9 +823,9 @@
}
},
"node_modules/@parcel/watcher-linux-arm-musl": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.0.tgz",
"integrity": "sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==",
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz",
"integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==",
"cpu": [
"arm"
],
@ -844,9 +844,9 @@
}
},
"node_modules/@parcel/watcher-linux-arm64-glibc": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.0.tgz",
"integrity": "sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==",
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz",
"integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==",
"cpu": [
"arm64"
],
@ -865,9 +865,9 @@
}
},
"node_modules/@parcel/watcher-linux-arm64-musl": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.0.tgz",
"integrity": "sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==",
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz",
"integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==",
"cpu": [
"arm64"
],
@ -886,9 +886,9 @@
}
},
"node_modules/@parcel/watcher-linux-x64-glibc": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.0.tgz",
"integrity": "sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==",
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz",
"integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==",
"cpu": [
"x64"
],
@ -907,9 +907,9 @@
}
},
"node_modules/@parcel/watcher-linux-x64-musl": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.0.tgz",
"integrity": "sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==",
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz",
"integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==",
"cpu": [
"x64"
],
@ -928,9 +928,9 @@
}
},
"node_modules/@parcel/watcher-win32-arm64": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.0.tgz",
"integrity": "sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==",
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz",
"integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==",
"cpu": [
"arm64"
],
@ -949,9 +949,9 @@
}
},
"node_modules/@parcel/watcher-win32-ia32": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.0.tgz",
"integrity": "sha512-+rgpsNRKwo8A53elqbbHXdOMtY/tAtTzManTWShB5Kk54N8Q9mzNWV7tV+IbGueCbcj826MfWGU3mprWtuf1TA==",
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz",
"integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==",
"cpu": [
"ia32"
],
@ -970,9 +970,9 @@
}
},
"node_modules/@parcel/watcher-win32-x64": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.0.tgz",
"integrity": "sha512-lPrxve92zEHdgeff3aiu4gDOIt4u7sJYha6wbdEZDCDUhtjTsOMiaJzG5lMY4GkWH8p0fMmO2Ppq5G5XXG+DQw==",
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz",
"integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==",
"cpu": [
"x64"
],
@ -1008,9 +1008,9 @@
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.30.1.tgz",
"integrity": "sha512-pSWY+EVt3rJ9fQ3IqlrEUtXh3cGqGtPDH1FQlNZehO2yYxCHEX1SPsz1M//NXwYfbTlcKr9WObLnJX9FsS9K1Q==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.32.0.tgz",
"integrity": "sha512-G2fUQQANtBPsNwiVFg4zKiPQyjVKZCUdQUol53R8E71J7AsheRMV/Yv/nB8giOcOVqP7//eB5xPqieBYZe9bGg==",
"cpu": [
"arm"
],
@ -1022,9 +1022,9 @@
]
},
"node_modules/@rollup/rollup-android-arm64": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.30.1.tgz",
"integrity": "sha512-/NA2qXxE3D/BRjOJM8wQblmArQq1YoBVJjrjoTSBS09jgUisq7bqxNHJ8kjCHeV21W/9WDGwJEWSN0KQ2mtD/w==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.32.0.tgz",
"integrity": "sha512-qhFwQ+ljoymC+j5lXRv8DlaJYY/+8vyvYmVx074zrLsu5ZGWYsJNLjPPVJJjhZQpyAKUGPydOq9hRLLNvh1s3A==",
"cpu": [
"arm64"
],
@ -1036,9 +1036,9 @@
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.30.1.tgz",
"integrity": "sha512-r7FQIXD7gB0WJ5mokTUgUWPl0eYIH0wnxqeSAhuIwvnnpjdVB8cRRClyKLQr7lgzjctkbp5KmswWszlwYln03Q==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.32.0.tgz",
"integrity": "sha512-44n/X3lAlWsEY6vF8CzgCx+LQaoqWGN7TzUfbJDiTIOjJm4+L2Yq+r5a8ytQRGyPqgJDs3Rgyo8eVL7n9iW6AQ==",
"cpu": [
"arm64"
],
@ -1050,9 +1050,9 @@
]
},
"node_modules/@rollup/rollup-darwin-x64": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.30.1.tgz",
"integrity": "sha512-x78BavIwSH6sqfP2xeI1hd1GpHL8J4W2BXcVM/5KYKoAD3nNsfitQhvWSw+TFtQTLZ9OmlF+FEInEHyubut2OA==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.32.0.tgz",
"integrity": "sha512-F9ct0+ZX5Np6+ZDztxiGCIvlCaW87HBdHcozUfsHnj1WCUTBUubAoanhHUfnUHZABlElyRikI0mgcw/qdEm2VQ==",
"cpu": [
"x64"
],
@ -1064,9 +1064,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.30.1.tgz",
"integrity": "sha512-HYTlUAjbO1z8ywxsDFWADfTRfTIIy/oUlfIDmlHYmjUP2QRDTzBuWXc9O4CXM+bo9qfiCclmHk1x4ogBjOUpUQ==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.32.0.tgz",
"integrity": "sha512-JpsGxLBB2EFXBsTLHfkZDsXSpSmKD3VxXCgBQtlPcuAqB8TlqtLcbeMhxXQkCDv1avgwNjF8uEIbq5p+Cee0PA==",
"cpu": [
"arm64"
],
@ -1078,9 +1078,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.30.1.tgz",
"integrity": "sha512-1MEdGqogQLccphhX5myCJqeGNYTNcmTyaic9S7CG3JhwuIByJ7J05vGbZxsizQthP1xpVx7kd3o31eOogfEirw==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.32.0.tgz",
"integrity": "sha512-wegiyBT6rawdpvnD9lmbOpx5Sph+yVZKHbhnSP9MqUEDX08G4UzMU+D87jrazGE7lRSyTRs6NEYHtzfkJ3FjjQ==",
"cpu": [
"x64"
],
@ -1092,9 +1092,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.30.1.tgz",
"integrity": "sha512-PaMRNBSqCx7K3Wc9QZkFx5+CX27WFpAMxJNiYGAXfmMIKC7jstlr32UhTgK6T07OtqR+wYlWm9IxzennjnvdJg==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.32.0.tgz",
"integrity": "sha512-3pA7xecItbgOs1A5H58dDvOUEboG5UfpTq3WzAdF54acBbUM+olDJAPkgj1GRJ4ZqE12DZ9/hNS2QZk166v92A==",
"cpu": [
"arm"
],
@ -1106,9 +1106,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.30.1.tgz",
"integrity": "sha512-B8Rcyj9AV7ZlEFqvB5BubG5iO6ANDsRKlhIxySXcF1axXYUyqwBok+XZPgIYGBgs7LDXfWfifxhw0Ik57T0Yug==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.32.0.tgz",
"integrity": "sha512-Y7XUZEVISGyge51QbYyYAEHwpGgmRrAxQXO3siyYo2kmaj72USSG8LtlQQgAtlGfxYiOwu+2BdbPjzEpcOpRmQ==",
"cpu": [
"arm"
],
@ -1120,9 +1120,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.30.1.tgz",
"integrity": "sha512-hqVyueGxAj3cBKrAI4aFHLV+h0Lv5VgWZs9CUGqr1z0fZtlADVV1YPOij6AhcK5An33EXaxnDLmJdQikcn5NEw==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.32.0.tgz",
"integrity": "sha512-r7/OTF5MqeBrZo5omPXcTnjvv1GsrdH8a8RerARvDFiDwFpDVDnJyByYM/nX+mvks8XXsgPUxkwe/ltaX2VH7w==",
"cpu": [
"arm64"
],
@ -1134,9 +1134,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.30.1.tgz",
"integrity": "sha512-i4Ab2vnvS1AE1PyOIGp2kXni69gU2DAUVt6FSXeIqUCPIR3ZlheMW3oP2JkukDfu3PsexYRbOiJrY+yVNSk9oA==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.32.0.tgz",
"integrity": "sha512-HJbifC9vex9NqnlodV2BHVFNuzKL5OnsV2dvTw6e1dpZKkNjPG6WUq+nhEYV6Hv2Bv++BXkwcyoGlXnPrjAKXw==",
"cpu": [
"arm64"
],
@ -1148,9 +1148,9 @@
]
},
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.30.1.tgz",
"integrity": "sha512-fARcF5g296snX0oLGkVxPmysetwUk2zmHcca+e9ObOovBR++9ZPOhqFUM61UUZ2EYpXVPN1redgqVoBB34nTpQ==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.32.0.tgz",
"integrity": "sha512-VAEzZTD63YglFlWwRj3taofmkV1V3xhebDXffon7msNz4b14xKsz7utO6F8F4cqt8K/ktTl9rm88yryvDpsfOw==",
"cpu": [
"loong64"
],
@ -1162,9 +1162,9 @@
]
},
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.30.1.tgz",
"integrity": "sha512-GLrZraoO3wVT4uFXh67ElpwQY0DIygxdv0BNW9Hkm3X34wu+BkqrDrkcsIapAY+N2ATEbvak0XQ9gxZtCIA5Rw==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.32.0.tgz",
"integrity": "sha512-Sts5DST1jXAc9YH/iik1C9QRsLcCoOScf3dfbY5i4kH9RJpKxiTBXqm7qU5O6zTXBTEZry69bGszr3SMgYmMcQ==",
"cpu": [
"ppc64"
],
@ -1176,9 +1176,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.30.1.tgz",
"integrity": "sha512-0WKLaAUUHKBtll0wvOmh6yh3S0wSU9+yas923JIChfxOaaBarmb/lBKPF0w/+jTVozFnOXJeRGZ8NvOxvk/jcw==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.32.0.tgz",
"integrity": "sha512-qhlXeV9AqxIyY9/R1h1hBD6eMvQCO34ZmdYvry/K+/MBs6d1nRFLm6BOiITLVI+nFAAB9kUB6sdJRKyVHXnqZw==",
"cpu": [
"riscv64"
],
@ -1190,9 +1190,9 @@
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.30.1.tgz",
"integrity": "sha512-GWFs97Ruxo5Bt+cvVTQkOJ6TIx0xJDD/bMAOXWJg8TCSTEK8RnFeOeiFTxKniTc4vMIaWvCplMAFBt9miGxgkA==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.32.0.tgz",
"integrity": "sha512-8ZGN7ExnV0qjXa155Rsfi6H8M4iBBwNLBM9lcVS+4NcSzOFaNqmt7djlox8pN1lWrRPMRRQ8NeDlozIGx3Omsw==",
"cpu": [
"s390x"
],
@ -1204,9 +1204,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.30.1.tgz",
"integrity": "sha512-UtgGb7QGgXDIO+tqqJ5oZRGHsDLO8SlpE4MhqpY9Llpzi5rJMvrK6ZGhsRCST2abZdBqIBeXW6WPD5fGK5SDwg==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.32.0.tgz",
"integrity": "sha512-VDzNHtLLI5s7xd/VubyS10mq6TxvZBp+4NRWoW+Hi3tgV05RtVm4qK99+dClwTN1McA6PHwob6DEJ6PlXbY83A==",
"cpu": [
"x64"
],
@ -1218,9 +1218,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.30.1.tgz",
"integrity": "sha512-V9U8Ey2UqmQsBT+xTOeMzPzwDzyXmnAoO4edZhL7INkwQcaW1Ckv3WJX3qrrp/VHaDkEWIBWhRwP47r8cdrOow==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.32.0.tgz",
"integrity": "sha512-qcb9qYDlkxz9DxJo7SDhWxTWV1gFuwznjbTiov289pASxlfGbaOD54mgbs9+z94VwrXtKTu+2RqwlSTbiOqxGg==",
"cpu": [
"x64"
],
@ -1232,9 +1232,9 @@
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.30.1.tgz",
"integrity": "sha512-WabtHWiPaFF47W3PkHnjbmWawnX/aE57K47ZDT1BXTS5GgrBUEpvOzq0FI0V/UYzQJgdb8XlhVNH8/fwV8xDjw==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.32.0.tgz",
"integrity": "sha512-pFDdotFDMXW2AXVbfdUEfidPAk/OtwE/Hd4eYMTNVVaCQ6Yl8et0meDaKNL63L44Haxv4UExpv9ydSf3aSayDg==",
"cpu": [
"arm64"
],
@ -1246,9 +1246,9 @@
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.30.1.tgz",
"integrity": "sha512-pxHAU+Zv39hLUTdQQHUVHf4P+0C47y/ZloorHpzs2SXMRqeAWmGghzAhfOlzFHHwjvgokdFAhC4V+6kC1lRRfw==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.32.0.tgz",
"integrity": "sha512-/TG7WfrCAjeRNDvI4+0AAMoHxea/USWhAzf9PVDFHbcqrQ7hMMKp4jZIy4VEjk72AAfN5k4TiSMRXRKf/0akSw==",
"cpu": [
"ia32"
],
@ -1260,9 +1260,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.30.1.tgz",
"integrity": "sha512-D6qjsXGcvhTjv0kI4fU8tUuBDF/Ueee4SVX79VfNDXZa64TfCW1Slkb6Z7O1p7vflqZjcmOVdZlqf8gvJxc6og==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.32.0.tgz",
"integrity": "sha512-5hqO5S3PTEO2E5VjCePxv40gIgyS2KvO7E7/vvC/NbIW4SIRamkMr1hqj+5Y67fbBWv/bQLB6KelBQmXlyCjWA==",
"cpu": [
"x64"
],
@ -1784,9 +1784,9 @@
}
},
"node_modules/eslint": {
"version": "9.18.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.18.0.tgz",
"integrity": "sha512-+waTfRWQlSbpt3KWE+CjrPPYnbq9kfZIYUqapc0uBXyjTp8aYXZDsUH16m39Ryq3NjAVP4tjuF7KaukeqoCoaA==",
"version": "9.19.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.19.0.tgz",
"integrity": "sha512-ug92j0LepKlbbEv6hD911THhoRHmbdXt2gX+VDABAW/Ir7D3nqKdv5Pf5vtlyY6HQMTEP2skXY43ueqTCWssEA==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -1795,7 +1795,7 @@
"@eslint/config-array": "^0.19.0",
"@eslint/core": "^0.10.0",
"@eslint/eslintrc": "^3.2.0",
"@eslint/js": "9.18.0",
"@eslint/js": "9.19.0",
"@eslint/plugin-kit": "^0.2.5",
"@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1",
@ -2606,9 +2606,9 @@
}
},
"node_modules/postcss": {
"version": "8.5.0",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.0.tgz",
"integrity": "sha512-27VKOqrYfPncKA2NrFOVhP5MGAfHKLYn/Q0mz9cNQyRAKYi3VNHwYU2qKKqPCqgBmeeJ0uAFB56NumXZ5ZReXg==",
"version": "8.5.1",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz",
"integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==",
"dev": true,
"funding": [
{
@ -2794,9 +2794,9 @@
}
},
"node_modules/rollup": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.30.1.tgz",
"integrity": "sha512-mlJ4glW020fPuLi7DkM/lN97mYEZGWeqBnrljzN0gs7GLctqX3lNWxKQ7Gl712UAX+6fog/L3jh4gb7R6aVi3w==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.32.0.tgz",
"integrity": "sha512-JmrhfQR31Q4AuNBjjAX4s+a/Pu/Q8Q9iwjWBsjRH1q52SPFE2NqRMK6fUZKKnvKO6id+h7JIRf0oYsph53eATg==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -2810,25 +2810,25 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.30.1",
"@rollup/rollup-android-arm64": "4.30.1",
"@rollup/rollup-darwin-arm64": "4.30.1",
"@rollup/rollup-darwin-x64": "4.30.1",
"@rollup/rollup-freebsd-arm64": "4.30.1",
"@rollup/rollup-freebsd-x64": "4.30.1",
"@rollup/rollup-linux-arm-gnueabihf": "4.30.1",
"@rollup/rollup-linux-arm-musleabihf": "4.30.1",
"@rollup/rollup-linux-arm64-gnu": "4.30.1",
"@rollup/rollup-linux-arm64-musl": "4.30.1",
"@rollup/rollup-linux-loongarch64-gnu": "4.30.1",
"@rollup/rollup-linux-powerpc64le-gnu": "4.30.1",
"@rollup/rollup-linux-riscv64-gnu": "4.30.1",
"@rollup/rollup-linux-s390x-gnu": "4.30.1",
"@rollup/rollup-linux-x64-gnu": "4.30.1",
"@rollup/rollup-linux-x64-musl": "4.30.1",
"@rollup/rollup-win32-arm64-msvc": "4.30.1",
"@rollup/rollup-win32-ia32-msvc": "4.30.1",
"@rollup/rollup-win32-x64-msvc": "4.30.1",
"@rollup/rollup-android-arm-eabi": "4.32.0",
"@rollup/rollup-android-arm64": "4.32.0",
"@rollup/rollup-darwin-arm64": "4.32.0",
"@rollup/rollup-darwin-x64": "4.32.0",
"@rollup/rollup-freebsd-arm64": "4.32.0",
"@rollup/rollup-freebsd-x64": "4.32.0",
"@rollup/rollup-linux-arm-gnueabihf": "4.32.0",
"@rollup/rollup-linux-arm-musleabihf": "4.32.0",
"@rollup/rollup-linux-arm64-gnu": "4.32.0",
"@rollup/rollup-linux-arm64-musl": "4.32.0",
"@rollup/rollup-linux-loongarch64-gnu": "4.32.0",
"@rollup/rollup-linux-powerpc64le-gnu": "4.32.0",
"@rollup/rollup-linux-riscv64-gnu": "4.32.0",
"@rollup/rollup-linux-s390x-gnu": "4.32.0",
"@rollup/rollup-linux-x64-gnu": "4.32.0",
"@rollup/rollup-linux-x64-musl": "4.32.0",
"@rollup/rollup-win32-arm64-msvc": "4.32.0",
"@rollup/rollup-win32-ia32-msvc": "4.32.0",
"@rollup/rollup-win32-x64-msvc": "4.32.0",
"fsevents": "~2.3.2"
}
},
@ -3184,9 +3184,9 @@
"license": "MIT"
},
"node_modules/vite": {
"version": "5.4.11",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz",
"integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==",
"version": "5.4.14",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.14.tgz",
"integrity": "sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==",
"dev": true,
"license": "MIT",
"dependencies": {

View File

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

6
go.mod
View File

@ -19,7 +19,7 @@ require (
gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b
go.uber.org/multierr v1.11.0
golang.org/x/crypto v0.32.0
golang.org/x/image v0.23.0
golang.org/x/image v0.24.0
golang.org/x/oauth2 v0.25.0
gopkg.in/fsnotify.v1 v1.4.7
)
@ -80,9 +80,9 @@ require (
golang.org/x/arch v0.8.0 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/net v0.34.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sync v0.11.0 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/text v0.22.0 // indirect
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.34.1 // indirect

6
go.sum
View File

@ -599,6 +599,8 @@ 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.23.0 h1:HseQ7c2OpPKTPVzNjG5fwJsOTCiiwS4QdsYi5XU6H68=
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/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.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
@ -730,6 +732,8 @@ 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.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
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/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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -861,6 +865,8 @@ 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.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
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/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-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -414,6 +414,7 @@ CREATE TABLE IF NOT EXISTS exercice_solved(
}
if _, err := db.Exec(`
CREATE TABLE IF NOT EXISTS exercice_tries(
id_try INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
id_exercice INTEGER NOT NULL,
id_team INTEGER 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_team) REFERENCES teams(id_team)
) 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 {
return err
}

View File

@ -3,6 +3,7 @@ package fic
import (
"errors"
"fmt"
"log"
"math"
"time"
)
@ -444,11 +445,25 @@ func (e *Exercice) GetOrdinal() (int, error) {
}
// NewTry registers a solving attempt for the given Team.
func (e *Exercice) NewTry(t *Team, cksum []byte) error {
if _, err := DBExec("INSERT INTO exercice_tries (id_exercice, id_team, time, cksum) VALUES (?, ?, ?, ?)", e.Id, t.Id, time.Now(), cksum); err != nil {
return err
func (e *Exercice) NewTry(t *Team, cksum []byte, flags ...Flag) (int64, error) {
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 0, err
} 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).
// 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) {
if err := e.NewTry(t, cksum); err != nil {
if tryId, err := e.NewTry(t, cksum); err != nil {
return false, err
} else if flags, err := e.GetFlagKeys(); err != nil {
return false, err
@ -565,6 +580,10 @@ func (e *Exercice) CheckResponse(cksum []byte, respflags map[int]string, respmcq
// Check MCQs
for _, mcq := range mcqs {
if mcq.HasOneEntry(respmcq) {
e.NewTryFlag(tryId, mcq)
}
if d := mcq.Check(respmcq); d > 0 {
if !PartialValidation || t.HasPartiallySolved(mcq) == nil {
valid = false
@ -589,15 +608,21 @@ func (e *Exercice) CheckResponse(cksum []byte, respflags map[int]string, respmcq
for _, flag := range flags {
if res, ok := respflags[flag.Id]; !ok && (!PartialValidation || t.HasPartiallySolved(flag) == nil) {
valid = valid && flag.IsOptionnal()
} else if flag.Check([]byte(res)) != 0 {
if !PartialValidation || t.HasPartiallySolved(flag) == nil {
valid = valid && flag.IsOptionnal()
} else if ok {
if len(res) > 0 {
e.NewTryFlag(tryId, flag)
}
} else {
err := flag.FoundBy(t)
if err == nil {
// err is unicity issue, probably flag already found
goodResponses += 1
if flag.Check([]byte(res)) != 0 {
if !PartialValidation || t.HasPartiallySolved(flag) == nil {
valid = valid && flag.IsOptionnal()
}
} 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" {
bid := make([]byte, 5)
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 {
return team.OpenHint(&EHint{Id: *secondary})
} 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.
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
} else if size == 0 {
if _, _, err := checkFileHash(path.Join(FilesDir, f.Path+".gz"), f.Checksum); err != nil {
@ -400,9 +405,17 @@ func (f *EFile) CheckFileOnDisk() error {
} else {
return nil
}
} else {
return nil
} else if err != 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.

View File

@ -14,6 +14,9 @@ type Flag interface {
Check(val interface{}) int
IsOptionnal() bool
FoundBy(t *Team) error
NbTries() (int64, error)
TeamsOnIt() ([]int64, error)
DeleteTries() error
}
// 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.
func (k *FlagKey) Create(e *Exercice) (Flag, error) {
// 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.
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 {

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.
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 {
@ -207,7 +255,7 @@ func (m *MCQ) AddEntry(e *MCQ_entry) (*MCQ_entry, error) {
// Update applies modifications back to the database.
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
} else if nb, err := res.RowsAffected(); err != nil {
return 0, err
@ -319,6 +367,24 @@ func (m *MCQ) IsOptionnal() bool {
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.
func (m *MCQ) Check(v interface{}) int {
var vals map[int]bool

186
qa/ui/package-lock.json generated
View File

@ -524,9 +524,9 @@
}
},
"node_modules/@eslint/js": {
"version": "9.18.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.18.0.tgz",
"integrity": "sha512-fK6L7rxcq6/z+AaQMtiFTkvbHkBLNlwyRxHpKawP0x3u9+NC6MQTnFW+AdpwC6gfHTW0051cokQgtTN2FqlxQA==",
"version": "9.19.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.19.0.tgz",
"integrity": "sha512-rbq9/g38qjfqFLOVPvwjIvFFdNziEC5S65jmjPw5r6A//QH+W91akh9irMwjDN8zKUTak6W9EsAv4m/7Wnw0UQ==",
"dev": true,
"license": "MIT",
"engines": {
@ -689,9 +689,9 @@
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.30.1.tgz",
"integrity": "sha512-pSWY+EVt3rJ9fQ3IqlrEUtXh3cGqGtPDH1FQlNZehO2yYxCHEX1SPsz1M//NXwYfbTlcKr9WObLnJX9FsS9K1Q==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.32.0.tgz",
"integrity": "sha512-G2fUQQANtBPsNwiVFg4zKiPQyjVKZCUdQUol53R8E71J7AsheRMV/Yv/nB8giOcOVqP7//eB5xPqieBYZe9bGg==",
"cpu": [
"arm"
],
@ -703,9 +703,9 @@
]
},
"node_modules/@rollup/rollup-android-arm64": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.30.1.tgz",
"integrity": "sha512-/NA2qXxE3D/BRjOJM8wQblmArQq1YoBVJjrjoTSBS09jgUisq7bqxNHJ8kjCHeV21W/9WDGwJEWSN0KQ2mtD/w==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.32.0.tgz",
"integrity": "sha512-qhFwQ+ljoymC+j5lXRv8DlaJYY/+8vyvYmVx074zrLsu5ZGWYsJNLjPPVJJjhZQpyAKUGPydOq9hRLLNvh1s3A==",
"cpu": [
"arm64"
],
@ -717,9 +717,9 @@
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.30.1.tgz",
"integrity": "sha512-r7FQIXD7gB0WJ5mokTUgUWPl0eYIH0wnxqeSAhuIwvnnpjdVB8cRRClyKLQr7lgzjctkbp5KmswWszlwYln03Q==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.32.0.tgz",
"integrity": "sha512-44n/X3lAlWsEY6vF8CzgCx+LQaoqWGN7TzUfbJDiTIOjJm4+L2Yq+r5a8ytQRGyPqgJDs3Rgyo8eVL7n9iW6AQ==",
"cpu": [
"arm64"
],
@ -731,9 +731,9 @@
]
},
"node_modules/@rollup/rollup-darwin-x64": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.30.1.tgz",
"integrity": "sha512-x78BavIwSH6sqfP2xeI1hd1GpHL8J4W2BXcVM/5KYKoAD3nNsfitQhvWSw+TFtQTLZ9OmlF+FEInEHyubut2OA==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.32.0.tgz",
"integrity": "sha512-F9ct0+ZX5Np6+ZDztxiGCIvlCaW87HBdHcozUfsHnj1WCUTBUubAoanhHUfnUHZABlElyRikI0mgcw/qdEm2VQ==",
"cpu": [
"x64"
],
@ -745,9 +745,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.30.1.tgz",
"integrity": "sha512-HYTlUAjbO1z8ywxsDFWADfTRfTIIy/oUlfIDmlHYmjUP2QRDTzBuWXc9O4CXM+bo9qfiCclmHk1x4ogBjOUpUQ==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.32.0.tgz",
"integrity": "sha512-JpsGxLBB2EFXBsTLHfkZDsXSpSmKD3VxXCgBQtlPcuAqB8TlqtLcbeMhxXQkCDv1avgwNjF8uEIbq5p+Cee0PA==",
"cpu": [
"arm64"
],
@ -759,9 +759,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.30.1.tgz",
"integrity": "sha512-1MEdGqogQLccphhX5myCJqeGNYTNcmTyaic9S7CG3JhwuIByJ7J05vGbZxsizQthP1xpVx7kd3o31eOogfEirw==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.32.0.tgz",
"integrity": "sha512-wegiyBT6rawdpvnD9lmbOpx5Sph+yVZKHbhnSP9MqUEDX08G4UzMU+D87jrazGE7lRSyTRs6NEYHtzfkJ3FjjQ==",
"cpu": [
"x64"
],
@ -773,9 +773,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.30.1.tgz",
"integrity": "sha512-PaMRNBSqCx7K3Wc9QZkFx5+CX27WFpAMxJNiYGAXfmMIKC7jstlr32UhTgK6T07OtqR+wYlWm9IxzennjnvdJg==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.32.0.tgz",
"integrity": "sha512-3pA7xecItbgOs1A5H58dDvOUEboG5UfpTq3WzAdF54acBbUM+olDJAPkgj1GRJ4ZqE12DZ9/hNS2QZk166v92A==",
"cpu": [
"arm"
],
@ -787,9 +787,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.30.1.tgz",
"integrity": "sha512-B8Rcyj9AV7ZlEFqvB5BubG5iO6ANDsRKlhIxySXcF1axXYUyqwBok+XZPgIYGBgs7LDXfWfifxhw0Ik57T0Yug==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.32.0.tgz",
"integrity": "sha512-Y7XUZEVISGyge51QbYyYAEHwpGgmRrAxQXO3siyYo2kmaj72USSG8LtlQQgAtlGfxYiOwu+2BdbPjzEpcOpRmQ==",
"cpu": [
"arm"
],
@ -801,9 +801,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.30.1.tgz",
"integrity": "sha512-hqVyueGxAj3cBKrAI4aFHLV+h0Lv5VgWZs9CUGqr1z0fZtlADVV1YPOij6AhcK5An33EXaxnDLmJdQikcn5NEw==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.32.0.tgz",
"integrity": "sha512-r7/OTF5MqeBrZo5omPXcTnjvv1GsrdH8a8RerARvDFiDwFpDVDnJyByYM/nX+mvks8XXsgPUxkwe/ltaX2VH7w==",
"cpu": [
"arm64"
],
@ -815,9 +815,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.30.1.tgz",
"integrity": "sha512-i4Ab2vnvS1AE1PyOIGp2kXni69gU2DAUVt6FSXeIqUCPIR3ZlheMW3oP2JkukDfu3PsexYRbOiJrY+yVNSk9oA==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.32.0.tgz",
"integrity": "sha512-HJbifC9vex9NqnlodV2BHVFNuzKL5OnsV2dvTw6e1dpZKkNjPG6WUq+nhEYV6Hv2Bv++BXkwcyoGlXnPrjAKXw==",
"cpu": [
"arm64"
],
@ -829,9 +829,9 @@
]
},
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.30.1.tgz",
"integrity": "sha512-fARcF5g296snX0oLGkVxPmysetwUk2zmHcca+e9ObOovBR++9ZPOhqFUM61UUZ2EYpXVPN1redgqVoBB34nTpQ==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.32.0.tgz",
"integrity": "sha512-VAEzZTD63YglFlWwRj3taofmkV1V3xhebDXffon7msNz4b14xKsz7utO6F8F4cqt8K/ktTl9rm88yryvDpsfOw==",
"cpu": [
"loong64"
],
@ -843,9 +843,9 @@
]
},
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.30.1.tgz",
"integrity": "sha512-GLrZraoO3wVT4uFXh67ElpwQY0DIygxdv0BNW9Hkm3X34wu+BkqrDrkcsIapAY+N2ATEbvak0XQ9gxZtCIA5Rw==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.32.0.tgz",
"integrity": "sha512-Sts5DST1jXAc9YH/iik1C9QRsLcCoOScf3dfbY5i4kH9RJpKxiTBXqm7qU5O6zTXBTEZry69bGszr3SMgYmMcQ==",
"cpu": [
"ppc64"
],
@ -857,9 +857,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.30.1.tgz",
"integrity": "sha512-0WKLaAUUHKBtll0wvOmh6yh3S0wSU9+yas923JIChfxOaaBarmb/lBKPF0w/+jTVozFnOXJeRGZ8NvOxvk/jcw==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.32.0.tgz",
"integrity": "sha512-qhlXeV9AqxIyY9/R1h1hBD6eMvQCO34ZmdYvry/K+/MBs6d1nRFLm6BOiITLVI+nFAAB9kUB6sdJRKyVHXnqZw==",
"cpu": [
"riscv64"
],
@ -871,9 +871,9 @@
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.30.1.tgz",
"integrity": "sha512-GWFs97Ruxo5Bt+cvVTQkOJ6TIx0xJDD/bMAOXWJg8TCSTEK8RnFeOeiFTxKniTc4vMIaWvCplMAFBt9miGxgkA==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.32.0.tgz",
"integrity": "sha512-8ZGN7ExnV0qjXa155Rsfi6H8M4iBBwNLBM9lcVS+4NcSzOFaNqmt7djlox8pN1lWrRPMRRQ8NeDlozIGx3Omsw==",
"cpu": [
"s390x"
],
@ -885,9 +885,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.30.1.tgz",
"integrity": "sha512-UtgGb7QGgXDIO+tqqJ5oZRGHsDLO8SlpE4MhqpY9Llpzi5rJMvrK6ZGhsRCST2abZdBqIBeXW6WPD5fGK5SDwg==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.32.0.tgz",
"integrity": "sha512-VDzNHtLLI5s7xd/VubyS10mq6TxvZBp+4NRWoW+Hi3tgV05RtVm4qK99+dClwTN1McA6PHwob6DEJ6PlXbY83A==",
"cpu": [
"x64"
],
@ -899,9 +899,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.30.1.tgz",
"integrity": "sha512-V9U8Ey2UqmQsBT+xTOeMzPzwDzyXmnAoO4edZhL7INkwQcaW1Ckv3WJX3qrrp/VHaDkEWIBWhRwP47r8cdrOow==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.32.0.tgz",
"integrity": "sha512-qcb9qYDlkxz9DxJo7SDhWxTWV1gFuwznjbTiov289pASxlfGbaOD54mgbs9+z94VwrXtKTu+2RqwlSTbiOqxGg==",
"cpu": [
"x64"
],
@ -913,9 +913,9 @@
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.30.1.tgz",
"integrity": "sha512-WabtHWiPaFF47W3PkHnjbmWawnX/aE57K47ZDT1BXTS5GgrBUEpvOzq0FI0V/UYzQJgdb8XlhVNH8/fwV8xDjw==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.32.0.tgz",
"integrity": "sha512-pFDdotFDMXW2AXVbfdUEfidPAk/OtwE/Hd4eYMTNVVaCQ6Yl8et0meDaKNL63L44Haxv4UExpv9ydSf3aSayDg==",
"cpu": [
"arm64"
],
@ -927,9 +927,9 @@
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.30.1.tgz",
"integrity": "sha512-pxHAU+Zv39hLUTdQQHUVHf4P+0C47y/ZloorHpzs2SXMRqeAWmGghzAhfOlzFHHwjvgokdFAhC4V+6kC1lRRfw==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.32.0.tgz",
"integrity": "sha512-/TG7WfrCAjeRNDvI4+0AAMoHxea/USWhAzf9PVDFHbcqrQ7hMMKp4jZIy4VEjk72AAfN5k4TiSMRXRKf/0akSw==",
"cpu": [
"ia32"
],
@ -941,9 +941,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.30.1.tgz",
"integrity": "sha512-D6qjsXGcvhTjv0kI4fU8tUuBDF/Ueee4SVX79VfNDXZa64TfCW1Slkb6Z7O1p7vflqZjcmOVdZlqf8gvJxc6og==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.32.0.tgz",
"integrity": "sha512-5hqO5S3PTEO2E5VjCePxv40gIgyS2KvO7E7/vvC/NbIW4SIRamkMr1hqj+5Y67fbBWv/bQLB6KelBQmXlyCjWA==",
"cpu": [
"x64"
],
@ -1414,9 +1414,9 @@
}
},
"node_modules/eslint": {
"version": "9.18.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.18.0.tgz",
"integrity": "sha512-+waTfRWQlSbpt3KWE+CjrPPYnbq9kfZIYUqapc0uBXyjTp8aYXZDsUH16m39Ryq3NjAVP4tjuF7KaukeqoCoaA==",
"version": "9.19.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.19.0.tgz",
"integrity": "sha512-ug92j0LepKlbbEv6hD911THhoRHmbdXt2gX+VDABAW/Ir7D3nqKdv5Pf5vtlyY6HQMTEP2skXY43ueqTCWssEA==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -1425,7 +1425,7 @@
"@eslint/config-array": "^0.19.0",
"@eslint/core": "^0.10.0",
"@eslint/eslintrc": "^3.2.0",
"@eslint/js": "9.18.0",
"@eslint/js": "9.19.0",
"@eslint/plugin-kit": "^0.2.5",
"@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1",
@ -2154,9 +2154,9 @@
"license": "ISC"
},
"node_modules/postcss": {
"version": "8.4.49",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz",
"integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==",
"version": "8.5.1",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz",
"integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==",
"dev": true,
"funding": [
{
@ -2174,7 +2174,7 @@
],
"license": "MIT",
"dependencies": {
"nanoid": "^3.3.7",
"nanoid": "^3.3.8",
"picocolors": "^1.1.1",
"source-map-js": "^1.2.1"
},
@ -2328,9 +2328,9 @@
}
},
"node_modules/rollup": {
"version": "4.30.1",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.30.1.tgz",
"integrity": "sha512-mlJ4glW020fPuLi7DkM/lN97mYEZGWeqBnrljzN0gs7GLctqX3lNWxKQ7Gl712UAX+6fog/L3jh4gb7R6aVi3w==",
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.32.0.tgz",
"integrity": "sha512-JmrhfQR31Q4AuNBjjAX4s+a/Pu/Q8Q9iwjWBsjRH1q52SPFE2NqRMK6fUZKKnvKO6id+h7JIRf0oYsph53eATg==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -2344,25 +2344,25 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.30.1",
"@rollup/rollup-android-arm64": "4.30.1",
"@rollup/rollup-darwin-arm64": "4.30.1",
"@rollup/rollup-darwin-x64": "4.30.1",
"@rollup/rollup-freebsd-arm64": "4.30.1",
"@rollup/rollup-freebsd-x64": "4.30.1",
"@rollup/rollup-linux-arm-gnueabihf": "4.30.1",
"@rollup/rollup-linux-arm-musleabihf": "4.30.1",
"@rollup/rollup-linux-arm64-gnu": "4.30.1",
"@rollup/rollup-linux-arm64-musl": "4.30.1",
"@rollup/rollup-linux-loongarch64-gnu": "4.30.1",
"@rollup/rollup-linux-powerpc64le-gnu": "4.30.1",
"@rollup/rollup-linux-riscv64-gnu": "4.30.1",
"@rollup/rollup-linux-s390x-gnu": "4.30.1",
"@rollup/rollup-linux-x64-gnu": "4.30.1",
"@rollup/rollup-linux-x64-musl": "4.30.1",
"@rollup/rollup-win32-arm64-msvc": "4.30.1",
"@rollup/rollup-win32-ia32-msvc": "4.30.1",
"@rollup/rollup-win32-x64-msvc": "4.30.1",
"@rollup/rollup-android-arm-eabi": "4.32.0",
"@rollup/rollup-android-arm64": "4.32.0",
"@rollup/rollup-darwin-arm64": "4.32.0",
"@rollup/rollup-darwin-x64": "4.32.0",
"@rollup/rollup-freebsd-arm64": "4.32.0",
"@rollup/rollup-freebsd-x64": "4.32.0",
"@rollup/rollup-linux-arm-gnueabihf": "4.32.0",
"@rollup/rollup-linux-arm-musleabihf": "4.32.0",
"@rollup/rollup-linux-arm64-gnu": "4.32.0",
"@rollup/rollup-linux-arm64-musl": "4.32.0",
"@rollup/rollup-linux-loongarch64-gnu": "4.32.0",
"@rollup/rollup-linux-powerpc64le-gnu": "4.32.0",
"@rollup/rollup-linux-riscv64-gnu": "4.32.0",
"@rollup/rollup-linux-s390x-gnu": "4.32.0",
"@rollup/rollup-linux-x64-gnu": "4.32.0",
"@rollup/rollup-linux-x64-musl": "4.32.0",
"@rollup/rollup-win32-arm64-msvc": "4.32.0",
"@rollup/rollup-win32-ia32-msvc": "4.32.0",
"@rollup/rollup-win32-x64-msvc": "4.32.0",
"fsevents": "~2.3.2"
}
},
@ -2627,9 +2627,9 @@
"license": "MIT"
},
"node_modules/vite": {
"version": "5.4.11",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz",
"integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==",
"version": "5.4.14",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.14.tgz",
"integrity": "sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==",
"dev": true,
"license": "MIT",
"dependencies": {