mirror of
https://github.com/ProtonMail/proton-bridge.git
synced 2025-12-15 14:56:42 +00:00
Merge branch 'release/james' into devel
This commit is contained in:
@ -33,16 +33,24 @@ import (
|
||||
|
||||
pmmime "github.com/ProtonMail/proton-bridge/pkg/mime"
|
||||
|
||||
a "github.com/stretchr/testify/assert"
|
||||
r "github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const testAttachmentCleartext = `cc,
|
||||
dille.
|
||||
`
|
||||
|
||||
// Attachment cleartext encrypted with testPrivateKeyRing.
|
||||
const testKeyPacket = `wcBMA0fcZ7XLgmf2AQf/cHhfDRM9zlIuBi+h2W6DKjbbyIHMkgF6ER3JEvn/tSruUH8KTGt0N7Z+a80FFMCuXn1Y1I/nW7MVrNhGuJZAF4OymD8ugvuoAMIQX0eCYEpPXzRIWJBZg82AuowmFMsv8Dgvq4bTZq4cttI3CZcxKUNXuAearmNpmgplUKWj5USmRXK4iGB3VFGjidXkxbElrP4fD5A/rfEZ5aJgCsegqcXxX3MEjWXi9pFzgd/9phOvl1ZFm9U9hNoVAW3QsgmVeihnKaDZUyf2Qsigij21QKAUxw9U3y89eTUIqZAcmIgqeDujA3RWBgJwjtY/lOyhEmkf3AWKzehvf1xtJmCWDg==`
|
||||
const testDataPacket = `0ksB6S4f4l8C1NB8yzmd/jNi0xqEZsyTDLdTP+N4Qxh3NZjla+yGRvC9rGmoUL7XVyowsG/GKTf2LXF/5E5FkX/3WMYwIv1n11ExyAE=`
|
||||
|
||||
var testAttachment = &Attachment{
|
||||
ID: "y6uKIlc2HdoHPAwPSrvf7dXoZNMYvBgxshYUN67cY5DJjL2O8NYewuvGHcYvCfd8LpEoAI_GdymO0Jr0mHlsEw==",
|
||||
Name: "croutonmail.txt",
|
||||
Size: 77,
|
||||
MIMEType: "text/plain",
|
||||
KeyPackets: "wcBMA0fcZ7XLgmf2AQgAiRsOlnm1kSB4/lr7tYe6pBsRGn10GqwUhrwU5PMKOHdCgnO12jO3y3CzP0Yl/jGhAYja9wLDqH8X0sk3tY32u4Sb1Qe5IuzggAiCa4dwOJj5gEFMTHMzjIMPHR7A70XqUxMhmILye8V4KRm/j4c1sxbzA1rM3lYBumQuB5l/ck0Kgt4ZqxHVXHK5Q1l65FHhSXRj8qnunasHa30TYNzP8nmBA8BinnJxpiQ7FGc2umnUhgkFtjm5ixu9vyjr9ukwDTbwAXXfmY+o7tK7kqIXJcmTL6k2UeC6Mz1AagQtRCRtU+bv/3zGojq/trZo9lom3naIeQYa36Ketmcpj2Qwjg==",
|
||||
KeyPackets: testKeyPacket,
|
||||
|
||||
Header: textproto.MIMEHeader{
|
||||
"Content-Description": {"You'll never believe what's in this text file"},
|
||||
"X-Mailer": {"Microsoft Outlook 15.0", "Microsoft Live Mail 42.0"},
|
||||
@ -50,12 +58,13 @@ var testAttachment = &Attachment{
|
||||
MessageID: "h3CD-DT7rLoAw1vmpcajvIPAl-wwDfXR2MHtWID3wuQURDBKTiGUAwd6E2WBbS44QQKeXImW-axm6X0hAfcVCA==",
|
||||
}
|
||||
|
||||
// Part of GET /mail/messages/{id} response from server.
|
||||
const testAttachmentJSON = `{
|
||||
"ID": "y6uKIlc2HdoHPAwPSrvf7dXoZNMYvBgxshYUN67cY5DJjL2O8NYewuvGHcYvCfd8LpEoAI_GdymO0Jr0mHlsEw==",
|
||||
"Name": "croutonmail.txt",
|
||||
"Size": 77,
|
||||
"MIMEType": "text/plain",
|
||||
"KeyPackets": "wcBMA0fcZ7XLgmf2AQgAiRsOlnm1kSB4/lr7tYe6pBsRGn10GqwUhrwU5PMKOHdCgnO12jO3y3CzP0Yl/jGhAYja9wLDqH8X0sk3tY32u4Sb1Qe5IuzggAiCa4dwOJj5gEFMTHMzjIMPHR7A70XqUxMhmILye8V4KRm/j4c1sxbzA1rM3lYBumQuB5l/ck0Kgt4ZqxHVXHK5Q1l65FHhSXRj8qnunasHa30TYNzP8nmBA8BinnJxpiQ7FGc2umnUhgkFtjm5ixu9vyjr9ukwDTbwAXXfmY+o7tK7kqIXJcmTL6k2UeC6Mz1AagQtRCRtU+bv/3zGojq/trZo9lom3naIeQYa36Ketmcpj2Qwjg==",
|
||||
"KeyPackets": "` + testKeyPacket + `",
|
||||
"Headers": {
|
||||
"content-description": "You'll never believe what's in this text file",
|
||||
"x-mailer": [
|
||||
@ -66,68 +75,66 @@ const testAttachmentJSON = `{
|
||||
}
|
||||
`
|
||||
|
||||
const testAttachmentCleartext = `cc,
|
||||
dille.
|
||||
`
|
||||
|
||||
const testAttachmentEncrypted = `wcBMA0fcZ7XLgmf2AQf/cHhfDRM9zlIuBi+h2W6DKjbbyIHMkgF6ER3JEvn/tSruUH8KTGt0N7Z+a80FFMCuXn1Y1I/nW7MVrNhGuJZAF4OymD8ugvuoAMIQX0eCYEpPXzRIWJBZg82AuowmFMsv8Dgvq4bTZq4cttI3CZcxKUNXuAearmNpmgplUKWj5USmRXK4iGB3VFGjidXkxbElrP4fD5A/rfEZ5aJgCsegqcXxX3MEjWXi9pFzgd/9phOvl1ZFm9U9hNoVAW3QsgmVeihnKaDZUyf2Qsigij21QKAUxw9U3y89eTUIqZAcmIgqeDujA3RWBgJwjtY/lOyhEmkf3AWKzehvf1xtJmCWDtJLAekuH+JfAtTQfMs5nf4zYtMahGbMkwy3Uz/jeEMYdzWY5WvshkbwvaxpqFC+11cqMLBvxik39i1xf+RORZF/91jGMCL9Z9dRMcgB`
|
||||
|
||||
const testCreateAttachmentBody = `{
|
||||
// POST /mail/attachment/ response from server.
|
||||
const testCreatedAttachmentBody = `{
|
||||
"Code": 1000,
|
||||
"Attachment": {"ID": "y6uKIlc2HdoHPAwPSrvf7dXoZNMYvBgxshYUN67cY5DJjL2O8NYewuvGHcYvCfd8LpEoAI_GdymO0Jr0mHlsEw=="}
|
||||
}`
|
||||
|
||||
func TestAttachment_UnmarshalJSON(t *testing.T) {
|
||||
r := require.New(t)
|
||||
att := new(Attachment)
|
||||
err := json.Unmarshal([]byte(testAttachmentJSON), att)
|
||||
r.NoError(t, err)
|
||||
r.NoError(err)
|
||||
|
||||
att.MessageID = testAttachment.MessageID // This isn't in the JSON object
|
||||
att.MessageID = testAttachment.MessageID // This isn't in the server response
|
||||
|
||||
r.Equal(t, testAttachment, att)
|
||||
r.Equal(testAttachment, att)
|
||||
}
|
||||
|
||||
func TestClient_CreateAttachment(t *testing.T) {
|
||||
r := require.New(t)
|
||||
s, c := newTestClient(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
r.NoError(t, checkMethodAndPath(req, "POST", "/mail/v4/attachments"))
|
||||
r.NoError(checkMethodAndPath(req, "POST", "/mail/v4/attachments"))
|
||||
|
||||
contentType, params, err := pmmime.ParseMediaType(req.Header.Get("Content-Type"))
|
||||
r.NoError(t, err)
|
||||
r.Equal(t, "multipart/form-data", contentType)
|
||||
r.NoError(err)
|
||||
r.Equal("multipart/form-data", contentType)
|
||||
|
||||
mr := multipart.NewReader(req.Body, params["boundary"])
|
||||
form, err := mr.ReadForm(10 * 1024)
|
||||
r.NoError(t, err)
|
||||
defer r.NoError(t, form.RemoveAll())
|
||||
r.NoError(err)
|
||||
defer r.NoError(form.RemoveAll())
|
||||
|
||||
r.Equal(t, testAttachment.Name, form.Value["Filename"][0])
|
||||
r.Equal(t, testAttachment.MessageID, form.Value["MessageID"][0])
|
||||
r.Equal(t, testAttachment.MIMEType, form.Value["MIMEType"][0])
|
||||
r.Equal(testAttachment.Name, form.Value["Filename"][0])
|
||||
r.Equal(testAttachment.MessageID, form.Value["MessageID"][0])
|
||||
r.Equal(testAttachment.MIMEType, form.Value["MIMEType"][0])
|
||||
|
||||
dataFile, err := form.File["DataPacket"][0].Open()
|
||||
r.NoError(t, err)
|
||||
defer r.NoError(t, dataFile.Close())
|
||||
r.NoError(err)
|
||||
defer r.NoError(dataFile.Close())
|
||||
|
||||
b, err := ioutil.ReadAll(dataFile)
|
||||
r.NoError(t, err)
|
||||
r.Equal(t, testAttachmentCleartext, string(b))
|
||||
r.NoError(err)
|
||||
r.Equal(testAttachmentCleartext, string(b))
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
fmt.Fprint(w, testCreateAttachmentBody)
|
||||
fmt.Fprint(w, testCreatedAttachmentBody)
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
reader := strings.NewReader(testAttachmentCleartext) // In reality, this thing is encrypted
|
||||
created, err := c.CreateAttachment(context.Background(), testAttachment, reader, strings.NewReader(""))
|
||||
r.NoError(t, err)
|
||||
r.NoError(err)
|
||||
|
||||
r.Equal(t, testAttachment.ID, created.ID)
|
||||
r.Equal(testAttachment.ID, created.ID)
|
||||
}
|
||||
|
||||
func TestClient_GetAttachment(t *testing.T) {
|
||||
r := require.New(t)
|
||||
s, c := newTestClient(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
r.NoError(t, checkMethodAndPath(req, "GET", "/mail/v4/attachments/"+testAttachment.ID))
|
||||
r.NoError(checkMethodAndPath(req, "GET", "/mail/v4/attachments/"+testAttachment.ID))
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprint(w, testAttachmentCleartext)
|
||||
@ -135,39 +142,61 @@ func TestClient_GetAttachment(t *testing.T) {
|
||||
defer s.Close()
|
||||
|
||||
att, err := c.GetAttachment(context.Background(), testAttachment.ID)
|
||||
r.NoError(t, err)
|
||||
r.NoError(err)
|
||||
defer att.Close() //nolint[errcheck]
|
||||
|
||||
// In reality, r contains encrypted data
|
||||
b, err := ioutil.ReadAll(att)
|
||||
r.NoError(t, err)
|
||||
r.NoError(err)
|
||||
|
||||
r.Equal(t, testAttachmentCleartext, string(b))
|
||||
r.Equal(testAttachmentCleartext, string(b))
|
||||
}
|
||||
|
||||
func TestAttachment_Encrypt(t *testing.T) {
|
||||
data := bytes.NewBufferString(testAttachmentCleartext)
|
||||
r, err := testAttachment.Encrypt(testPublicKeyRing, data)
|
||||
a.Nil(t, err)
|
||||
b, err := ioutil.ReadAll(r)
|
||||
a.Nil(t, err)
|
||||
func TestAttachmentDecrypt(t *testing.T) {
|
||||
r := require.New(t)
|
||||
|
||||
// Result is always different, so the best way is to test it by decrypting again.
|
||||
// Another test for decrypting will help us to be sure it's working.
|
||||
dataEnc := bytes.NewBuffer(b)
|
||||
decryptAndCheck(t, dataEnc)
|
||||
rawKeyPacket, err := base64.StdEncoding.DecodeString(testKeyPacket)
|
||||
r.NoError(err)
|
||||
|
||||
rawDataPacket, err := base64.StdEncoding.DecodeString(testDataPacket)
|
||||
r.NoError(err)
|
||||
|
||||
decryptAndCheck(r, bytes.NewBuffer(append(rawKeyPacket, rawDataPacket...)))
|
||||
}
|
||||
|
||||
func TestAttachment_Decrypt(t *testing.T) {
|
||||
dataBytes, _ := base64.StdEncoding.DecodeString(testAttachmentEncrypted)
|
||||
dataReader := bytes.NewBuffer(dataBytes)
|
||||
decryptAndCheck(t, dataReader)
|
||||
func TestAttachmentEncrypt(t *testing.T) {
|
||||
r := require.New(t)
|
||||
|
||||
encryptedReader, err := testAttachment.Encrypt(
|
||||
testPublicKeyRing,
|
||||
bytes.NewBufferString(testAttachmentCleartext),
|
||||
)
|
||||
r.NoError(err)
|
||||
|
||||
// The result is always different due to session key. The best way is to
|
||||
// test result of encryption by decrypting again acn coparet to cleartext.
|
||||
decryptAndCheck(r, encryptedReader)
|
||||
}
|
||||
|
||||
func decryptAndCheck(t *testing.T, data io.Reader) {
|
||||
r, err := testAttachment.Decrypt(data, testPrivateKeyRing)
|
||||
a.Nil(t, err)
|
||||
b, err := ioutil.ReadAll(r)
|
||||
a.Nil(t, err)
|
||||
a.Equal(t, testAttachmentCleartext, string(b))
|
||||
func decryptAndCheck(r *require.Assertions, data io.Reader) {
|
||||
// First separate KeyPacket from encrypted data. In our case keypacket
|
||||
// has 271 bytes.
|
||||
raw, err := ioutil.ReadAll(data)
|
||||
r.NoError(err)
|
||||
rawKeyPacket := raw[:271]
|
||||
rawDataPacket := raw[271:]
|
||||
|
||||
// KeyPacket is retrieve by get GET /mail/messages/{id}
|
||||
haveAttachment := &Attachment{
|
||||
KeyPackets: base64.StdEncoding.EncodeToString(rawKeyPacket),
|
||||
}
|
||||
|
||||
// DataPacket is received from GET /mail/attachments/{id}
|
||||
decryptedReader, err := haveAttachment.Decrypt(bytes.NewBuffer(rawDataPacket), testPrivateKeyRing)
|
||||
r.NoError(err)
|
||||
|
||||
b, err := ioutil.ReadAll(decryptedReader)
|
||||
r.NoError(err)
|
||||
|
||||
r.Equal(testAttachmentCleartext, string(b))
|
||||
}
|
||||
|
||||
@ -22,7 +22,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/ProtonMail/gopenpgp/v2/crypto"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func loadPMKeys(jsonKeys string) (keys *PMKeys) {
|
||||
@ -31,6 +31,7 @@ func loadPMKeys(jsonKeys string) (keys *PMKeys) {
|
||||
}
|
||||
|
||||
func TestPMKeys_GetKeyRingAndUnlock(t *testing.T) {
|
||||
r := require.New(t)
|
||||
addrKeysWithTokens := loadPMKeys(readTestFile("keyring_addressKeysWithTokens_JSON", false))
|
||||
addrKeysWithoutTokens := loadPMKeys(readTestFile("keyring_addressKeysWithoutTokens_JSON", false))
|
||||
addrKeysPrimaryHasToken := loadPMKeys(readTestFile("keyring_addressKeysPrimaryHasToken_JSON", false))
|
||||
@ -42,7 +43,7 @@ func TestPMKeys_GetKeyRingAndUnlock(t *testing.T) {
|
||||
}
|
||||
|
||||
userKey, err := crypto.NewKeyRing(key)
|
||||
assert.NoError(t, err, "Expected not to receive an error unlocking user key")
|
||||
r.NoError(err, "Expected not to receive an error unlocking user key")
|
||||
|
||||
type args struct {
|
||||
userKeyring *crypto.KeyRing
|
||||
@ -77,9 +78,7 @@ func TestPMKeys_GetKeyRingAndUnlock(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
kr, err := tt.keys.UnlockAll(tt.args.passphrase, tt.args.userKeyring) // nolint[scopelint]
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
r.NoError(err)
|
||||
|
||||
// assert at least one key has been decrypted
|
||||
atLeastOneDecrypted := false
|
||||
@ -96,7 +95,21 @@ func TestPMKeys_GetKeyRingAndUnlock(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
assert.True(t, atLeastOneDecrypted)
|
||||
r.True(atLeastOneDecrypted)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGopenpgpEncryptAttachment(t *testing.T) {
|
||||
r := require.New(t)
|
||||
|
||||
wantMessage := crypto.NewPlainMessage([]byte(testAttachmentCleartext))
|
||||
|
||||
pgpSplitMessage, err := testPublicKeyRing.EncryptAttachment(wantMessage, "")
|
||||
r.NoError(err)
|
||||
|
||||
haveMessage, err := testPrivateKeyRing.DecryptAttachment(pgpSplitMessage)
|
||||
r.NoError(err)
|
||||
|
||||
r.Equal(wantMessage.Data, haveMessage.Data)
|
||||
}
|
||||
|
||||
@ -22,7 +22,7 @@ import (
|
||||
"encoding/base64"
|
||||
"time"
|
||||
|
||||
"github.com/ProtonMail/proton-bridge/pkg/srp"
|
||||
"github.com/ProtonMail/go-srp"
|
||||
)
|
||||
|
||||
func (m *manager) NewClient(uid, acc, ref string, exp time.Time) Client {
|
||||
@ -44,7 +44,7 @@ func (m *manager) NewClientWithRefresh(ctx context.Context, uid, ref string) (Cl
|
||||
return c.withAuth(auth.AccessToken, auth.RefreshToken, expiresIn(auth.ExpiresIn)), auth, nil
|
||||
}
|
||||
|
||||
func (m *manager) NewClientWithLogin(ctx context.Context, username, password string) (Client, *Auth, error) {
|
||||
func (m *manager) NewClientWithLogin(ctx context.Context, username string, password []byte) (Client, *Auth, error) {
|
||||
log.Trace("New client with login")
|
||||
|
||||
info, err := m.getAuthInfo(ctx, GetAuthInfoReq{Username: username})
|
||||
@ -52,12 +52,12 @@ func (m *manager) NewClientWithLogin(ctx context.Context, username, password str
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
srpAuth, err := srp.NewSrpAuth(info.Version, username, password, info.Salt, info.Modulus, info.ServerEphemeral)
|
||||
srpAuth, err := srp.NewAuth(info.Version, username, password, info.Salt, info.Modulus, info.ServerEphemeral)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
proofs, err := srpAuth.GenerateSrpProofs(2048)
|
||||
proofs, err := srpAuth.GenerateProofs(2048)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
@ -29,7 +29,7 @@ import (
|
||||
type Manager interface {
|
||||
NewClient(string, string, string, time.Time) Client
|
||||
NewClientWithRefresh(context.Context, string, string) (Client, *AuthRefresh, error)
|
||||
NewClientWithLogin(context.Context, string, string) (Client, *Auth, error)
|
||||
NewClientWithLogin(context.Context, string, []byte) (Client, *Auth, error)
|
||||
|
||||
DownloadAndVerify(kr *crypto.KeyRing, url, sig string) ([]byte, error)
|
||||
ReportBug(context.Context, ReportBugReq) error
|
||||
|
||||
@ -670,7 +670,7 @@ func (mr *MockManagerMockRecorder) NewClient(arg0, arg1, arg2, arg3 interface{})
|
||||
}
|
||||
|
||||
// NewClientWithLogin mocks base method
|
||||
func (m *MockManager) NewClientWithLogin(arg0 context.Context, arg1, arg2 string) (pmapi.Client, *pmapi.Auth, error) {
|
||||
func (m *MockManager) NewClientWithLogin(arg0 context.Context, arg1 string, arg2 []byte) (pmapi.Client, *pmapi.Auth, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "NewClientWithLogin", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(pmapi.Client)
|
||||
|
||||
@ -20,13 +20,14 @@ package pmapi
|
||||
import (
|
||||
"encoding/base64"
|
||||
|
||||
"github.com/jameskeane/bcrypt"
|
||||
"github.com/ProtonMail/go-srp"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func HashMailboxPassword(password, salt string) ([]byte, error) {
|
||||
// HashMailboxPassword expectects 128bit long salt encoded by standard base64.
|
||||
func HashMailboxPassword(password []byte, salt string) ([]byte, error) {
|
||||
if salt == "" {
|
||||
return []byte(password), nil
|
||||
return password, nil
|
||||
}
|
||||
|
||||
decodedSalt, err := base64.StdEncoding.DecodeString(salt)
|
||||
@ -34,15 +35,10 @@ func HashMailboxPassword(password, salt string) ([]byte, error) {
|
||||
return nil, errors.Wrap(err, "failed to decode salt")
|
||||
}
|
||||
|
||||
encodedSalt := base64.NewEncoding("./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789").WithPadding(base64.NoPadding).EncodeToString(decodedSalt)
|
||||
hashResult, err := bcrypt.Hash(password, "$2y$10$"+encodedSalt)
|
||||
hash, err := srp.MailboxPassword(password, decodedSalt)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to bcrypt-hash password")
|
||||
return nil, errors.Wrap(err, "failed to hash password")
|
||||
}
|
||||
|
||||
if len(hashResult) != 60 {
|
||||
return nil, errors.New("pmapi: invalid mailbox password hash")
|
||||
}
|
||||
|
||||
return []byte(hashResult[len(hashResult)-31:]), nil
|
||||
return hash[len(hash)-31:], nil
|
||||
}
|
||||
|
||||
44
pkg/pmapi/passwords_test.go
Normal file
44
pkg/pmapi/passwords_test.go
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright (c) 2021 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 pmapi
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestMailboxPassword(t *testing.T) {
|
||||
// wantHash was generated with passprase and salt defined below. It
|
||||
// should not change when changing implementation of the function.
|
||||
wantHash := []byte("B5nwpsJQSTJ16ldr64Vdq6oeCCn32Fi")
|
||||
|
||||
// Valid salt is 128bit long (16bytes)
|
||||
// $echo aaaabbbbccccdddd | base64
|
||||
salt := "YWFhYWJiYmJjY2NjZGRkZAo="
|
||||
|
||||
passphrase := []byte("random")
|
||||
|
||||
r := require.New(t)
|
||||
_, err := HashMailboxPassword(passphrase, "badsalt")
|
||||
r.Error(err)
|
||||
|
||||
haveHash, err := HashMailboxPassword(passphrase, salt)
|
||||
r.NoError(err)
|
||||
r.Equal(wantHash, haveHash)
|
||||
}
|
||||
Reference in New Issue
Block a user