package widgets
import (
"errors"
"git.sr.ht/~sircmpwn/aerc/lib/ui"
"github.com/gdamore/tcell"
"golang.org/x/crypto/openpgp"
pgperrors "golang.org/x/crypto/openpgp/errors"
)
type PGPInfo struct {
ui.Invalidatable
details *openpgp.MessageDetails
}
func NewPGPInfo(details *openpgp.MessageDetails) *PGPInfo {
return &PGPInfo{details: details}
}
func (p *PGPInfo) DrawSignature(ctx *ui.Context, offs bool) {
errorStyle := tcell.StyleDefault.Background(tcell.ColorRed).
Foreground(tcell.ColorWhite).Bold(true)
softErrorStyle := tcell.StyleDefault.Foreground(tcell.ColorYellow).
Reverse(true).Bold(true)
validStyle := tcell.StyleDefault.Foreground(tcell.ColorGreen).Bold(true)
header := "Signature "
if offs {
header += " "
}
// TODO: Nicer prompt for TOFU, fetch from keyserver, etc
if errors.Is(p.details.SignatureError, pgperrors.ErrUnknownIssuer) ||
p.details.SignedBy == nil {
x := ctx.Printf(0, 0, tcell.StyleDefault.Bold(true), "%s", header)
x += ctx.Printf(x, 0, softErrorStyle, " Unknown ")
x += ctx.Printf(x, 0, tcell.StyleDefault,
" Signed with unknown key (%8X); authenticity unknown",
p.details.SignedByKeyId)
} else if p.details.SignatureError != nil {
x := ctx.Printf(0, 0, tcell.StyleDefault.Bold(true), "%s", header)
x += ctx.Printf(x, 0, errorStyle, " ✗ Invalid! ")
x += ctx.Printf(x, 0, tcell.StyleDefault.
Foreground(tcell.ColorRed).Bold(true),
" This message may have been tampered with! (%s)",
p.details.SignatureError.Error())
} else {
entity := p.details.SignedBy.Entity
var ident *openpgp.Identity
// TODO: Pick identity more intelligently
for _, ident = range entity.Identities {
break
}
ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', validStyle)
x := ctx.Printf(0, 0, tcell.StyleDefault.Bold(true), "%s", header)
x += ctx.Printf(x, 0, validStyle, "✓ Signed ")
x += ctx.Printf(x, 0, tcell.StyleDefault,
"by %s (%8X)", ident.Name, p.details.SignedByKeyId)
}
}
func (p *PGPInfo) DrawEncryption(ctx *ui.Context, y int) {
validStyle := tcell.StyleDefault.Foreground(tcell.ColorGreen).Bold(true)
entity := p.details.DecryptedWith.Entity
var ident *openpgp.Identity
// TODO: Pick identity more intelligently
for _, ident = range entity.Identities {
break
}
x := ctx.Printf(0, y, tcell.StyleDefault.Bold(true), "Encryption ")
x += ctx.Printf(x, y, validStyle, "✓ Encrypted ")
x += ctx.Printf(x, y, tcell.StyleDefault,
"for %s (%8X) ", ident.Name, p.details.DecryptedWith.PublicKey.KeyId)
}
func (p *PGPInfo) Draw(ctx *ui.Context) {
ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', tcell.StyleDefault)
if p.details.IsSigned && p.details.IsEncrypted {
p.DrawSignature(ctx, true)
p.DrawEncryption(ctx, 1)
} else if p.details.IsSigned {
p.DrawSignature(ctx, false)
} else if p.details.IsEncrypted {
p.DrawEncryption(ctx, 0)
}
}
func (p *PGPInfo) Invalidate() {
p.DoInvalidate(p)
}