Canonicalize line endings for text messages (#86)
* Canonicalize line endings for text messages * Improve cleartext messages
This commit is contained in:
parent
a4d89bce32
commit
ce607e0fa8
6 changed files with 25 additions and 25 deletions
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"regexp"
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/ProtonMail/gopenpgp/v2/armor"
|
"github.com/ProtonMail/gopenpgp/v2/armor"
|
||||||
"github.com/ProtonMail/gopenpgp/v2/constants"
|
"github.com/ProtonMail/gopenpgp/v2/constants"
|
||||||
|
|
@ -86,7 +87,7 @@ func NewPlainMessageFromFile(data []byte, filename string, time uint32) *PlainMe
|
||||||
// ready for encryption, signature, or verification from an unencrypted string.
|
// ready for encryption, signature, or verification from an unencrypted string.
|
||||||
func NewPlainMessageFromString(text string) *PlainMessage {
|
func NewPlainMessageFromString(text string) *PlainMessage {
|
||||||
return &PlainMessage{
|
return &PlainMessage{
|
||||||
Data: []byte(text),
|
Data: []byte(strings.ReplaceAll(strings.ReplaceAll(text, "\r\n", "\n"), "\n", "\r\n")),
|
||||||
TextType: true,
|
TextType: true,
|
||||||
time: uint32(GetUnixTime()),
|
time: uint32(GetUnixTime()),
|
||||||
}
|
}
|
||||||
|
|
@ -195,7 +196,7 @@ func (msg *PlainMessage) GetBinary() []byte {
|
||||||
|
|
||||||
// GetString returns the content of the message as a string.
|
// GetString returns the content of the message as a string.
|
||||||
func (msg *PlainMessage) GetString() string {
|
func (msg *PlainMessage) GetString() string {
|
||||||
return string(msg.Data)
|
return strings.ReplaceAll(string(msg.Data), "\r\n", "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBase64 returns the base-64 encoded binary content of the message as a
|
// GetBase64 returns the base-64 encoded binary content of the message as a
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ func (keyRing *KeyRing) DecryptMIMEMessage(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
body, attachments, attachmentHeaders, err := parseMIME(decryptedMessage.GetString(), verifyKey)
|
body, attachments, attachmentHeaders, err := parseMIME(string(decryptedMessage.GetBinary()), verifyKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
callbacks.OnError(err)
|
callbacks.OnError(err)
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,8 @@ func TestVerifyTextDetachedSigWrong(t *testing.T) {
|
||||||
func TestSignBinDetached(t *testing.T) {
|
func TestSignBinDetached(t *testing.T) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
binSignature, err = keyRingTestPrivate.SignDetached(NewPlainMessage([]byte(signedPlainText)))
|
message = NewPlainMessage([]byte(signedPlainText))
|
||||||
|
binSignature, err = keyRingTestPrivate.SignDetached(message)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("Cannot generate signature:", err)
|
t.Fatal("Cannot generate signature:", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
package helper
|
package helper
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/ProtonMail/gopenpgp/v2/crypto"
|
"github.com/ProtonMail/gopenpgp/v2/crypto"
|
||||||
"github.com/ProtonMail/gopenpgp/v2/internal"
|
"github.com/ProtonMail/gopenpgp/v2/internal"
|
||||||
)
|
)
|
||||||
|
|
@ -50,7 +48,7 @@ func VerifyCleartextMessageArmored(publicKey, armored string, verifyTime int64)
|
||||||
// SignCleartextMessage signs text given a private keyring, canonicalizes and
|
// SignCleartextMessage signs text given a private keyring, canonicalizes and
|
||||||
// trims the newlines, and returns the PGP-compliant special armoring.
|
// trims the newlines, and returns the PGP-compliant special armoring.
|
||||||
func SignCleartextMessage(keyRing *crypto.KeyRing, text string) (string, error) {
|
func SignCleartextMessage(keyRing *crypto.KeyRing, text string) (string, error) {
|
||||||
text = canonicalizeAndTrim(text)
|
text = internal.TrimWhitespace(text)
|
||||||
message := crypto.NewPlainMessageFromString(text)
|
message := crypto.NewPlainMessageFromString(text)
|
||||||
|
|
||||||
signature, err := keyRing.SignDetached(message)
|
signature, err := keyRing.SignDetached(message)
|
||||||
|
|
@ -79,12 +77,3 @@ func VerifyCleartextMessage(keyRing *crypto.KeyRing, armored string, verifyTime
|
||||||
|
|
||||||
return message.GetString(), nil
|
return message.GetString(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----- INTERNAL FUNCTIONS -----
|
|
||||||
|
|
||||||
// canonicalizeAndTrim alters a string canonicalizing and trimming the newlines.
|
|
||||||
func canonicalizeAndTrim(text string) string {
|
|
||||||
text = internal.TrimNewlines(text)
|
|
||||||
text = strings.ReplaceAll(strings.ReplaceAll(text, "\r\n", "\n"), "\n", "\r\n")
|
|
||||||
return text
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,16 @@ package helper
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ProtonMail/gopenpgp/v2/crypto"
|
"github.com/ProtonMail/gopenpgp/v2/crypto"
|
||||||
|
"github.com/ProtonMail/gopenpgp/v2/internal"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
const signedPlainText = "Signed message\n"
|
const inputPlainText = " Signed message\n \n "
|
||||||
|
const signedPlainText = " Signed message\n\n"
|
||||||
|
|
||||||
var signedMessageTest = regexp.MustCompile(
|
var signedMessageTest = regexp.MustCompile(
|
||||||
"(?s)^-----BEGIN PGP SIGNED MESSAGE-----.*-----BEGIN PGP SIGNATURE-----.*-----END PGP SIGNATURE-----$")
|
"(?s)^-----BEGIN PGP SIGNED MESSAGE-----.*-----BEGIN PGP SIGNATURE-----.*-----END PGP SIGNATURE-----$")
|
||||||
|
|
@ -18,7 +21,7 @@ func TestSignClearText(t *testing.T) {
|
||||||
armored, err := SignCleartextMessageArmored(
|
armored, err := SignCleartextMessageArmored(
|
||||||
readTestFile("keyring_privateKey", false),
|
readTestFile("keyring_privateKey", false),
|
||||||
testMailboxPassword,
|
testMailboxPassword,
|
||||||
signedPlainText,
|
inputPlainText,
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -36,11 +39,17 @@ func TestSignClearText(t *testing.T) {
|
||||||
t.Fatal("Cannot verify message:", err)
|
t.Fatal("Cannot verify message:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Exactly(t, canonicalizeAndTrim(signedPlainText), verified)
|
assert.Exactly(t, signedPlainText, verified)
|
||||||
|
|
||||||
|
clearTextMessage, err := crypto.NewClearTextMessageFromArmored(armored)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Cannot parse message:", err)
|
||||||
|
}
|
||||||
|
assert.Exactly(t, canonicalizeAndTrim(inputPlainText), string(clearTextMessage.GetBinary()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMessageCanonicalizeAndTrim(t *testing.T) {
|
func canonicalizeAndTrim(text string) string {
|
||||||
text := "Hi \ntest!\r\n\n"
|
text = internal.TrimWhitespace(text)
|
||||||
canon := canonicalizeAndTrim(text)
|
text = strings.ReplaceAll(strings.ReplaceAll(text, "\r\n", "\n"), "\n", "\r\n")
|
||||||
assert.Exactly(t, "Hi\r\ntest!\r\n\r\n", canon)
|
return text
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@ import (
|
||||||
"github.com/ProtonMail/gopenpgp/v2/constants"
|
"github.com/ProtonMail/gopenpgp/v2/constants"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TrimNewlines removes whitespace from the end of each line of the input
|
// TrimWhitespace removes whitespace from the end of each line of the input
|
||||||
// string.
|
// string.
|
||||||
func TrimNewlines(input string) string {
|
func TrimWhitespace(input string) string {
|
||||||
var re = regexp.MustCompile(`(?m)[ \t]*$`)
|
var re = regexp.MustCompile(`(?m)[ \t]*$`)
|
||||||
return re.ReplaceAllString(input, "")
|
return re.ReplaceAllString(input, "")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue