atr/templates/keys-review.html (185 lines of code) (raw):

{% extends "layouts/base.html" %} {% block title %} Manage keys ~ ATR {% endblock title %} {% block description %} Review your keys. {% endblock description %} {% block content %} <h1>Manage keys</h1> <p class="mb-4"> <a href="#your-public-keys" class="btn btn-sm btn-secondary me-3">Your public keys</a> <a href="#your-committee-keys" class="btn btn-sm btn-secondary">Your committee's keys</a> </p> <h2 id="your-public-keys">Your public keys</h2> <p>Review your public keys used for signing release artifacts.</p> <div> <p> Welcome, <strong>{{ asf_id }}</strong>! You are authenticated as an ASF committer. </p> </div> <div class="d-flex gap-3 mb-4"> <a href="{{ as_url(routes.keys.add) }}" class="btn btn-outline-primary">Add your GPG key</a> <a href="{{ as_url(routes.keys.ssh_add) }}" class="btn btn-outline-primary">Add your SSH key</a> </div> <h3>GPG keys</h3> {% if user_keys %} <div class="mb-5 p-4 bg-light rounded"> <div class="d-grid gap-4"> {% for key in user_keys %} <div class="card p-3 border"> <table class="mb-0"> <tbody> <tr> <th class="p-2 text-dark">Fingerprint</th> <td class="text-break">{{ key.fingerprint }}</td> </tr> <tr> <th class="p-2 text-dark">Type</th> <td class="text-break">{{ algorithms[key.algorithm] }} ({{ key.length }} bits)</td> </tr> <tr> <th class="p-2 text-dark">Created</th> <td class="text-break">{{ key.created.strftime("%Y-%m-%d %H:%M:%S") }}</td> </tr> <tr> <th class="p-2 text-dark">Expires</th> <td class="text-break"> {% if key.expires %} {% set days_until_expiry = (key.expires - now).days %} {% if days_until_expiry < 0 %} <span class="text-danger fw-bold"> {{ key.expires.strftime("%Y-%m-%d %H:%M:%S") }} <span class="badge bg-danger text-white ms-2">Expired</span> </span> {% elif days_until_expiry <= 30 %} <span class="text-warning fw-bold"> {{ key.expires.strftime("%Y-%m-%d %H:%M:%S") }} <span class="badge bg-warning text-dark ms-2">Expires in {{ days_until_expiry }} days</span> </span> {% else %} {{ key.expires.strftime("%Y-%m-%d %H:%M:%S") }} {% endif %} {% else %} Never {% endif %} </td> </tr> <tr> <th class="p-2 text-dark">User ID</th> <td class="text-break">{{ key.declared_uid or 'Not specified' }}</td> </tr> <tr> <th class="p-2 text-dark">Associated PMCs</th> <td class="text-break"> {% if key.committees %} {{ key.committees|map(attribute='name') |join(', ') }} {% else %} No PMCs associated {% endif %} </td> </tr> </tbody> </table> <!-- TODO: We could link to a downloadable version of the key instead --> <details class="mt-3 p-3 bg-light rounded"> <summary class="fw-bold">View whole key</summary> <pre class="mt-3">{{ key.ascii_armored_key }}</pre> </details> <form method="post" action="{{ as_url(routes.keys.delete) }}" class="mt-3" onsubmit="return confirm('Are you sure you want to delete this GPG key?');"> {{ delete_form.hidden_tag() }} <input type="hidden" name="fingerprint" value="{{ key.fingerprint }}" /> {{ delete_form.submit(class_='btn btn-danger', value='Delete key') }} </form> </div> {% endfor %} </div> </div> {% else %} <p> <strong>You haven't added any personal GPG keys yet.</strong> </p> {% endif %} <h3>SSH keys</h3> {% if user_ssh_keys %} <div class="mb-5 p-4 bg-light rounded"> <div class="d-grid gap-4"> {% for key in user_ssh_keys %} <div id="ssh-key-{{ key.fingerprint }}" class="card p-3 border"> <table class="mb-0"> <tbody> <tr> <th class="p-2 text-dark">Fingerprint</th> <td class="text-break">{{ key.fingerprint }}</td> </tr> <tr> <th class="p-2 text-dark">Type</th> <td class="text-break">{{ key.key.split()[0] }}</td> </tr> </tbody> </table> <details class="mt-3 p-3 bg-light rounded"> <summary class="fw-bold">View whole key</summary> <pre class="mt-3">{{ key.key }}</pre> </details> <form method="post" action="{{ as_url(routes.keys.delete) }}" class="mt-3" onsubmit="return confirm('Are you sure you want to delete this SSH key?');"> {{ delete_form.hidden_tag() }} <input type="hidden" name="fingerprint" value="{{ key.fingerprint }}" /> {{ delete_form.submit(class_='btn btn-danger', value='Delete key') }} </form> </div> {% endfor %} </div> </div> {% else %} <p> <strong>You haven't added any SSH keys yet.</strong> </p> {% endif %} <h2 id="your-committee-keys">Your committee's keys</h2> <div class="mb-4"> <a href="{{ as_url(routes.keys.upload) }}" class="btn btn-outline-primary">Upload a KEYS file</a> </div> {% for committee in committees %} <h3 class="mt-3">{{ committee.display_name }}</h3> {% if committee.public_signing_keys %} <div class="table-responsive mb-2"> <table class="table border table-striped table-hover table-sm"> <thead> <tr> <th class="px-2" scope="col">Fingerprint</th> <th class="px-2" scope="col">Email</th> <th class="px-2" scope="col">Apache UID</th> </tr> </thead> <tbody> {% for key in committee.public_signing_keys %} <tr> <td class="text-break font-monospace px-2"> <a href="{{ as_url(routes.keys.show_gpg_key, fingerprint=key.fingerprint) }}">{{ key.fingerprint[:16]|upper }}</a> </td> <td class="text-break px-2">{{ key.declared_uid or 'Not specified' }}</td> <td class="text-break px-2">{{ key.apache_uid }}</td> </tr> {% endfor %} </tbody> </table> </div> <form method="post" action="{{ as_url(routes.keys.update_committee_keys, committee_name=committee.name) }}" class="mb-4 d-inline-block"> {{ update_committee_keys_form.hidden_tag() }} {{ update_committee_keys_form.submit(class_='btn btn-sm btn-outline-secondary') }} </form> {% else %} <p class="mb-4">No keys uploaded for this committee yet.</p> {% endif %} {% endfor %} {% endblock content %}