2024-01-02 13:32:11 +00:00
|
|
|
// Copyright (c) 2024 Proton AG
|
2022-10-20 00:41:43 +00:00
|
|
|
//
|
|
|
|
// 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 tests
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2022-10-21 10:00:35 +00:00
|
|
|
"fmt"
|
2023-02-02 15:25:27 +00:00
|
|
|
"os"
|
2022-10-20 00:41:43 +00:00
|
|
|
"runtime"
|
|
|
|
|
2023-03-30 15:50:40 +00:00
|
|
|
"github.com/ProtonMail/gluon/async"
|
2022-11-23 14:17:56 +00:00
|
|
|
"github.com/ProtonMail/go-proton-api"
|
2022-10-31 12:52:11 +00:00
|
|
|
"github.com/ProtonMail/gopenpgp/v2/crypto"
|
2024-02-19 10:43:35 +00:00
|
|
|
"github.com/ProtonMail/proton-bridge/v3/internal/dialer"
|
2022-10-20 00:41:43 +00:00
|
|
|
"github.com/bradenaw/juniper/stream"
|
|
|
|
)
|
|
|
|
|
2022-12-12 12:49:34 +00:00
|
|
|
// withProton executes the given function with a proton manager configured to use the test API.
|
|
|
|
func (t *testCtx) withProton(fn func(*proton.Manager) error) error {
|
2024-02-19 10:43:35 +00:00
|
|
|
tr := proton.InsecureTransport()
|
|
|
|
if isBlack() {
|
|
|
|
dialer.SetBasicTransportTimeouts(tr)
|
|
|
|
}
|
|
|
|
|
2022-12-12 12:49:34 +00:00
|
|
|
m := proton.New(
|
2022-11-23 14:17:56 +00:00
|
|
|
proton.WithHostURL(t.api.GetHostURL()),
|
2024-02-19 10:43:35 +00:00
|
|
|
proton.WithTransport(tr),
|
2022-12-13 00:46:02 +00:00
|
|
|
proton.WithAppVersion(t.api.GetAppVersion()),
|
2023-02-02 15:25:27 +00:00
|
|
|
proton.WithDebug(os.Getenv("FEATURE_API_DEBUG") != ""),
|
2022-12-12 12:49:34 +00:00
|
|
|
)
|
|
|
|
defer m.Close()
|
2022-10-20 00:41:43 +00:00
|
|
|
|
2022-12-12 12:49:34 +00:00
|
|
|
return fn(m)
|
|
|
|
}
|
2022-10-21 10:00:35 +00:00
|
|
|
|
2022-12-12 12:49:34 +00:00
|
|
|
// withClient executes the given function with a client that is logged in as the given (known) user.
|
|
|
|
func (t *testCtx) withClient(ctx context.Context, username string, fn func(context.Context, *proton.Client) error) error {
|
2023-02-07 16:32:44 +00:00
|
|
|
return t.withClientPass(ctx, username, t.getUserByName(username).getUserPass(), fn)
|
2022-12-12 12:49:34 +00:00
|
|
|
}
|
2022-10-20 00:41:43 +00:00
|
|
|
|
2022-12-12 12:49:34 +00:00
|
|
|
// withClient executes the given function with a client that is logged in with the given username and password.
|
|
|
|
func (t *testCtx) withClientPass(ctx context.Context, username, password string, fn func(context.Context, *proton.Client) error) error {
|
|
|
|
return t.withProton(func(m *proton.Manager) error {
|
|
|
|
c, _, err := m.NewClientWithLogin(ctx, username, []byte(password))
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to create client: %w", err)
|
|
|
|
}
|
|
|
|
defer c.Close()
|
|
|
|
|
|
|
|
if err := fn(ctx, c); err != nil {
|
|
|
|
return fmt.Errorf("failed to execute with client: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := c.AuthDelete(ctx); err != nil {
|
|
|
|
return fmt.Errorf("failed to delete auth: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|
2022-10-20 00:41:43 +00:00
|
|
|
|
2022-12-12 12:49:34 +00:00
|
|
|
// runQuarkCmd runs the given quark command with the given arguments.
|
2022-12-13 00:46:02 +00:00
|
|
|
func (t *testCtx) runQuarkCmd(ctx context.Context, command string, args ...string) ([]byte, error) {
|
|
|
|
var out []byte
|
|
|
|
|
|
|
|
if err := t.withProton(func(m *proton.Manager) error {
|
|
|
|
res, err := m.QuarkRes(ctx, command, args...)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
out = res
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return out, nil
|
2022-10-20 00:41:43 +00:00
|
|
|
}
|
|
|
|
|
2024-02-19 10:43:35 +00:00
|
|
|
func (t *testCtx) decryptID(id string) ([]byte, error) {
|
|
|
|
return t.runQuarkCmd(context.Background(),
|
|
|
|
"encryption:id",
|
|
|
|
"--decrypt",
|
|
|
|
"--",
|
|
|
|
id,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2022-10-31 12:52:11 +00:00
|
|
|
func (t *testCtx) withAddrKR(
|
|
|
|
ctx context.Context,
|
2022-11-23 14:17:56 +00:00
|
|
|
c *proton.Client,
|
2022-10-31 12:52:11 +00:00
|
|
|
username, addrID string,
|
|
|
|
fn func(context.Context, *crypto.KeyRing) error,
|
|
|
|
) error {
|
|
|
|
user, err := c.GetUser(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
addr, err := c.GetAddresses(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
salt, err := c.GetSalts(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-02-07 16:32:44 +00:00
|
|
|
keyPass, err := salt.SaltForKey([]byte(t.getUserByName(username).getUserPass()), user.Keys.Primary().ID)
|
2022-10-31 12:52:11 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-03-30 15:50:40 +00:00
|
|
|
_, addrKRs, err := proton.Unlock(user, addr, keyPass, async.NoopPanicHandler{})
|
2022-10-31 12:52:11 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return fn(ctx, addrKRs[addrID])
|
|
|
|
}
|
|
|
|
|
2022-11-23 14:17:56 +00:00
|
|
|
func (t *testCtx) createMessages(ctx context.Context, username, addrID string, req []proton.ImportReq) error {
|
|
|
|
return t.withClient(ctx, username, func(ctx context.Context, c *proton.Client) error {
|
2022-10-31 12:52:11 +00:00
|
|
|
return t.withAddrKR(ctx, c, username, addrID, func(ctx context.Context, addrKR *crypto.KeyRing) error {
|
2023-02-09 15:24:40 +00:00
|
|
|
str, err := c.ImportMessages(
|
2022-10-31 12:52:11 +00:00
|
|
|
ctx,
|
|
|
|
addrKR,
|
|
|
|
runtime.NumCPU(),
|
|
|
|
runtime.NumCPU(),
|
|
|
|
req...,
|
2023-02-09 15:24:40 +00:00
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to prepare messages for import: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, err := stream.Collect(ctx, str); err != nil {
|
|
|
|
return fmt.Errorf("failed to import messages: %w", err)
|
2022-10-31 12:52:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
2022-10-20 00:41:43 +00:00
|
|
|
})
|
|
|
|
}
|