]> Sergey Matveev's repositories - pgpmaildecryptor.git/commitdiff
Initial commit
authorSergey Matveev <stargrave@stargrave.org>
Thu, 9 Jan 2025 15:02:23 +0000 (18:02 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Thu, 9 Jan 2025 15:02:23 +0000 (18:02 +0300)
go.mod [new file with mode: 0644]
main.go [new file with mode: 0644]

diff --git a/go.mod b/go.mod
new file mode 100644 (file)
index 0000000..bfc15c6
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,3 @@
+module go.stargrave.org/pgpmaildecryptor
+
+go 1.23.4
diff --git a/main.go b/main.go
new file mode 100644 (file)
index 0000000..50dd1d9
--- /dev/null
+++ b/main.go
@@ -0,0 +1,136 @@
+package main
+
+import (
+       "bufio"
+       "bytes"
+       "io"
+       "log"
+       "mime"
+       "net/mail"
+       "net/textproto"
+       "os"
+       "os/exec"
+       "strings"
+)
+
+func main() {
+       log.SetFlags(log.Lshortfile)
+       rawEnc, err := io.ReadAll(bufio.NewReader(os.Stdin))
+       if err != nil {
+               log.Fatal(err)
+       }
+       msgEnc, err := mail.ReadMessage(bytes.NewReader(rawEnc))
+       if err != nil {
+               log.Fatal(err)
+       }
+       {
+               ct := msgEnc.Header.Get("Content-Type")
+               if ct == "" {
+                       log.Fatal("no Content-Type")
+               }
+               mt, params, errParse := mime.ParseMediaType(ct)
+               if errParse != nil {
+                       log.Fatal(errParse)
+               }
+               if mt != "multipart/encrypted" {
+                       log.Fatal("not multipart/encrypted")
+               }
+               if proto := params["protocol"]; proto != "application/pgp-encrypted" {
+                       log.Fatal("not application/pgp-encrypted")
+               }
+       }
+       var rawDec []byte
+       {
+               cmd := exec.Command("gpg", "--batch", "--decrypt", "--status-fd", "3")
+               cmd.Stderr = os.Stderr
+               var stdin io.WriteCloser
+               stdin, err = cmd.StdinPipe()
+               if err != nil {
+                       log.Fatal(err)
+               }
+               var stdout io.ReadCloser
+               stdout, err = cmd.StdoutPipe()
+               if err != nil {
+                       log.Fatal(err)
+               }
+               var statusR, statusW *os.File
+               statusR, statusW, err = os.Pipe()
+               if err != nil {
+                       log.Fatal(err)
+               }
+               cmd.ExtraFiles = append(cmd.ExtraFiles, statusW)
+
+               err = cmd.Start()
+               if err != nil {
+                       log.Fatal(err)
+               }
+               go func() {
+                       _, errStdin := io.Copy(stdin, msgEnc.Body)
+                       if err != nil {
+                               log.Print(errStdin)
+                       }
+                       if errStdin = stdin.Close(); err != nil {
+                               log.Print(errStdin)
+                       }
+               }()
+               var goodDec bool
+               go func() {
+                       s := bufio.NewScanner(statusR)
+                       var t string
+                       for s.Scan() {
+                               t = s.Text()
+                               if t == "[GNUPG:] DECRYPTION_OKAY" {
+                                       goodDec = true
+                               }
+                               log.Print(t)
+                       }
+                       if s.Err() != nil {
+                               log.Print(s.Err())
+                       }
+               }()
+               rawDec, err = io.ReadAll(stdout)
+               if err != nil {
+                       log.Fatal(err)
+               }
+               err = cmd.Wait()
+               if err != nil {
+                       log.Fatal(err)
+               }
+               if !goodDec {
+                       log.Fatal("no DECRYPTION_OKAY received")
+               }
+       }
+       msgDec, err := mail.ReadMessage(bytes.NewReader(rawDec))
+       if err != nil {
+               log.Fatal(err)
+       }
+       stdout := bufio.NewWriter(os.Stdout)
+       r := textproto.NewReader(bufio.NewReader(bytes.NewReader(rawEnc)))
+       var t string
+       var hdr string
+       for {
+               t, err = r.ReadContinuedLine()
+               if err != nil {
+                       log.Fatal(err)
+               }
+               if t == "" {
+                       break
+               }
+               hdr = t[:strings.Index(t, ":")]
+               if msgDec.Header.Get(hdr) != "" {
+                       continue
+               }
+               if _, err = stdout.WriteString(t); err != nil {
+                       log.Fatal(err)
+               }
+               if _, err = stdout.WriteString("\n"); err != nil {
+                       log.Fatal(err)
+               }
+       }
+       if _, err = io.Copy(stdout, bytes.NewReader(rawDec)); err != nil {
+               log.Fatal(err)
+       }
+       if err = stdout.Flush(); err != nil {
+               log.Fatal(err)
+       }
+}