From fa794a982b68a4a4bfdb1a4003425dcbe06588db Mon Sep 17 00:00:00 2001 From: Romain Le Jeune Date: Fri, 15 Sep 2023 10:53:58 +0000 Subject: [PATCH] feat(GODT-2597): Implement contact specific settings in integration tests. --- COPYING_NOTES.md | 2 +- go.mod | 4 +- go.sum | 4 +- internal/services/smtp/smtp.go | 2 +- tests/contact_test.go | 448 ++++++++++++++++++++++++++++ tests/features/user/contact.feature | 65 ++++ tests/steps_test.go | 14 + tests/testdata/keys/pubkey.asc | 35 +++ tests/types_test.go | 9 + 9 files changed, 577 insertions(+), 6 deletions(-) create mode 100644 tests/contact_test.go create mode 100644 tests/features/user/contact.feature create mode 100644 tests/testdata/keys/pubkey.asc diff --git a/COPYING_NOTES.md b/COPYING_NOTES.md index f7f4d43a..1fc10d94 100644 --- a/COPYING_NOTES.md +++ b/COPYING_NOTES.md @@ -40,6 +40,7 @@ Proton Mail Bridge includes the following 3rd party software: * [go-message](https://github.com/emersion/go-message) available under [license](https://github.com/emersion/go-message/blob/master/LICENSE) * [go-sasl](https://github.com/emersion/go-sasl) available under [license](https://github.com/emersion/go-sasl/blob/master/LICENSE) * [go-smtp](https://github.com/emersion/go-smtp) available under [license](https://github.com/emersion/go-smtp/blob/master/LICENSE) +* [go-vcard](https://github.com/emersion/go-vcard) available under [license](https://github.com/emersion/go-vcard/blob/master/LICENSE) * [color](https://github.com/fatih/color) available under [license](https://github.com/fatih/color/blob/master/LICENSE) * [sentry-go](https://github.com/getsentry/sentry-go) available under [license](https://github.com/getsentry/sentry-go/blob/master/LICENSE) * [resty](https://github.com/go-resty/resty/v2) available under [license](https://github.com/go-resty/resty/v2/blob/master/LICENSE) @@ -83,7 +84,6 @@ Proton Mail Bridge includes the following 3rd party software: * [go-spew](https://github.com/davecgh/go-spew) available under [license](https://github.com/davecgh/go-spew/blob/master/LICENSE) * [go-windows](https://github.com/elastic/go-windows) available under [license](https://github.com/elastic/go-windows/blob/master/LICENSE) * [go-textwrapper](https://github.com/emersion/go-textwrapper) available under [license](https://github.com/emersion/go-textwrapper/blob/master/LICENSE) -* [go-vcard](https://github.com/emersion/go-vcard) available under [license](https://github.com/emersion/go-vcard/blob/master/LICENSE) * [fgprof](https://github.com/felixge/fgprof) available under [license](https://github.com/felixge/fgprof/blob/master/LICENSE) * [go-shlex](https://github.com/flynn-archive/go-shlex) available under [license](https://github.com/flynn-archive/go-shlex/blob/master/LICENSE) * [mimetype](https://github.com/gabriel-vasile/mimetype) available under [license](https://github.com/gabriel-vasile/mimetype/blob/master/LICENSE) diff --git a/go.mod b/go.mod index 2280031e..d5882959 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/Masterminds/semver/v3 v3.2.0 github.com/ProtonMail/gluon v0.17.1-0.20230911134257-5eb2eeebbef5 github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a - github.com/ProtonMail/go-proton-api v0.4.1-0.20230831064234-0e3a549b3f36 + github.com/ProtonMail/go-proton-api v0.4.1-0.20230915070741-3de73982c764 github.com/ProtonMail/gopenpgp/v2 v2.7.1-proton github.com/PuerkitoBio/goquery v1.8.1 github.com/abiosoft/ishell v2.0.0+incompatible @@ -22,6 +22,7 @@ require ( github.com/emersion/go-message v0.16.0 github.com/emersion/go-sasl v0.0.0-20220912192320-0145f2c60ead github.com/emersion/go-smtp v0.15.1-0.20221021114529-49b17434419d + github.com/emersion/go-vcard v0.0.0-20230331202150-f3d26859ccd3 github.com/fatih/color v1.13.0 github.com/getsentry/sentry-go v0.15.0 github.com/go-resty/resty/v2 v2.7.0 @@ -68,7 +69,6 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/elastic/go-windows v1.0.1 // indirect github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594 // indirect - github.com/emersion/go-vcard v0.0.0-20230331202150-f3d26859ccd3 // indirect github.com/felixge/fgprof v0.9.3 // indirect github.com/flynn-archive/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect diff --git a/go.sum b/go.sum index ba8ee115..034e0724 100644 --- a/go.sum +++ b/go.sum @@ -35,8 +35,8 @@ github.com/ProtonMail/go-message v0.13.1-0.20230526094639-b62c999c85b7 h1:+j+Kd/ github.com/ProtonMail/go-message v0.13.1-0.20230526094639-b62c999c85b7/go.mod h1:NBAn21zgCJ/52WLDyed18YvYFm5tEoeDauubFqLokM4= github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f h1:tCbYj7/299ekTTXpdwKYF8eBlsYsDVoggDAuAjoK66k= github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f/go.mod h1:gcr0kNtGBqin9zDW9GOHcVntrwnjrK+qdJ06mWYBybw= -github.com/ProtonMail/go-proton-api v0.4.1-0.20230831064234-0e3a549b3f36 h1:JVMK2w90bCWayUCXJIb3wkQ5+j2P/NbnrX3BrDoLzsc= -github.com/ProtonMail/go-proton-api v0.4.1-0.20230831064234-0e3a549b3f36/go.mod h1:nS8hMGjJLgC0Iej0JMYbsI388LesEkM1Hj/jCCxQeaQ= +github.com/ProtonMail/go-proton-api v0.4.1-0.20230915070741-3de73982c764 h1:2rEmoo5BgEap+9Y484xAL8cod1bbjDaeWaGFLS/a1Ec= +github.com/ProtonMail/go-proton-api v0.4.1-0.20230915070741-3de73982c764/go.mod h1:nS8hMGjJLgC0Iej0JMYbsI388LesEkM1Hj/jCCxQeaQ= github.com/ProtonMail/go-srp v0.0.7 h1:Sos3Qk+th4tQR64vsxGIxYpN3rdnG9Wf9K4ZloC1JrI= github.com/ProtonMail/go-srp v0.0.7/go.mod h1:giCp+7qRnMIcCvI6V6U3S1lDDXDQYx2ewJ6F/9wdlJk= github.com/ProtonMail/gopenpgp/v2 v2.7.1-proton h1:YS6M20yvjCJPR1r4ADW5TPn6rahs4iAyZaACei86bEc= diff --git a/internal/services/smtp/smtp.go b/internal/services/smtp/smtp.go index 58730228..b26fd143 100644 --- a/internal/services/smtp/smtp.go +++ b/internal/services/smtp/smtp.go @@ -535,7 +535,7 @@ func getContactSettings( return proton.ContactSettings{}, fmt.Errorf("failed to get contact: %w", err) } - return contact.GetSettings(userKR, recipient) + return contact.GetSettings(userKR, recipient, proton.CardTypeSigned) } func getMessageSender(parser *parser.Parser) (string, bool) { diff --git a/tests/contact_test.go b/tests/contact_test.go new file mode 100644 index 00000000..aeab60ae --- /dev/null +++ b/tests/contact_test.go @@ -0,0 +1,448 @@ +// 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 . + +package tests + +import ( + "context" + "errors" + "os" + + "github.com/ProtonMail/gluon/rfc822" + "github.com/ProtonMail/go-proton-api" + "github.com/ProtonMail/gopenpgp/v2/crypto" + "github.com/cucumber/godog" + "github.com/emersion/go-vcard" +) + +func (s *scenario) userHasContacts(user string, contacts *godog.Table) error { + return s.t.withClient(context.Background(), user, func(ctx context.Context, c *proton.Client) error { + addrID := s.t.getUserByName(user).getAddrID(s.t.getUserByName(user).getEmails()[0]) + return s.t.withAddrKR(ctx, c, user, addrID, func(ctx context.Context, addrKR *crypto.KeyRing) error { + contactList, err := unmarshalTable[Contact](contacts) + if err != nil { + return err + } + for _, contact := range contactList { + var settings = proton.ContactSettings{} + format, err := stringToMimeType(contact.Format) + if err != nil { + settings.MIMEType = nil + } else { + settings.SetMimeType(format) + } + scheme, err := stringToEncryptionScheme(contact.Scheme) + if err != nil { + settings.Scheme = nil + } else { + settings.SetScheme(scheme) + } + sign, err := stringToBool(contact.Sign) + if err != nil { + settings.Sign = nil + } else { + settings.SetSign(sign) + } + encrypt, err := stringToBool(contact.Encrypt) + if err != nil { + settings.Encrypt = nil + } else { + settings.SetEncrypt(encrypt) + } + if err := createContact(ctx, c, contact.Email, contact.Name, addrKR, &settings); err != nil { + return err + } + } + return nil + }) + }) +} + +func (s *scenario) userHasContactWithName(user, contact, name string) error { + return s.t.withClient(context.Background(), user, func(ctx context.Context, c *proton.Client) error { + addrID := s.t.getUserByName(user).getAddrID(s.t.getUserByName(user).getEmails()[0]) + return s.t.withAddrKR(ctx, c, user, addrID, func(ctx context.Context, addrKR *crypto.KeyRing) error { + return createContact(ctx, c, contact, name, addrKR, nil) + }) + }) +} + +func (s *scenario) contactOfUserHasNoMessageFormat(email, user string) error { + return s.t.withClient(context.Background(), user, func(ctx context.Context, c *proton.Client) error { + addrID := s.t.getUserByName(user).getAddrID(s.t.getUserByName(user).getEmails()[0]) + return s.t.withAddrKR(ctx, c, user, addrID, func(ctx context.Context, addrKR *crypto.KeyRing) error { + contact, err := getContact(ctx, c, email) + if err != nil { + return err + } + for _, card := range contact.Cards { + settings, err := contact.GetSettings(addrKR, email, card.Type) + if err != nil { + return err + } + settings.MIMEType = nil + + err = contact.SetSettings(addrKR, email, card.Type, settings) + if err != nil { + return err + } + } + _, err = c.UpdateContact(ctx, contact.ContactMetadata.ID, proton.UpdateContactReq{Cards: contact.Cards}) + return err + }) + }) +} + +func (s *scenario) contactOfUserHasMessageFormat(email, user, format string) error { + value, err := stringToMimeType(format) + if err != nil { + return err + } + return s.t.withClient(context.Background(), user, func(ctx context.Context, c *proton.Client) error { + addrID := s.t.getUserByName(user).getAddrID(s.t.getUserByName(user).getEmails()[0]) + return s.t.withAddrKR(ctx, c, user, addrID, func(ctx context.Context, addrKR *crypto.KeyRing) error { + contact, err := getContact(ctx, c, email) + if err != nil { + return err + } + for _, card := range contact.Cards { + settings, err := contact.GetSettings(addrKR, email, card.Type) + if err != nil { + return err + } + settings.SetMimeType(value) + + err = contact.SetSettings(addrKR, email, card.Type, settings) + if err != nil { + return err + } + } + _, err = c.UpdateContact(ctx, contact.ContactMetadata.ID, proton.UpdateContactReq{Cards: contact.Cards}) + return err + }) + }) +} + +func (s *scenario) contactOfUserHasNoEncryptionScheme(email, user string) error { + return s.t.withClient(context.Background(), user, func(ctx context.Context, c *proton.Client) error { + addrID := s.t.getUserByName(user).getAddrID(s.t.getUserByName(user).getEmails()[0]) + return s.t.withAddrKR(ctx, c, user, addrID, func(ctx context.Context, addrKR *crypto.KeyRing) error { + contact, err := getContact(ctx, c, email) + if err != nil { + return err + } + for _, card := range contact.Cards { + settings, err := contact.GetSettings(addrKR, email, card.Type) + if err != nil { + return err + } + settings.Scheme = nil + + err = contact.SetSettings(addrKR, email, card.Type, settings) + if err != nil { + return err + } + } + _, err = c.UpdateContact(ctx, contact.ContactMetadata.ID, proton.UpdateContactReq{Cards: contact.Cards}) + return err + }) + }) +} + +func (s *scenario) contactOfUserHasEncryptionScheme(email, user, scheme string) error { + value := proton.PGPInlineScheme + switch { + case scheme == "inline": + value = proton.PGPInlineScheme + case scheme == "MIME": + value = proton.PGPMIMEScheme + default: + return errors.New("parameter should either be 'inline' or 'MIME'") + } + return s.t.withClient(context.Background(), user, func(ctx context.Context, c *proton.Client) error { + addrID := s.t.getUserByName(user).getAddrID(s.t.getUserByName(user).getEmails()[0]) + return s.t.withAddrKR(ctx, c, user, addrID, func(ctx context.Context, addrKR *crypto.KeyRing) error { + contact, err := getContact(ctx, c, email) + if err != nil { + return err + } + for _, card := range contact.Cards { + settings, err := contact.GetSettings(addrKR, email, card.Type) + if err != nil { + return err + } + settings.SetScheme(value) + + err = contact.SetSettings(addrKR, email, card.Type, settings) + if err != nil { + return err + } + } + _, err = c.UpdateContact(ctx, contact.ContactMetadata.ID, proton.UpdateContactReq{Cards: contact.Cards}) + return err + }) + }) +} + +func (s *scenario) contactOfUserHasNoSignature(email, user string) error { + return s.t.withClient(context.Background(), user, func(ctx context.Context, c *proton.Client) error { + addrID := s.t.getUserByName(user).getAddrID(s.t.getUserByName(user).getEmails()[0]) + return s.t.withAddrKR(ctx, c, user, addrID, func(ctx context.Context, addrKR *crypto.KeyRing) error { + contact, err := getContact(ctx, c, email) + if err != nil { + return err + } + for _, card := range contact.Cards { + settings, err := contact.GetSettings(addrKR, email, card.Type) + if err != nil { + return err + } + settings.Sign = nil + + err = contact.SetSettings(addrKR, email, card.Type, settings) + if err != nil { + return err + } + } + _, err = c.UpdateContact(ctx, contact.ContactMetadata.ID, proton.UpdateContactReq{Cards: contact.Cards}) + return err + }) + }) +} + +func (s *scenario) contactOfUserHasSignature(email, user, enabled string) error { + value := true + switch { + case enabled == "enabled": + value = true + case enabled == "disabled": + value = false + default: + return errors.New("parameter should either be 'enabled' or 'disabled'") + } + return s.t.withClient(context.Background(), user, func(ctx context.Context, c *proton.Client) error { + addrID := s.t.getUserByName(user).getAddrID(s.t.getUserByName(user).getEmails()[0]) + return s.t.withAddrKR(ctx, c, user, addrID, func(ctx context.Context, addrKR *crypto.KeyRing) error { + contact, err := getContact(ctx, c, email) + if err != nil { + return err + } + for _, card := range contact.Cards { + settings, err := contact.GetSettings(addrKR, email, card.Type) + if err != nil { + return err + } + settings.SetSign(value) + + err = contact.SetSettings(addrKR, email, card.Type, settings) + if err != nil { + return err + } + } + _, err = c.UpdateContact(ctx, contact.ContactMetadata.ID, proton.UpdateContactReq{Cards: contact.Cards}) + return err + }) + }) +} + +func (s *scenario) contactOfUserHasNoEncryption(email, user string) error { + return s.t.withClient(context.Background(), user, func(ctx context.Context, c *proton.Client) error { + addrID := s.t.getUserByName(user).getAddrID(s.t.getUserByName(user).getEmails()[0]) + return s.t.withAddrKR(ctx, c, user, addrID, func(ctx context.Context, addrKR *crypto.KeyRing) error { + contact, err := getContact(ctx, c, email) + if err != nil { + return err + } + for _, card := range contact.Cards { + settings, err := contact.GetSettings(addrKR, email, card.Type) + if err != nil { + return err + } + settings.Encrypt = nil + + err = contact.SetSettings(addrKR, email, card.Type, settings) + if err != nil { + return err + } + } + _, err = c.UpdateContact(ctx, contact.ContactMetadata.ID, proton.UpdateContactReq{Cards: contact.Cards}) + return err + }) + }) +} + +func (s *scenario) contactOfUserHasEncryption(email, user, enabled string) error { + value := true + switch { + case enabled == "enabled": + value = true + case enabled == "disabled": + value = false + default: + return errors.New("parameter should either be 'enabled' or 'disabled'") + } + return s.t.withClient(context.Background(), user, func(ctx context.Context, c *proton.Client) error { + addrID := s.t.getUserByName(user).getAddrID(s.t.getUserByName(user).getEmails()[0]) + return s.t.withAddrKR(ctx, c, user, addrID, func(ctx context.Context, addrKR *crypto.KeyRing) error { + contact, err := getContact(ctx, c, email) + if err != nil { + return err + } + for _, card := range contact.Cards { + settings, err := contact.GetSettings(addrKR, email, card.Type) + if err != nil { + return err + } + settings.SetEncrypt(value) + + err = contact.SetSettings(addrKR, email, card.Type, settings) + if err != nil { + return err + } + } + _, err = c.UpdateContact(ctx, contact.ContactMetadata.ID, proton.UpdateContactReq{Cards: contact.Cards}) + return err + }) + }) +} + +func (s *scenario) contactOfUserHasPubKey(email, user string, pubKey *godog.DocString) error { + return s.addContactKey(email, user, pubKey.Content) +} + +func (s *scenario) contactOfUserHasPubKeyFromFile(email, user, file string) error { + body, err := os.ReadFile(file) + if err != nil { + return err + } + return s.addContactKey(email, user, string(body)) +} + +func getContact(ctx context.Context, c *proton.Client, email string) (proton.Contact, error) { + contacts, err := c.GetAllContactEmails(ctx, email) + if err != nil { + return proton.Contact{}, err + } + if len(contacts) == 0 { + return proton.Contact{}, errors.New("No contact found with email " + email) + } + return c.GetContact(ctx, contacts[0].ContactID) +} + +func createContact(ctx context.Context, c *proton.Client, contact, name string, addrKR *crypto.KeyRing, settings *proton.ContactSettings) error { + card, err := proton.NewCard(addrKR, proton.CardTypeSigned) + if err != nil { + return err + } + if err := card.Set(addrKR, vcard.FieldUID, &vcard.Field{Value: "proton-legacy-139892c2-f691-4118-8c29-061196013e04", Group: "test"}); err != nil { + return err + } + + if err := card.Set(addrKR, vcard.FieldFormattedName, &vcard.Field{Value: name, Group: "test"}); err != nil { + return err + } + if err := card.Set(addrKR, vcard.FieldEmail, &vcard.Field{Value: contact, Group: "test"}); err != nil { + return err + } + res, err := c.CreateContacts(ctx, proton.CreateContactsReq{Contacts: []proton.ContactCards{{Cards: []*proton.Card{card}}}, Overwrite: 1}) + if err != nil { + return err + } + if res[0].Response.APIError.Code != proton.SuccessCode { + return errors.New("APIError " + res[0].Response.APIError.Message + " while creating contact") + } + + if settings != nil { + ctact, err := getContact(ctx, c, contact) + if err != nil { + return err + } + for _, card := range ctact.Cards { + settings, err := ctact.GetSettings(addrKR, contact, card.Type) + if err != nil { + return err + } + + err = ctact.SetSettings(addrKR, contact, card.Type, settings) + if err != nil { + return err + } + } + } + + return nil +} + +func (s *scenario) addContactKey(email, user string, pubKey string) error { + return s.t.withClient(context.Background(), user, func(ctx context.Context, c *proton.Client) error { + addrID := s.t.getUserByName(user).getAddrID(s.t.getUserByName(user).getEmails()[0]) + return s.t.withAddrKR(ctx, c, user, addrID, func(ctx context.Context, addrKR *crypto.KeyRing) error { + contact, err := getContact(ctx, c, email) + if err != nil { + return err + } + for _, card := range contact.Cards { + settings, err := contact.GetSettings(addrKR, email, card.Type) + if err != nil { + return err + } + key, err := crypto.NewKeyFromArmored(pubKey) + if err != nil { + return err + } + settings.AddKey(key) + + err = contact.SetSettings(addrKR, email, card.Type, settings) + if err != nil { + return err + } + } + _, err = c.UpdateContact(ctx, contact.ContactMetadata.ID, proton.UpdateContactReq{Cards: contact.Cards}) + return err + }) + }) +} + +func stringToMimeType(value string) (rfc822.MIMEType, error) { + switch { + case value == "plain": + return rfc822.TextPlain, nil + case value == "HTML": + return rfc822.TextHTML, nil + } + return rfc822.TextPlain, errors.New("parameter should either be 'plain' or 'HTML'") +} + +func stringToEncryptionScheme(value string) (proton.EncryptionScheme, error) { + switch { + case value == "inline": + return proton.PGPInlineScheme, nil + case value == "MIME": + return proton.PGPMIMEScheme, nil + } + return proton.PGPInlineScheme, errors.New("parameter should either be 'inline' or 'MIME'") +} + +func stringToBool(value string) (bool, error) { + switch { + case value == "enabled": + return true, nil + case value == "disabled": + return false, nil + } + return false, errors.New("parameter should either be 'enabled' or 'disabled'") +} diff --git a/tests/features/user/contact.feature b/tests/features/user/contact.feature new file mode 100644 index 00000000..08ce8643 --- /dev/null +++ b/tests/features/user/contact.feature @@ -0,0 +1,65 @@ +Feature: user's contact + Background: + Given there exists an account with username "[user:user]" and password "password" + And user "[user:user]" has contact "SuperTester@proton.me" with name "Super TESTER" + And user "[user:user]" has contacts: + | name | email | format | scheme | signature | encryption | + | Tester One | tester1@proton.me | plain | MIME | enabled | enabled | + | Tester Two | tester2@proton.me | HTML | inline | disabled | disabled | + Then it succeeds + When bridge starts + And the user logs in with username "[user:user]" and password "password" + Then it succeeds + + + Scenario: Playing with contact settings + When the contact "SuperTester@proton.me" of user "[user:user]" has message format "plain" + When the contact "SuperTester@proton.me" of user "[user:user]" has message format "HTML" + When the contact "SuperTester@proton.me" of user "[user:user]" has encryption scheme "inline" + When the contact "SuperTester@proton.me" of user "[user:user]" has encryption scheme "MIME" + When the contact "SuperTester@proton.me" of user "[user:user]" has no signature + When the contact "SuperTester@proton.me" of user "[user:user]" has no encryption + When the contact "SuperTester@proton.me" of user "[user:user]" has signature "enabled" + When the contact "SuperTester@proton.me" of user "[user:user]" has encryption "enabled" + When the contact "SuperTester@proton.me" of user "[user:user]" has signature "disabled" + When the contact "SuperTester@proton.me" of user "[user:user]" has encryption "disabled" + When the contact "SuperTester@proton.me" of user "[user:user]" has public key from file "testdata/keys/pubkey.asc" + When the contact "SuperTester@proton.me" of user "[user:user]" has public key: + """ + -----BEGIN PGP PUBLIC KEY BLOCK----- + + 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 + =9sH1 + -----END PGP PUBLIC KEY BLOCK----- + """ + diff --git a/tests/steps_test.go b/tests/steps_test.go index afe452b8..f987c70a 100644 --- a/tests/steps_test.go +++ b/tests/steps_test.go @@ -194,4 +194,18 @@ func (s *scenario) steps(ctx *godog.ScenarioContext) { ctx.Step(`^config status event "([^"]*)" is eventually send (\d+) time`, s.configStatusEventIsEventuallySendXTime) ctx.Step(`^config status event "([^"]*)" is not send more than (\d+) time`, s.configStatusEventIsNotSendMoreThanXTime) ctx.Step(`^force config status progress to be sent for user"([^"]*)"$`, s.forceConfigStatusProgressToBeSentForUser) + + // ==== CONTACT ==== + ctx.Step(`^user "([^"]*)" has contact "([^"]*)" with name "([^"]*)"$`, s.userHasContactWithName) + ctx.Step(`^user "([^"]*)" has contacts:$`, s.userHasContacts) + ctx.Step(`^the contact "([^"]*)" of user "([^"]*)" has no message format$`, s.contactOfUserHasNoMessageFormat) + ctx.Step(`^the contact "([^"]*)" of user "([^"]*)" has message format "([^"]*)"$`, s.contactOfUserHasMessageFormat) + ctx.Step(`^the contact "([^"]*)" of user "([^"]*)" has no encryption scheme$`, s.contactOfUserHasNoEncryptionScheme) + ctx.Step(`^the contact "([^"]*)" of user "([^"]*)" has encryption scheme "([^"]*)"$`, s.contactOfUserHasEncryptionScheme) + ctx.Step(`^the contact "([^"]*)" of user "([^"]*)" has no signature$`, s.contactOfUserHasNoSignature) + ctx.Step(`^the contact "([^"]*)" of user "([^"]*)" has signature "([^"]*)"$`, s.contactOfUserHasSignature) + ctx.Step(`^the contact "([^"]*)" of user "([^"]*)" has no encryption$`, s.contactOfUserHasNoEncryption) + ctx.Step(`^the contact "([^"]*)" of user "([^"]*)" has encryption "([^"]*)"$`, s.contactOfUserHasEncryption) + ctx.Step(`^the contact "([^"]*)" of user "([^"]*)" has public key:$`, s.contactOfUserHasPubKey) + ctx.Step(`^the contact "([^"]*)" of user "([^"]*)" has public key from file "([^"]*)"$`, s.contactOfUserHasPubKeyFromFile) } diff --git a/tests/testdata/keys/pubkey.asc b/tests/testdata/keys/pubkey.asc new file mode 100644 index 00000000..a66987af --- /dev/null +++ b/tests/testdata/keys/pubkey.asc @@ -0,0 +1,35 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +=9sH1 +-----END PGP PUBLIC KEY BLOCK----- diff --git a/tests/types_test.go b/tests/types_test.go index e654635d..27b7e982 100644 --- a/tests/types_test.go +++ b/tests/types_test.go @@ -327,3 +327,12 @@ func mustParseBool(s string) bool { return v } + +type Contact struct { + Name string `bdd:"name"` + Email string `bdd:"email"` + Format string `bdd:"format"` + Scheme string `bdd:"scheme"` + Sign string `bdd:"signature"` + Encrypt string `bdd:"encryption"` +}