PGP import feature

This commit is contained in:
nemunaire 2022-09-03 16:16:41 +02:00
parent 9436220685
commit de4bb43e86
12 changed files with 547 additions and 0 deletions

View file

@ -0,0 +1,52 @@
<script lang="ts">
import { getKeys, getKey, Key } from '../lib/key';
export let student = null;
</script>
<table class="table table-striped table-hover mb-0">
<thead>
<tr>
<th>ID</th>
<th>Type</th>
<th>Informations</th>
</tr>
</thead>
<tbody>
{#await getKeys(student.id)}
<tr>
<td colspan="4">
<div class="d-flex justify-content-center">
<div class="spinner-border me-2" role="status"></div>
Chargement des clefs&hellip;
</div>
</td>
</tr>
{:then keys}
{#if keys && keys.length > 0}
{#each keys as keyid}
{#await getKey(keyid)}
Veuillez patienter
{:then key}
<tr>
<td>{key.id}</td>
<td>{key.type.toUpperCase()}</td>
<td>
<dl>
{#each Object.keys(key.infos) as k}
<dt class="float-start me-3 my-0 py-0">{k}</dt>
<dd>{#if key.infos[k]}{key.infos[k]}{:else}<span class="fst-italic">-</span>{/if}</dd>
{/each}
</dl>
</td>
</tr>
{/await}
{/each}
{:else}
<tr>
<td colspan="4" class="text-center fst-italic">Cet utilisateur n'a pas défini de clef</td>
</tr>
{/if}
{/await}
</tbody>
</table>

61
ui/src/lib/key.js Normal file
View file

@ -0,0 +1,61 @@
export class Key {
constructor(res) {
if (res) {
this.update(res);
}
}
update({ id, id_user, type, key, time, infos }) {
this.id = id;
this.id_user = id_user;
this.type = type;
this.key = key;
this.time = time;
this.infos = infos;
}
async delete() {
const res = await fetch(`api/keys/${this.id}`, {
method: 'DELETE',
headers: {'Accept': 'application/json'}
});
if (res.status == 200) {
return true;
} else {
throw new Error((await res.json()).errmsg);
}
}
async save() {
const res = await fetch(this.id?`api/keys/${this.id}`:'api/keys', {
method: this.id?'PUT':'POST',
headers: {'Accept': 'application/json'},
body: JSON.stringify(this),
});
if (res.status == 200) {
const data = await res.json();
this.update(data);
return data;
} else {
throw new Error((await res.json()).errmsg);
}
}
}
export async function getKeys(userid) {
const res = await fetch(userid?`api/users/${userid}/keys`:`api/keys`, {headers: {'Accept': 'application/json'}})
if (res.status == 200) {
return await res.json();
} else {
throw new Error((await res.json()).errmsg);
}
}
export async function getKey(kid) {
const res = await fetch(`api/keys/${kid}`, {headers: {'Accept': 'application/json'}})
if (res.status == 200) {
return new Key(await res.json());
} else {
throw new Error((await res.json()).errmsg);
}
}

View file

@ -125,6 +125,7 @@
<img class="rounded-circle" src="//photos.cri.epita.fr/square/{$user.login}" alt="Menu" style="margin: -0.75em 0; max-height: 2.5em; border: 2px solid white;">
</a>
<ul class="dropdown-menu dropdown-menu-end">
<li><a class="dropdown-item" class:active={rroute === 'keys'} href="keys">Clef PGP</a></li>
<li><a class="dropdown-item" class:active={rroute === 'help'} href="help">Besoin d'aide&nbsp;?</a></li>
<li><a class="dropdown-item" class:active={rroute === 'bug-bounty'} href="bug-bounty">Bug Bounty</a></li>
<li><hr class="dropdown-divider"></li>

102
ui/src/routes/keys.svelte Normal file
View file

@ -0,0 +1,102 @@
<script>
import { getKeys, getKey, Key } from '../lib/key';
import { user } from '../stores/user';
import { ToastsStore } from '../stores/toasts';
let keysP = getKeys();
let mykey = "";
let holdSubmit = false;
async function submitPGPKey() {
holdSubmit = true;
let key = new Key({ type: 'pgp', key: mykey });
key.save().then(() => {
keysP = getKeys();
holdSubmit = false;
mykey = "";
ToastsStore.addToast({
msg: "Votre nouvelle clef a bien été enregistrée.",
color: "success",
title: "Clef PGP",
});
}, (error) => {
submitInProgress = false;
ToastsStore.addErrorToast({
msg: "Une erreur s'est produite durant l'envoi de votre clef : " + error + "\nVeuillez réessayer dans quelques instants.",
});
});
}
</script>
<h2>Ma clef PGP</h2>
<p class="lead">
Vos rendus doivent être signés avec votre clef PGP.
</p>
{#await keysP}
Veuillez patienter
{:then keys}
{#if keys && keys.length > 0}
<p>
Vous avez actuellement enregistré {#if keys.length > 1}les clefs publiques suivantes{:else}la clef publique suivante{/if}&nbsp;:
</p>
{#each keys as keyid}
{#await getKey(keyid)}
Veuillez patienter
{:then key}
<div class="alert alert-dark d-flex justify-content-between">
<div class="d-flex">
<div class="d-flex flex-column justify-content-center me-3">
<i class="bi bi-key-fill display-4"></i>
<div class="text-center badge bg-light" style="font-variant: small-caps;">
{key.type}
</div>
</div>
<div>
Adresse électronique&nbsp;: <strong class="badge bg-secondary">{key.infos.email}</strong><br>
Nom&nbsp;: <strong>{key.infos.identity}</strong> {#if key.infos.comment}<span class="fst-italic">({key.infos.identity})</span>{/if}<br>
Key ID&nbsp;: <strong>{key.infos.keyid}</strong><br>
Date de la signature&nbsp;: <strong>{key.infos.creation}</strong><br>
Clef expirée&nbsp;: <span class="badge" class:bg-danger={key.infos.sigexpired} class:bg-info={!key.infos.sigexpired}>{key.infos.sigexpired?"oui":"non"}</span>
</div>
</div>
<div class="d-flex flex-column justify-content-center">
<button
type="button"
class="btn btn-outline-danger float-end"
on:click={() => key.delete().then(() => { keysP = getKeys(); })}
>
Supprimer la clef
</button>
</div>
</div>
{/await}
{/each}
{:else}
<p>
Afin de pouvoir les vérifier, veuillez envoyer votre clef publique dans le formulaire ci-dessous.
Utilisez la commande <code>gpg --export --armor {#if $user}{$user.email}{:else}login_x@epita.fr{/if}</code>&nbsp;:
</p>
<form class="container" on:submit|preventDefault={submitPGPKey}>
<textarea
class="form-control"
rows="10"
bind:value={mykey}
placeholder="-----BEGIN PGP PUBLIC KEY BLOCK-----
QmllbiBzw7tyIHF1ZSBjJ2VzdCB1bmUgY2hhw65uZSBxdWkgdmV1dCBkaXJlIHF1
ZWxxdWUgY2hvc2UK ...
-----END PGP PUBLIC KEY BLOCK-----"
></textarea>
<button
type="submit"
class="mt-2 btn btn-primary"
>
Enregistrer cette clef PGP
</button>
</form>
{/if}
{/await}

View file

@ -9,6 +9,7 @@
</script>
<script lang="ts">
import UserKeys from '../../../components/UserKeys.svelte';
import UserSurveys from '../../../components/UserSurveys.svelte';
import { user } from '../../../stores/user';
import { getSurveys } from '../../../lib/surveys';
@ -102,6 +103,14 @@
</div>
</div>
</div>
<div class="card-header">
<h3 class="card-title">
Clefs
</h3>
</div>
<UserKeys
{student}
/>
<div class="card-header">
<button
class="btn btn-secondary float-end"