parent
3182a3296b
commit
92da6ca550
14 changed files with 0 additions and 1064 deletions
@ -1,19 +0,0 @@ |
||||
// Copyright (c) 2022 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 algo provides some algorithm utils.
|
||||
package algo |
||||
@ -1,47 +0,0 @@ |
||||
// Copyright (c) 2022 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 algo |
||||
|
||||
import "reflect" |
||||
|
||||
// SetIntersection complexity: O(n^2), could be better but this is simple enough.
|
||||
func SetIntersection(a, b interface{}, eq func(a, b interface{}) bool) []interface{} { |
||||
set := make([]interface{}, 0) |
||||
av := reflect.ValueOf(a) |
||||
|
||||
for i := 0; i < av.Len(); i++ { |
||||
el := av.Index(i).Interface() |
||||
if contains(b, el, eq) { |
||||
set = append(set, el) |
||||
} |
||||
} |
||||
|
||||
return set |
||||
} |
||||
|
||||
func contains(a, e interface{}, eq func(a, b interface{}) bool) bool { |
||||
v := reflect.ValueOf(a) |
||||
|
||||
for i := 0; i < v.Len(); i++ { |
||||
if eq(v.Index(i).Interface(), e) { |
||||
return true |
||||
} |
||||
} |
||||
|
||||
return false |
||||
} |
||||
@ -1,71 +0,0 @@ |
||||
// Copyright (c) 2022 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 algo |
||||
|
||||
import ( |
||||
"testing" |
||||
|
||||
"github.com/google/go-cmp/cmp" |
||||
) |
||||
|
||||
type T struct { |
||||
k, v int |
||||
} |
||||
|
||||
func TestSetIntersection(t *testing.T) { |
||||
keysAreEqual := func(a, b interface{}) bool { |
||||
return a.(T).k == b.(T).k |
||||
} |
||||
|
||||
type args struct { |
||||
a interface{} |
||||
b interface{} |
||||
eq func(a, b interface{}) bool |
||||
} |
||||
|
||||
tests := []struct { |
||||
name string |
||||
args args |
||||
want interface{} |
||||
}{ |
||||
{ |
||||
name: "integer sets", |
||||
args: args{a: []int{1, 2, 3}, b: []int{3, 4, 5}, eq: func(a, b interface{}) bool { return a == b }}, |
||||
want: []int{3}, |
||||
}, |
||||
{ |
||||
name: "string sets", |
||||
args: args{a: []string{"1", "2", "3"}, b: []string{"3", "4", "5"}, eq: func(a, b interface{}) bool { return a == b }}, |
||||
want: []string{"3"}, |
||||
}, |
||||
{ |
||||
name: "custom comp, only compare on keys, prefer first set if keys are the same", |
||||
args: args{a: []T{{k: 1, v: 1}, {k: 2, v: 2}}, b: []T{{k: 2, v: 1234}, {k: 3, v: 3}}, eq: keysAreEqual}, |
||||
want: []T{{k: 2, v: 2}}, |
||||
}, |
||||
} |
||||
for _, tt := range tests { |
||||
t.Run(tt.name, func(t *testing.T) { |
||||
// using cmp.Equal because it handles the interfaces correctly; testify/assert doesn't
|
||||
// treat these as equal because their types are different ([]interface vs []int)
|
||||
if got := SetIntersection(tt.args.a, tt.args.b, tt.args.eq); cmp.Equal(got, tt.want) { |
||||
t.Errorf("SetIntersection() = %v, want %v", got, tt.want) |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
@ -1,38 +0,0 @@ |
||||
// Copyright (c) 2022 Proton Technologies AG
|
||||
//
|
||||
// This file is part of ProtonMail Bridge.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 constants contains variables that are set via ldflags during build.
|
||||
package constants |
||||
|
||||
import "fmt" |
||||
|
||||
const VendorName = "protonmail" |
||||
|
||||
// nolint[gochecknoglobals]
|
||||
var ( |
||||
// Version of the build.
|
||||
Version = "1000.1000.1000+git" |
||||
|
||||
// Revision is current hash of the build.
|
||||
Revision = "bf2a7aaf0f" |
||||
|
||||
// BuildTime stamp of the build.
|
||||
BuildTime = "2022-01-01T17:20:35+0100" |
||||
|
||||
// BuildVersion is derived from LongVersion and BuildTime.
|
||||
BuildVersion = fmt.Sprintf("%v (%v) %v", Version, Revision, BuildTime) |
||||
) |
||||
@ -1,28 +0,0 @@ |
||||
// Copyright (c) 2022 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/>.
|
||||
|
||||
// +build !build_qa
|
||||
|
||||
package constants |
||||
|
||||
import "time" |
||||
|
||||
// nolint[gochecknoglobals]
|
||||
var ( |
||||
// UpdateCheckInterval defines how often we check for new version
|
||||
UpdateCheckInterval = time.Hour //nolint[gochecknoglobals]
|
||||
) |
||||
@ -1,28 +0,0 @@ |
||||
// Copyright (c) 2022 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/>.
|
||||
|
||||
// +build build_qa
|
||||
|
||||
package constants |
||||
|
||||
import "time" |
||||
|
||||
// nolint[gochecknoglobals]
|
||||
var ( |
||||
// UpdateCheckInterval defines how often we check for new version
|
||||
UpdateCheckInterval = time.Duration(5 * time.Minute) |
||||
) |
||||
@ -1,46 +0,0 @@ |
||||
// Copyright (c) 2022 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 dialer |
||||
|
||||
import ( |
||||
"net" |
||||
"net/http" |
||||
"time" |
||||
) |
||||
|
||||
const ( |
||||
// ClientTimeout is the timeout for the whole request (from dial to
|
||||
// receiving the response body). It should be large enough to download
|
||||
// even the largest attachments or the new binary of the Bridge, but
|
||||
// should be hit if the server hangs (default is infinite which is bad).
|
||||
clientTimeout = 30 * time.Minute |
||||
dialTimeout = 3 * time.Second |
||||
) |
||||
|
||||
// DialTimeoutClient creates client with overridden dialTimeout.
|
||||
func DialTimeoutClient() *http.Client { |
||||
transport := &http.Transport{ |
||||
Dial: func(network, addr string) (net.Conn, error) { |
||||
return net.DialTimeout(network, addr, dialTimeout) |
||||
}, |
||||
} |
||||
return &http.Client{ |
||||
Timeout: clientTimeout, |
||||
Transport: transport, |
||||
} |
||||
} |
||||
@ -1,75 +0,0 @@ |
||||
// Copyright (c) 2022 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 mobileconfig |
||||
|
||||
import ( |
||||
"io" |
||||
"text/template" |
||||
|
||||
"github.com/google/uuid" |
||||
) |
||||
|
||||
// Config represents an Apple mobileconfig file.
|
||||
type Config struct { |
||||
EmailAddress string |
||||
DisplayName string |
||||
Identifier string |
||||
Organization string |
||||
AccountDescription string |
||||
|
||||
IMAP *IMAP |
||||
SMTP *SMTP |
||||
|
||||
Description string |
||||
ContentUUID string |
||||
UUID string |
||||
} |
||||
|
||||
type IMAP struct { |
||||
Hostname string |
||||
Port int |
||||
TLS bool |
||||
|
||||
Username string |
||||
Password string |
||||
} |
||||
|
||||
type SMTP struct { |
||||
Hostname string |
||||
Port int |
||||
TLS bool |
||||
|
||||
// Leave Username blank to do not use SMTP authentication.
|
||||
Username string |
||||
// Leave Password blank to use IMAP credentials.
|
||||
Password string |
||||
} |
||||
|
||||
func (c *Config) WriteOut(w io.Writer) error { |
||||
if c.ContentUUID == "" { |
||||
uuid := uuid.New() |
||||
c.ContentUUID = uuid.String() |
||||
} |
||||
|
||||
if c.UUID == "" { |
||||
uuid := uuid.New() |
||||
c.UUID = uuid.String() |
||||
} |
||||
|
||||
return template.Must(template.New("mobileconfig").Parse(mailTemplate)).Execute(w, c) |
||||
} |
||||
@ -1,153 +0,0 @@ |
||||
// Copyright (c) 2022 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 mobileconfig |
||||
|
||||
const mailTemplate = `<?xml version="1.0" encoding="UTF-8"?> |
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
||||
<plist version="1.0"> |
||||
<dict> |
||||
<key>PayloadContent</key> |
||||
<array> |
||||
<dict> |
||||
{{- if .AccountDescription}} |
||||
<key>EmailAccountDescription</key> |
||||
<string>{{.AccountDescription}}</string> |
||||
{{- end}} |
||||
|
||||
{{- if .IMAP}} |
||||
<key>EmailAccountType</key> |
||||
<string>EmailTypeIMAP</string> |
||||
|
||||
<key>EmailAddress</key> |
||||
<string>{{.EmailAddress}}</string> |
||||
|
||||
<key>IncomingMailServerAuthentication</key> |
||||
<string>EmailAuthPassword</string> |
||||
|
||||
<key>IncomingMailServerHostName</key> |
||||
<string>{{.IMAP.Hostname}}</string> |
||||
|
||||
<key>IncomingMailServerPortNumber</key> |
||||
<integer>{{.IMAP.Port}}</integer> |
||||
|
||||
<key>IncomingMailServerUseSSL</key> |
||||
{{- if .IMAP.TLS}} |
||||
<true/> |
||||
{{- else}} |
||||
<false/> |
||||
{{- end}} |
||||
|
||||
<key>IncomingMailServerUsername</key> |
||||
<string>{{.IMAP.Username}}</string> |
||||
|
||||
<key>IncomingPassword</key> |
||||
<string>{{.IMAP.Password}}</string> |
||||
{{- end}} |
||||
|
||||
{{ if .SMTP}} |
||||
<key>OutgoingMailServerAuthentication</key> |
||||
<string>{{if .SMTP.Username}}EmailAuthPassword{{else}}EmailAuthNone{{end}}</string> |
||||
|
||||
<key>OutgoingMailServerHostName</key> |
||||
<string>{{.SMTP.Hostname}}</string> |
||||
|
||||
<key>OutgoingMailServerPortNumber</key> |
||||
<integer>{{.SMTP.Port}}</integer> |
||||
|
||||
<key>OutgoingMailServerUseSSL</key> |
||||
{{- if .SMTP.TLS}} |
||||
<true/> |
||||
{{- else}} |
||||
<false/> |
||||
{{- end}} |
||||
|
||||
{{- if .SMTP.Username}} |
||||
<key>OutgoingMailServerUsername</key> |
||||
<string>{{.SMTP.Username}}</string> |
||||
{{- end}} |
||||
|
||||
{{- if .SMTP.Password}} |
||||
<key>OutgoingPassword</key> |
||||
<string>{{.SMTP.Password}}</string> |
||||
{{- else}} |
||||
<key>OutgoingPasswordSameAsIncomingPassword</key> |
||||
<true/> |
||||
{{- end}} |
||||
{{end}} |
||||
|
||||
<key>PayloadDescription</key> |
||||
<string>Configures email account.</string> |
||||
|
||||
<key>PayloadDisplayName</key> |
||||
<string>{{.DisplayName}}</string> |
||||
|
||||
<key>PayloadIdentifier</key> |
||||
<string>{{.Identifier}}</string> |
||||
|
||||
{{- if .Organization}} |
||||
<key>PayloadOrganization</key> |
||||
<string>{{.Organization}}</string> |
||||
{{- end}} |
||||
|
||||
<key>PayloadType</key> |
||||
<string>com.apple.mail.managed</string> |
||||
|
||||
<key>PayloadUUID</key> |
||||
<string>{{.ContentUUID}}</string> |
||||
|
||||
<key>PayloadVersion</key> |
||||
<integer>1</integer> |
||||
|
||||
<key>PreventAppSheet</key> |
||||
<false/> |
||||
|
||||
<key>PreventMove</key> |
||||
<false/> |
||||
|
||||
<key>SMIMEEnabled</key> |
||||
<false/> |
||||
</dict> |
||||
</array> |
||||
|
||||
<key>PayloadDescription</key> |
||||
<string>{{if .Description}}{{.Description}}{{else}}Install this profile to auto configure email account for {{.EmailAddress}}.{{- end}}</string> |
||||
|
||||
<key>PayloadDisplayName</key> |
||||
<string>{{.DisplayName}}</string> |
||||
|
||||
<key>PayloadIdentifier</key> |
||||
<string>{{.Identifier}}</string> |
||||
|
||||
{{- if .Organization}} |
||||
<key>PayloadOrganization</key> |
||||
<string>{{.Organization}}</string> |
||||
{{- end}} |
||||
|
||||
<key>PayloadRemovalDisallowed</key> |
||||
<false/> |
||||
|
||||
<key>PayloadType</key> |
||||
<string>Configuration</string> |
||||
|
||||
<key>PayloadUUID</key> |
||||
<string>{{.UUID}}</string> |
||||
|
||||
<key>PayloadVersion</key> |
||||
<integer>1</integer> |
||||
</dict> |
||||
</plist>` |
||||
@ -1,43 +0,0 @@ |
||||
// Copyright (c) 2022 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 signature implements functions to verify files by their detached signatures.
|
||||
package signature |
||||
|
||||
import ( |
||||
"github.com/ProtonMail/gopenpgp/v2/crypto" |
||||
"github.com/pkg/errors" |
||||
) |
||||
|
||||
// Verify verifies the given file by its signature using the given armored public key.
|
||||
func Verify(fileBytes, sigBytes []byte, pubKey string) error { |
||||
key, err := crypto.NewKeyFromArmored(pubKey) |
||||
if err != nil { |
||||
return errors.Wrap(err, "failed to load key") |
||||
} |
||||
|
||||
kr, err := crypto.NewKeyRing(key) |
||||
if err != nil { |
||||
return errors.Wrap(err, "failed to create keyring") |
||||
} |
||||
|
||||
return kr.VerifyDetached( |
||||
crypto.NewPlainMessage(fileBytes), |
||||
crypto.NewPGPSignature(sigBytes), |
||||
crypto.GetUnixTime(), |
||||
) |
||||
} |
||||
@ -1,85 +0,0 @@ |
||||
// Copyright (c) 2022 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 sum |
||||
|
||||
import ( |
||||
"crypto/sha512" |
||||
"encoding/base64" |
||||
"io" |
||||
"os" |
||||
"path/filepath" |
||||
|
||||
"github.com/sirupsen/logrus" |
||||
) |
||||
|
||||
// RecursiveSum computes the sha512 sum of all files in the root directory and descendents.
|
||||
// If a skipFile is provided (e.g. the path of a checksum file relative to
|
||||
// rootDir), it (and its signature) is ignored.
|
||||
func RecursiveSum(rootDir, skipFileName string) ([]byte, error) { |
||||
hash := sha512.New() |
||||
// In windows filepath accepts both delimiters `\` and `/`. In order to
|
||||
// to properly skip file we have to choose one native delimiter.
|
||||
rootDir = filepath.FromSlash(rootDir) |
||||
skipFile := filepath.Join(rootDir, skipFileName) |
||||
skipFileSig := skipFile + ".sig" |
||||
|
||||
if err := filepath.Walk(rootDir, func(path string, info os.FileInfo, err error) error { |
||||
log := logrus. |
||||
WithField("path", path). |
||||
WithField("sum", base64.StdEncoding.EncodeToString(hash.Sum([]byte{}))) |
||||
log.Debug("Next file") |
||||
if err != nil { |
||||
log.WithError(err).Error("Walk failed") |
||||
return err |
||||
} |
||||
if info.IsDir() { |
||||
log.Debug("Skip dir") |
||||
return nil |
||||
} |
||||
|
||||
// The hashfile itself isn't included in the hash.
|
||||
if path == skipFile || path == skipFileSig { |
||||
log.Debug("Skip file") |
||||
return nil |
||||
} |
||||
|
||||
rel, err := filepath.Rel(rootDir, path) |
||||
if err != nil { |
||||
log.WithError(err).Error("Failed to find relative path") |
||||
return err |
||||
} |
||||
if _, err := hash.Write([]byte(rel)); err != nil { |
||||
log.WithError(err).Error("Failed to write path") |
||||
return err |
||||
} |
||||
f, err := os.Open(path) // nolint[gosec]
|
||||
if err != nil { |
||||
log.WithError(err).Error("Failed to open file") |
||||
return err |
||||
} |
||||
if _, err := io.Copy(hash, f); err != nil { |
||||
log.WithError(err).Error("Copy to hash failed") |
||||
return err |
||||
} |
||||
return f.Close() |
||||
}); err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return hash.Sum([]byte{}), nil |
||||
} |
||||
@ -1,112 +0,0 @@ |
||||
// Copyright (c) 2022 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 sum |
||||
|
||||
import ( |
||||
"io/ioutil" |
||||
"os" |
||||
"path/filepath" |
||||
"testing" |
||||
|
||||
"github.com/stretchr/testify/require" |
||||
) |
||||
|
||||
func TestRecursiveSum(t *testing.T) { |
||||
tempDir, err := ioutil.TempDir("", "verify-test") |
||||
require.NoError(t, err) |
||||
|
||||
createFiles(t, tempDir, |
||||
filepath.Join("a", "1"), |
||||
filepath.Join("a", "2"), |
||||
filepath.Join("b", "3"), |
||||
filepath.Join("b", "4"), |
||||
filepath.Join("b", "c", "5"), |
||||
filepath.Join("b", "c", "6"), |
||||
) |
||||
|
||||
sumOriginal := sum(t, tempDir) |
||||
|
||||
// Renaming files should produce a different checksum.
|
||||
require.NoError(t, os.Rename(filepath.Join(tempDir, "a", "1"), filepath.Join(tempDir, "a", "11"))) |
||||
sumRenamed := sum(t, tempDir) |
||||
require.NotEqual(t, sumOriginal, sumRenamed) |
||||
|
||||
// Reverting to the original name should produce the same checksum again.
|
||||
require.NoError(t, os.Rename(filepath.Join(tempDir, "a", "11"), filepath.Join(tempDir, "a", "1"))) |
||||
require.Equal(t, sumOriginal, sum(t, tempDir)) |
||||
|
||||
// Moving files should produce a different checksum.
|
||||
require.NoError(t, os.Rename(filepath.Join(tempDir, "a", "1"), filepath.Join(tempDir, "1"))) |
||||
sumMoved := sum(t, tempDir) |
||||
require.NotEqual(t, sumOriginal, sumMoved) |
||||
|
||||
// Moving files back to their original location should produce the same checksum again.
|
||||
require.NoError(t, os.Rename(filepath.Join(tempDir, "1"), filepath.Join(tempDir, "a", "1"))) |
||||
require.Equal(t, sumOriginal, sum(t, tempDir)) |
||||
|
||||
// Changing file data should produce a different checksum.
|
||||
originalData := modifyFile(t, filepath.Join(tempDir, "a", "1"), []byte("something")) |
||||
require.NotEqual(t, sumOriginal, sum(t, tempDir)) |
||||
|
||||
// Reverting file data should produce the original checksum.
|
||||
modifyFile(t, filepath.Join(tempDir, "a", "1"), originalData) |
||||
require.Equal(t, sumOriginal, sum(t, tempDir)) |
||||
} |
||||
|
||||
func createFiles(t *testing.T, root string, paths ...string) { |
||||
for _, path := range paths { |
||||
makeFile(t, filepath.Join(root, path)) |
||||
} |
||||
} |
||||
|
||||
func makeFile(t *testing.T, path string) { |
||||
require.NoError(t, os.MkdirAll(filepath.Dir(path), 0700)) |
||||
|
||||
f, err := os.Create(path) |
||||
require.NoError(t, err) |
||||
|
||||
_, err = f.WriteString(path) |
||||
require.NoError(t, err) |
||||
|
||||
require.NoError(t, f.Close()) |
||||
} |
||||
|
||||
func sum(t *testing.T, path string) []byte { |
||||
sum, err := RecursiveSum(path, "") |
||||
require.NoError(t, err) |
||||
|
||||
return sum |
||||
} |
||||
|
||||
func modifyFile(t *testing.T, path string, data []byte) []byte { |
||||
r, err := os.Open(path) |
||||
require.NoError(t, err) |
||||
|
||||
b, err := ioutil.ReadAll(r) |
||||
require.NoError(t, err) |
||||
require.NoError(t, r.Close()) |
||||
|
||||
f, err := os.Create(path) |
||||
require.NoError(t, err) |
||||
|
||||
_, err = f.Write(data) |
||||
require.NoError(t, err) |
||||
require.NoError(t, f.Close()) |
||||
|
||||
return b |
||||
} |
||||
@ -1,104 +0,0 @@ |
||||
// Copyright (c) 2022 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 tar |
||||
|
||||
import ( |
||||
"archive/tar" |
||||
"errors" |
||||
"io" |
||||
"os" |
||||
"path/filepath" |
||||
"runtime" |
||||
|
||||
"github.com/sirupsen/logrus" |
||||
) |
||||
|
||||
// maxFileSize limit tre single file size after decopression is not larger than 1GB.
|
||||
const maxFileSize = int64(1 * 1024 * 1024 * 1024) // 1 GB
|
||||
|
||||
// ErrFileTooLarge returned when decompressed file is too large.
|
||||
var ErrFileTooLarge = errors.New("trying to decompress file larger than 1GB") |
||||
|
||||
type limitReader struct { |
||||
r io.Reader |
||||
n int64 |
||||
} |
||||
|
||||
// Read returns error if limit was exceeded. Inspired by io.LimitReader.Read
|
||||
// implementation.
|
||||
func (lr *limitReader) Read(p []byte) (n int, err error) { |
||||
if lr.n <= 0 { |
||||
return 0, ErrFileTooLarge |
||||
} |
||||
if int64(len(p)) > lr.n { |
||||
p = p[0:lr.n] |
||||
} |
||||
n, err = lr.r.Read(p) |
||||
lr.n -= int64(n) |
||||
return |
||||
} |
||||
|
||||
// UntarToDir decopmress and unarchive the files into directory.
|
||||
func UntarToDir(r io.Reader, dir string) error { |
||||
tr := tar.NewReader(r) |
||||
|
||||
for { |
||||
header, err := tr.Next() |
||||
if err == io.EOF { |
||||
return nil |
||||
} |
||||
if err != nil { |
||||
return err |
||||
} |
||||
if header == nil { |
||||
continue |
||||
} |
||||
|
||||
target := filepath.Join(dir, filepath.Clean(header.Name)) // gosec G305
|
||||
|
||||
switch { |
||||
case header.Typeflag == tar.TypeSymlink: |
||||
if err := os.Symlink(header.Linkname, target); err != nil { |
||||
return err |
||||
} |
||||
|
||||
case header.FileInfo().IsDir(): |
||||
if err := os.MkdirAll(target, header.FileInfo().Mode()); err != nil { |
||||
return err |
||||
} |
||||
|
||||
default: |
||||
f, err := os.Create(target) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
lr := &limitReader{r: tr, n: maxFileSize} // gosec G110
|
||||
if _, err := io.Copy(f, lr); err != nil { |
||||
return err |
||||
} |
||||
if runtime.GOOS != "windows" { |
||||
if err := f.Chmod(header.FileInfo().Mode()); err != nil { |
||||
return err |
||||
} |
||||
} |
||||
if err := f.Close(); err != nil { |
||||
logrus.WithError(err).Error("Failed to close file") |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -1,215 +0,0 @@ |
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/ljanyst/peroxide/pkg/transfer (interfaces: PanicHandler,IMAPClientProvider)
|
||||
|
||||
// Package mocks is a generated GoMock package.
|
||||
package mocks |
||||
|
||||
import ( |
||||
reflect "reflect" |
||||
|
||||
imap "github.com/emersion/go-imap" |
||||
sasl "github.com/emersion/go-sasl" |
||||
gomock "github.com/golang/mock/gomock" |
||||
) |
||||
|
||||
// MockPanicHandler is a mock of PanicHandler interface.
|
||||
type MockPanicHandler struct { |
||||
ctrl *gomock.Controller |
||||
recorder *MockPanicHandlerMockRecorder |
||||
} |
||||
|
||||
// MockPanicHandlerMockRecorder is the mock recorder for MockPanicHandler.
|
||||
type MockPanicHandlerMockRecorder struct { |
||||
mock *MockPanicHandler |
||||
} |
||||
|
||||
// NewMockPanicHandler creates a new mock instance.
|
||||
func NewMockPanicHandler(ctrl *gomock.Controller) *MockPanicHandler { |
||||
mock := &MockPanicHandler{ctrl: ctrl} |
||||
mock.recorder = &MockPanicHandlerMockRecorder{mock} |
||||
return mock |
||||
} |
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockPanicHandler) EXPECT() *MockPanicHandlerMockRecorder { |
||||
return m.recorder |
||||
} |
||||
|
||||
// HandlePanic mocks base method.
|
||||
func (m *MockPanicHandler) HandlePanic() { |
||||
m.ctrl.T.Helper() |
||||
m.ctrl.Call(m, "HandlePanic") |
||||
} |
||||
|
||||
// HandlePanic indicates an expected call of HandlePanic.
|
||||
func (mr *MockPanicHandlerMockRecorder) HandlePanic() *gomock.Call { |
||||
mr.mock.ctrl.T.Helper() |
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandlePanic", reflect.TypeOf((*MockPanicHandler)(nil).HandlePanic)) |
||||
} |
||||
|
||||
// MockIMAPClientProvider is a mock of IMAPClientProvider interface.
|
||||
type MockIMAPClientProvider struct { |
||||
ctrl *gomock.Controller |
||||
recorder *MockIMAPClientProviderMockRecorder |
||||
} |
||||
|
||||
// MockIMAPClientProviderMockRecorder is the mock recorder for MockIMAPClientProvider.
|
||||
type MockIMAPClientProviderMockRecorder struct { |
||||
mock *MockIMAPClientProvider |
||||
} |
||||
|
||||
// NewMockIMAPClientProvider creates a new mock instance.
|
||||
func NewMockIMAPClientProvider(ctrl *gomock.Controller) *MockIMAPClientProvider { |
||||
mock := &MockIMAPClientProvider{ctrl: ctrl} |
||||
mock.recorder = &MockIMAPClientProviderMockRecorder{mock} |
||||
return mock |
||||
} |
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockIMAPClientProvider) EXPECT() *MockIMAPClientProviderMockRecorder { |
||||
return m.recorder |
||||
} |
||||
|
||||
// Authenticate mocks base method.
|
||||
func (m *MockIMAPClientProvider) Authenticate(arg0 sasl.Client) error { |
||||
m.ctrl.T.Helper() |
||||
ret := m.ctrl.Call(m, "Authenticate", arg0) |
||||
ret0, _ := ret[0].(error) |
||||
return ret0 |
||||
} |
||||
|
||||
// Authenticate indicates an expected call of Authenticate.
|
||||
func (mr *MockIMAPClientProviderMockRecorder) Authenticate(arg0 interface{}) *gomock.Call { |
||||
mr.mock.ctrl.T.Helper() |
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Authenticate", reflect.TypeOf((*MockIMAPClientProvider)(nil).Authenticate), arg0) |
||||
} |
||||
|
||||
// Capability mocks base method.
|
||||
func (m *MockIMAPClientProvider) Capability() (map[string]bool, error) { |
||||
m.ctrl.T.Helper() |
||||
ret := m.ctrl.Call(m, "Capability") |
||||
ret0, _ := ret[0].(map[string]bool) |
||||
ret1, _ := ret[1].(error) |
||||
return ret0, ret1 |
||||
} |
||||
|
||||
// Capability indicates an expected call of Capability.
|
||||
func (mr *MockIMAPClientProviderMockRecorder) Capability() *gomock.Call { |
||||
mr.mock.ctrl.T.Helper() |
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Capability", reflect.TypeOf((*MockIMAPClientProvider)(nil).Capability)) |
||||
} |
||||
|
||||
// Fetch mocks base method.
|
||||
func (m *MockIMAPClientProvider) Fetch(arg0 *imap.SeqSet, arg1 []imap.FetchItem, arg2 chan *imap.Message) error { |
||||
m.ctrl.T.Helper() |
||||
ret := m.ctrl.Call(m, "Fetch", arg0, arg1, arg2) |
||||
ret0, _ := ret[0].(error) |
||||
return ret0 |
||||
} |
||||
|
||||
// Fetch indicates an expected call of Fetch.
|
||||
func (mr *MockIMAPClientProviderMockRecorder) Fetch(arg0, arg1, arg2 interface{}) *gomock.Call { |
||||
mr.mock.ctrl.T.Helper() |
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Fetch", reflect.TypeOf((*MockIMAPClientProvider)(nil).Fetch), arg0, arg1, arg2) |
||||
} |
||||
|
||||
// List mocks base method.
|
||||
func (m *MockIMAPClientProvider) List(arg0, arg1 string, arg2 chan *imap.MailboxInfo) error { |
||||
m.ctrl.T.Helper() |
||||
ret := m.ctrl.Call(m, "List", arg0, arg1, arg2) |
||||
ret0, _ := ret[0].(error) |
||||
return ret0 |
||||
} |
||||
|
||||
// List indicates an expected call of List.
|
||||
func (mr *MockIMAPClientProviderMockRecorder) List(arg0, arg1, arg2 interface{}) *gomock.Call { |
||||
mr.mock.ctrl.T.Helper() |
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockIMAPClientProvider)(nil).List), arg0, arg1, arg2) |
||||
} |
||||
|
||||
// Login mocks base method.
|
||||
func (m *MockIMAPClientProvider) Login(arg0, arg1 string) error { |
||||
m.ctrl.T.Helper() |
||||
ret := m.ctrl.Call(m, "Login", arg0, arg1) |
||||
ret0, _ := ret[0].(error) |
||||
return ret0 |
||||
} |
||||
|
||||
// Login indicates an expected call of Login.
|
||||
func (mr *MockIMAPClientProviderMockRecorder) Login(arg0, arg1 interface{}) *gomock.Call { |
||||
mr.mock.ctrl.T.Helper() |
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Login", reflect.TypeOf((*MockIMAPClientProvider)(nil).Login), arg0, arg1) |
||||
} |
||||
|
||||
// Select mocks base method.
|
||||
func (m *MockIMAPClientProvider) Select(arg0 string, arg1 bool) (*imap.MailboxStatus, error) { |
||||
m.ctrl.T.Helper() |
||||
ret := m.ctrl.Call(m, "Select", arg0, arg1) |
||||
ret0, _ := ret[0].(*imap.MailboxStatus) |
||||
ret1, _ := ret[1].(error) |
||||
return ret0, ret1 |
||||
} |
||||
|
||||
// Select indicates an expected call of Select.
|
||||
func (mr *MockIMAPClientProviderMockRecorder) Select(arg0, arg1 interface{}) *gomock.Call { |
||||
mr.mock.ctrl.T.Helper() |
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Select", reflect.TypeOf((*MockIMAPClientProvider)(nil).Select), arg0, arg1) |
||||
} |
||||
|
||||
// State mocks base method.
|
||||
func (m *MockIMAPClientProvider) State() imap.ConnState { |
||||
m.ctrl.T.Helper() |
||||
ret := m.ctrl.Call(m, "State") |
||||
ret0, _ := ret[0].(imap.ConnState) |
||||
return ret0 |
||||
} |
||||
|
||||
// State indicates an expected call of State.
|
||||
func (mr *MockIMAPClientProviderMockRecorder) State() *gomock.Call { |
||||
mr.mock.ctrl.T.Helper() |
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "State", reflect.TypeOf((*MockIMAPClientProvider)(nil).State)) |
||||
} |
||||
|
||||
// Support mocks base method.
|
||||
func (m *MockIMAPClientProvider) Support(arg0 string) (bool, error) { |
||||
m.ctrl.T.Helper() |
||||
ret := m.ctrl.Call(m, "Support", arg0) |
||||
ret0, _ := ret[0].(bool) |
||||
ret1, _ := ret[1].(error) |
||||
return ret0, ret1 |
||||
} |
||||
|
||||
// Support indicates an expected call of Support.
|
||||
func (mr *MockIMAPClientProviderMockRecorder) Support(arg0 interface{}) *gomock.Call { |
||||
mr.mock.ctrl.T.Helper() |
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Support", reflect.TypeOf((*MockIMAPClientProvider)(nil).Support), arg0) |
||||
} |
||||
|
||||
// SupportAuth mocks base method.
|
||||
func (m *MockIMAPClientProvider) SupportAuth(arg0 string) (bool, error) { |
||||
m.ctrl.T.Helper() |
||||
ret := m.ctrl.Call(m, "SupportAuth", arg0) |
||||
ret0, _ := ret[0].(bool) |
||||
ret1, _ := ret[1].(error) |
||||
return ret0, ret1 |
||||
} |
||||
|
||||
// SupportAuth indicates an expected call of SupportAuth.
|
||||
func (mr *MockIMAPClientProviderMockRecorder) SupportAuth(arg0 interface{}) *gomock.Call { |
||||
mr.mock.ctrl.T.Helper() |
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SupportAuth", reflect.TypeOf((*MockIMAPClientProvider)(nil).SupportAuth), arg0) |
||||
} |
||||
|
||||
// UidFetch mocks base method.
|
||||
func (m *MockIMAPClientProvider) UidFetch(arg0 *imap.SeqSet, arg1 []imap.FetchItem, arg2 chan *imap.Message) error { |
||||
m.ctrl.T.Helper() |
||||
ret := m.ctrl.Call(m, "UidFetch", arg0, arg1, arg2) |
||||
ret0, _ := ret[0].(error) |
||||
return ret0 |
||||
} |
||||
|
||||
// UidFetch indicates an expected call of UidFetch.
|
||||
func (mr *MockIMAPClientProviderMockRecorder) UidFetch(arg0, arg1, arg2 interface{}) *gomock.Call { |
||||
mr.mock.ctrl.T.Helper() |
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UidFetch", reflect.TypeOf((*MockIMAPClientProvider)(nil).UidFetch), arg0, arg1, arg2) |
||||
} |
||||
Loading…
Reference in new issue