mirror of
https://github.com/overcuriousity/trace.git
synced 2025-12-20 13:02:21 +00:00
Display raw PGP signature in verification dialog
Modified the verify_note_signature() function to show the complete raw PGP signature text when users press 'V' in the note details view. This allows users to copy/paste signatures into external tools like Kleopatra for independent verification. Changes: - Added raw signature display after verification status info - Implemented scrollable dialog with arrow keys and Page Up/Down support - Added clear separator and label for the signature section - Shows signature for verified, failed, and unsigned notes (when present) Users can now easily copy PGP signatures for external verification workflows.
This commit is contained in:
@@ -119,7 +119,7 @@ class TUI:
|
|||||||
self.flash_time = time.time()
|
self.flash_time = time.time()
|
||||||
|
|
||||||
def verify_note_signature(self):
|
def verify_note_signature(self):
|
||||||
"""Show detailed verification dialog for current note"""
|
"""Show detailed verification dialog for current note with raw signature"""
|
||||||
if not self.current_note:
|
if not self.current_note:
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -134,6 +134,7 @@ class TUI:
|
|||||||
"To sign notes, enable GPG signing in settings",
|
"To sign notes, enable GPG signing in settings",
|
||||||
"and ensure you have a GPG key configured."
|
"and ensure you have a GPG key configured."
|
||||||
]
|
]
|
||||||
|
signature_lines = []
|
||||||
elif verified:
|
elif verified:
|
||||||
title = "✓ Signature Verified"
|
title = "✓ Signature Verified"
|
||||||
message = [
|
message = [
|
||||||
@@ -141,8 +142,13 @@ class TUI:
|
|||||||
"",
|
"",
|
||||||
f"Signed by: {info}",
|
f"Signed by: {info}",
|
||||||
"",
|
"",
|
||||||
"This note has not been tampered with since signing."
|
"This note has not been tampered with since signing.",
|
||||||
|
"",
|
||||||
|
"─" * 60,
|
||||||
|
"RAW PGP SIGNATURE (copy/paste for external verification):",
|
||||||
|
"─" * 60,
|
||||||
]
|
]
|
||||||
|
signature_lines = self.current_note.signature.split('\n')
|
||||||
else:
|
else:
|
||||||
title = "✗ Signature Verification Failed"
|
title = "✗ Signature Verification Failed"
|
||||||
message = [
|
message = [
|
||||||
@@ -153,37 +159,79 @@ class TUI:
|
|||||||
"Possible causes:",
|
"Possible causes:",
|
||||||
"- Public key not in keyring",
|
"- Public key not in keyring",
|
||||||
"- Note content was modified after signing",
|
"- Note content was modified after signing",
|
||||||
"- Signature is corrupted"
|
"- Signature is corrupted",
|
||||||
|
"",
|
||||||
|
"─" * 60,
|
||||||
|
"RAW PGP SIGNATURE (copy/paste for external verification):",
|
||||||
|
"─" * 60,
|
||||||
]
|
]
|
||||||
|
signature_lines = self.current_note.signature.split('\n')
|
||||||
|
|
||||||
# Display dialog (reuse pattern from other dialogs)
|
# Combine message and signature
|
||||||
|
all_lines = message + signature_lines
|
||||||
|
|
||||||
|
# Display scrollable dialog
|
||||||
h, w = self.stdscr.getmaxyx()
|
h, w = self.stdscr.getmaxyx()
|
||||||
dialog_h = min(len(message) + 6, h - 4)
|
dialog_h = min(h - 4, 40) # Max height for dialog
|
||||||
dialog_w = min(max(len(line) for line in [title] + message) + 6, w - 4)
|
dialog_w = min(w - 4, 100) # Max width for dialog
|
||||||
start_y = (h - dialog_h) // 2
|
start_y = (h - dialog_h) // 2
|
||||||
start_x = (w - dialog_w) // 2
|
start_x = (w - dialog_w) // 2
|
||||||
|
|
||||||
# Create dialog window
|
# Create dialog window
|
||||||
dialog = curses.newwin(dialog_h, dialog_w, start_y, start_x)
|
dialog = curses.newwin(dialog_h, dialog_w, start_y, start_x)
|
||||||
dialog.box()
|
|
||||||
|
|
||||||
# Title
|
scroll_offset = 0
|
||||||
dialog.attron(curses.A_BOLD)
|
max_scroll = max(0, len(all_lines) - (dialog_h - 6))
|
||||||
title_x = (dialog_w - len(title)) // 2
|
|
||||||
dialog.addstr(1, title_x, title)
|
|
||||||
dialog.attroff(curses.A_BOLD)
|
|
||||||
|
|
||||||
# Message
|
while True:
|
||||||
for i, line in enumerate(message):
|
dialog.clear()
|
||||||
dialog.addstr(3 + i, 2, line)
|
dialog.box()
|
||||||
|
|
||||||
# Footer
|
# Title
|
||||||
footer = "Press any key to close"
|
dialog.attron(curses.A_BOLD)
|
||||||
footer_x = (dialog_w - len(footer)) // 2
|
title_x = (dialog_w - len(title)) // 2
|
||||||
dialog.addstr(dialog_h - 2, footer_x, footer, curses.color_pair(3))
|
try:
|
||||||
|
dialog.addstr(1, title_x, title)
|
||||||
|
except curses.error:
|
||||||
|
pass
|
||||||
|
dialog.attroff(curses.A_BOLD)
|
||||||
|
|
||||||
dialog.refresh()
|
# Display visible lines
|
||||||
dialog.getch()
|
visible_lines = all_lines[scroll_offset:scroll_offset + dialog_h - 6]
|
||||||
|
for i, line in enumerate(visible_lines):
|
||||||
|
try:
|
||||||
|
# Truncate line if too long for dialog width
|
||||||
|
truncated_line = line[:dialog_w - 4]
|
||||||
|
dialog.addstr(3 + i, 2, truncated_line)
|
||||||
|
except curses.error:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Footer with scroll indicators
|
||||||
|
if max_scroll > 0:
|
||||||
|
footer = f"↑/↓ Scroll ({scroll_offset + 1}/{len(all_lines)}) Any other key to close"
|
||||||
|
else:
|
||||||
|
footer = "Press any key to close"
|
||||||
|
footer_x = max(2, (dialog_w - len(footer)) // 2)
|
||||||
|
try:
|
||||||
|
dialog.addstr(dialog_h - 2, footer_x, footer[:dialog_w - 4], curses.color_pair(3))
|
||||||
|
except curses.error:
|
||||||
|
pass
|
||||||
|
|
||||||
|
dialog.refresh()
|
||||||
|
|
||||||
|
# Handle input
|
||||||
|
key = dialog.getch()
|
||||||
|
if key == curses.KEY_UP and scroll_offset > 0:
|
||||||
|
scroll_offset -= 1
|
||||||
|
elif key == curses.KEY_DOWN and scroll_offset < max_scroll:
|
||||||
|
scroll_offset += 1
|
||||||
|
elif key == curses.KEY_PPAGE: # Page Up
|
||||||
|
scroll_offset = max(0, scroll_offset - (dialog_h - 6))
|
||||||
|
elif key == curses.KEY_NPAGE: # Page Down
|
||||||
|
scroll_offset = min(max_scroll, scroll_offset + (dialog_h - 6))
|
||||||
|
else:
|
||||||
|
# Any other key closes the dialog
|
||||||
|
break
|
||||||
|
|
||||||
def _save_nav_position(self):
|
def _save_nav_position(self):
|
||||||
"""Save current navigation position before changing views"""
|
"""Save current navigation position before changing views"""
|
||||||
|
|||||||
Reference in New Issue
Block a user