Files
Proton-API-Bridge/common/keyring.go
Mark Ferrell 04a533aec9 feat: leverage go's mod replace sanely
The Proton-API-Bridge should not be attempting to take over, nor
re-define, the existing proton-go-api interfaces. This is known has an
"unfriendly fork" and increases the overall complexity of maintaining
the Proton-API-Bridge.

All changes to the proton-go-api should be done as "friendly" as
possible, and should be submitted back upstream for inclusion. This
improves the functionality of the proton-go-api for more than just 1
project, and it reduces the long-term maintenance required for
Proton-API-Bridge.

To this end, Proton-API-Bridge should be written to always assume it is
using github.com/ProtonMail/proton-go-api and leverage the `replace`
operation in go.mod in order to leverage our "friendly fork" of
proton-go-api. I.e. the long-term goal should be to _not_ maintain a
fork of proton-go-api.

> Anything else would be uncivilized.
2025-01-16 05:38:50 -08:00

76 lines
2.1 KiB
Go

package common
import (
"context"
"github.com/ProtonMail/gopenpgp/v2/crypto"
"github.com/ProtonMail/go-proton-api"
)
/*
The Proton account keys are organized in the following hierarchy.
An account has some users, each of the user will have one or more user keys.
Each of the user will have some addresses, each of the address will have one or more address keys.
A key is encrypted by a passphrase, and the passphrase is encrypted by another key.
The address keyrings are encrypted with the primary user keyring at the time.
The primary address key is used to create (encrypt) and retrieve (decrypt) data, e.g. shares
*/
func getAccountKRs(ctx context.Context, c *proton.Client, keyPass, saltedKeyPass []byte) (*crypto.KeyRing, map[string]*crypto.KeyRing, map[string]proton.Address, []byte, error) {
/* Code taken and modified from proton-bridge */
user, err := c.GetUser(ctx)
if err != nil {
return nil, nil, nil, nil, err
}
// log.Printf("user %#v", user)
addrsArr, err := c.GetAddresses(ctx)
if err != nil {
return nil, nil, nil, nil, err
}
// log.Printf("addr %#v", addr)
if saltedKeyPass == nil {
if keyPass == nil {
return nil, nil, nil, nil, ErrKeyPassOrSaltedKeyPassMustBeNotNil
}
/*
Notes for -> BUG: Access token does not have sufficient scope
Only within the first x minutes that the user logs in with username and password, the getSalts route will be available to be called!
*/
salts, err := c.GetSalts(ctx)
if err != nil {
return nil, nil, nil, nil, err
}
// log.Printf("salts %#v", salts)
saltedKeyPass, err = salts.SaltForKey(keyPass, user.Keys.Primary().ID)
if err != nil {
return nil, nil, nil, nil, err
}
// log.Printf("saltedKeyPass ok")
}
userKR, addrKRs, err := proton.Unlock(user, addrsArr, saltedKeyPass, nil)
if err != nil {
return nil, nil, nil, nil, err
} else if userKR.CountDecryptionEntities() == 0 {
if err != nil {
return nil, nil, nil, nil, ErrFailedToUnlockUserKeys
}
}
addrs := make(map[string]proton.Address)
for _, addr := range addrsArr {
addrs[addr.Email] = addr
}
return userKR, addrKRs, addrs, saltedKeyPass, nil
}