123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- package eostre
- import (
- "bytes"
- "encoding/base64"
- "fmt"
- "io"
- "log"
- "os"
- "os/exec"
- "path"
- "strings"
- "time"
- "apiote.xyz/p/asgard/jotunheim"
- "filippo.io/age"
- "github.com/emersion/go-imap"
- "github.com/emersion/go-imap/client"
- "github.com/emersion/go-message"
- _ "github.com/emersion/go-message/charset"
- "github.com/emersion/go-sasl"
- "github.com/emersion/go-smtp"
- )
- func DownloadDiary(config jotunheim.Config) error {
- c, err := client.DialTLS(config.Eostre.DiaryImapAddress, nil)
- if err != nil {
- log.Fatalln(err)
- }
- defer c.Close()
- log.Println("Connected")
- defer c.Logout()
- if err := c.Login(config.Eostre.DiaryImapUsername, config.Eostre.DiaryImapPassword); err != nil {
- log.Fatalln(err)
- }
- log.Println("Logged in")
- mbox, err := c.Select("INBOX", false)
- if err != nil {
- log.Fatalln(err)
- }
- from := uint32(1)
- to := mbox.Messages
- seqset := new(imap.SeqSet)
- seqset.AddRange(from, to)
- messages := make(chan *imap.Message, 10)
- done := make(chan error, 1)
- section := &imap.BodySectionName{}
- go func() {
- done <- c.Fetch(seqset, []imap.FetchItem{imap.FetchEnvelope, section.FetchItem(), imap.FetchFlags, imap.FetchUid, imap.FetchInternalDate}, messages)
- }()
- var latestMessage message.Entity
- var latestDate time.Time
- for msg := range messages {
- subject := msg.Envelope.Subject
- if subject != config.Eostre.DiarySubject {
- log.Printf("ignoring subject %s\n", subject)
- continue
- }
- sender := msg.Envelope.From[0]
- if sender.Address() != config.Eostre.DiarySender {
- log.Printf("ignoring from %s as not authorised\n", sender)
- continue
- }
- bodyReader := msg.GetBody(section)
- if bodyReader == nil {
- log.Printf("body for %d is nil\n", msg.Uid)
- continue
- }
- m, err := message.Read(bodyReader)
- if err != nil {
- log.Println(err)
- continue
- }
- t, _, err := m.Header.ContentType()
- if err != nil {
- log.Println(err)
- continue
- }
- if t != "application/age" {
- log.Printf("%d is not age\n", msg.Uid)
- continue
- }
- log.Printf("msg %v is after %v?\n", msg.InternalDate, latestDate)
- if msg.InternalDate.After(latestDate) {
- log.Printf("yes\n")
- latestDate = msg.InternalDate
- latestMessage = *m
- }
- }
- if latestMessage.Header.Len() == 0 {
- return fmt.Errorf("No messages with diary")
- }
- identity, err := age.ParseX25519Identity(config.Eostre.DiaryPrivateKey)
- if err != nil {
- log.Fatalf("Failed to parse private key: %v", err)
- }
- r, err := age.Decrypt(latestMessage.Body, identity)
- if err != nil {
- log.Fatalf("Failed to open encrypted file: %v", err)
- }
- out, err := os.Create("diary.epub")
- if err != nil {
- log.Fatalf("Failed to create diary file: %v", err)
- }
- if _, err := io.Copy(out, r); err != nil {
- log.Fatalf("Failed to read encrypted file: %v", err)
- }
- out.Close()
- return nil
- }
- func UpdateDiary(config jotunheim.Config) error {
- home, err := os.UserHomeDir()
- if err != nil {
- return err
- }
- // TODO find also in /usr/share/asgard
- _, err = exec.Command(path.Join(home, ".local/share/asgard/eostre.sh")).Output()
- return err
- }
- func SendDiary(config jotunheim.Config) error {
- recipient, err := age.ParseX25519Recipient(config.Eostre.DiaryPublicKey)
- if err != nil {
- log.Fatalf("Failed to parse public key: %v", err)
- }
- b := &bytes.Buffer{}
- b64 := base64.NewEncoder(base64.StdEncoding, b)
- in, err := os.Open("diary.epub")
- if err != nil {
- log.Fatalf("Failed to open decrypted file: %v", err)
- }
- w, err := age.Encrypt(b64, recipient)
- if err != nil {
- log.Fatalf("Failed to encrypt file: %v", err)
- }
- if _, err := io.Copy(w, in); err != nil {
- log.Fatalf("Failed to read decrypted file: %v", err)
- }
- in.Close()
- w.Close()
- b64.Close()
- os.Remove("diary.epub")
- now := time.Now().Format("20060102T150405Z0700")
- msg := strings.NewReader("To: " + config.Eostre.DiaryRecipient + "\r\n" +
- "From: " + config.Eostre.DiarySender + "\r\n" +
- "Date: " + now + "\r\n" +
- "Message-ID: " + now + "_eostre@apiote.xyz\r\n" +
- "MIME-Version: 1.0\r\n" +
- "Subject: Diary\r\n" +
- "Content-Type: application/age; name=diary.epub.age\r\n" +
- "Content-Transfer-Encoding: base64\r\n" +
- "\r\n" +
- string(b.Bytes()),
- )
- c, err := smtp.DialTLS(config.Eostre.DiarySmtpAddress, nil)
- if err != nil {
- log.Fatalf("Failed smtp dial: %v", err)
- }
- auth := sasl.NewPlainClient("", config.Eostre.DiarySmtpUsername, config.Eostre.DiarySmtpPassword)
- err = c.Auth(auth)
- if err != nil {
- log.Fatalf("Failed smtp auth: %v", err)
- }
- err = c.SendMail(config.Eostre.DiarySender, []string{config.Eostre.DiaryRecipient}, msg)
- if err != nil {
- return err
- }
- return nil
- }
|