forked from Silverfish/proton-bridge
feat(GODT-3015): Add simple algorithm to deal with multiple attachment for bug report.
This commit is contained in:
2
go.mod
2
go.mod
@ -7,7 +7,7 @@ require (
|
|||||||
github.com/Masterminds/semver/v3 v3.2.0
|
github.com/Masterminds/semver/v3 v3.2.0
|
||||||
github.com/ProtonMail/gluon v0.17.1-0.20231009084701-3af0474b0b3c
|
github.com/ProtonMail/gluon v0.17.1-0.20231009084701-3af0474b0b3c
|
||||||
github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a
|
github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a
|
||||||
github.com/ProtonMail/go-proton-api v0.4.1-0.20231018070752-2449db500edd
|
github.com/ProtonMail/go-proton-api v0.4.1-0.20231020080353-2b3fddd7f72d
|
||||||
github.com/ProtonMail/gopenpgp/v2 v2.7.3-proton
|
github.com/ProtonMail/gopenpgp/v2 v2.7.3-proton
|
||||||
github.com/PuerkitoBio/goquery v1.8.1
|
github.com/PuerkitoBio/goquery v1.8.1
|
||||||
github.com/abiosoft/ishell v2.0.0+incompatible
|
github.com/abiosoft/ishell v2.0.0+incompatible
|
||||||
|
|||||||
4
go.sum
4
go.sum
@ -34,8 +34,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-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 h1:tCbYj7/299ekTTXpdwKYF8eBlsYsDVoggDAuAjoK66k=
|
||||||
github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f/go.mod h1:gcr0kNtGBqin9zDW9GOHcVntrwnjrK+qdJ06mWYBybw=
|
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.20231018070752-2449db500edd h1:/Z3nwzsVeSwTFkrIKG7BLD24P4cxpaJBn8mzbSe2kPg=
|
github.com/ProtonMail/go-proton-api v0.4.1-0.20231020080353-2b3fddd7f72d h1:w+DiszDUNfGz64zEmmOnetV+YQssrLcOr3NkofW/Nog=
|
||||||
github.com/ProtonMail/go-proton-api v0.4.1-0.20231018070752-2449db500edd/go.mod h1:ZmvQMA8hanLiD1tFsvu9+qGBcuxbIRfch/4z/nqBhXA=
|
github.com/ProtonMail/go-proton-api v0.4.1-0.20231020080353-2b3fddd7f72d/go.mod h1:ZmvQMA8hanLiD1tFsvu9+qGBcuxbIRfch/4z/nqBhXA=
|
||||||
github.com/ProtonMail/go-srp v0.0.7 h1:Sos3Qk+th4tQR64vsxGIxYpN3rdnG9Wf9K4ZloC1JrI=
|
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/go-srp v0.0.7/go.mod h1:giCp+7qRnMIcCvI6V6U3S1lDDXDQYx2ewJ6F/9wdlJk=
|
||||||
github.com/ProtonMail/gopenpgp/v2 v2.7.3-proton h1:wuAxBUU9qF2wyDVJprn/2xPDx000eol5gwlKbOUYY88=
|
github.com/ProtonMail/gopenpgp/v2 v2.7.3-proton h1:wuAxBUU9qF2wyDVJprn/2xPDx000eol5gwlKbOUYY88=
|
||||||
|
|||||||
@ -19,6 +19,7 @@ package bridge
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/ProtonMail/go-proton-api"
|
"github.com/ProtonMail/go-proton-api"
|
||||||
@ -33,65 +34,133 @@ const (
|
|||||||
DefaultMaxSessionCountForBugReport = 10
|
DefaultMaxSessionCountForBugReport = 10
|
||||||
)
|
)
|
||||||
|
|
||||||
func (bridge *Bridge) ReportBug(ctx context.Context, osType, osVersion, title, description, username, email, client string, attachLogs bool) error {
|
type ReportBugReq struct {
|
||||||
var account = username
|
OSType string
|
||||||
|
OSVersion string
|
||||||
|
Title string
|
||||||
|
Description string
|
||||||
|
Username string
|
||||||
|
Email string
|
||||||
|
EmailClient string
|
||||||
|
IncludeLogs bool
|
||||||
|
}
|
||||||
|
|
||||||
if info, err := bridge.QueryUserInfo(username); err == nil {
|
func (bridge *Bridge) ReportBug(ctx context.Context, report *ReportBugReq) error {
|
||||||
account = info.Username
|
if info, err := bridge.QueryUserInfo(report.Username); err == nil {
|
||||||
|
report.Username = info.Username
|
||||||
} else if userIDs := bridge.GetUserIDs(); len(userIDs) > 0 {
|
} else if userIDs := bridge.GetUserIDs(); len(userIDs) > 0 {
|
||||||
if err := bridge.vault.GetUser(userIDs[0], func(user *vault.User) {
|
if err := bridge.vault.GetUser(userIDs[0], func(user *vault.User) {
|
||||||
account = user.Username()
|
report.Username = user.Username()
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var attachment []proton.ReportBugAttachment
|
var attachments []proton.ReportBugAttachment
|
||||||
|
if report.IncludeLogs {
|
||||||
if attachLogs {
|
logs, err := bridge.CollectLogs()
|
||||||
logsPath, err := bridge.locator.ProvideLogsPath()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
attachments = append(attachments, logs)
|
||||||
|
}
|
||||||
|
|
||||||
buffer, err := logging.ZipLogsForBugReport(logsPath, DefaultMaxSessionCountForBugReport, DefaultMaxBugReportZipSize)
|
var firstAtt proton.ReportBugAttachment
|
||||||
if err != nil {
|
if len(attachments) > 0 && report.IncludeLogs {
|
||||||
|
firstAtt = attachments[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
attachmentType := proton.AttachmentTypeSync
|
||||||
|
if len(attachments) > 1 {
|
||||||
|
attachmentType = proton.AttachmentTypeAsync
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := bridge.createTicket(ctx, report, attachmentType, firstAtt)
|
||||||
|
if err != nil || token == "" {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
body, err := io.ReadAll(buffer)
|
safe.RLock(func() {
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
attachment = append(attachment, proton.ReportBugAttachment{
|
|
||||||
Name: "logs.zip",
|
|
||||||
Filename: "logs.zip",
|
|
||||||
MIMEType: "application/zip",
|
|
||||||
Body: body,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
safe.Lock(func() {
|
|
||||||
for _, user := range bridge.users {
|
for _, user := range bridge.users {
|
||||||
user.ReportBugSent()
|
user.ReportBugSent()
|
||||||
}
|
}
|
||||||
}, bridge.usersLock)
|
}, bridge.usersLock)
|
||||||
|
|
||||||
_, err := bridge.api.ReportBug(ctx, proton.ReportBugReq{
|
// if we have a token we can append more attachment to the bugReport
|
||||||
OS: osType,
|
for i, att := range attachments {
|
||||||
OSVersion: osVersion,
|
if i == 0 && report.IncludeLogs {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
err := bridge.appendComment(ctx, token, att)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
Title: "[Bridge] Bug - " + title,
|
func (bridge *Bridge) CollectLogs() (proton.ReportBugAttachment, error) {
|
||||||
Description: description,
|
logsPath, err := bridge.locator.ProvideLogsPath()
|
||||||
|
if err != nil {
|
||||||
|
return proton.ReportBugAttachment{}, err
|
||||||
|
}
|
||||||
|
|
||||||
Client: client,
|
buffer, err := logging.ZipLogsForBugReport(logsPath, DefaultMaxSessionCountForBugReport, DefaultMaxBugReportZipSize)
|
||||||
|
if err != nil {
|
||||||
|
return proton.ReportBugAttachment{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := io.ReadAll(buffer)
|
||||||
|
if err != nil {
|
||||||
|
return proton.ReportBugAttachment{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return proton.ReportBugAttachment{
|
||||||
|
Name: "logs.zip",
|
||||||
|
Filename: "logs.zip",
|
||||||
|
MIMEType: "application/zip",
|
||||||
|
Body: body,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *Bridge) createTicket(ctx context.Context, report *ReportBugReq,
|
||||||
|
asyncAttach proton.AttachmentType, att proton.ReportBugAttachment) (string, error) {
|
||||||
|
var attachments []proton.ReportBugAttachment
|
||||||
|
attachments = append(attachments, att)
|
||||||
|
res, err := bridge.api.ReportBug(ctx, proton.ReportBugReq{
|
||||||
|
OS: report.OSType,
|
||||||
|
OSVersion: report.OSVersion,
|
||||||
|
|
||||||
|
Title: "[Bridge] Bug - " + report.Title,
|
||||||
|
Description: report.Description,
|
||||||
|
|
||||||
|
Client: report.EmailClient,
|
||||||
ClientType: proton.ClientTypeEmail,
|
ClientType: proton.ClientTypeEmail,
|
||||||
ClientVersion: constants.AppVersion(bridge.curVersion.Original()),
|
ClientVersion: constants.AppVersion(bridge.curVersion.Original()),
|
||||||
|
|
||||||
Username: account,
|
Username: report.Username,
|
||||||
Email: email,
|
Email: report.Email,
|
||||||
}, attachment...)
|
|
||||||
|
|
||||||
return err
|
AsyncAttachments: asyncAttach,
|
||||||
|
}, attachments...)
|
||||||
|
|
||||||
|
if err != nil || asyncAttach != proton.AttachmentTypeAsync {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if asyncAttach == proton.AttachmentTypeAsync && res.Token == nil {
|
||||||
|
return "", errors.New("no token returns for AsyncAttachments")
|
||||||
|
}
|
||||||
|
|
||||||
|
return *res.Token, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *Bridge) appendComment(ctx context.Context, token string, att proton.ReportBugAttachment) error {
|
||||||
|
var attachments []proton.ReportBugAttachment
|
||||||
|
attachments = append(attachments, att)
|
||||||
|
return bridge.api.ReportBugAttachement(ctx, proton.ReportBugAttachmentReq{
|
||||||
|
Product: proton.ClientTypeEmail,
|
||||||
|
Body: "Comment adding attachment: " + att.Filename,
|
||||||
|
Token: token,
|
||||||
|
}, attachments...)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -339,18 +339,17 @@ func (s *Service) ReportBug(_ context.Context, report *ReportBugRequest) (*empty
|
|||||||
defer async.HandlePanic(s.panicHandler)
|
defer async.HandlePanic(s.panicHandler)
|
||||||
|
|
||||||
defer func() { _ = s.SendEvent(NewReportBugFinishedEvent()) }()
|
defer func() { _ = s.SendEvent(NewReportBugFinishedEvent()) }()
|
||||||
|
reportReq := bridge.ReportBugReq{
|
||||||
if err := s.bridge.ReportBug(
|
OSType: report.OsType,
|
||||||
context.Background(),
|
OSVersion: report.OsVersion,
|
||||||
report.OsType,
|
Title: report.Title,
|
||||||
report.OsVersion,
|
Description: report.Description,
|
||||||
report.Title,
|
Username: report.Address,
|
||||||
report.Description,
|
Email: report.Address,
|
||||||
report.Address,
|
EmailClient: report.EmailClient,
|
||||||
report.Address,
|
IncludeLogs: report.IncludeLogs,
|
||||||
report.EmailClient,
|
}
|
||||||
report.IncludeLogs,
|
if err := s.bridge.ReportBug(context.Background(), &reportReq); err != nil {
|
||||||
); err != nil {
|
|
||||||
s.log.WithError(err).Error("Failed to report bug")
|
s.log.WithError(err).Error("Failed to report bug")
|
||||||
_ = s.SendEvent(NewReportBugErrorEvent())
|
_ = s.SendEvent(NewReportBugErrorEvent())
|
||||||
return
|
return
|
||||||
|
|||||||
@ -155,34 +155,29 @@ func (s *scenario) theUserSetSMTPModeToSSL() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type testBugReport struct {
|
type testBugReport struct {
|
||||||
OSType string `json:"OS"`
|
request bridge.ReportBugReq
|
||||||
OSVersion string `json:"OSVersion"`
|
|
||||||
Title string `json:"Title"`
|
|
||||||
Description string `json:"Description"`
|
|
||||||
Username string `json:"Username"`
|
|
||||||
Email string `json:"Email"`
|
|
||||||
Client string `json:"Client"`
|
|
||||||
Attachment bool `json:"Attachment"`
|
|
||||||
|
|
||||||
bridge *bridge.Bridge
|
bridge *bridge.Bridge
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestBugReport(bridge *bridge.Bridge) *testBugReport {
|
func newTestBugReport(br *bridge.Bridge) *testBugReport {
|
||||||
return &testBugReport{
|
request := bridge.ReportBugReq{
|
||||||
OSType: "osType",
|
OSType: "osType",
|
||||||
OSVersion: "osVersion",
|
OSVersion: "osVersion",
|
||||||
Title: "title",
|
Title: "title",
|
||||||
Description: "description",
|
Description: "description",
|
||||||
Username: "username",
|
Username: "username",
|
||||||
Email: "email",
|
Email: "email",
|
||||||
Client: "client",
|
EmailClient: "client",
|
||||||
Attachment: false,
|
IncludeLogs: false,
|
||||||
bridge: bridge,
|
}
|
||||||
|
return &testBugReport{
|
||||||
|
request: request,
|
||||||
|
bridge: br,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *testBugReport) report() error {
|
func (r *testBugReport) report() error {
|
||||||
return r.bridge.ReportBug(context.Background(), r.OSType, r.OSVersion, r.Title, r.Description, r.Username, r.Email, r.Client, r.Attachment)
|
return r.bridge.ReportBug(context.Background(), &r.request)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *scenario) theUserReportsABug() error {
|
func (s *scenario) theUserReportsABug() error {
|
||||||
@ -194,25 +189,25 @@ func (s *scenario) theUserReportsABugWithSingleHeaderChange(key, value string) e
|
|||||||
|
|
||||||
switch key {
|
switch key {
|
||||||
case "osType":
|
case "osType":
|
||||||
bugReport.OSType = value
|
bugReport.request.OSType = value
|
||||||
case "osVersion":
|
case "osVersion":
|
||||||
bugReport.OSVersion = value
|
bugReport.request.OSVersion = value
|
||||||
case "Title":
|
case "Title":
|
||||||
bugReport.Title = value
|
bugReport.request.Title = value
|
||||||
case "Description":
|
case "Description":
|
||||||
bugReport.Description = value
|
bugReport.request.Description = value
|
||||||
case "Username":
|
case "Username":
|
||||||
bugReport.Username = value
|
bugReport.request.Username = value
|
||||||
case "Email":
|
case "Email":
|
||||||
bugReport.Email = value
|
bugReport.request.Email = value
|
||||||
case "Client":
|
case "Client":
|
||||||
bugReport.Client = value
|
bugReport.request.EmailClient = value
|
||||||
case "Attachment":
|
case "Attachment":
|
||||||
att, err := strconv.ParseBool(value)
|
att, err := strconv.ParseBool(value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to parse bug report attachment preferences: %w", err)
|
return fmt.Errorf("failed to parse bug report attachment preferences: %w", err)
|
||||||
}
|
}
|
||||||
bugReport.Attachment = att
|
bugReport.request.IncludeLogs = att
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("Wrong header (\"%s\") is being checked", key)
|
return fmt.Errorf("Wrong header (\"%s\") is being checked", key)
|
||||||
}
|
}
|
||||||
@ -222,10 +217,9 @@ func (s *scenario) theUserReportsABugWithSingleHeaderChange(key, value string) e
|
|||||||
|
|
||||||
func (s *scenario) theUserReportsABugWithDetails(value *godog.DocString) error {
|
func (s *scenario) theUserReportsABugWithDetails(value *godog.DocString) error {
|
||||||
bugReport := newTestBugReport(s.t.bridge)
|
bugReport := newTestBugReport(s.t.bridge)
|
||||||
if err := json.Unmarshal([]byte(value.Content), &bugReport); err != nil {
|
if err := json.Unmarshal([]byte(value.Content), &bugReport.request); err != nil {
|
||||||
return fmt.Errorf("cannot parse bug report details: %w", err)
|
return fmt.Errorf("cannot parse bug report details: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return bugReport.report()
|
return bugReport.report()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -41,7 +41,7 @@ Feature: The user reports a problem
|
|||||||
"Description": "Testing Description",
|
"Description": "Testing Description",
|
||||||
"Username": "[user:user]",
|
"Username": "[user:user]",
|
||||||
"Email": "[user:user]@[domain]",
|
"Email": "[user:user]@[domain]",
|
||||||
"Client": "Apple Mail"
|
"EmailClient": "Apple Mail"
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
Then the header in the "POST" multipart request to "/core/v4/reports/bug" has "Title" set to "[Bridge] Bug - Testing Title"
|
Then the header in the "POST" multipart request to "/core/v4/reports/bug" has "Title" set to "[Bridge] Bug - Testing Title"
|
||||||
|
|||||||
Reference in New Issue
Block a user