Custom types for flags and encrypted outside test

This commit is contained in:
Jakub
2020-11-20 10:03:42 +01:00
committed by Jakub Cuth
parent 6e1e5a2afe
commit 945bdf4c60
6 changed files with 68 additions and 50 deletions

View File

@ -45,7 +45,7 @@ type SendPreferences struct {
// internal emails (including the so-called encrypted-to-outside emails, // internal emails (including the so-called encrypted-to-outside emails,
// which even though meant for external users, they don't really get out of // which even though meant for external users, they don't really get out of
// our platform). If the email is sent unencrypted, no PGP scheme is needed. // our platform). If the email is sent unencrypted, no PGP scheme is needed.
Scheme int Scheme pmapi.PackageFlag
// MIMEType is the MIME type to use for formatting the body of the email // MIMEType is the MIME type to use for formatting the body of the email
// (before encryption/after decryption). The standard possibilities are the // (before encryption/after decryption). The standard possibilities are the

View File

@ -41,7 +41,7 @@ func TestPreferencesBuilder(t *testing.T) {
wantEncrypt bool wantEncrypt bool
wantSign bool wantSign bool
wantScheme int wantScheme pmapi.PackageFlag
wantMIMEType string wantMIMEType string
wantPublicKey string wantPublicKey string
}{ }{

View File

@ -283,7 +283,7 @@ func (su *smtpUser) Send(from string, to []string, messageReader io.Reader) (err
return err return err
} }
var signature int var signature pmapi.SignatureFlag
if sendPreferences.Sign { if sendPreferences.Sign {
signature = pmapi.SignatureDetached signature = pmapi.SignatureDetached
} else { } else {

View File

@ -31,21 +31,38 @@ const (
DraftActionForward = 2 DraftActionForward = 2
) )
// Message send package types. // PackageFlag for send message package types
type PackageFlag int
func (p *PackageFlag) Has(flag PackageFlag) bool { return iHasFlag(int(*p), int(flag)) }
func (p *PackageFlag) HasAtLeastOne(flag PackageFlag) bool {
return iHasAtLeastOneFlag(int(*p), int(flag))
}
func (p *PackageFlag) Is(flag PackageFlag) bool { return iIsFlag(int(*p), int(flag)) }
func (p *PackageFlag) HasNo(flag PackageFlag) bool { return iHasNoneOfFlag(int(*p), int(flag)) }
// Send message package types.
const ( const (
InternalPackage = 1 InternalPackage = PackageFlag(1)
EncryptedOutsidePackage = 2 EncryptedOutsidePackage = PackageFlag(2)
ClearPackage = 4 ClearPackage = PackageFlag(4)
PGPInlinePackage = 8 PGPInlinePackage = PackageFlag(8)
PGPMIMEPackage = 16 PGPMIMEPackage = PackageFlag(16)
ClearMIMEPackage = 32 ClearMIMEPackage = PackageFlag(32)
) )
// SignatureFlag for send signature types.
type SignatureFlag int
func (p *SignatureFlag) Is(flag SignatureFlag) bool { return iIsFlag(int(*p), int(flag)) }
func (p *SignatureFlag) Has(flag SignatureFlag) bool { return iHasFlag(int(*p), int(flag)) }
func (p *SignatureFlag) HasNo(flag SignatureFlag) bool { return iHasNoneOfFlag(int(*p), int(flag)) }
// Send signature types. // Send signature types.
const ( const (
SignatureNone = 0 SignatureNone = SignatureFlag(0)
SignatureDetached = 1 SignatureDetached = SignatureFlag(1)
SignatureAttachedArmored = 2 SignatureAttachedArmored = SignatureFlag(2)
) )
// DraftReq defines paylod for creating drafts // DraftReq defines paylod for creating drafts
@ -79,15 +96,15 @@ type AlgoKey struct {
} }
type MessageAddress struct { type MessageAddress struct {
Type int Type PackageFlag
EncryptedBodyKeyPacket string `json:"BodyKeyPacket"` // base64-encoded key packet. EncryptedBodyKeyPacket string `json:"BodyKeyPacket"` // base64-encoded key packet.
Signature int Signature SignatureFlag
EncryptedAttachmentKeyPackets map[string]string `json:"AttachmentKeyPackets"` EncryptedAttachmentKeyPackets map[string]string `json:"AttachmentKeyPackets"`
} }
type MessagePackage struct { type MessagePackage struct {
Addresses map[string]*MessageAddress Addresses map[string]*MessageAddress
Type int Type PackageFlag
MIMEType string MIMEType string
EncryptedBody string `json:"Body"` // base64-encoded encrypted data packet. EncryptedBody string `json:"Body"` // base64-encoded encrypted data packet.
DecryptedBodyKey AlgoKey `json:"BodyKey"` // base64-encoded session key (only if cleartext recipients). DecryptedBodyKey AlgoKey `json:"BodyKey"` // base64-encoded session key (only if cleartext recipients).
@ -105,13 +122,12 @@ func newMessagePackage(
Type: send.sharedScheme, Type: send.sharedScheme,
} }
if send.sharedScheme&ClearPackage == ClearPackage || if send.sharedScheme.HasAtLeastOne(ClearPackage | ClearMIMEPackage) {
send.sharedScheme&ClearMIMEPackage == ClearMIMEPackage {
pkg.DecryptedBodyKey.Key = send.decryptedBodyKey.GetBase64Key() pkg.DecryptedBodyKey.Key = send.decryptedBodyKey.GetBase64Key()
pkg.DecryptedBodyKey.Algorithm = send.decryptedBodyKey.Algo pkg.DecryptedBodyKey.Algorithm = send.decryptedBodyKey.Algo
} }
if attKeys != nil && send.sharedScheme&ClearPackage == ClearPackage { if len(attKeys) != 0 && send.sharedScheme.Has(ClearPackage) {
pkg.DecryptedAttachmentKeys = attKeys pkg.DecryptedAttachmentKeys = attKeys
} }
@ -121,7 +137,7 @@ func newMessagePackage(
type sendData struct { type sendData struct {
decryptedBodyKey *crypto.SessionKey //body session key decryptedBodyKey *crypto.SessionKey //body session key
addressMap map[string]*MessageAddress addressMap map[string]*MessageAddress
sharedScheme int sharedScheme PackageFlag
ciphertext []byte ciphertext []byte
cleartext string cleartext string
contentType string contentType string
@ -161,30 +177,30 @@ func NewSendMessageReq(
} }
var ( var (
errUnknownContentType = errors.New("unknown content type") errUnknownContentType = errors.New("unknown content type")
errMultipartInNonMIME = errors.New("multipart mixed not allowed in this scheme") errMultipartInNonMIME = errors.New("multipart mixed not allowed in this scheme")
errAttSignNotSupported = errors.New("attached signature not supported") errAttSignNotSupported = errors.New("attached signature not supported")
errEncryptMustSign = errors.New("encrypted package must be signed") errEncryptMustSign = errors.New("encrypted package must be signed")
errEONotSupported = errors.New("encrypted outside is not supported") errEncryptedOutsideNotSupported = errors.New("encrypted outside is not supported")
errWrongSendScheme = errors.New("wrong send scheme") errWrongSendScheme = errors.New("wrong send scheme")
errInternalMustEncrypt = errors.New("internal package must be encrypted") errInternalMustEncrypt = errors.New("internal package must be encrypted")
errInlineMustEncrypt = errors.New("PGP Inline package must be encrypted") errInlineMustEncrypt = errors.New("PGP Inline package must be encrypted")
errInlineMustBePlain = errors.New("PGP Inline package must be plain text") errInlineMustBePlain = errors.New("PGP Inline package must be plain text")
errMissingPubkey = errors.New("cannot encrypt body key packet: missing pubkey") errMissingPubkey = errors.New("cannot encrypt body key packet: missing pubkey")
errSignMustBeMultipart = errors.New("clear signed html packet must be multipart") errSignMustBeMultipart = errors.New("clear signed html packet must be multipart")
errMIMEMustBeMultipart = errors.New("MIME packet must be multipart") errMIMEMustBeMultipart = errors.New("MIME packet must be multipart")
) )
func (req *SendMessageReq) AddRecipient( func (req *SendMessageReq) AddRecipient(
email string, sendScheme int, email string, sendScheme PackageFlag,
pubkey *crypto.KeyRing, signature int, pubkey *crypto.KeyRing, signature SignatureFlag,
contentType string, doEncrypt bool, contentType string, doEncrypt bool,
) (err error) { ) (err error) {
if signature == SignatureAttachedArmored { if signature.Has(SignatureAttachedArmored) {
return errAttSignNotSupported return errAttSignNotSupported
} }
if doEncrypt && signature != SignatureDetached { if doEncrypt && signature.HasNo(SignatureDetached) {
return errEncryptMustSign return errEncryptMustSign
} }
@ -197,19 +213,19 @@ func (req *SendMessageReq) AddRecipient(
case InternalPackage, ClearPackage, PGPInlinePackage: case InternalPackage, ClearPackage, PGPInlinePackage:
return req.addNonMIMERecipient(email, sendScheme, pubkey, signature, contentType, doEncrypt) return req.addNonMIMERecipient(email, sendScheme, pubkey, signature, contentType, doEncrypt)
case EncryptedOutsidePackage: case EncryptedOutsidePackage:
return errEONotSupported return errEncryptedOutsideNotSupported
default: default:
return errWrongSendScheme return errWrongSendScheme
} }
} }
func (req *SendMessageReq) addNonMIMERecipient( func (req *SendMessageReq) addNonMIMERecipient(
email string, sendScheme int, email string, sendScheme PackageFlag,
pubkey *crypto.KeyRing, signature int, pubkey *crypto.KeyRing, signature SignatureFlag,
contentType string, doEncrypt bool, contentType string, doEncrypt bool,
) (err error) { ) (err error) {
if sendScheme == ClearPackage && if sendScheme.Is(ClearPackage) &&
signature == SignatureDetached && signature.Is(SignatureDetached) &&
contentType == ContentTypeHTML { contentType == ContentTypeHTML {
return errSignMustBeMultipart return errSignMustBeMultipart
} }
@ -236,13 +252,13 @@ func (req *SendMessageReq) addNonMIMERecipient(
} }
newAddress := &MessageAddress{Type: sendScheme, Signature: signature} newAddress := &MessageAddress{Type: sendScheme, Signature: signature}
if sendScheme == PGPInlinePackage && !doEncrypt { if sendScheme.Is(PGPInlinePackage) && !doEncrypt {
return errInlineMustEncrypt return errInlineMustEncrypt
} }
if sendScheme == PGPInlinePackage && contentType == ContentTypeHTML { if sendScheme.Is(PGPInlinePackage) && contentType == ContentTypeHTML {
return errInlineMustBePlain return errInlineMustBePlain
} }
if sendScheme == InternalPackage && !doEncrypt { if sendScheme.Is(InternalPackage) && !doEncrypt {
return errInternalMustEncrypt return errInternalMustEncrypt
} }
if doEncrypt && pubkey == nil { if doEncrypt && pubkey == nil {
@ -262,8 +278,8 @@ func (req *SendMessageReq) addNonMIMERecipient(
} }
func (req *SendMessageReq) addMIMERecipient( func (req *SendMessageReq) addMIMERecipient(
email string, sendScheme int, email string, sendScheme PackageFlag,
pubkey *crypto.KeyRing, signature int, pubkey *crypto.KeyRing, signature SignatureFlag,
) (err error) { ) (err error) {
req.mime.contentType = ContentTypeMultipartMixed req.mime.contentType = ContentTypeMultipartMixed
if req.mime.decryptedBodyKey == nil { if req.mime.decryptedBodyKey == nil {
@ -272,7 +288,7 @@ func (req *SendMessageReq) addMIMERecipient(
} }
} }
if sendScheme == PGPMIMEPackage { if sendScheme.Is(PGPMIMEPackage) {
if pubkey == nil { if pubkey == nil {
return errMissingPubkey return errMissingPubkey
} }

View File

@ -27,9 +27,9 @@ import (
type recipient struct { type recipient struct {
email string email string
sendScheme int sendScheme PackageFlag
pubkey *crypto.KeyRing pubkey *crypto.KeyRing
signature int signature SignatureFlag
contentType string contentType string
doEncrypt bool doEncrypt bool
wantError error wantError error
@ -181,6 +181,7 @@ func TestSendReq(t *testing.T) {
"mime@gpg.com": {"", PGPMIMEPackage, testPublicKeyRing, SignatureDetached, ContentTypeMultipartMixed, true, nil}, "mime@gpg.com": {"", PGPMIMEPackage, testPublicKeyRing, SignatureDetached, ContentTypeMultipartMixed, true, nil},
"plain@gpg.com": {"", PGPInlinePackage, testPublicKeyRing, SignatureDetached, ContentTypePlainText, true, nil}, "plain@gpg.com": {"", PGPInlinePackage, testPublicKeyRing, SignatureDetached, ContentTypePlainText, true, nil},
// External Encryption bad // External Encryption bad
"eo@gpg.com": {"", EncryptedOutsidePackage, testPublicKeyRing, SignatureDetached, ContentTypeHTML, true, errEncryptedOutsideNotSupported},
"inline-html@gpg.com": {"", PGPInlinePackage, testPublicKeyRing, SignatureDetached, ContentTypeHTML, true, errInlineMustBePlain}, "inline-html@gpg.com": {"", PGPInlinePackage, testPublicKeyRing, SignatureDetached, ContentTypeHTML, true, errInlineMustBePlain},
"inline-mixed@gpg.com": {"", PGPInlinePackage, testPublicKeyRing, SignatureDetached, ContentTypeMultipartMixed, true, errMultipartInNonMIME}, "inline-mixed@gpg.com": {"", PGPInlinePackage, testPublicKeyRing, SignatureDetached, ContentTypeMultipartMixed, true, errMultipartInNonMIME},
"inline-clear@gpg.com": {"", PGPInlinePackage, nil, SignatureDetached, ContentTypePlainText, false, errInlineMustEncrypt}, "inline-clear@gpg.com": {"", PGPInlinePackage, nil, SignatureDetached, ContentTypePlainText, false, errInlineMustEncrypt},
@ -278,6 +279,7 @@ func TestSendReq(t *testing.T) {
"mime-plain@email.com", "mime-plain@email.com",
"mime-html@email.com", "mime-html@email.com",
"eo@gpg.com",
"inline-html@gpg.com", "inline-html@gpg.com",
"inline-mixed@gpg.com", "inline-mixed@gpg.com",
"inline-clear@gpg.com", "inline-clear@gpg.com",

View File

@ -85,7 +85,7 @@ type MailSettings struct {
RightToLeft int RightToLeft int
AttachPublicKey int AttachPublicKey int
Sign int Sign int
PGPScheme int PGPScheme PackageFlag
PromptPin int PromptPin int
Autocrypt int Autocrypt int
NumMessagePerPage int NumMessagePerPage int