source: Klonkt/src/views/pages/owa-consent.ejs@ d85b66f

main
Last change on this file since d85b66f was d85b66f, checked in by Bart <bart@…>, 3 weeks ago

De home-kant erbij: twee Klonkts kunnen elkaar nu aanmelden

Er was alleen de ontvangende helft: een bezoeker van Hubzilla kwam wel door onze
fanpoort, maar onze eigen gebruikers konden zich nergens bewijzen. Nu allebei.

/magic doet het spiegelbeeld: onze ingelogde gebruiker komt binnen met een
bdest, wij halen ondertekend een token bij die site, ontsleutelen het met onze
eigen prive-sleutel en sturen hem terug met ?owt=. Dit is de enige plek waar die
sleutel nodig is -- en meteen waarom alleen een echte instance deze kant speelt.

WELKE IDENTITEIT: op Klonkt is de fediverse-identiteit de SITE, niet het account.
Eén site gaat meteen door, meer sites laat kiezen. Ondertekenen en ontsleutelen
kan alleen met een sleutel die de gebruiker ook echt beheert, dus de gekozen
site wordt getoetst tegen zijn eigen sites.

EN ER IS EEN TUSSENSCHERM. De FEP waarschuwt onder "Information leakage" dat
OpenWebAuth een sterke identiteitsclaim afgeeft aan elke site die erom vraagt,
desnoods ongemerkt. De omweg langs je eigen server is het enige moment waarop je
kunt zeggen: deze site niet. Vandaar dat de doelhost er groot staat.

EEN FOUT DIE IK ONDERWEG IN MIJN EIGEN WERK VOND: de FEP schrijft voor dat de
handtekening in Authorization: Signature ... gaat, terwijl de rest van de
fediverse (en dus AP.verifyRequest) de Signature-header leest. Ons
token-endpoint las alleen die laatste, dus elke ECHTE client -- Hubzilla,
(streams), Forte -- had een 401 gekregen terwijl hij alles goed deed. Dat was
pas bij de eerste interop-proef opgevallen. Nu leest het endpoint allebei.

Open redirect, nu ook van deze kant: lukt het ontdekken van het token-endpoint
niet, of wijst het naar een andere origin dan bdest, dan volgt een fout en GEEN
doorverwijzing. Anders is /magic het doorgeefluik.

Gemeten en vastgelegd bij decryptToken: de ondergrens van 16 tekens is geen rond
getal. Implicit rejection geeft onzin van willekeurige lengte (5 tot 209 bytes
gezien, 18 van de 300 korter dan 16), en bij zo'n kort stukje is "toevallig
allemaal URL-veilig" niet verwaarloosbaar. De tekenset ving 300 van de 300, de
ondergrens dekt de staart.

1145 toetsen groen (was 1135).

Co-Authored-By: Claude Opus 5 <claude@…>

  • Property mode set to 100644
File size: 3.0 KB
Line 
1<%
2// Het toestemmingsscherm van /magic.
3//
4// Dit scherm bestaat omdat de FEP er onder "Information leakage" om vraagt:
5// OpenWebAuth geeft een STERKE identiteitsclaim af aan elke site die erom
6// vraagt, en desnoods zonder dat je het merkt. De omweg langs je eigen server is
7// het enige moment waarop je nog kunt zeggen: deze site niet.
8//
9// Daarom staat de doelhost groot en apart. Niet als versiering: wie hier
10// doorklikt vertelt die host wie hij is, en dat hoort de zin te zijn die hij
11// gelezen heeft.
12var _sites = (typeof owaSites !== 'undefined' && owaSites) ? owaSites : [];
13%>
14
15<section class="owa">
16 <div class="owa-card">
17 <h1 class="owa-h1"><%= t('owa.title') %></h1>
18
19 <p class="owa-host"><%= owaHost %></p>
20 <p class="owa-sub"><%= t('owa.sub') %></p>
21
22 <form method="post" action="/magic">
23 <input type="hidden" name="bdest" value="<%= owaBdest %>">
24
25 <% if (_sites.length === 1) { %>
26 <input type="hidden" name="slug" value="<%= _sites[0].slug %>">
27 <p class="owa-as"><%= t('owa.as') %> <strong><%= _sites[0].title || _sites[0].slug %></strong></p>
28 <% } else { %>
29 <%# Meer dan één site: kiezen is hier geen luxe. Ondertekenen en
30 ontsleutelen kan alleen met een sleutel die hij ook echt beheert. %>
31 <p class="owa-as"><%= t('owa.choose') %></p>
32 <ul class="owa-list">
33 <% _sites.forEach(function(s, i) { %>
34 <li>
35 <label>
36 <input type="radio" name="slug" value="<%= s.slug %>"<%= i === 0 ? ' checked' : '' %>>
37 <span><%= s.title || s.slug %></span>
38 </label>
39 </li>
40 <% }); %>
41 </ul>
42 <% } %>
43
44 <div class="owa-actions">
45 <button class="owa-btn" type="submit"><%= t('owa.go') %></button>
46 <a class="owa-no" href="/"><%= t('owa.cancel') %></a>
47 </div>
48 </form>
49
50 <p class="owa-fine"><%= t('owa.fine') %></p>
51 </div>
52</section>
53
54<style>
55 .owa { max-width: 480px; margin: 0 auto; padding: 56px 18px; text-align: center; }
56 .owa-card { border: 1px solid rgba(128,128,128,.2); border-radius: 18px; padding: 36px 28px; }
57 .owa-h1 { font-size: 22px; margin: 0 0 14px; }
58 .owa-host { font-size: 20px; font-weight: 600; margin: 0 0 6px; word-break: break-all; }
59 .owa-sub { opacity: .85; line-height: 1.6; margin: 0 0 20px; }
60 .owa-as { font-size: .95rem; margin: 0 0 10px; }
61 .owa-list { list-style: none; padding: 0; margin: 0 0 18px; text-align: left; }
62 .owa-list li { padding: 6px 0; }
63 .owa-list label { display: flex; gap: 10px; align-items: center; cursor: pointer; }
64 .owa-actions { display: flex; gap: 14px; align-items: center; justify-content: center; flex-wrap: wrap; }
65 .owa-btn { padding: 12px 22px; border-radius: 10px; border: 0; background: var(--accent,#6b8f71);
66 color: #fff; font-weight: 600; font-family: inherit; font-size: 1rem; cursor: pointer; }
67 .owa-no { font-size: .9rem; opacity: .7; }
68 .owa-fine { font-size: .8rem; opacity: .6; line-height: 1.5; margin: 18px 0 0; }
69</style>
Note: See TracBrowser for help on using the repository browser.