rustango 0.61.13

Batteries-included web framework for Rust: ORM + migrations + auto-admin + multi-tenancy + audit log + auth (sessions, JWT, OAuth2/OIDC, HMAC) + APIs (ViewSet, OpenAPI auto-derive, JSON:API) + jobs (in-mem + Postgres) + email + media (S3 / R2 / B2 / MinIO + presigned uploads + collections + tags) + production middleware (CSRF, CSP, rate-limiting, compression, idempotency, etc.).
Documentation
{% extends "op_layout.html" %}
{% block title %}Two-factor sign-in — {{ brand_name | default(value='Rustango Operator Console') }}{% endblock %}
{% block content %}
<style nonce="{{ csp_nonce }}">
  .pw-card {
    max-width: 480px;
    padding: var(--space-5);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-bg-surface);
    box-shadow: var(--shadow-sm);
  }
  .pw-card h1 { margin: 0 0 var(--space-3) 0; font-size: 1.25rem; }
  .pw-card p.sub {
    color: var(--color-fg-muted);
    margin: 0 0 var(--space-4) 0;
    font-size: var(--font-size-sm);
  }
  .pw-card label {
    display: block;
    font-size: var(--font-size-xs);
    color: var(--color-fg-muted);
    margin-top: var(--space-3);
    text-transform: uppercase;
    letter-spacing: 0.05em;
  }
  .pw-card input[type=text] {
    width: 100%;
    padding: 0.5rem 0.6rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    font: inherit;
    margin-top: var(--space-1);
    box-sizing: border-box;
    background: var(--color-bg-input);
    color: var(--color-fg);
  }
  .pw-card input:focus { outline: 2px solid var(--color-accent); outline-offset: 1px; }
  .pw-card button {
    margin-top: var(--space-5);
    padding: 0.55rem 1.2rem;
    background: var(--color-accent);
    color: var(--color-fg-on-accent);
    border: 0;
    border-radius: var(--radius-sm);
    font: inherit;
    font-weight: 600;
    cursor: pointer;
  }
  .pw-card .error, .pw-card .success {
    padding: 0.6rem 0.8rem;
    border-radius: var(--radius-sm);
    margin-bottom: var(--space-3);
    font-size: var(--font-size-sm);
  }
  .pw-card .error {
    background: var(--color-bg-error, #fdecea);
    color: var(--color-fg-error, #b00020);
    border: 1px solid var(--color-border-error, #f5c2c7);
  }
  .pw-card .success {
    background: var(--color-bg-success, #e6f4ea);
    color: var(--color-fg-success, #1e7d32);
    border: 1px solid var(--color-border-success, #b7dfbe);
  }
  .pw-card .key {
    font-family: var(--font-family-mono, monospace);
    letter-spacing: 0.1em;
    word-break: break-all;
    padding: 0.5rem 0.6rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    background: var(--color-bg-input);
  }
  .pw-card .uri { font-size: var(--font-size-xs); color: var(--color-fg-muted); word-break: break-all; }
  .pw-card a.button { display: inline-block; margin-top: var(--space-3); color: var(--color-accent); }
</style>
<div class="pw-card">
  <h1>Two-factor sign-in</h1>
  {% if error %}<div class="error">{{ error }}</div>{% endif %}
  {% if success %}<div class="success">{{ success }}</div>{% endif %}
  {% if enabled %}
  <p class="sub">Signing in to <strong>{{ operator_username }}</strong> asks for a code
    from your authenticator app after the password.</p>
  {% if required %}<p class="sub">This console requires it: turning it off makes
    your next sign-in set up a new device.</p>{% endif %}
  <form method="post" action="{{ console_prefix }}/account/totp/disable">
    {{ csrf_input | default(value='') | safe }}
    <label for="totp_code">Current code</label>
    <input type="text" id="totp_code" name="totp_code" inputmode="numeric"
           autocomplete="one-time-code" pattern="[0-9]*" maxlength="8" required>
    <button type="submit">Turn off</button>
  </form>
  {% elif secret_base32 %}
  <p class="sub">Add this key to your authenticator app (or import the
    <code>otpauth</code> link), then confirm with the 6-digit code it shows.
    The key is shown only until you confirm.</p>
  <label>Setup key</label>
  <p class="key">{{ secret_base32 }}</p>
  <label>otpauth link</label>
  <p class="uri">{{ otpauth_url }}</p>
  <form method="post" action="{{ console_prefix }}/account/totp">
    {{ csrf_input | default(value='') | safe }}
    <label for="totp_code">Code</label>
    <input type="text" id="totp_code" name="totp_code" inputmode="numeric"
           autocomplete="one-time-code" pattern="[0-9]*" maxlength="8" required autofocus>
    <button type="submit">Turn on</button>
  </form>
  {% elif key_missing %}
  <p class="sub">Set <code>RUSTANGO_SECRET_KEY</code> to 32 or more random bytes
    (<code>openssl rand -base64 48</code>) and restart the server; then set up
    two-factor sign-in here.</p>
  {% else %}
  <p class="sub">Two-factor sign-in is off for <strong>{{ operator_username }}</strong>.</p>
  <a class="button" href="{{ console_prefix }}/account/totp">Set it up</a>
  {% endif %}
</div>
{% endblock %}