Skip to content

Commit 7b19a77

Browse files
committed
feat: Add rfc822.Encrypt
1 parent 57d6607 commit 7b19a77

File tree

3 files changed

+269
-1
lines changed

3 files changed

+269
-1
lines changed

go.mod

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ go 1.18
44

55
require (
66
entgo.io/ent v0.10.1
7+
github.com/ProtonMail/gopenpgp/v2 v2.4.7
78
github.com/bradenaw/juniper v0.6.0
89
github.com/emersion/go-imap v1.2.1-0.20220429085312-746087b7a317
910
github.com/emersion/go-imap-uidplus v0.0.0-20200503180755-e75854c361e9
@@ -15,11 +16,14 @@ require (
1516
github.com/sirupsen/logrus v1.8.1
1617
github.com/stretchr/testify v1.7.1-0.20210427113832-6241f9ab9942
1718
golang.org/x/exp v0.0.0-20220217172124-1812c5b45e43
19+
golang.org/x/text v0.3.7
1820
google.golang.org/protobuf v1.27.1
1921
)
2022

2123
require (
2224
ariga.io/atlas v0.3.7-0.20220303204946-787354f533c3 // indirect
25+
github.com/ProtonMail/go-crypto v0.0.0-20220113124808-70ae35bab23f // indirect
26+
github.com/ProtonMail/go-mime v0.0.0-20220302105931-303f85f7fe0f // indirect
2327
github.com/agext/levenshtein v1.2.1 // indirect
2428
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
2529
github.com/davecgh/go-spew v1.1.1 // indirect
@@ -32,9 +36,9 @@ require (
3236
github.com/pmezard/go-difflib v1.0.0 // indirect
3337
github.com/rogpeppe/go-internal v1.8.0 // indirect
3438
github.com/zclconf/go-cty v1.8.0 // indirect
39+
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
3540
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57 // indirect
3641
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
3742
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d // indirect
38-
golang.org/x/text v0.3.7 // indirect
3943
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
4044
)

go.sum

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,14 @@ ariga.io/atlas v0.3.7-0.20220303204946-787354f533c3 h1:fjG4oFCQEfGrRi0QoxWcH2OO2
22
ariga.io/atlas v0.3.7-0.20220303204946-787354f533c3/go.mod h1:yWGf4VPiD4SW83+kAqzD624txN9VKoJC+bpVXr2pKJA=
33
entgo.io/ent v0.10.1 h1:dM5h4Zk6yHGIgw4dCqVzGw3nWgpGYJiV4/kyHEF6PFo=
44
entgo.io/ent v0.10.1/go.mod h1:YPgxeLnoQ/YdpVORRtqjBF+wCy9NX9IR7veTv3Bffus=
5+
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
56
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
7+
github.com/ProtonMail/go-crypto v0.0.0-20220113124808-70ae35bab23f h1:J2FzIrXN82q5uyUraeJpLIm7U6PffRwje2ORho5yIik=
8+
github.com/ProtonMail/go-crypto v0.0.0-20220113124808-70ae35bab23f/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
9+
github.com/ProtonMail/go-mime v0.0.0-20220302105931-303f85f7fe0f h1:CGq7OieOz3wyQJ1fO8S0eO9TCW1JyvLrf8fhzz1i8ko=
10+
github.com/ProtonMail/go-mime v0.0.0-20220302105931-303f85f7fe0f/go.mod h1:NYt+V3/4rEeDuaev/zw1zCq8uqVEuPHzDPo3OZrlGJ4=
11+
github.com/ProtonMail/gopenpgp/v2 v2.4.7 h1:V3xeelvXgJiZXZuPtSSE+uYbtPw4RmbmyPqXDAESPhg=
12+
github.com/ProtonMail/gopenpgp/v2 v2.4.7/go.mod h1:ZW1KxHNG6q5LMgFKf9Ap/d2eVYeyGf5+fAUEAjJWtmo=
613
github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tjT8=
714
github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
815
github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM=
@@ -43,6 +50,7 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
4350
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
4451
github.com/hashicorp/hcl/v2 v2.10.0 h1:1S1UnuhDGlv3gRFV4+0EdwB+znNP5HmcGbIqwnSCByg=
4552
github.com/hashicorp/hcl/v2 v2.10.0/go.mod h1:FwWsfWEjyV/CMj8s/gqAuiviY72rJ1/oayI9WftqcKg=
53+
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
4654
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
4755
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
4856
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
@@ -66,11 +74,14 @@ github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUA
6674
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
6775
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
6876
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
77+
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
6978
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
7079
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
7180
github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
7281
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
82+
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
7383
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
84+
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
7485
github.com/stretchr/testify v1.7.1-0.20210427113832-6241f9ab9942 h1:t0lM6y/M5IiUZyvbBTcngso8SZEZICH7is9B6g/obVU=
7586
github.com/stretchr/testify v1.7.1-0.20210427113832-6241f9ab9942/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
7687
github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
@@ -83,24 +94,39 @@ github.com/zclconf/go-cty v1.8.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUA
8394
github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8=
8495
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
8596
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
97+
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
8698
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
99+
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
100+
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
101+
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
102+
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
87103
golang.org/x/exp v0.0.0-20220217172124-1812c5b45e43 h1:Xo03zeNci09uW1tocp7+8X7YizAdkD/BKNkl9lsqKHQ=
88104
golang.org/x/exp v0.0.0-20220217172124-1812c5b45e43/go.mod h1:lRnflEfy7nRvpQCcpkwaSP1nkrSyjkyFNcqXKfSXLMc=
105+
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
106+
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
107+
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
108+
golang.org/x/mobile v0.0.0-20200801112145-973feb4309de/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4=
109+
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
110+
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
111+
golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
89112
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
90113
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57 h1:LQmS1nU0twXLA96Kt7U9qtHJEbBk3z6Q0V4UXjZkpr4=
91114
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
92115
golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
116+
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
93117
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
94118
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
95119
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
96120
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
121+
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
97122
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
98123
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
99124
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
100125
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
101126
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
102127
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
103128
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
129+
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
104130
golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
105131
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
106132
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -117,7 +143,9 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
117143
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
118144
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
119145
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
146+
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
120147
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
148+
golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
121149
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
122150
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
123151
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -133,6 +161,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
133161
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
134162
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
135163
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
164+
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
136165
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
137166
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
138167
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

rfc822/encrypt.go

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
package rfc822
2+
3+
import (
4+
"bytes"
5+
"encoding/base64"
6+
"errors"
7+
"fmt"
8+
"io"
9+
"mime"
10+
"mime/quotedprintable"
11+
"strings"
12+
13+
"github.com/ProtonMail/gopenpgp/v2/crypto"
14+
"golang.org/x/text/encoding/htmlindex"
15+
"golang.org/x/text/encoding/ianaindex"
16+
)
17+
18+
func Encrypt(kr *crypto.KeyRing, r io.Reader) ([]byte, error) {
19+
b, err := io.ReadAll(r)
20+
if err != nil {
21+
return nil, err
22+
}
23+
24+
header, body, err := Split(b)
25+
if err != nil {
26+
return nil, err
27+
}
28+
29+
buf := new(bytes.Buffer)
30+
31+
result, err := writeEncryptedPart(kr, ParseHeader(header), bytes.NewReader(body))
32+
if err != nil {
33+
return nil, err
34+
}
35+
36+
if _, err := buf.Write(header); err != nil {
37+
return nil, err
38+
}
39+
40+
if _, err := result.WriteTo(buf); err != nil {
41+
return nil, err
42+
}
43+
44+
return buf.Bytes(), nil
45+
}
46+
47+
func writeEncryptedPart(kr *crypto.KeyRing, header *Header, r io.Reader) (io.WriterTo, error) {
48+
decoder := getTransferDecoder(r, string(header.Get("Content-Transfer-Encoding")))
49+
encoded := new(bytes.Buffer)
50+
51+
contentType, contentParams, err := ParseContentType(header.Get("Content-Type"))
52+
if err != nil && !errors.Is(err, mime.ErrInvalidMediaParameter) {
53+
return nil, err
54+
}
55+
56+
switch {
57+
case contentType == "", strings.HasPrefix(contentType, "text/"), strings.HasPrefix(contentType, "message/"):
58+
header.Del("Content-Transfer-Encoding")
59+
60+
if charset, ok := contentParams["charset"]; ok {
61+
decoder = getCharsetDecoder(decoder, charset)
62+
63+
contentParams["charset"] = "utf-8"
64+
65+
header.Set("Content-Type", mime.FormatMediaType(contentType, contentParams))
66+
}
67+
68+
if err := encode(&writeCloser{encoded}, func(w io.Writer) error {
69+
return writeEncryptedTextPart(w, decoder, kr)
70+
}); err != nil {
71+
return nil, err
72+
}
73+
74+
case contentType == "multipart/encrypted":
75+
if _, err := encoded.ReadFrom(decoder); err != nil {
76+
return nil, err
77+
}
78+
79+
case strings.HasPrefix(contentType, "multipart/"):
80+
if err := encode(&writeCloser{encoded}, func(w io.Writer) error {
81+
return writeEncryptedMultiPart(kr, w, header, decoder)
82+
}); err != nil {
83+
return nil, err
84+
}
85+
86+
default:
87+
header.Set("Content-Transfer-Encoding", "base64")
88+
89+
if err := encode(base64.NewEncoder(base64.StdEncoding, encoded), func(w io.Writer) error {
90+
return writeEncryptedAttachmentPart(w, decoder, kr)
91+
}); err != nil {
92+
return nil, err
93+
}
94+
}
95+
96+
return encoded, nil
97+
}
98+
99+
func writeEncryptedTextPart(w io.Writer, r io.Reader, kr *crypto.KeyRing) error {
100+
dec, err := io.ReadAll(r)
101+
if err != nil {
102+
return err
103+
}
104+
105+
var arm string
106+
107+
if msg, err := crypto.NewPGPMessageFromArmored(string(dec)); err != nil {
108+
enc, err := kr.Encrypt(crypto.NewPlainMessage(dec), kr)
109+
if err != nil {
110+
return err
111+
}
112+
113+
if arm, err = enc.GetArmored(); err != nil {
114+
return err
115+
}
116+
} else {
117+
if arm, err = msg.GetArmored(); err != nil {
118+
return err
119+
}
120+
}
121+
122+
if _, err := io.WriteString(w, arm); err != nil {
123+
return err
124+
}
125+
126+
return nil
127+
}
128+
129+
func writeEncryptedAttachmentPart(w io.Writer, r io.Reader, kr *crypto.KeyRing) error {
130+
dec, err := io.ReadAll(r)
131+
if err != nil {
132+
return err
133+
}
134+
135+
enc, err := kr.Encrypt(crypto.NewPlainMessage(dec), kr)
136+
if err != nil {
137+
return err
138+
}
139+
140+
if _, err := w.Write(enc.GetBinary()); err != nil {
141+
return err
142+
}
143+
144+
return nil
145+
}
146+
147+
func writeEncryptedMultiPart(kr *crypto.KeyRing, w io.Writer, header *Header, r io.Reader) error {
148+
_, contentParams, err := ParseContentType(header.Get("Content-Type"))
149+
if err != nil {
150+
return err
151+
}
152+
153+
scanner, err := NewScanner(r, contentParams["boundary"])
154+
if err != nil {
155+
return err
156+
}
157+
158+
parts, err := scanner.ScanAll()
159+
if err != nil {
160+
return err
161+
}
162+
163+
multipartWriter := NewMultipartWriter(w, contentParams["boundary"])
164+
165+
for _, part := range parts {
166+
header, body, err := Split(part.Data)
167+
if err != nil {
168+
return err
169+
}
170+
171+
result, err := writeEncryptedPart(kr, ParseHeader(header), bytes.NewReader(body))
172+
if err != nil {
173+
return err
174+
}
175+
176+
if err := multipartWriter.AddPart(func(w io.Writer) error {
177+
if _, err := w.Write(header); err != nil {
178+
return err
179+
}
180+
181+
if _, err := result.WriteTo(w); err != nil {
182+
return err
183+
}
184+
185+
return nil
186+
}); err != nil {
187+
return err
188+
}
189+
}
190+
191+
return multipartWriter.Done()
192+
}
193+
194+
func getTransferDecoder(r io.Reader, encoding string) io.Reader {
195+
switch strings.ToLower(encoding) {
196+
case "base64":
197+
return base64.NewDecoder(base64.StdEncoding, r)
198+
199+
case "quoted-printable":
200+
return quotedprintable.NewReader(r)
201+
202+
default:
203+
return r
204+
}
205+
}
206+
207+
func getCharsetDecoder(r io.Reader, charset string) io.Reader {
208+
if enc, err := ianaindex.MIME.Encoding(strings.ToLower(charset)); err == nil {
209+
return enc.NewDecoder().Reader(r)
210+
}
211+
212+
if enc, err := ianaindex.MIME.Encoding("cs" + strings.ToLower(charset)); err == nil {
213+
return enc.NewDecoder().Reader(r)
214+
}
215+
216+
if enc, err := htmlindex.Get(strings.ToLower(charset)); err == nil {
217+
return enc.NewDecoder().Reader(r)
218+
}
219+
220+
panic(fmt.Errorf("unsupported charset: %v", charset))
221+
}
222+
223+
func encode(wc io.WriteCloser, fn func(io.Writer) error) error {
224+
if err := fn(wc); err != nil {
225+
return err
226+
}
227+
228+
return wc.Close()
229+
}
230+
231+
type writeCloser struct {
232+
io.Writer
233+
}
234+
235+
func (writeCloser) Close() error { return nil }

0 commit comments

Comments
 (0)