fix: Footer-Copyright und Signatur-Fingerprint vereinheitlichen

Footer zeigt KnorrLabs/Markus F.J. Busche mit Mailto nur am Namen. Signatur-Normalisierung ist für Persistenz und isDirty-Check konsistent.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-30 11:12:26 +02:00
co-authored by Cursor
parent 10f01f1ffc
commit ebe4199b8b
4 changed files with 28 additions and 13 deletions
+5 -1
View File
@@ -3046,10 +3046,14 @@ html.theme-cupertino .events-scroll-container {
.app-version-footer__copyright { .app-version-footer__copyright {
color: #94a3b8; color: #94a3b8;
}
.app-version-footer__copyright a {
color: inherit;
text-decoration: none; text-decoration: none;
} }
.app-version-footer__copyright:hover { .app-version-footer__copyright a:hover {
color: #e2e8f0; color: #e2e8f0;
text-decoration: underline; text-decoration: underline;
} }
+4 -3
View File
@@ -7,9 +7,10 @@ export default function AppFooter() {
<span className="app-version-footer__sep" aria-hidden="true"> <span className="app-version-footer__sep" aria-hidden="true">
· ·
</span> </span>
<a className="app-version-footer__copyright" href="mailto:elpatron+kd@mailbox.org"> <span className="app-version-footer__copyright">
© 2026 Markus F.J. Busche © 2026 KnorrLabs/
</a> <a href="mailto:elpatron+kd@mailbox.org">Markus F.J. Busche</a>
</span>
</footer> </footer>
) )
} }
+10 -9
View File
@@ -13,7 +13,8 @@ import TrackMap from './TrackMap.tsx'
import { useDialog } from './ModalDialog.tsx' import { useDialog } from './ModalDialog.tsx'
import { import {
normalizeSignature, normalizeSignature,
serializeSignature, fingerprintSignature,
normalizedSerializedSignature,
isPasskeySignature, isPasskeySignature,
isSignatureValidForEntry, isSignatureValidForEntry,
hasAnySignature hasAnySignature
@@ -79,8 +80,8 @@ function fingerprintFromStoredEntry(decrypted: Record<string, unknown>): string
return JSON.stringify({ return JSON.stringify({
...payload, ...payload,
signSkipper: serializeSignature(normalizeSignature(decrypted.signSkipper as SignatureValue | '') || '') ?? '', signSkipper: fingerprintSignature(decrypted.signSkipper),
signCrew: serializeSignature(normalizeSignature(decrypted.signCrew as SignatureValue | '') || '') ?? '' signCrew: fingerprintSignature(decrypted.signCrew)
}) })
} }
@@ -241,8 +242,8 @@ export default function LogEntryEditor({
const payload = buildPayloadForSigning() const payload = buildPayloadForSigning()
return JSON.stringify({ return JSON.stringify({
...payload, ...payload,
signSkipper: serializeSignature(signSkipper) ?? '', signSkipper: fingerprintSignature(signSkipper),
signCrew: serializeSignature(signCrew) ?? '' signCrew: fingerprintSignature(signCrew)
}) })
}, [buildPayloadForSigning, signSkipper, signCrew]) }, [buildPayloadForSigning, signSkipper, signCrew])
@@ -256,8 +257,8 @@ export default function LogEntryEditor({
const entryData = { const entryData = {
...buildPayloadForSigning(eventsOverride), ...buildPayloadForSigning(eventsOverride),
signSkipper: serializeSignature(signSkipper), signSkipper: normalizedSerializedSignature(signSkipper),
signCrew: serializeSignature(signCrew) signCrew: normalizedSerializedSignature(signCrew)
} }
const encrypted = await encryptJson(entryData, masterKey) const encrypted = await encryptJson(entryData, masterKey)
@@ -285,8 +286,8 @@ export default function LogEntryEditor({
setSavedFingerprint(JSON.stringify({ setSavedFingerprint(JSON.stringify({
...buildPayloadForSigning(eventsOverride), ...buildPayloadForSigning(eventsOverride),
signSkipper: serializeSignature(signSkipper) ?? '', signSkipper: fingerprintSignature(signSkipper),
signCrew: serializeSignature(signCrew) ?? '' signCrew: fingerprintSignature(signCrew)
})) }))
}, [ }, [
readOnly, logbookId, entryId, events, buildPayloadForSigning, signSkipper, signCrew readOnly, logbookId, entryId, events, buildPayloadForSigning, signSkipper, signCrew
+9
View File
@@ -68,3 +68,12 @@ export function serializeSignature(value: SignatureValue | '' | undefined): Sign
const trimmed = value.trim() const trimmed = value.trim()
return trimmed || undefined return trimmed || undefined
} }
/** Normalize then serialize — canonical form for persistence and dirty-check fingerprints. */
export function normalizedSerializedSignature(value: unknown): SignatureValue | undefined {
return serializeSignature(normalizeSignature(value) || '')
}
export function fingerprintSignature(value: unknown): string {
return normalizedSerializedSignature(value) ?? ''
}