diff options
| author | Leonardo Bishop <me@leonardobishop.net> | 2026-01-07 23:39:53 +0000 |
|---|---|---|
| committer | Leonardo Bishop <me@leonardobishop.net> | 2026-01-07 23:39:53 +0000 |
| commit | 03cd6bdfbd473dba3f3dc50a1b15e389aac5bc70 (patch) | |
| tree | 5fea2b1840e298aaab953add749fb9226bd4a710 /web/views | |
Initial commit
Diffstat (limited to 'web/views')
| -rw-r--r-- | web/views/auth.html | 51 | ||||
| -rw-r--r-- | web/views/f_auth_error.html | 3 | ||||
| -rw-r--r-- | web/views/f_deploy.html | 32 | ||||
| -rw-r--r-- | web/views/f_instance.html | 28 | ||||
| -rw-r--r-- | web/views/f_instance_result.html | 4 | ||||
| -rw-r--r-- | web/views/index.html | 98 |
6 files changed, 216 insertions, 0 deletions
diff --git a/web/views/auth.html b/web/views/auth.html new file mode 100644 index 0000000..995815a --- /dev/null +++ b/web/views/auth.html @@ -0,0 +1,51 @@ + +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <title>Challenge Instancer</title> + + <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet"> + <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.2/dist/umd/popper.min.js" integrity="sha384-IQsoLXl5PILFhosVNubq5LC7Qb9DXgDA9i+tQ8Zj3iwWAwPtgFTxbJ8NT4GN1R8p" crossorigin="anonymous"></script> + <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.min.js" integrity="sha384-cVKIPhGWiC2Al4u+LWgxfKTRIcfu0JTxR+EQDz/bgldoEyl4H0zUF0QKbrJ0EcQF" crossorigin="anonymous"></script> + <script src="https://cdn.jsdelivr.net/npm/htmx.org@2.0.8/dist/htmx.min.js" integrity="sha384-/TgkGk7p307TH7EXJDuUlgG3Ce1UVolAOFopFekQkkXihi5u/6OCvVKyz1W+idaz" crossorigin="anonymous"></script> + <script src="https://cdn.jsdelivr.net/npm/htmx-ext-sse@2.2.4" integrity="sha384-A986SAtodyH8eg8x8irJnYUk7i9inVQqYigD6qZ9evobksGNIXfeFvDwLSHcp31N" crossorigin="anonymous"></script> +</head> +<body class="bg-light"> + +<div class="container py-5"> + <div class="row justify-content-center"> + <div class="col-12 col-md-6 col-lg-4"> + <div class="card mx-auto"> + <div class="card-body"> + <h4 class="card-title mb-3">Enter a team ID</h4> + + <div id="auth-response"></div> + + <form hx-post="/auth" hx-target="#auth-response" hx-swap="innerHTML"> + <div class="input-group"> + <span class="input-group-text">ID</span> + <input id="team" name="team" class="form-control" type="number" required> + </input> + <button id="deploy-btn" type="submit" class="btn btn-primary"> + Continue + </button> + </div> + </form> + </div> + </div> + + <div class="card mt-4 mx-auto"> + <div class="card-body"> + <p class="card-text"> + <b>Attacking this platform is out of scope of the CTF and is forbidden.</b> + If there are any issues, please speak to an organiser. + </p> + </div> + </div> + </div> + </div> +</div> + +</body> +</html> diff --git a/web/views/f_auth_error.html b/web/views/f_auth_error.html new file mode 100644 index 0000000..4ebdac3 --- /dev/null +++ b/web/views/f_auth_error.html @@ -0,0 +1,3 @@ +<div class="alert alert-danger" role="alert"> + {{.Message}} +</div> diff --git a/web/views/f_deploy.html b/web/views/f_deploy.html new file mode 100644 index 0000000..52edd5f --- /dev/null +++ b/web/views/f_deploy.html @@ -0,0 +1,32 @@ +<div + id="deploy-{{.DeployKey}}" + class="card mt-4" + hx-ext="sse" + hx-on::sse-close="document.getElementById('progress-{{.DeployKey}}').remove(); document.getElementById('close-deploy-{{.DeployKey}}').classList.remove('d-none');" + sse-connect="/deploy/stream?deploy={{.DeployKey}}" + sse-close="done"> + + <div class="card-body"> + + <div class="d-flex justify-content-between align-items-start"> + <h5 class="card-title mb-3">Deploying {{.Challenge}}</h5> + <button id="close-deploy-{{.DeployKey}}" type="button" class="btn-close d-none" aria-label="Close" hx-on:click="document.getElementById('deploy-{{.DeployKey}}').remove()"></button> + </div> + + <div class="d-flex gap-3 flex-column"> + <div id="progress-{{.DeployKey}}" class="d-flex align-items-center gap-2"> + <div class="spinner-grow spinner-grow-sm" role="status"> + </div> + <div id="status-log" sse-swap="progress"> + Deployment requested + </div> + </div> + + <div id="deployment-result-{{.DeployKey}}" class="d-none"></div> + + <div>Instance <code>{{.DeployKey}}</code></div> + </div> + <span sse-swap="success" hx-target="#deployment-result-{{.DeployKey}}" hx-swap="outerHTML"></span> + <span sse-swap="error" hx-target="#deployment-result-{{.DeployKey}}" hx-swap="outerHTML"></span> + </div> +</div> diff --git a/web/views/f_instance.html b/web/views/f_instance.html new file mode 100644 index 0000000..1518ee2 --- /dev/null +++ b/web/views/f_instance.html @@ -0,0 +1,28 @@ +{{range .Instances}} +<tr> +<td> + <div class="d-flex flex-column gap-2 justify-content-between"> + <b>{{.Address}}</b> + + <span>Expires in <code>{{.ExpiresIn}}</code></span> + + <small>Instance <code>{{.DeployKey}}</code> of <i>{{.ChallengeName}}</i></small> + </div> +</td> +<td> + <button + hx-post="/instances/{{.DeployKey}}/stop" + hx-target="#instance-action-result" + hx-swap="beforeend" + class="btn btn-danger"> + Stop + </button> +</td> +</tr> +{{else}} +<tr> +<td colspan="2"> +<i class="text-center text-muted">Your team does not have any instances</i> +</td> +</tr> +{{end}} diff --git a/web/views/f_instance_result.html b/web/views/f_instance_result.html new file mode 100644 index 0000000..85bd4eb --- /dev/null +++ b/web/views/f_instance_result.html @@ -0,0 +1,4 @@ +<div class="alert alert-{{.State}} alert-dismissible fade show" role="alert"> + {{.Message}} + <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button> +</div> diff --git a/web/views/index.html b/web/views/index.html new file mode 100644 index 0000000..97edc88 --- /dev/null +++ b/web/views/index.html @@ -0,0 +1,98 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <title>Challenge Instancer</title> + + <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet"> + <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.2/dist/umd/popper.min.js" integrity="sha384-IQsoLXl5PILFhosVNubq5LC7Qb9DXgDA9i+tQ8Zj3iwWAwPtgFTxbJ8NT4GN1R8p" crossorigin="anonymous"></script> + <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.min.js" integrity="sha384-cVKIPhGWiC2Al4u+LWgxfKTRIcfu0JTxR+EQDz/bgldoEyl4H0zUF0QKbrJ0EcQF" crossorigin="anonymous"></script> + <script src="https://cdn.jsdelivr.net/npm/htmx.org@2.0.8/dist/htmx.min.js" integrity="sha384-/TgkGk7p307TH7EXJDuUlgG3Ce1UVolAOFopFekQkkXihi5u/6OCvVKyz1W+idaz" crossorigin="anonymous"></script> + <script src="https://cdn.jsdelivr.net/npm/htmx-ext-sse@2.2.4" integrity="sha384-A986SAtodyH8eg8x8irJnYUk7i9inVQqYigD6qZ9evobksGNIXfeFvDwLSHcp31N" crossorigin="anonymous"></script> +</head> +<body class="bg-light"> + +<div class="container py-5"> + <div class="row justify-content-center"> + <div class="col-9"> + <div class="card"> + <div class="card-body"> + <h4 class="card-title mb-3">Deploy challenge</h4> + + <form hx-post="/deploy" hx-target="#deployment-area" hx-swap="afterbegin"> + <div class="input-group"> + <span class="input-group-text">Challenge</span> + <select id="challenge" name="challenge" class="form-select" required> + <option value="" disabled selected>Choose a challenge</option> + {{range .Challenges}} + <option value="{{.}}"> + {{.}} + </option> + {{end}} + </select> + <button id="deploy-btn" type="submit" class="btn btn-primary"> + Deploy + </button> + </div> + </form> + </div> + </div> + + <div + id="instances" + class="card mt-4"> + <div class="card-body"> + <div class="d-flex justify-content-between align-items-start"> + <h5 class="card-title mb-3">Instances</h5> + <span class="badge bg-primary">Refreshing</span> + </div> + + <div id="instance-action-result"></div> + + <table class="table align-middle"> + <thead> + <tr> + <th scope="col">Instance</th> + <th scope="col">Controls</th> + </tr> + </thead> + <tbody id="instances-tbody" hx-get="/instances" hx-trigger="load, every 5s, poll-instances-now from:body"> + + </tbody> + </table> + </div> + </div> + + <div id="deployment-area"></div> + + </div> + <div class="col"> + <div class="card"> + <div class="card-body"> + <h5 class="card-title mb-3">What is this?</h5> + <p class="card-text"> + This platform allows you to spawn an instance of a challenge for your team. + Each instance is shared across your team and can be stopped at any time. + </p> + <p> + Instances will automatically stop after a while; if more time is needed then + you can stop the instance and deploy a new one. + </p> + <p class="card-text"> + <b>Attacking this platform is out of scope of the CTF and is forbidden.</b> + If there are any issues, please speak to an organiser. + </p> + </div> + </div> + <div class="mt-2 px-3"> + <small class="text-muted"> + Logged in as <b>{{.Team}}</b>. + <a href="/logout">Not you</a>? + </small> + </div> + </div> + </div> +</div> + +</body> +</html> |
