b19b844a63
implements PGP/MIME encryption with go-pgpmail. The Encrypt() function of go-pgpmail requires a list of public keys which are taken from the keystore. The keystore is searched for the email addresses of all recipients (to, cc, and bcc). If you want to be able to read the encrypted email afterwards, add yourself as a recipient in either to, cc, or bcc as well. Public keys can be exported from gpg into aerc as follows: $ gpg --export >> ~/.local/share/aerc/keyring.asc When composing a message, the encryption is enabled with the ":encrypt" command. This sets a bool flag in the Composer struct. A reapted application of this command will toggle the flag. The encrypted message can also be signed by using the ":sign" command before or after ":encrypt". References: https://todo.sr.ht/~rjarry/aerc/6 Signed-off-by: Koni Marti <koni.marti@gmail.com>
105 lines
2.1 KiB
Go
105 lines
2.1 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 GetEntityByEmail(email string) (e *openpgp.Entity, err error) {
|
|
for _, entity := range Keyring {
|
|
ident := entity.PrimaryIdentity()
|
|
if ident != nil && ident.UserId.Email == email {
|
|
return entity, nil
|
|
}
|
|
}
|
|
return nil, fmt.Errorf("entity not found in keyring")
|
|
}
|
|
|
|
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
|
|
}
|