diff options
author | maride <maride@darknebu.la> | 2018-08-22 11:18:37 +0200 |
---|---|---|
committer | maride <maride@darknebu.la> | 2018-08-22 11:18:37 +0200 |
commit | 71f083bebcb76d28ced994f24a2babd79dd84bb5 (patch) | |
tree | 3c0569092367f08a90ccab63acdda87770542795 | |
parent | 1e15776d63fc685549e694b5e99529100e96c9ba (diff) |
Add filter for challenge categories
-rw-r--r-- | hosted/challenges.html | 135 | ||||
-rw-r--r-- | src/seed.go | 7 |
2 files changed, 95 insertions, 47 deletions
diff --git a/hosted/challenges.html b/hosted/challenges.html index 34c1ab5..e42d7f0 100644 --- a/hosted/challenges.html +++ b/hosted/challenges.html @@ -5,50 +5,68 @@ <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous"> <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.11/handlebars.min.js"></script> <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> + <style type="text/css"> + body { + overflow-y: scroll; + } + </style> </head> - <script id="body-template" type="text/x-handlebars-template"> - <div class="container"> - <div class="alert alert-secondary" role="alert"> - <strong>Please note:</strong> All flags are case-sensitive and look like <samp>CIRCUS{IS_REALLY_C00L}</samp>. - </div> - {{#each challenges}} - <div class="card {{#if foundFlag}}border-success{{/if}}" style="margin-bottom: 20px"> - <div class="card-header"> + <script id="nav-template" type="text/x-handlebars-template"> + <ul class="nav nav-pills" id="navigation-pills"> + <li class="nav-item"> + <a class="nav-link active" href="#" onclick="filterChallenges()" circus-category="ALL"> + All + </a> + </li> + {{#each categories as |count name|}} + <li class="nav-item"> + <a class="nav-link" href="#" onclick="filterChallenges('{{ name }}')" circus-category="{{ name }}"> {{ name }} - <span class="badge badge-light"> - {{ category }} - </span> - </div> - <div class="card-body"> - <p> - {{{ description }}} - </p> - {{#if ContainsLaunchable}} - {{#if IPAddress}} - <p class="text-primary"> - Container running IPv4: <kbd>{{IPAddress}}</kbd> - </p> - <button class="btn btn-primary" onclick="stopContainer('{{ name }}');$(this).prop('disabled', true)">Stop Container</button> - {{else}} - <button class="btn btn-primary" onclick="startContainer('{{ name }}');$(this).prop('disabled', true)">Launch Container</button> - {{/if}} - {{/if}} - <hr> - {{#if foundFlag}} - <p class="text-success">Flag found!</p> + <span class="badge badge-light">{{ count }}</span> + </a> + </li> + {{/each}} + </ul> + </script> + <script id="challenge-template" type="text/x-handlebars-template"> + <div id="challenge-container"> + {{#each challenges}} + <div class="card {{#if foundFlag}}border-success{{/if}}" style="margin-bottom: 20px" circus-category="{{ category }}"> + <div class="card-header"> + {{ name }} + <span class="badge badge-light"> + {{ category }} + </span> + </div> + <div class="card-body"> + <p> + {{{ description }}} + </p> + {{#if ContainsLaunchable}} + {{#if IPAddress}} + <p class="text-primary"> + Container running IPv4: <kbd>{{IPAddress}}</kbd> + </p> + <button class="btn btn-primary" onclick="stopContainer('{{ name }}');$(this).prop('disabled', true)">Stop Container</button> {{else}} - <form class="input-group mb-3" onsubmit="event.preventDefault();submitThis(this);"> - <input type="hidden" name="challengeName" value="{{ name }}"> - <input type="text" class="form-control" aria-label="Flag" aria-describedby="button-submit" name="flag"> - <div class="input-group-append"> - <button class="btn btn-outline-primary" type="submit" id="button-submit">Submit flag</button> - </div> - </form> + <button class="btn btn-primary" onclick="startContainer('{{ name }}');$(this).prop('disabled', true)">Launch Container</button> {{/if}} - </div> + {{/if}} + <hr> + {{#if foundFlag}} + <p class="text-success">Flag found!</p> + {{else}} + <form class="input-group mb-3" onsubmit="event.preventDefault();submitThis(this);"> + <input type="hidden" name="challengeName" value="{{ name }}"> + <input type="text" class="form-control" aria-label="Flag" aria-describedby="button-submit" name="flag"> + <div class="input-group-append"> + <button class="btn btn-outline-primary" type="submit" id="button-submit">Submit flag</button> + </div> + </form> + {{/if}} </div> - {{/each}} - </div> + </div> + {{/each}} </script> <body> <nav class="navbar navbar-expand-md navbar-dark bg-dark mb-4"> @@ -70,22 +88,33 @@ </form> </div> </nav> - <main class="container" role="main" id="challenge-list"> - <div class="alert alert-info" role="alert"> - Loading challenges... + <main class="container" role="main"> + <div id="nav-list"> + + </div> + <br> + <div id="challenge-list"> + <div class="alert alert-info" role="alert"> + Loading challenges... + </div> </div> </main> </body> <script type="text/javascript"> - var template = Handlebars.compile($("#body-template").html()); + var navTemplate = Handlebars.compile($("#nav-template").html()); + var challengeTemplate = Handlebars.compile($("#challenge-template").html()); + var renderedNav = false; function loadChallengesAndRender() { $.ajax({ url: "/api/getChallenges", success: function(result) { - $("#challenge-list").html( - template(jQuery.parseJSON(result)) - ); + if(!renderedNav) { + $("#nav-list").html(navTemplate(jQuery.parseJSON(result))); + renderedNav = true; + } + $("#challenge-list").html(challengeTemplate(jQuery.parseJSON(result))); + filterChallenges($('#navigation-pills > li > a.active').attr("circus-category")); } }); } @@ -126,6 +155,20 @@ }); } + function filterChallenges(category) { + $("#navigation-pills > li > a").removeClass("active"); + + if(category && category != "ALL") { + $("#challenge-container > div").hide(); + $("#challenge-container > div[circus-category=" + category + "]").show(); + $("#navigation-pills > li > a[circus-category=" + category + "]").addClass("active"); + } else { + // Show ALL + $("#challenge-container > div").show(); + $("#navigation-pills > li > a[circus-category=ALL]").addClass("active"); + } + } + $(document).ready(function() { loadChallengesAndRender(); }); diff --git a/src/seed.go b/src/seed.go index fde4265..5dc849c 100644 --- a/src/seed.go +++ b/src/seed.go @@ -78,13 +78,18 @@ func getChallengesFromSeedFile() { func generateJSONFromChallenges() (string, error) { // To avoid leakage of container name or the flag towards the user, we need to strip the challenges var strippedChallenges []StrippedChallenge + categories := map[string]int{} for _, challenge := range challenges { + // Append challenge to list strippedChallenges = append(strippedChallenges, stripChallenge(challenge)) + + categories[challenge.Category]++ } - marshalled, marshalError := json.Marshal(map[string][]StrippedChallenge{ + marshalled, marshalError := json.Marshal(map[string]interface{}{ "challenges": strippedChallenges, + "categories": categories, }) return string(marshalled), marshalError } |