|
@@ -14,6 +14,7 @@ import (
|
|
"fmt"
|
|
"fmt"
|
|
"io"
|
|
"io"
|
|
"strings"
|
|
"strings"
|
|
|
|
+ "sync"
|
|
"time"
|
|
"time"
|
|
|
|
|
|
"github.com/gogo/protobuf/proto"
|
|
"github.com/gogo/protobuf/proto"
|
|
@@ -41,11 +42,11 @@ const (
|
|
// must decrypt those and answer requests by encrypting the data.
|
|
// must decrypt those and answer requests by encrypting the data.
|
|
type encryptedModel struct {
|
|
type encryptedModel struct {
|
|
model Model
|
|
model Model
|
|
- folderKeys map[string]*[keySize]byte // folder ID -> key
|
|
|
|
|
|
+ folderKeys *folderKeyRegistry
|
|
}
|
|
}
|
|
|
|
|
|
func (e encryptedModel) Index(deviceID DeviceID, folder string, files []FileInfo) error {
|
|
func (e encryptedModel) Index(deviceID DeviceID, folder string, files []FileInfo) error {
|
|
- if folderKey, ok := e.folderKeys[folder]; ok {
|
|
|
|
|
|
+ if folderKey, ok := e.folderKeys.get(folder); ok {
|
|
// incoming index data to be decrypted
|
|
// incoming index data to be decrypted
|
|
if err := decryptFileInfos(files, folderKey); err != nil {
|
|
if err := decryptFileInfos(files, folderKey); err != nil {
|
|
return err
|
|
return err
|
|
@@ -55,7 +56,7 @@ func (e encryptedModel) Index(deviceID DeviceID, folder string, files []FileInfo
|
|
}
|
|
}
|
|
|
|
|
|
func (e encryptedModel) IndexUpdate(deviceID DeviceID, folder string, files []FileInfo) error {
|
|
func (e encryptedModel) IndexUpdate(deviceID DeviceID, folder string, files []FileInfo) error {
|
|
- if folderKey, ok := e.folderKeys[folder]; ok {
|
|
|
|
|
|
+ if folderKey, ok := e.folderKeys.get(folder); ok {
|
|
// incoming index data to be decrypted
|
|
// incoming index data to be decrypted
|
|
if err := decryptFileInfos(files, folderKey); err != nil {
|
|
if err := decryptFileInfos(files, folderKey); err != nil {
|
|
return err
|
|
return err
|
|
@@ -65,7 +66,7 @@ func (e encryptedModel) IndexUpdate(deviceID DeviceID, folder string, files []Fi
|
|
}
|
|
}
|
|
|
|
|
|
func (e encryptedModel) Request(deviceID DeviceID, folder, name string, blockNo, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (RequestResponse, error) {
|
|
func (e encryptedModel) Request(deviceID DeviceID, folder, name string, blockNo, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (RequestResponse, error) {
|
|
- folderKey, ok := e.folderKeys[folder]
|
|
|
|
|
|
+ folderKey, ok := e.folderKeys.get(folder)
|
|
if !ok {
|
|
if !ok {
|
|
return e.model.Request(deviceID, folder, name, blockNo, size, offset, hash, weakHash, fromTemporary)
|
|
return e.model.Request(deviceID, folder, name, blockNo, size, offset, hash, weakHash, fromTemporary)
|
|
}
|
|
}
|
|
@@ -123,7 +124,7 @@ func (e encryptedModel) Request(deviceID DeviceID, folder, name string, blockNo,
|
|
}
|
|
}
|
|
|
|
|
|
func (e encryptedModel) DownloadProgress(deviceID DeviceID, folder string, updates []FileDownloadProgressUpdate) error {
|
|
func (e encryptedModel) DownloadProgress(deviceID DeviceID, folder string, updates []FileDownloadProgressUpdate) error {
|
|
- if _, ok := e.folderKeys[folder]; !ok {
|
|
|
|
|
|
+ if _, ok := e.folderKeys.get(folder); !ok {
|
|
return e.model.DownloadProgress(deviceID, folder, updates)
|
|
return e.model.DownloadProgress(deviceID, folder, updates)
|
|
}
|
|
}
|
|
|
|
|
|
@@ -135,42 +136,46 @@ func (e encryptedModel) ClusterConfig(deviceID DeviceID, config ClusterConfig) e
|
|
return e.model.ClusterConfig(deviceID, config)
|
|
return e.model.ClusterConfig(deviceID, config)
|
|
}
|
|
}
|
|
|
|
|
|
-func (e encryptedModel) Closed(conn Connection, err error) {
|
|
|
|
- e.model.Closed(conn, err)
|
|
|
|
|
|
+func (e encryptedModel) Closed(device DeviceID, err error) {
|
|
|
|
+ e.model.Closed(device, err)
|
|
}
|
|
}
|
|
|
|
|
|
// The encryptedConnection sits between the model and the encrypted device. It
|
|
// The encryptedConnection sits between the model and the encrypted device. It
|
|
// encrypts outgoing metadata and decrypts incoming responses.
|
|
// encrypts outgoing metadata and decrypts incoming responses.
|
|
type encryptedConnection struct {
|
|
type encryptedConnection struct {
|
|
ConnectionInfo
|
|
ConnectionInfo
|
|
- conn Connection
|
|
|
|
- folderKeys map[string]*[keySize]byte // folder ID -> key
|
|
|
|
|
|
+ conn *rawConnection
|
|
|
|
+ folderKeys *folderKeyRegistry
|
|
}
|
|
}
|
|
|
|
|
|
func (e encryptedConnection) Start() {
|
|
func (e encryptedConnection) Start() {
|
|
e.conn.Start()
|
|
e.conn.Start()
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+func (e encryptedConnection) SetFolderPasswords(passwords map[string]string) {
|
|
|
|
+ e.folderKeys.setPasswords(passwords)
|
|
|
|
+}
|
|
|
|
+
|
|
func (e encryptedConnection) ID() DeviceID {
|
|
func (e encryptedConnection) ID() DeviceID {
|
|
return e.conn.ID()
|
|
return e.conn.ID()
|
|
}
|
|
}
|
|
|
|
|
|
func (e encryptedConnection) Index(ctx context.Context, folder string, files []FileInfo) error {
|
|
func (e encryptedConnection) Index(ctx context.Context, folder string, files []FileInfo) error {
|
|
- if folderKey, ok := e.folderKeys[folder]; ok {
|
|
|
|
|
|
+ if folderKey, ok := e.folderKeys.get(folder); ok {
|
|
encryptFileInfos(files, folderKey)
|
|
encryptFileInfos(files, folderKey)
|
|
}
|
|
}
|
|
return e.conn.Index(ctx, folder, files)
|
|
return e.conn.Index(ctx, folder, files)
|
|
}
|
|
}
|
|
|
|
|
|
func (e encryptedConnection) IndexUpdate(ctx context.Context, folder string, files []FileInfo) error {
|
|
func (e encryptedConnection) IndexUpdate(ctx context.Context, folder string, files []FileInfo) error {
|
|
- if folderKey, ok := e.folderKeys[folder]; ok {
|
|
|
|
|
|
+ if folderKey, ok := e.folderKeys.get(folder); ok {
|
|
encryptFileInfos(files, folderKey)
|
|
encryptFileInfos(files, folderKey)
|
|
}
|
|
}
|
|
return e.conn.IndexUpdate(ctx, folder, files)
|
|
return e.conn.IndexUpdate(ctx, folder, files)
|
|
}
|
|
}
|
|
|
|
|
|
func (e encryptedConnection) Request(ctx context.Context, folder string, name string, blockNo int, offset int64, size int, hash []byte, weakHash uint32, fromTemporary bool) ([]byte, error) {
|
|
func (e encryptedConnection) Request(ctx context.Context, folder string, name string, blockNo int, offset int64, size int, hash []byte, weakHash uint32, fromTemporary bool) ([]byte, error) {
|
|
- folderKey, ok := e.folderKeys[folder]
|
|
|
|
|
|
+ folderKey, ok := e.folderKeys.get(folder)
|
|
if !ok {
|
|
if !ok {
|
|
return e.conn.Request(ctx, folder, name, blockNo, offset, size, hash, weakHash, fromTemporary)
|
|
return e.conn.Request(ctx, folder, name, blockNo, offset, size, hash, weakHash, fromTemporary)
|
|
}
|
|
}
|
|
@@ -205,7 +210,7 @@ func (e encryptedConnection) Request(ctx context.Context, folder string, name st
|
|
}
|
|
}
|
|
|
|
|
|
func (e encryptedConnection) DownloadProgress(ctx context.Context, folder string, updates []FileDownloadProgressUpdate) {
|
|
func (e encryptedConnection) DownloadProgress(ctx context.Context, folder string, updates []FileDownloadProgressUpdate) {
|
|
- if _, ok := e.folderKeys[folder]; !ok {
|
|
|
|
|
|
+ if _, ok := e.folderKeys.get(folder); !ok {
|
|
e.conn.DownloadProgress(ctx, folder, updates)
|
|
e.conn.DownloadProgress(ctx, folder, updates)
|
|
}
|
|
}
|
|
|
|
|
|
@@ -590,3 +595,27 @@ func isEncryptedParentFromComponents(pathComponents []string) bool {
|
|
}
|
|
}
|
|
return true
|
|
return true
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+type folderKeyRegistry struct {
|
|
|
|
+ keys map[string]*[keySize]byte // folder ID -> key
|
|
|
|
+ mut sync.RWMutex
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func newFolderKeyRegistry(passwords map[string]string) *folderKeyRegistry {
|
|
|
|
+ return &folderKeyRegistry{
|
|
|
|
+ keys: keysFromPasswords(passwords),
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (r *folderKeyRegistry) get(folder string) (*[keySize]byte, bool) {
|
|
|
|
+ r.mut.RLock()
|
|
|
|
+ key, ok := r.keys[folder]
|
|
|
|
+ r.mut.RUnlock()
|
|
|
|
+ return key, ok
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (r *folderKeyRegistry) setPasswords(passwords map[string]string) {
|
|
|
|
+ r.mut.Lock()
|
|
|
|
+ r.keys = keysFromPasswords(passwords)
|
|
|
|
+ r.mut.Unlock()
|
|
|
|
+}
|