69d4e3895f
implements PGP/MIME signing with go-pgpmail. The Sign() function of go-pgpmail requires a private (signing) key. The signing key which matches the senders email address (from field in email header) is looked up in aerc's copy of the keyring. Private keys can be exported from gpg into aerc as follows: $ gpg --export-secret-keys >> ~/.local/share/aerc/keyring.asc A message is signed with the ":sign" command. The sign command sets a bool flag in the Composer struct. Using the command repeatedly will toggle the flag. References: https://todo.sr.ht/~rjarry/aerc/6 Signed-off-by: Koni Marti <koni.marti@gmail.com>
95 lines
1.9 KiB
Go
95 lines
1.9 KiB
Go
package lib
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path"
|
|
|
|
"github.com/ProtonMail/go-crypto/openpgp"
|
|
"github.com/ProtonMail/go-crypto/openpgp/packet"
|
|
"github.com/kyoh86/xdg"
|
|
)
|
|
|
|
var (
|
|
Keyring openpgp.EntityList
|
|
|
|
locked bool
|
|
)
|
|
|
|
func InitKeyring() {
|
|
os.MkdirAll(path.Join(xdg.DataHome(), "aerc"), 0700)
|
|
|
|
lockpath := path.Join(xdg.DataHome(), "aerc", "keyring.lock")
|
|
lockfile, err := os.OpenFile(lockpath, os.O_CREATE|os.O_EXCL, 0600)
|
|
if err != nil {
|
|
// TODO: Consider connecting to main process over IPC socket
|
|
locked = false
|
|
} else {
|
|
locked = true
|
|
lockfile.Close()
|
|
}
|
|
|
|
keypath := path.Join(xdg.DataHome(), "aerc", "keyring.asc")
|
|
keyfile, err := os.Open(keypath)
|
|
if os.IsNotExist(err) {
|
|
return
|
|
} else if err != nil {
|
|
panic(err)
|
|
}
|
|
defer keyfile.Close()
|
|
|
|
Keyring, err = openpgp.ReadKeyRing(keyfile)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func UnlockKeyring() {
|
|
if !locked {
|
|
return
|
|
}
|
|
lockpath := path.Join(xdg.DataHome(), "aerc", "keyring.lock")
|
|
os.Remove(lockpath)
|
|
}
|
|
|
|
func GetSignerEntityByEmail(email string) (e *openpgp.Entity, err error) {
|
|
for _, key := range Keyring.DecryptionKeys() {
|
|
if key.Entity == nil {
|
|
continue
|
|
}
|
|
ident := key.Entity.PrimaryIdentity()
|
|
if ident != nil && ident.UserId.Email == email {
|
|
return key.Entity, nil
|
|
}
|
|
}
|
|
return nil, fmt.Errorf("entity not found in keyring")
|
|
}
|
|
|
|
func ImportKeys(r io.Reader) error {
|
|
keys, err := openpgp.ReadKeyRing(r)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
Keyring = append(Keyring, keys...)
|
|
if locked {
|
|
keypath := path.Join(xdg.DataHome(), "aerc", "keyring.asc")
|
|
keyfile, err := os.OpenFile(keypath, os.O_CREATE|os.O_APPEND, 0600)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer keyfile.Close()
|
|
|
|
for _, key := range keys {
|
|
if key.PrivateKey != nil {
|
|
err = key.SerializePrivate(keyfile, &packet.Config{})
|
|
} else {
|
|
err = key.Serialize(keyfile)
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|