diff --git a/COPYING_NOTES.md b/COPYING_NOTES.md index a54faf11..b9af649d 100644 --- a/COPYING_NOTES.md +++ b/COPYING_NOTES.md @@ -56,6 +56,7 @@ Proton Mail Bridge includes the following 3rd party software: * [logrus](https://github.com/sirupsen/logrus) available under [license](https://github.com/sirupsen/logrus/blob/master/LICENSE) * [testify](https://github.com/stretchr/testify) available under [license](https://github.com/stretchr/testify/blob/master/LICENSE) * [cli](https://github.com/urfave/cli/v2) available under [license](https://github.com/urfave/cli/v2/blob/master/LICENSE) +* [msgpack](https://github.com/vmihailenco/msgpack/v5) available under [license](https://github.com/vmihailenco/msgpack/v5/blob/master/LICENSE) * [liteapi](https://gitlab.protontech.ch/go/liteapi) * [goleak](https://go.uber.org/goleak) * [exp](https://golang.org/x/exp) available under [license](https://cs.opensource.google/go/x/exp/+/master:LICENSE) @@ -120,6 +121,7 @@ Proton Mail Bridge includes the following 3rd party software: * [pflag](https://github.com/spf13/pflag) available under [license](https://github.com/spf13/pflag/blob/master/LICENSE) * [bom](https://github.com/ssor/bom) available under [license](https://github.com/ssor/bom/blob/master/LICENSE) * [codec](https://github.com/ugorji/go/codec) available under [license](https://github.com/ugorji/go/codec/blob/master/LICENSE) +* [tagparser](https://github.com/vmihailenco/tagparser/v2) available under [license](https://github.com/vmihailenco/tagparser/v2/blob/master/LICENSE) * [smetrics](https://github.com/xrash/smetrics) available under [license](https://github.com/xrash/smetrics/blob/master/LICENSE) * [go-cty](https://github.com/zclconf/go-cty) available under [license](https://github.com/zclconf/go-cty/blob/master/LICENSE) * [crypto](https://golang.org/x/crypto) available under [license](https://cs.opensource.google/go/x/crypto/+/master:LICENSE) diff --git a/go.mod b/go.mod index a32e83e1..4ed4b968 100644 --- a/go.mod +++ b/go.mod @@ -38,6 +38,7 @@ require ( github.com/sirupsen/logrus v1.9.0 github.com/stretchr/testify v1.8.0 github.com/urfave/cli/v2 v2.20.3 + github.com/vmihailenco/msgpack/v5 v5.3.5 gitlab.protontech.ch/go/liteapi v0.36.1 go.uber.org/goleak v1.2.0 golang.org/x/exp v0.0.0-20221023144134-a1e5550cf13e @@ -105,6 +106,7 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect github.com/ugorji/go/codec v1.2.7 // indirect + github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/zclconf/go-cty v1.11.0 // indirect golang.org/x/crypto v0.1.0 // indirect diff --git a/go.sum b/go.sum index 508e5bff..8bf4ab37 100644 --- a/go.sum +++ b/go.sum @@ -393,6 +393,10 @@ github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0 github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= github.com/urfave/cli/v2 v2.20.3 h1:lOgGidH/N5loaigd9HjFsOIhXSTrzl7tBpHswZ428w4= github.com/urfave/cli/v2 v2.20.3/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI= +github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= +github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= +github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= +github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= diff --git a/internal/vault/settings.go b/internal/vault/settings.go index 239a9a16..e3e50b3b 100644 --- a/internal/vault/settings.go +++ b/internal/vault/settings.go @@ -168,13 +168,13 @@ func (vault *Vault) SetAutoUpdate(autoUpdate bool) error { // GetLastVersion returns the last version of the bridge that was run. func (vault *Vault) GetLastVersion() *semver.Version { - return vault.get().Settings.LastVersion + return semver.MustParse(vault.get().Settings.LastVersion) } // SetLastVersion sets the last version of the bridge that was run. func (vault *Vault) SetLastVersion(version *semver.Version) error { return vault.mod(func(data *Data) { - data.Settings.LastVersion = version + data.Settings.LastVersion = version.String() }) } diff --git a/internal/vault/types.go b/internal/vault/types.go index b760ff89..976bbb34 100644 --- a/internal/vault/types.go +++ b/internal/vault/types.go @@ -20,7 +20,6 @@ package vault import ( "math/rand" - "github.com/Masterminds/semver/v3" "github.com/ProtonMail/gluon/imap" "github.com/ProtonMail/proton-bridge/v2/internal/updater" ) @@ -58,7 +57,7 @@ type Settings struct { Autostart bool AutoUpdate bool - LastVersion *semver.Version + LastVersion string FirstStart bool FirstStartGUI bool } @@ -81,7 +80,7 @@ func newDefaultSettings(gluonDir string) Settings { Autostart: false, AutoUpdate: true, - LastVersion: semver.MustParse("0.0.0"), + LastVersion: "0.0.0", FirstStart: true, FirstStartGUI: true, } diff --git a/internal/vault/vault.go b/internal/vault/vault.go index 20dc37f0..9d11ae48 100644 --- a/internal/vault/vault.go +++ b/internal/vault/vault.go @@ -22,7 +22,6 @@ import ( "crypto/cipher" "crypto/rand" "crypto/sha256" - "encoding/json" "errors" "fmt" "io/fs" @@ -32,6 +31,7 @@ import ( "github.com/ProtonMail/proton-bridge/v2/internal/certs" "github.com/bradenaw/juniper/xslices" + "github.com/vmihailenco/msgpack/v5" ) // Vault is an encrypted data vault that stores bridge and user data. @@ -253,7 +253,7 @@ func (vault *Vault) get() Data { var data Data - if err := json.Unmarshal(dec, &data); err != nil { + if err := msgpack.Unmarshal(dec, &data); err != nil { panic(err) } @@ -271,13 +271,13 @@ func (vault *Vault) mod(fn func(data *Data)) error { var data Data - if err := json.Unmarshal(dec, &data); err != nil { + if err := msgpack.Unmarshal(dec, &data); err != nil { return err } fn(&data) - mod, err := json.Marshal(data) + mod, err := msgpack.Marshal(data) if err != nil { return err } @@ -314,7 +314,7 @@ func initVault(path, gluonDir string, gcm cipher.AEAD) ([]byte, error) { return nil, err } - dec, err := json.Marshal(Data{ + dec, err := msgpack.Marshal(Data{ Settings: newDefaultSettings(gluonDir), Certs: Certs{ diff --git a/internal/vault/vault_bench_test.go b/internal/vault/vault_bench_test.go new file mode 100644 index 00000000..1596211d --- /dev/null +++ b/internal/vault/vault_bench_test.go @@ -0,0 +1,58 @@ +// Copyright (c) 2022 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 vault_test + +import ( + "bytes" + "testing" + + "github.com/ProtonMail/proton-bridge/v2/internal/vault" + "github.com/google/uuid" + "github.com/stretchr/testify/require" +) + +func BenchmarkVault(b *testing.B) { + vaultDir, gluonDir := b.TempDir(), b.TempDir() + + // Create a new vault. + s, corrupt, err := vault.New(vaultDir, gluonDir, []byte("my secret key")) + require.NoError(b, err) + require.False(b, corrupt) + + // Add 10kB of cookies to the vault. + require.NoError(b, s.SetCookies(bytes.Repeat([]byte("a"), 10_000))) + + // Create 10 vault users. + for idx := 0; idx < 10; idx++ { + user, err := s.AddUser(uuid.NewString(), "username", "authUID", "authRef", []byte("keyPass")) + require.NoError(b, err) + + require.NoError(b, user.SetKeyPass([]byte("new key pass"))) + } + + b.ResetTimer() + + // Time how quickly we can iterate through the users and get their key pass and bridge pass. + for i := 0; i < b.N; i++ { + require.NoError(b, s.ForUser(func(user *vault.User) error { + require.NotEmpty(b, user.KeyPass()) + require.NotEmpty(b, user.BridgePass()) + return nil + })) + } +}