Files
proton-bridge/internal/smtp/vcard_tools.go
2020-09-11 11:41:03 +02:00

95 lines
2.9 KiB
Go

// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package smtp
import (
"encoding/base64"
"strconv"
"strings"
"github.com/ProtonMail/go-vcard"
"github.com/ProtonMail/proton-bridge/pkg/pmapi"
)
type ContactMetadata struct {
Email string
Keys []string
Scheme string
Sign bool
SignIsSet bool
Encrypt bool
MIMEType string
}
const (
FieldPMScheme = "X-PM-SCHEME"
FieldPMEncrypt = "X-PM-ENCRYPT"
FieldPMSign = "X-PM-SIGN"
FieldPMMIMEType = "X-PM-MIMETYPE"
)
func GetContactMetadataFromVCards(cards []pmapi.Card, email string) (contactMeta *ContactMetadata, err error) {
for _, card := range cards {
dec := vcard.NewDecoder(strings.NewReader(card.Data))
parsedCard, err := dec.Decode()
if err != nil {
return nil, err
}
group := parsedCard.GetGroupByValue(vcard.FieldEmail, email)
if len(group) == 0 {
continue
}
keys := []string{}
for _, key := range parsedCard.GetAllValueByGroup(vcard.FieldKey, group) {
keybyte, err := base64.StdEncoding.DecodeString(strings.Split(key, "base64,")[1])
if err != nil {
return nil, err
}
// It would be better to always have correct data on the server, but mistakes
// can happen -- we had an issue where KEY was included in VCARD, but was empty.
// It's valid and we need to handle it by not including it in the keys, which would fail later.
if len(keybyte) > 0 {
keys = append(keys, string(keybyte))
}
}
scheme := parsedCard.GetValueByGroup(FieldPMScheme, group)
// Warn: ParseBool treats 1, T, True, true as true and 0, F, Fale, false as false.
// However PMEL declares 'true' is true, 'false' is false. every other string is true
encrypt, _ := strconv.ParseBool(parsedCard.GetValueByGroup(FieldPMEncrypt, group))
var sign, signIsSet bool
if len(parsedCard[FieldPMSign]) == 0 {
signIsSet = false
} else {
sign, _ = strconv.ParseBool(parsedCard.GetValueByGroup(FieldPMSign, group))
signIsSet = true
}
mimeType := parsedCard.GetValueByGroup(FieldPMMIMEType, group)
return &ContactMetadata{
Email: email,
Keys: keys,
Scheme: scheme,
Sign: sign,
SignIsSet: signIsSet,
Encrypt: encrypt,
MIMEType: mimeType,
}, nil
}
return &ContactMetadata{}, nil
}