mirror of
https://github.com/ProtonMail/proton-bridge.git
synced 2025-12-10 04:36:43 +00:00
446 lines
16 KiB
Go
446 lines
16 KiB
Go
// Copyright (c) 2023 Proton AG
|
|
//
|
|
// This file is part of Proton Mail Bridge.
|
|
//
|
|
// Proton Mail 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.
|
|
//
|
|
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
package user
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/ProtonMail/gluon/rfc822"
|
|
"github.com/ProtonMail/go-proton-api"
|
|
"github.com/ProtonMail/gopenpgp/v2/crypto"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestPreferencesBuilder(t *testing.T) {
|
|
testContactKey := loadContactKey(t, testPublicKey)
|
|
testOtherContactKey := loadContactKey(t, testOtherPublicKey)
|
|
|
|
tests := []struct { //nolint:maligned
|
|
name string
|
|
|
|
contactMeta *contactSettings
|
|
receivedKeys []proton.PublicKey
|
|
isInternal bool
|
|
mailSettings proton.MailSettings
|
|
composerMIMEType string
|
|
|
|
wantEncrypt bool
|
|
wantSign proton.SignatureType
|
|
wantScheme proton.EncryptionScheme
|
|
wantMIMEType rfc822.MIMEType
|
|
wantPublicKey string
|
|
}{
|
|
{
|
|
name: "internal",
|
|
|
|
contactMeta: &contactSettings{},
|
|
receivedKeys: []proton.PublicKey{{PublicKey: testPublicKey}},
|
|
isInternal: true,
|
|
mailSettings: proton.MailSettings{PGPScheme: proton.PGPMIMEScheme, DraftMIMEType: "text/html"},
|
|
|
|
wantEncrypt: true,
|
|
wantSign: proton.DetachedSignature,
|
|
wantScheme: proton.InternalScheme,
|
|
wantMIMEType: "text/html",
|
|
wantPublicKey: testPublicKey,
|
|
},
|
|
|
|
{
|
|
name: "internal with contact-specific email format",
|
|
|
|
contactMeta: &contactSettings{MIMEType: "text/plain"},
|
|
receivedKeys: []proton.PublicKey{{PublicKey: testPublicKey}},
|
|
isInternal: true,
|
|
mailSettings: proton.MailSettings{PGPScheme: proton.PGPMIMEScheme, DraftMIMEType: "text/html"},
|
|
|
|
wantEncrypt: true,
|
|
wantSign: proton.DetachedSignature,
|
|
wantScheme: proton.InternalScheme,
|
|
wantMIMEType: "text/plain",
|
|
wantPublicKey: testPublicKey,
|
|
},
|
|
|
|
{
|
|
name: "internal with pinned contact public key",
|
|
|
|
contactMeta: &contactSettings{Keys: []string{testContactKey}},
|
|
receivedKeys: []proton.PublicKey{{PublicKey: testPublicKey}},
|
|
isInternal: true,
|
|
mailSettings: proton.MailSettings{PGPScheme: proton.PGPMIMEScheme, DraftMIMEType: "text/html"},
|
|
|
|
wantEncrypt: true,
|
|
wantSign: proton.DetachedSignature,
|
|
wantScheme: proton.InternalScheme,
|
|
wantMIMEType: "text/html",
|
|
wantPublicKey: testPublicKey,
|
|
},
|
|
|
|
{
|
|
// NOTE: Need to figured out how to test that this calls the frontend to check for user confirmation.
|
|
name: "internal with conflicting contact public key",
|
|
|
|
contactMeta: &contactSettings{Keys: []string{testOtherContactKey}},
|
|
receivedKeys: []proton.PublicKey{{PublicKey: testPublicKey}},
|
|
isInternal: true,
|
|
mailSettings: proton.MailSettings{PGPScheme: proton.PGPMIMEScheme, DraftMIMEType: "text/html"},
|
|
|
|
wantEncrypt: true,
|
|
wantSign: proton.DetachedSignature,
|
|
wantScheme: proton.InternalScheme,
|
|
wantMIMEType: "text/html",
|
|
wantPublicKey: testPublicKey,
|
|
},
|
|
|
|
{
|
|
name: "wkd-external",
|
|
|
|
contactMeta: &contactSettings{},
|
|
receivedKeys: []proton.PublicKey{{PublicKey: testPublicKey}},
|
|
isInternal: false,
|
|
mailSettings: proton.MailSettings{PGPScheme: proton.PGPMIMEScheme, DraftMIMEType: "text/html"},
|
|
|
|
wantEncrypt: true,
|
|
wantSign: proton.DetachedSignature,
|
|
wantScheme: proton.PGPMIMEScheme,
|
|
wantMIMEType: "multipart/mixed",
|
|
wantPublicKey: testPublicKey,
|
|
},
|
|
|
|
{
|
|
name: "wkd-external with contact-specific email format",
|
|
|
|
contactMeta: &contactSettings{MIMEType: "text/plain"},
|
|
receivedKeys: []proton.PublicKey{{PublicKey: testPublicKey}},
|
|
isInternal: false,
|
|
mailSettings: proton.MailSettings{PGPScheme: proton.PGPMIMEScheme, DraftMIMEType: "text/html"},
|
|
|
|
wantEncrypt: true,
|
|
wantSign: proton.DetachedSignature,
|
|
wantScheme: proton.PGPMIMEScheme,
|
|
wantMIMEType: "multipart/mixed",
|
|
wantPublicKey: testPublicKey,
|
|
},
|
|
|
|
{
|
|
name: "wkd-external with global pgp-inline scheme",
|
|
|
|
contactMeta: &contactSettings{},
|
|
receivedKeys: []proton.PublicKey{{PublicKey: testPublicKey}},
|
|
isInternal: false,
|
|
mailSettings: proton.MailSettings{PGPScheme: proton.PGPInlineScheme, DraftMIMEType: "text/html"},
|
|
|
|
wantEncrypt: true,
|
|
wantSign: proton.DetachedSignature,
|
|
wantScheme: proton.PGPInlineScheme,
|
|
wantMIMEType: "text/plain",
|
|
wantPublicKey: testPublicKey,
|
|
},
|
|
|
|
{
|
|
name: "wkd-external with contact-specific pgp-inline scheme overriding global pgp-mime setting",
|
|
|
|
contactMeta: &contactSettings{Scheme: pgpInline},
|
|
receivedKeys: []proton.PublicKey{{PublicKey: testPublicKey}},
|
|
isInternal: false,
|
|
mailSettings: proton.MailSettings{PGPScheme: proton.PGPMIMEScheme, DraftMIMEType: "text/html"},
|
|
|
|
wantEncrypt: true,
|
|
wantSign: proton.DetachedSignature,
|
|
wantScheme: proton.PGPInlineScheme,
|
|
wantMIMEType: "text/plain",
|
|
wantPublicKey: testPublicKey,
|
|
},
|
|
|
|
{
|
|
name: "wkd-external with contact-specific pgp-mime scheme overriding global pgp-inline setting",
|
|
|
|
contactMeta: &contactSettings{Scheme: pgpMIME},
|
|
receivedKeys: []proton.PublicKey{{PublicKey: testPublicKey}},
|
|
isInternal: false,
|
|
mailSettings: proton.MailSettings{PGPScheme: proton.PGPInlineScheme, DraftMIMEType: "text/html"},
|
|
|
|
wantEncrypt: true,
|
|
wantSign: proton.DetachedSignature,
|
|
wantScheme: proton.PGPMIMEScheme,
|
|
wantMIMEType: "multipart/mixed",
|
|
wantPublicKey: testPublicKey,
|
|
},
|
|
|
|
{
|
|
name: "wkd-external with additional pinned contact public key",
|
|
|
|
contactMeta: &contactSettings{Keys: []string{testContactKey}},
|
|
receivedKeys: []proton.PublicKey{{PublicKey: testPublicKey}},
|
|
isInternal: false,
|
|
mailSettings: proton.MailSettings{PGPScheme: proton.PGPMIMEScheme, DraftMIMEType: "text/html"},
|
|
|
|
wantEncrypt: true,
|
|
wantSign: proton.DetachedSignature,
|
|
wantScheme: proton.PGPMIMEScheme,
|
|
wantMIMEType: "multipart/mixed",
|
|
wantPublicKey: testPublicKey,
|
|
},
|
|
|
|
{
|
|
// NOTE: Need to figured out how to test that this calls the frontend to check for user confirmation.
|
|
name: "wkd-external with additional conflicting contact public key",
|
|
|
|
contactMeta: &contactSettings{Keys: []string{testOtherContactKey}},
|
|
receivedKeys: []proton.PublicKey{{PublicKey: testPublicKey}},
|
|
isInternal: false,
|
|
mailSettings: proton.MailSettings{PGPScheme: proton.PGPMIMEScheme, DraftMIMEType: "text/html"},
|
|
|
|
wantEncrypt: true,
|
|
wantSign: proton.DetachedSignature,
|
|
wantScheme: proton.PGPMIMEScheme,
|
|
wantMIMEType: "multipart/mixed",
|
|
wantPublicKey: testPublicKey,
|
|
},
|
|
|
|
{
|
|
name: "external",
|
|
|
|
contactMeta: &contactSettings{},
|
|
receivedKeys: []proton.PublicKey{},
|
|
isInternal: false,
|
|
mailSettings: proton.MailSettings{PGPScheme: proton.PGPMIMEScheme, DraftMIMEType: "text/html"},
|
|
|
|
wantEncrypt: false,
|
|
wantSign: proton.NoSignature,
|
|
wantScheme: proton.ClearScheme,
|
|
wantMIMEType: "text/html",
|
|
},
|
|
|
|
{
|
|
name: "external with contact-specific email format",
|
|
|
|
contactMeta: &contactSettings{MIMEType: "text/plain"},
|
|
receivedKeys: []proton.PublicKey{},
|
|
isInternal: false,
|
|
mailSettings: proton.MailSettings{PGPScheme: proton.PGPMIMEScheme, DraftMIMEType: "text/html"},
|
|
|
|
wantEncrypt: false,
|
|
wantSign: proton.NoSignature,
|
|
wantScheme: proton.ClearScheme,
|
|
wantMIMEType: "text/plain",
|
|
},
|
|
|
|
{
|
|
name: "external with sign enabled",
|
|
|
|
contactMeta: &contactSettings{Sign: true, SignIsSet: true},
|
|
receivedKeys: []proton.PublicKey{},
|
|
isInternal: false,
|
|
mailSettings: proton.MailSettings{PGPScheme: proton.PGPMIMEScheme, DraftMIMEType: "text/html"},
|
|
|
|
wantEncrypt: false,
|
|
wantSign: proton.DetachedSignature,
|
|
wantScheme: proton.ClearMIMEScheme,
|
|
wantMIMEType: "multipart/mixed",
|
|
},
|
|
|
|
{
|
|
name: "external with contact sign enabled and plain text",
|
|
|
|
contactMeta: &contactSettings{MIMEType: "text/plain", Scheme: pgpInline, Sign: true, SignIsSet: true},
|
|
receivedKeys: []proton.PublicKey{},
|
|
isInternal: false,
|
|
mailSettings: proton.MailSettings{PGPScheme: proton.PGPMIMEScheme, DraftMIMEType: "text/html"},
|
|
|
|
wantEncrypt: false,
|
|
wantSign: proton.DetachedSignature,
|
|
wantScheme: proton.ClearScheme,
|
|
wantMIMEType: "text/plain",
|
|
},
|
|
|
|
{
|
|
name: "external with sign enabled, sending plaintext, should still send as ClearMIME",
|
|
|
|
contactMeta: &contactSettings{Sign: true, SignIsSet: true},
|
|
receivedKeys: []proton.PublicKey{},
|
|
isInternal: false,
|
|
mailSettings: proton.MailSettings{PGPScheme: proton.PGPMIMEScheme, DraftMIMEType: "text/plain"},
|
|
|
|
wantEncrypt: false,
|
|
wantSign: proton.DetachedSignature,
|
|
wantScheme: proton.ClearMIMEScheme,
|
|
wantMIMEType: "multipart/mixed",
|
|
},
|
|
|
|
{
|
|
name: "external with pinned contact public key but no intention to encrypt/sign",
|
|
|
|
contactMeta: &contactSettings{Keys: []string{testContactKey}},
|
|
receivedKeys: []proton.PublicKey{},
|
|
isInternal: false,
|
|
mailSettings: proton.MailSettings{PGPScheme: proton.PGPMIMEScheme, DraftMIMEType: "text/html"},
|
|
|
|
wantEncrypt: false,
|
|
wantSign: proton.NoSignature,
|
|
wantScheme: proton.ClearScheme,
|
|
wantMIMEType: "text/html",
|
|
wantPublicKey: testPublicKey,
|
|
},
|
|
|
|
{
|
|
name: "external with pinned contact public key, encrypted and signed",
|
|
|
|
contactMeta: &contactSettings{Keys: []string{testContactKey}, Encrypt: true, Sign: true, SignIsSet: true},
|
|
receivedKeys: []proton.PublicKey{},
|
|
isInternal: false,
|
|
mailSettings: proton.MailSettings{PGPScheme: proton.PGPMIMEScheme, DraftMIMEType: "text/html"},
|
|
|
|
wantEncrypt: true,
|
|
wantSign: proton.DetachedSignature,
|
|
wantScheme: proton.PGPMIMEScheme,
|
|
wantMIMEType: "multipart/mixed",
|
|
wantPublicKey: testPublicKey,
|
|
},
|
|
|
|
{
|
|
name: "external with pinned contact public key, encrypted and signed using contact-specific pgp-inline",
|
|
|
|
contactMeta: &contactSettings{Keys: []string{testContactKey}, Encrypt: true, Sign: true, Scheme: pgpInline, SignIsSet: true},
|
|
receivedKeys: []proton.PublicKey{},
|
|
isInternal: false,
|
|
mailSettings: proton.MailSettings{PGPScheme: proton.PGPMIMEScheme, DraftMIMEType: "text/html"},
|
|
|
|
wantEncrypt: true,
|
|
wantSign: proton.DetachedSignature,
|
|
wantScheme: proton.PGPInlineScheme,
|
|
wantMIMEType: "text/plain",
|
|
wantPublicKey: testPublicKey,
|
|
},
|
|
|
|
{
|
|
name: "external with pinned contact public key, encrypted and signed using global pgp-inline",
|
|
|
|
contactMeta: &contactSettings{Keys: []string{testContactKey}, Encrypt: true, Sign: true, SignIsSet: true},
|
|
receivedKeys: []proton.PublicKey{},
|
|
isInternal: false,
|
|
mailSettings: proton.MailSettings{PGPScheme: proton.PGPInlineScheme, DraftMIMEType: "text/html"},
|
|
|
|
wantEncrypt: true,
|
|
wantSign: proton.DetachedSignature,
|
|
wantScheme: proton.PGPInlineScheme,
|
|
wantMIMEType: "text/plain",
|
|
wantPublicKey: testPublicKey,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
test := test // Avoid using range scope test inside function literal.
|
|
|
|
t.Run(test.name, func(t *testing.T) {
|
|
b := &sendPrefsBuilder{}
|
|
|
|
require.NoError(t, b.setPGPSettings(test.contactMeta, test.receivedKeys, test.isInternal))
|
|
b.setEncryptionPreferences(test.mailSettings)
|
|
b.setMIMEPreferences(test.composerMIMEType)
|
|
|
|
prefs := b.build()
|
|
|
|
assert.Equal(t, test.wantEncrypt, prefs.Encrypt)
|
|
assert.Equal(t, test.wantSign, prefs.SignatureType)
|
|
assert.Equal(t, test.wantScheme, prefs.EncryptionScheme)
|
|
assert.Equal(t, test.wantMIMEType, prefs.MIMEType)
|
|
|
|
if prefs.PubKey != nil {
|
|
wantKey, err := crypto.NewKeyFromArmored(test.wantPublicKey)
|
|
require.NoError(t, err)
|
|
|
|
haveKey, err := prefs.PubKey.GetKey(0)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, wantKey.GetFingerprint(), haveKey.GetFingerprint())
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func loadContactKey(t *testing.T, key string) string {
|
|
ck, err := crypto.NewKeyFromArmored(key)
|
|
require.NoError(t, err)
|
|
|
|
pk, err := ck.GetPublicKey()
|
|
require.NoError(t, err)
|
|
|
|
return string(pk)
|
|
}
|
|
|
|
const testPublicKey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
|
|
|
xsBNBFRJbc0BCAC0mMLZPDBbtSCWvxwmOfXfJkE2+ssM3ux21LhD/bPiWefEWSHl
|
|
CjJ8PqPHy7snSiUuxuj3f9AvXPvg+mjGLBwu1/QsnSP24sl3qD2onl39vPiLJXUq
|
|
Zs20ZRgnvX70gjkgEzMFBxINiy2MTIG+4RU8QA7y8KzWev0btqKiMeVa+GLEHhgZ
|
|
2KPOn4Jv1q4bI9hV0C9NUe2tTXS6/Vv3vbCY7lRR0kbJ65T5c8CmpqJuASIJNrSX
|
|
M/Q3NnnsY4kBYH0s5d2FgbASQvzrjuC2rngUg0EoPsrbDEVRA2/BCJonw7aASiNC
|
|
rSP92lkZdtYlax/pcoE/mQ4WSwySFmcFT7yFABEBAAHNBlVzZXJJRMLAcgQQAQgA
|
|
JgUCVEltzwYLCQgHAwIJED62JZ7fId8kBBUIAgoDFgIBAhsDAh4BAAD0nQf9EtH9
|
|
TC0JqSs8q194Zo244jjlJFM3EzxOSULq0zbywlLORfyoo/O8jU/HIuGz+LT98JDt
|
|
nltTqfjWgu6pS3ZL2/L4AGUKEoB7OI6oIdRwzMc61sqI+Qpbzxo7rzufH4CiXZc6
|
|
cxORUgL550xSCcqnq0q1mds7h5roKDzxMW6WLiEsc1dN8IQKzC7Ec5wA7U4oNGsJ
|
|
3TyI8jkIs0IhXrRCd26K0TW8Xp6GCsfblWXosR13y89WVNgC+xrrJKTZEisc0tRl
|
|
neIgjcwEUvwfIg2n9cDUFA/5BsfzTW5IurxqDEziIVP0L44PXjtJrBQaGMPlEbtP
|
|
5i2oi3OADVX2XbvsRc7ATQRUSW3PAQgAkPnu5fps5zhOB/e618v/iF3KiogxUeRh
|
|
A68TbvA+xnFfTxCx2Vo14aOL0CnaJ8gO5yRSqfomL2O1kMq07N1MGbqucbmc+aSf
|
|
oElc+Gd5xBE/w3RcEhKcAaYTi35vG22zlZup4x3ElioyIarOssFEkQgNNyDf5AXZ
|
|
jdHLA6qVxeqAb/Ff74+y9HUmLPSsRU9NwFzvK3Jv8C/ubHVLzTYdFgYkc4W1Uug9
|
|
Ou08K+/4NEMrwnPFBbZdJAuUjQz2zW2ZiEKiBggiorH2o5N3mYUnWEmUvqL3EOS8
|
|
TbWo8UBIW3DDm2JiZR8VrEgvBtc9mVDUj/x+5pR07Fy1D6DjRmAc9wARAQABwsBf
|
|
BBgBCAATBQJUSW3SCRA+tiWe3yHfJAIbDAAA/iwH/ik9RKZMB9Ir0x5mGpKPuqhu
|
|
gwrc3d04m1sOdXJm2NtD4ddzSEvzHwaPNvEvUl5v7FVMzf6+6mYGWHyNP4+e7Rtw
|
|
YLlRpud6smuGyDSsotUYyumiqP6680ZIeWVQ+a1TThNs878mAJy1FhvQFdTmA8XI
|
|
C616hDFpamQKPlpoO1a0wZnQhrPwT77HDYEEa+hqY4Jr/a7ui40S+7xYRHKL/7ZA
|
|
S4/grWllhU3dbNrwSzrOKwrA/U0/9t738Ap6JL71YymDeaL4sutcoaahda1pTrMW
|
|
ePtrCltz6uySwbZs7GXoEzjX3EAH+6qhkUJtzMaE3YEFEoQMGzcDTUEfXCJ3zJw=
|
|
=yT9U
|
|
-----END PGP PUBLIC KEY BLOCK-----`
|
|
|
|
const testOtherPublicKey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
|
|
|
mQENBF8Rmj4BCACgXXxRqLsmEUWZGd0f88BteXBfi9zL+9GysOTk4n9EgINLN2PU
|
|
5rYSmWvVocO8IAfl/z9zpTJQesQjGe5lHbygUWFmjadox2ZeecZw0PWCSRdAjk6w
|
|
Q4UX0JiCo3IuICZk1t53WWRtGnhA2Q21J4b2DJg4T5ZFKgKDzDhWoGF1ZStbI5X1
|
|
0rKTGFNHgreV5PqxUjxHVtx3rgT9Mx+13QTffqKR9oaYC6mNs4TNJdhyqfaYxqGw
|
|
ElxfdS9Wz6ODXrUNuSHETfgvAmo1Qep7GkefrC1isrmXA2+a+mXzFn4L0FCG073w
|
|
Vi/lEw6R/vKfN6QukHPxwoSguow4wTyhRRmfABEBAAG0GVRlc3RUZXN0IDx0ZXN0
|
|
dGVzdEBwbS5tZT6JAU4EEwEIADgWIQTsXZU1AxlWCPT02+BKdWAu4Q1jXQUCXxGa
|
|
PgIbAwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRBKdWAu4Q1jXQw+B/0ZudN+
|
|
W9EqJtL/elm7Qla47zNsFmB+pHObdGoKtp3mNc97CQoW1yQ/i/V0heBFTAioP00g
|
|
FgEk1ZUJfO++EtI8esNFdDZqY99826/Cl0FlJwubn/XYxi4XyaGTY1nhhyEJ2HWI
|
|
/mZ+Jfm9ojbHSLwO5/AHiQt5t+LPDsKLXZw1BDJTgf1xD6e36CwAZgrPGWDqCXJ9
|
|
BjlQn5hje7p0F8vYWBnnfSPkMHwibz9FlFqDh5v3XTgGpFIWDVkPVgAs8erM9AM2
|
|
TjdpGcdW8xfcymo3j/o2QUBGYGJwPTsGEO5IkFRre9c/3REa7MKIi17Y479ub0A6
|
|
2J3xgnqgI4sxmgmOuQENBF8Rmj4BCADX3BamNZsjC3I0knVIwjbz//1r8WOfNwGh
|
|
gg5LsvpfLkrsNUZy+deSwb+hS9Auyr1xsMmtVyiTPGUXTjU4uUzY2zyTYWgYfSEi
|
|
CojlXmYYLsjyPzR7KhVP6QIYZqYkOQXaCQDRlprRoFIEe4FzTCuqDHatJNwSesGy
|
|
5pPJrjiAeb47m9KaoEIacoe9D3w1z4FCKN3A8cjiWT8NRfhYTBoE/T34oXVUj8l+
|
|
jLIgVUQgGoBos160Z1Cnxd2PKWFVh/Br3QtIPTbNVDWhh5T1+N2ypbwsXCawy6fj
|
|
cbOaTLz/vF9g+RJKC0MtxdL5qUtv3d3Zn07Sg+9H6wjsboAdAvirABEBAAGJATYE
|
|
GAEIACAWIQTsXZU1AxlWCPT02+BKdWAu4Q1jXQUCXxGaPgIbDAAKCRBKdWAu4Q1j
|
|
Xc4WB/9+aTGMMTlIdAFs9rf0i7i83pUOOxuLl34YQ0t5WGsjteQ4IK+gfuFvp37W
|
|
ktv98ShOxAexbfqzGyGcYLLgaCxCbbB85fvSeX0xK/C2UbiH3Gv1z8GTelailCxt
|
|
vyx642TwpcLXW1obHaHTSIi5L35Tce9gbug9sKCRSlAH76dANYBbMLa2Bl0LSrF8
|
|
mcie9jJaPRXGOeHOyZmPZwwGhVYgadjptWqXnFz3ua8vxgqG0sefWF23F36iVz2q
|
|
UjxSE+nKLaPFLlEDLgxG4SwHkcR9fi7zaQVnXg4rEjr0uz5MSUqZC4MNB4rkhU3g
|
|
/rUMQyZupw+xJ+ayQNVBEtYZd/9u
|
|
=TNX4
|
|
-----END PGP PUBLIC KEY BLOCK-----`
|