aboutsummaryrefslogblamecommitdiffstats
path: root/widgets/pgpinfo.go
blob: b6a7a16c0344cf56dc2f87f97176bea4cae7bd2c (plain) (tree)




























































































                                                                                     
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)
}