mirror of
https://github.com/ProtonMail/go-proton-api.git
synced 2025-12-23 15:47:52 -05:00
185 lines
5.0 KiB
Go
185 lines
5.0 KiB
Go
package proton
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"errors"
|
|
|
|
"github.com/ProtonMail/gopenpgp/v2/crypto"
|
|
)
|
|
|
|
type LinkWalkFunc func([]string, Link, *crypto.KeyRing) error
|
|
|
|
// Link holds the tree structure, for the clients, they represent the files and folders of a given volume.
|
|
// They have a ParentLinkID that points to parent folders.
|
|
// Links also hold the file name (encrypted) and a hash of the name for name collisions.
|
|
// Link data is encrypted with its owning Share keyring.
|
|
type Link struct {
|
|
LinkID string // Encrypted file/folder ID
|
|
ParentLinkID string // Encrypted parent folder ID (LinkID). Root link has null ParentLinkID.
|
|
|
|
Type LinkType
|
|
Name string // Encrypted file name
|
|
Hash string // HMAC of name encrypted with parent hash key
|
|
Size int64
|
|
State LinkState
|
|
MIMEType string
|
|
|
|
CreateTime int64 // Link creation time
|
|
ModifyTime int64 // Link modification time (on API, real modify date is stored in XAttr)
|
|
ExpirationTime int64 // Link expiration time
|
|
|
|
NodeKey string // The private NodeKey, used to decrypt any file/folder content.
|
|
NodePassphrase string // The passphrase used to unlock the NodeKey, encrypted by the owning Link/Share keyring.
|
|
NodePassphraseSignature string
|
|
|
|
FileProperties *FileProperties
|
|
FolderProperties *FolderProperties
|
|
}
|
|
|
|
type LinkState int
|
|
|
|
const (
|
|
LinkStateDraft LinkState = iota
|
|
LinkStateActive
|
|
LinkStateTrashed
|
|
LinkStateDeleted
|
|
LinkStateRestoring
|
|
)
|
|
|
|
func (l Link) GetName(parentNodeKR, addrKR *crypto.KeyRing) (string, error) {
|
|
encName, err := crypto.NewPGPMessageFromArmored(l.Name)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
decName, err := parentNodeKR.Decrypt(encName, addrKR, crypto.GetUnixTime())
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return decName.GetString(), nil
|
|
}
|
|
|
|
func (l Link) GetKeyRing(parentNodeKR, addrKR *crypto.KeyRing) (*crypto.KeyRing, error) {
|
|
enc, err := crypto.NewPGPMessageFromArmored(l.NodePassphrase)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
dec, err := parentNodeKR.Decrypt(enc, nil, crypto.GetUnixTime())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
sig, err := crypto.NewPGPSignatureFromArmored(l.NodePassphraseSignature)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := addrKR.VerifyDetached(dec, sig, crypto.GetUnixTime()); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
lockedKey, err := crypto.NewKeyFromArmored(l.NodeKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
unlockedKey, err := lockedKey.Unlock(dec.GetBinary())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return crypto.NewKeyRing(unlockedKey)
|
|
}
|
|
|
|
func (l Link) GetHashKey(nodeKR *crypto.KeyRing) ([]byte, error) {
|
|
if l.Type != LinkTypeFolder {
|
|
return nil, errors.New("link is not a folder")
|
|
}
|
|
|
|
enc, err := crypto.NewPGPMessageFromArmored(l.FolderProperties.NodeHashKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
dec, err := nodeKR.Decrypt(enc, nodeKR, crypto.GetUnixTime())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return dec.GetBinary(), nil
|
|
}
|
|
|
|
func (l Link) GetSessionKey(nodeKR *crypto.KeyRing) (*crypto.SessionKey, error) {
|
|
if l.Type != LinkTypeFile {
|
|
return nil, errors.New("link is not a file")
|
|
}
|
|
|
|
dec, err := base64.StdEncoding.DecodeString(l.FileProperties.ContentKeyPacket)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
key, err := nodeKR.DecryptSessionKey(dec)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
sig, err := crypto.NewPGPSignatureFromArmored(l.FileProperties.ContentKeyPacketSignature)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := nodeKR.VerifyDetached(crypto.NewPlainMessage(key.Key), sig, crypto.GetUnixTime()); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return key, nil
|
|
}
|
|
|
|
type FileProperties struct {
|
|
ContentKeyPacket string // The block's key packet, encrypted with the node key.
|
|
ContentKeyPacketSignature string // Signature of the content key packet. Signature of the session key, signed with the NodeKey.
|
|
ActiveRevision RevisionMetadata // The active revision of the file.
|
|
}
|
|
|
|
type FolderProperties struct {
|
|
NodeHashKey string // HMAC key used to hash the folder's children names.
|
|
}
|
|
|
|
type LinkType int
|
|
|
|
const (
|
|
LinkTypeFolder LinkType = iota + 1
|
|
LinkTypeFile
|
|
)
|
|
|
|
type RevisionMetadata struct {
|
|
ID string // Encrypted Revision ID
|
|
CreateTime int64 // Unix timestamp of the revision creation time
|
|
Size int64 // Size of the revision in bytes
|
|
ManifestSignature string // Signature of the revision manifest, signed with user's address key of the share.
|
|
SignatureEmail string // Email of the user that signed the revision.
|
|
State RevisionState // State of revision
|
|
Thumbnail Bool // Whether the revision has a thumbnail
|
|
ThumbnailHash string // Hash of the thumbnail
|
|
}
|
|
|
|
// Revisions are only for files, they represent “versions” of files.
|
|
// Each file can have 1 active revision and n obsolete revisions.
|
|
type Revision struct {
|
|
RevisionMetadata
|
|
|
|
Blocks []Block
|
|
}
|
|
|
|
type RevisionState int
|
|
|
|
const (
|
|
RevisionStateDraft RevisionState = iota
|
|
RevisionStateActive
|
|
RevisionStateObsolete
|
|
RevisionStateDeleted
|
|
)
|