+7
-1
@@ -65,6 +65,7 @@ const (
|
||||
EventSubBufferSize = 1000
|
||||
defaultEventTimeout = time.Minute
|
||||
httpsCertLifetimeDays = 820
|
||||
featureFlagUntrusted = "untrusted"
|
||||
)
|
||||
|
||||
type service struct {
|
||||
@@ -110,7 +111,7 @@ func New(id protocol.DeviceID, cfg config.Wrapper, assetDir, tlsDefaultCommonNam
|
||||
s := &service{
|
||||
id: id,
|
||||
cfg: cfg,
|
||||
statics: newStaticsServer(cfg.GUI().Theme, assetDir),
|
||||
statics: newStaticsServer(cfg.GUI().Theme, assetDir, cfg.Options().FeatureFlag(featureFlagUntrusted)),
|
||||
model: m,
|
||||
eventSubs: map[events.EventType]events.BufferedSubscription{
|
||||
DefaultEventMask: defaultSub,
|
||||
@@ -449,7 +450,12 @@ func (s *service) CommitConfiguration(from, to config.Configuration) bool {
|
||||
// No action required when this changes, so mask the fact that it changed at all.
|
||||
from.GUI.Debugging = to.GUI.Debugging
|
||||
|
||||
if untrusted := to.Options.FeatureFlag(featureFlagUntrusted); untrusted != from.Options.FeatureFlag(featureFlagUntrusted) {
|
||||
s.statics.setUntrusted(untrusted)
|
||||
}
|
||||
|
||||
if to.GUI == from.GUI {
|
||||
// No GUI changes, we're done here.
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
+70
-32
@@ -30,15 +30,17 @@ type staticsServer struct {
|
||||
mut sync.RWMutex
|
||||
theme string
|
||||
lastThemeChange time.Time
|
||||
untrusted bool
|
||||
}
|
||||
|
||||
func newStaticsServer(theme, assetDir string) *staticsServer {
|
||||
func newStaticsServer(theme, assetDir string, untrusted bool) *staticsServer {
|
||||
s := &staticsServer{
|
||||
assetDir: assetDir,
|
||||
assets: auto.Assets(),
|
||||
mut: sync.NewRWMutex(),
|
||||
theme: theme,
|
||||
lastThemeChange: time.Now().UTC(),
|
||||
untrusted: untrusted,
|
||||
}
|
||||
|
||||
seen := make(map[string]struct{})
|
||||
@@ -60,6 +62,10 @@ func newStaticsServer(theme, assetDir string) *staticsServer {
|
||||
}
|
||||
}
|
||||
|
||||
if untrusted {
|
||||
l.Infoln(`Feature flag "untrusted":`, untrusted)
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -88,6 +94,7 @@ func (s *staticsServer) serveAsset(w http.ResponseWriter, r *http.Request) {
|
||||
s.mut.RLock()
|
||||
theme := s.theme
|
||||
modificationTime := s.lastThemeChange
|
||||
untrusted := s.untrusted
|
||||
s.mut.RUnlock()
|
||||
|
||||
// If path starts with special prefix, get theme and file from path
|
||||
@@ -105,44 +112,68 @@ func (s *staticsServer) serveAsset(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// Check for an override for the current theme.
|
||||
if s.assetDir != "" {
|
||||
p := filepath.Join(s.assetDir, theme, filepath.FromSlash(file))
|
||||
if _, err := os.Stat(p); err == nil {
|
||||
mtype := assets.MimeTypeForFile(file)
|
||||
if len(mtype) != 0 {
|
||||
w.Header().Set("Content-Type", mtype)
|
||||
}
|
||||
http.ServeFile(w, r, p)
|
||||
return
|
||||
}
|
||||
if untrusted && s.serveFromAssetDir(file, theme+"/untrusted", w, r) {
|
||||
l.Debugln("serving", file, "from override untrusted")
|
||||
return
|
||||
}
|
||||
if s.serveFromAssetDir(file, theme, w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
// Check for a compiled in asset for the current theme.
|
||||
as, ok := s.assets[theme+"/"+file]
|
||||
if !ok {
|
||||
// Check for an overridden default asset.
|
||||
if s.assetDir != "" {
|
||||
p := filepath.Join(s.assetDir, config.DefaultTheme, filepath.FromSlash(file))
|
||||
if _, err := os.Stat(p); err == nil {
|
||||
mtype := assets.MimeTypeForFile(file)
|
||||
if len(mtype) != 0 {
|
||||
w.Header().Set("Content-Type", mtype)
|
||||
}
|
||||
http.ServeFile(w, r, p)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Check for a compiled in default asset.
|
||||
as, ok = s.assets[config.DefaultTheme+"/"+file]
|
||||
if !ok {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
if untrusted && s.serveFromAssets(file, theme+"/untrusted", modificationTime, w, r) {
|
||||
l.Debugln("serving", file, "from compiled untrusted")
|
||||
return
|
||||
}
|
||||
if s.serveFromAssets(file, theme, modificationTime, w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
// Check for an overridden default asset.
|
||||
if untrusted && s.serveFromAssetDir(file, config.DefaultTheme+"/untrusted", w, r) {
|
||||
l.Debugln("serving", file, "from override untrusted")
|
||||
return
|
||||
}
|
||||
if s.serveFromAssetDir(file, config.DefaultTheme, w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
// Check for a compiled in default asset.
|
||||
if untrusted && s.serveFromAssets(file, config.DefaultTheme+"/untrusted", modificationTime, w, r) {
|
||||
l.Debugln("serving", file, "from compiled untrusted")
|
||||
return
|
||||
}
|
||||
if s.serveFromAssets(file, config.DefaultTheme, modificationTime, w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
|
||||
func (s *staticsServer) serveFromAssetDir(file, theme string, w http.ResponseWriter, r *http.Request) bool {
|
||||
if s.assetDir == "" {
|
||||
return false
|
||||
}
|
||||
p := filepath.Join(s.assetDir, theme, filepath.FromSlash(file))
|
||||
if _, err := os.Stat(p); err != nil {
|
||||
return false
|
||||
}
|
||||
mtype := assets.MimeTypeForFile(file)
|
||||
if len(mtype) != 0 {
|
||||
w.Header().Set("Content-Type", mtype)
|
||||
}
|
||||
http.ServeFile(w, r, p)
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *staticsServer) serveFromAssets(file, theme string, modificationTime time.Time, w http.ResponseWriter, r *http.Request) bool {
|
||||
as, ok := s.assets[theme+"/"+file]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
as.Modified = modificationTime
|
||||
assets.Serve(w, r, as)
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *staticsServer) serveThemes(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -158,6 +189,13 @@ func (s *staticsServer) setTheme(theme string) {
|
||||
s.mut.Unlock()
|
||||
}
|
||||
|
||||
func (s *staticsServer) setUntrusted(enabled bool) {
|
||||
s.mut.Lock()
|
||||
l.Infoln(`Feature flag "untrusted":`, enabled)
|
||||
s.untrusted = enabled
|
||||
s.mut.Unlock()
|
||||
}
|
||||
|
||||
func (s *staticsServer) String() string {
|
||||
return fmt.Sprintf("staticsServer@%p", s)
|
||||
}
|
||||
|
||||
@@ -114,6 +114,10 @@ func (c *mockedConfig) RemoveFolder(id string) (config.Waiter, error) {
|
||||
return noopWaiter{}, nil
|
||||
}
|
||||
|
||||
func (c *mockedConfig) FolderPasswords(device protocol.DeviceID) map[string]string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *mockedConfig) Device(id protocol.DeviceID) (config.DeviceConfiguration, bool) {
|
||||
return config.DeviceConfiguration{}, false
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ func (m *mockedModel) IndexUpdate(deviceID protocol.DeviceID, folder string, fil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mockedModel) Request(deviceID protocol.DeviceID, folder, name string, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (protocol.RequestResponse, error) {
|
||||
func (m *mockedModel) Request(deviceID protocol.DeviceID, folder, name string, blockNo, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (protocol.RequestResponse, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -419,6 +419,9 @@ nextPendingDevice:
|
||||
}
|
||||
}
|
||||
}
|
||||
if cfg.Options.FeatureFlags == nil {
|
||||
cfg.Options.FeatureFlags = []string{}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -432,6 +435,22 @@ func (cfg *Configuration) DeviceMap() map[protocol.DeviceID]DeviceConfiguration
|
||||
return m
|
||||
}
|
||||
|
||||
// FolderPasswords returns the folder passwords set for this device, for
|
||||
// folders that have an encryption password set.
|
||||
func (cfg Configuration) FolderPasswords(device protocol.DeviceID) map[string]string {
|
||||
res := make(map[string]string, len(cfg.Folders))
|
||||
nextFolder:
|
||||
for _, folder := range cfg.Folders {
|
||||
for _, dev := range folder.Devices {
|
||||
if dev.DeviceID == device && dev.EncryptionPassword != "" {
|
||||
res[folder.ID] = dev.EncryptionPassword
|
||||
continue nextFolder
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func ensureDevicePresent(devices []FolderDeviceConfiguration, myID protocol.DeviceID) []FolderDeviceConfiguration {
|
||||
for _, device := range devices {
|
||||
if device.DeviceID.Equals(myID) {
|
||||
|
||||
@@ -77,6 +77,7 @@ func TestDefaultValues(t *testing.T) {
|
||||
StunKeepaliveMinS: 20,
|
||||
RawStunServers: []string{"default"},
|
||||
AnnounceLANAddresses: true,
|
||||
FeatureFlags: []string{},
|
||||
}
|
||||
|
||||
cfg := New(device1)
|
||||
@@ -225,6 +226,7 @@ func TestOverriddenValues(t *testing.T) {
|
||||
StunKeepaliveStartS: 9000,
|
||||
StunKeepaliveMinS: 900,
|
||||
RawStunServers: []string{"foo"},
|
||||
FeatureFlags: []string{"feature"},
|
||||
}
|
||||
|
||||
os.Unsetenv("STNOUPGRADE")
|
||||
|
||||
@@ -42,6 +42,7 @@ type DeviceConfiguration struct {
|
||||
IgnoredFolders []ObservedFolder `protobuf:"bytes,14,rep,name=ignored_folders,json=ignoredFolders,proto3" json:"ignoredFolders" xml:"ignoredFolder"`
|
||||
PendingFolders []ObservedFolder `protobuf:"bytes,15,rep,name=pending_folders,json=pendingFolders,proto3" json:"pendingFolders" xml:"pendingFolder"`
|
||||
MaxRequestKiB int `protobuf:"varint,16,opt,name=max_request_kib,json=maxRequestKib,proto3,casttype=int" json:"maxRequestKiB" xml:"maxRequestKiB"`
|
||||
Untrusted bool `protobuf:"varint,17,opt,name=untrusted,proto3" json:"untrusted" xml:"untrusted"`
|
||||
}
|
||||
|
||||
func (m *DeviceConfiguration) Reset() { *m = DeviceConfiguration{} }
|
||||
@@ -86,64 +87,66 @@ func init() {
|
||||
}
|
||||
|
||||
var fileDescriptor_744b782bd13071dd = []byte{
|
||||
// 902 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x55, 0x31, 0x6f, 0xdb, 0x46,
|
||||
0x18, 0x15, 0xeb, 0xc4, 0xb6, 0xce, 0x96, 0x65, 0xd3, 0x88, 0xc3, 0x18, 0x88, 0x4e, 0x60, 0x35,
|
||||
0x28, 0x68, 0x2a, 0x17, 0x6e, 0x27, 0xa3, 0x1d, 0xca, 0x04, 0x45, 0x03, 0xa3, 0x49, 0x7b, 0xdd,
|
||||
0xbc, 0xb0, 0x24, 0xef, 0xac, 0x1c, 0x2c, 0xf2, 0x58, 0xf2, 0xa4, 0x48, 0x40, 0x87, 0x8e, 0x1d,
|
||||
0x3a, 0x14, 0x59, 0xbb, 0x14, 0x1d, 0x3a, 0xf4, 0x97, 0x18, 0xe8, 0x60, 0x8d, 0x45, 0x87, 0x03,
|
||||
0x62, 0x6f, 0x1c, 0x39, 0x66, 0x2a, 0x78, 0x47, 0x51, 0x24, 0x1d, 0x17, 0x06, 0xba, 0xdd, 0xbd,
|
||||
0xf7, 0xee, 0xbd, 0xe3, 0xd3, 0x7d, 0x10, 0xe8, 0x8d, 0xa8, 0x7b, 0xe0, 0xb1, 0xe0, 0x94, 0x0e,
|
||||
0x0f, 0x30, 0x99, 0x50, 0x8f, 0xa8, 0xcd, 0x38, 0x72, 0x38, 0x65, 0xc1, 0x20, 0x8c, 0x18, 0x67,
|
||||
0xfa, 0xaa, 0x02, 0xf7, 0xf7, 0x32, 0xb5, 0x84, 0x3c, 0x36, 0x3a, 0x70, 0x49, 0xa8, 0xf8, 0xfd,
|
||||
0x07, 0x25, 0x17, 0xe6, 0xc6, 0x24, 0x9a, 0x10, 0x9c, 0x53, 0x4d, 0x32, 0xe5, 0x6a, 0x69, 0xfe,
|
||||
0xb5, 0x05, 0x76, 0x9f, 0xca, 0x8c, 0x27, 0xe5, 0x0c, 0xfd, 0x4f, 0x0d, 0x34, 0x55, 0xb6, 0x4d,
|
||||
0xb1, 0xa1, 0x75, 0xb5, 0xfe, 0xa6, 0xf5, 0xb3, 0x76, 0x2e, 0x60, 0xe3, 0x1f, 0x01, 0x3f, 0x19,
|
||||
0x52, 0xfe, 0x72, 0xec, 0x0e, 0x3c, 0xe6, 0x1f, 0xc4, 0xb3, 0xc0, 0xe3, 0x2f, 0x69, 0x30, 0x2c,
|
||||
0xad, 0xca, 0x37, 0x1a, 0x28, 0xf7, 0x67, 0x4f, 0x2f, 0x05, 0x5c, 0x5f, 0xac, 0x13, 0x01, 0xd7,
|
||||
0x71, 0xbe, 0x4e, 0x05, 0x6c, 0x4d, 0xfd, 0xd1, 0x91, 0x49, 0xf1, 0x63, 0x87, 0xf3, 0xc8, 0x4c,
|
||||
0x2e, 0x7a, 0x6b, 0xf9, 0x3a, 0xbd, 0xe8, 0x15, 0xba, 0x9f, 0xe6, 0x3d, 0xed, 0xf5, 0xbc, 0x57,
|
||||
0x78, 0xa0, 0x05, 0x83, 0xf5, 0xaf, 0xc1, 0x9d, 0xc0, 0xf1, 0x89, 0xf1, 0x5e, 0x57, 0xeb, 0x37,
|
||||
0xad, 0x4f, 0x13, 0x01, 0xe5, 0x3e, 0x15, 0xf0, 0x81, 0x74, 0xce, 0x36, 0xd2, 0xef, 0x31, 0xf3,
|
||||
0x29, 0x27, 0x7e, 0xc8, 0x67, 0x59, 0xca, 0xee, 0x3b, 0x70, 0x24, 0x4f, 0xea, 0x53, 0xd0, 0x74,
|
||||
0x30, 0x8e, 0x48, 0x1c, 0x93, 0xd8, 0x58, 0xe9, 0xae, 0xf4, 0x9b, 0xd6, 0x49, 0x22, 0xe0, 0x12,
|
||||
0x4c, 0x05, 0x7c, 0x24, 0xbd, 0x73, 0xa4, 0xe4, 0xdc, 0xc5, 0xe4, 0xd4, 0x19, 0x8f, 0xf8, 0x91,
|
||||
0x89, 0x67, 0x81, 0xe3, 0x53, 0x2f, 0xcb, 0xda, 0xb9, 0xa6, 0x7b, 0x7b, 0xd1, 0x5b, 0xcb, 0x05,
|
||||
0x68, 0xe9, 0xab, 0x4f, 0xc0, 0x86, 0xc7, 0xfc, 0x30, 0xdb, 0x51, 0x16, 0x18, 0x77, 0xba, 0x5a,
|
||||
0x7f, 0xeb, 0xf0, 0xde, 0xa0, 0xa8, 0xf3, 0xc9, 0x92, 0xb4, 0x3e, 0x4b, 0x04, 0x2c, 0xab, 0x53,
|
||||
0x01, 0xf7, 0xe4, 0xa5, 0x4a, 0x58, 0xd1, 0xe9, 0x76, 0x1d, 0x44, 0xe5, 0xa3, 0x3a, 0x01, 0x4d,
|
||||
0x8f, 0x44, 0xdc, 0x96, 0x45, 0xde, 0x95, 0x45, 0x7e, 0x99, 0xfd, 0x4c, 0x19, 0xf8, 0x5c, 0x95,
|
||||
0xf9, 0x50, 0x79, 0xe7, 0xc0, 0x3b, 0x0a, 0xbd, 0x7f, 0x03, 0x87, 0x0a, 0x17, 0xfd, 0x04, 0x00,
|
||||
0x1a, 0xf0, 0x88, 0xe1, 0xb1, 0x47, 0x22, 0x63, 0xb5, 0xab, 0xf5, 0xd7, 0xad, 0xa3, 0x44, 0xc0,
|
||||
0x12, 0x9a, 0x0a, 0x78, 0x4f, 0x3d, 0x88, 0x02, 0x2a, 0x3e, 0xa2, 0x5d, 0xc3, 0x50, 0xe9, 0x9c,
|
||||
0xfe, 0xbb, 0x06, 0xf6, 0xe3, 0x33, 0x1a, 0xda, 0x0b, 0x2c, 0x7b, 0xc9, 0x76, 0x44, 0x7c, 0x36,
|
||||
0x71, 0x46, 0xb1, 0xb1, 0x26, 0xc3, 0x70, 0x22, 0xa0, 0x91, 0xa9, 0x9e, 0x95, 0x44, 0x28, 0xd7,
|
||||
0xa4, 0x02, 0xbe, 0x2f, 0xa3, 0x6f, 0x12, 0x14, 0x17, 0x79, 0xf8, 0x9f, 0x0a, 0x74, 0x63, 0x82,
|
||||
0xfe, 0x87, 0x06, 0x5a, 0xc5, 0x9d, 0xb1, 0xed, 0xce, 0x8c, 0x75, 0x39, 0x5c, 0x3f, 0xfe, 0xaf,
|
||||
0xe1, 0x4a, 0x04, 0xdc, 0x5c, 0xba, 0x5a, 0xb3, 0x54, 0xc0, 0xfb, 0xd5, 0x0e, 0xb1, 0x35, 0x2b,
|
||||
0x2e, 0xbf, 0x73, 0x0d, 0xcd, 0x86, 0x0b, 0x55, 0x1c, 0xf4, 0x43, 0xb0, 0x1a, 0x3a, 0xe3, 0x98,
|
||||
0x60, 0xa3, 0x29, 0x8b, 0xdb, 0x4f, 0x04, 0xcc, 0x91, 0x54, 0xc0, 0x4d, 0xe9, 0xae, 0xb6, 0x26,
|
||||
0xca, 0x71, 0xfd, 0x07, 0xb0, 0xed, 0x8c, 0x46, 0xec, 0x15, 0xc1, 0x76, 0x40, 0xf8, 0x2b, 0x16,
|
||||
0x9d, 0xc5, 0x06, 0x90, 0xd3, 0xf3, 0x4d, 0x22, 0x60, 0x3b, 0xe7, 0x9e, 0xe7, 0x54, 0x2a, 0x60,
|
||||
0x47, 0xcd, 0x50, 0x05, 0xaf, 0xbe, 0x29, 0xe3, 0x26, 0x12, 0xd5, 0xed, 0xf4, 0xef, 0xc0, 0xae,
|
||||
0x33, 0xe6, 0xcc, 0x76, 0x3c, 0x8f, 0x84, 0xdc, 0x3e, 0x65, 0x23, 0x4c, 0xa2, 0xd8, 0xd8, 0x90,
|
||||
0xd7, 0xff, 0x28, 0x11, 0x70, 0x27, 0xa3, 0x3f, 0x97, 0xec, 0x17, 0x8a, 0x2c, 0x7a, 0xba, 0xc6,
|
||||
0x98, 0xe8, 0xba, 0x5a, 0x7f, 0x01, 0x5a, 0xbe, 0x33, 0xb5, 0x63, 0x12, 0x60, 0xfb, 0xcc, 0x0d,
|
||||
0x63, 0x63, 0xb3, 0xab, 0xf5, 0xef, 0x5a, 0x1f, 0x64, 0x73, 0xe8, 0x3b, 0xd3, 0x6f, 0x49, 0x80,
|
||||
0x8f, 0xdd, 0x30, 0x73, 0xdd, 0x91, 0xae, 0x25, 0xcc, 0x7c, 0x2b, 0xe0, 0x0a, 0x0d, 0x38, 0x2a,
|
||||
0x0b, 0x17, 0x86, 0x11, 0xf1, 0x26, 0xca, 0xb0, 0x55, 0x31, 0x44, 0xc4, 0x9b, 0xd4, 0x0d, 0x17,
|
||||
0x58, 0xc5, 0x70, 0x01, 0xea, 0x01, 0x68, 0xd3, 0x61, 0xc0, 0x22, 0x82, 0x8b, 0xef, 0xdf, 0xea,
|
||||
0xae, 0xf4, 0x37, 0x0e, 0xf7, 0x06, 0xea, 0xbf, 0x60, 0xf0, 0x22, 0xff, 0x2f, 0x50, 0xdf, 0x64,
|
||||
0x7d, 0x98, 0x3d, 0xbb, 0x44, 0xc0, 0xad, 0xfc, 0xd8, 0xb2, 0x98, 0x5d, 0xf5, 0x80, 0xca, 0xb0,
|
||||
0x89, 0x6a, 0xb2, 0x2c, 0x2f, 0x24, 0x01, 0xa6, 0xc1, 0xb0, 0xc8, 0x6b, 0xdf, 0x2e, 0x2f, 0x3f,
|
||||
0x56, 0xcf, 0xab, 0xc0, 0x26, 0xaa, 0xc9, 0xf4, 0x5f, 0x35, 0xd0, 0x56, 0x8d, 0x7d, 0x3f, 0x26,
|
||||
0x31, 0xb7, 0xcf, 0xa8, 0x6b, 0x6c, 0xcb, 0xce, 0xe2, 0x4b, 0x01, 0x5b, 0x5f, 0x65, 0x55, 0x48,
|
||||
0xe6, 0x98, 0x5a, 0x89, 0x80, 0x2d, 0xbf, 0x0c, 0x14, 0x21, 0x15, 0x74, 0x51, 0x64, 0x72, 0xd1,
|
||||
0xab, 0xc9, 0xeb, 0xc0, 0xeb, 0x79, 0xaf, 0x9a, 0x80, 0x2a, 0xbc, 0x6b, 0x1d, 0x9f, 0xbf, 0xe9,
|
||||
0x34, 0xe6, 0x6f, 0x3a, 0x8d, 0xf3, 0xcb, 0x8e, 0x36, 0xbf, 0xec, 0x68, 0xbf, 0x5c, 0x75, 0x1a,
|
||||
0xbf, 0x5d, 0x75, 0xb4, 0xf9, 0x55, 0xa7, 0xf1, 0xf7, 0x55, 0xa7, 0x71, 0xf2, 0xe8, 0x16, 0xd3,
|
||||
0xad, 0x8a, 0x73, 0x57, 0xe5, 0x94, 0x7f, 0xfc, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xda, 0x35,
|
||||
0x78, 0xb9, 0x0f, 0x08, 0x00, 0x00,
|
||||
// 930 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x55, 0x3d, 0x6f, 0xdb, 0x46,
|
||||
0x00, 0x15, 0xeb, 0xc4, 0xb6, 0xce, 0x96, 0x65, 0xd3, 0x88, 0xc3, 0x18, 0x88, 0x8e, 0x60, 0x35,
|
||||
0x28, 0x68, 0x2a, 0x17, 0x6e, 0x27, 0xa3, 0x2d, 0x50, 0x26, 0x28, 0x1a, 0x18, 0x4d, 0xda, 0xeb,
|
||||
0xe6, 0x85, 0x25, 0x79, 0x67, 0xe5, 0x60, 0xf1, 0xa3, 0xe4, 0x51, 0x91, 0x80, 0x0e, 0x1d, 0x0b,
|
||||
0xb4, 0x43, 0x91, 0xb5, 0x4b, 0xd1, 0xa1, 0x43, 0x7f, 0x89, 0x37, 0x6b, 0x2c, 0x3a, 0x1c, 0x10,
|
||||
0x7b, 0xe3, 0xc8, 0x31, 0x53, 0xc1, 0x3b, 0x8a, 0x22, 0xe9, 0xb8, 0x08, 0x90, 0xed, 0xee, 0xbd,
|
||||
0x77, 0xef, 0x1d, 0x9f, 0xee, 0x74, 0xa0, 0x3f, 0xa6, 0xce, 0x81, 0x1b, 0xf8, 0xa7, 0x74, 0x74,
|
||||
0x80, 0xc9, 0x84, 0xba, 0x44, 0x4e, 0x92, 0xc8, 0x66, 0x34, 0xf0, 0x87, 0x61, 0x14, 0xb0, 0x40,
|
||||
0x5d, 0x95, 0xe0, 0xfe, 0x5e, 0xae, 0x16, 0x90, 0x1b, 0x8c, 0x0f, 0x1c, 0x12, 0x4a, 0x7e, 0xff,
|
||||
0x5e, 0xc5, 0x25, 0x70, 0x62, 0x12, 0x4d, 0x08, 0x2e, 0xa8, 0x36, 0x99, 0x32, 0x39, 0x34, 0x7e,
|
||||
0xe9, 0x82, 0xdd, 0xc7, 0x22, 0xe3, 0x51, 0x35, 0x43, 0xfd, 0x5b, 0x01, 0x6d, 0x99, 0x6d, 0x51,
|
||||
0xac, 0x29, 0xba, 0x32, 0xd8, 0x34, 0x7f, 0x55, 0xce, 0x39, 0x6c, 0xfd, 0xcb, 0xe1, 0x27, 0x23,
|
||||
0xca, 0x9e, 0x27, 0xce, 0xd0, 0x0d, 0xbc, 0x83, 0x78, 0xe6, 0xbb, 0xec, 0x39, 0xf5, 0x47, 0x95,
|
||||
0x51, 0x75, 0x47, 0x43, 0xe9, 0xfe, 0xe4, 0xf1, 0x25, 0x87, 0xeb, 0x8b, 0x71, 0xca, 0xe1, 0x3a,
|
||||
0x2e, 0xc6, 0x19, 0x87, 0x9d, 0xa9, 0x37, 0x3e, 0x32, 0x28, 0x7e, 0x68, 0x33, 0x16, 0x19, 0xe9,
|
||||
0x45, 0x7f, 0xad, 0x18, 0x67, 0x17, 0xfd, 0x52, 0xf7, 0xf3, 0xbc, 0xaf, 0xbc, 0x9c, 0xf7, 0x4b,
|
||||
0x0f, 0xb4, 0x60, 0xb0, 0xfa, 0x0d, 0xb8, 0xe5, 0xdb, 0x1e, 0xd1, 0xde, 0xd3, 0x95, 0x41, 0xdb,
|
||||
0xfc, 0x34, 0xe5, 0x50, 0xcc, 0x33, 0x0e, 0xef, 0x09, 0xe7, 0x7c, 0x22, 0xfc, 0x1e, 0x06, 0x1e,
|
||||
0x65, 0xc4, 0x0b, 0xd9, 0x2c, 0x4f, 0xd9, 0x7d, 0x03, 0x8e, 0xc4, 0x4a, 0x75, 0x0a, 0xda, 0x36,
|
||||
0xc6, 0x11, 0x89, 0x63, 0x12, 0x6b, 0x2b, 0xfa, 0xca, 0xa0, 0x6d, 0x9e, 0xa4, 0x1c, 0x2e, 0xc1,
|
||||
0x8c, 0xc3, 0x07, 0xc2, 0xbb, 0x40, 0x2a, 0xce, 0x3a, 0x26, 0xa7, 0x76, 0x32, 0x66, 0x47, 0x06,
|
||||
0x9e, 0xf9, 0xb6, 0x47, 0xdd, 0x3c, 0x6b, 0xe7, 0x9a, 0xee, 0xf5, 0x45, 0x7f, 0xad, 0x10, 0xa0,
|
||||
0xa5, 0xaf, 0x3a, 0x01, 0x1b, 0x6e, 0xe0, 0x85, 0xf9, 0x8c, 0x06, 0xbe, 0x76, 0x4b, 0x57, 0x06,
|
||||
0x5b, 0x87, 0x77, 0x86, 0x65, 0x9d, 0x8f, 0x96, 0xa4, 0xf9, 0x59, 0xca, 0x61, 0x55, 0x9d, 0x71,
|
||||
0xb8, 0x27, 0x36, 0x55, 0xc1, 0xca, 0x4e, 0xb7, 0x9b, 0x20, 0xaa, 0x2e, 0x55, 0x09, 0x68, 0xbb,
|
||||
0x24, 0x62, 0x96, 0x28, 0xf2, 0xb6, 0x28, 0xf2, 0xab, 0xfc, 0x67, 0xca, 0xc1, 0xa7, 0xb2, 0xcc,
|
||||
0xfb, 0xd2, 0xbb, 0x00, 0xde, 0x50, 0xe8, 0xdd, 0x1b, 0x38, 0x54, 0xba, 0xa8, 0x27, 0x00, 0x50,
|
||||
0x9f, 0x45, 0x01, 0x4e, 0x5c, 0x12, 0x69, 0xab, 0xba, 0x32, 0x58, 0x37, 0x8f, 0x52, 0x0e, 0x2b,
|
||||
0x68, 0xc6, 0xe1, 0x1d, 0x79, 0x20, 0x4a, 0xa8, 0xfc, 0x88, 0x6e, 0x03, 0x43, 0x95, 0x75, 0xea,
|
||||
0x9f, 0x0a, 0xd8, 0x8f, 0xcf, 0x68, 0x68, 0x2d, 0xb0, 0xfc, 0x24, 0x5b, 0x11, 0xf1, 0x82, 0x89,
|
||||
0x3d, 0x8e, 0xb5, 0x35, 0x11, 0x86, 0x53, 0x0e, 0xb5, 0x5c, 0xf5, 0xa4, 0x22, 0x42, 0x85, 0x26,
|
||||
0xe3, 0xf0, 0x7d, 0x11, 0x7d, 0x93, 0xa0, 0xdc, 0xc8, 0xfd, 0xff, 0x55, 0xa0, 0x1b, 0x13, 0xd4,
|
||||
0xbf, 0x14, 0xd0, 0x29, 0xf7, 0x8c, 0x2d, 0x67, 0xa6, 0xad, 0x8b, 0xcb, 0xf5, 0xd3, 0x3b, 0x5d,
|
||||
0xae, 0x94, 0xc3, 0xcd, 0xa5, 0xab, 0x39, 0xcb, 0x38, 0xbc, 0x5b, 0xef, 0x10, 0x9b, 0xb3, 0x72,
|
||||
0xf3, 0x3b, 0xd7, 0xd0, 0xfc, 0x72, 0xa1, 0x9a, 0x83, 0x7a, 0x08, 0x56, 0x43, 0x3b, 0x89, 0x09,
|
||||
0xd6, 0xda, 0xa2, 0xb8, 0xfd, 0x94, 0xc3, 0x02, 0xc9, 0x38, 0xdc, 0x14, 0xee, 0x72, 0x6a, 0xa0,
|
||||
0x02, 0x57, 0x7f, 0x04, 0xdb, 0xf6, 0x78, 0x1c, 0xbc, 0x20, 0xd8, 0xf2, 0x09, 0x7b, 0x11, 0x44,
|
||||
0x67, 0xb1, 0x06, 0xc4, 0xed, 0xf9, 0x36, 0xe5, 0xb0, 0x5b, 0x70, 0x4f, 0x0b, 0x2a, 0xe3, 0xb0,
|
||||
0x27, 0xef, 0x50, 0x0d, 0xaf, 0x9f, 0x29, 0xed, 0x26, 0x12, 0x35, 0xed, 0xd4, 0xef, 0xc1, 0xae,
|
||||
0x9d, 0xb0, 0xc0, 0xb2, 0x5d, 0x97, 0x84, 0xcc, 0x3a, 0x0d, 0xc6, 0x98, 0x44, 0xb1, 0xb6, 0x21,
|
||||
0xb6, 0xff, 0x51, 0xca, 0xe1, 0x4e, 0x4e, 0x7f, 0x21, 0xd8, 0x2f, 0x25, 0x59, 0xf6, 0x74, 0x8d,
|
||||
0x31, 0xd0, 0x75, 0xb5, 0xfa, 0x0c, 0x74, 0x3c, 0x7b, 0x6a, 0xc5, 0xc4, 0xc7, 0xd6, 0x99, 0x13,
|
||||
0xc6, 0xda, 0xa6, 0xae, 0x0c, 0x6e, 0x9b, 0x1f, 0xe4, 0xf7, 0xd0, 0xb3, 0xa7, 0xdf, 0x11, 0x1f,
|
||||
0x1f, 0x3b, 0x61, 0xee, 0xba, 0x23, 0x5c, 0x2b, 0x98, 0xf1, 0x9a, 0xc3, 0x15, 0xea, 0x33, 0x54,
|
||||
0x15, 0x2e, 0x0c, 0x23, 0xe2, 0x4e, 0xa4, 0x61, 0xa7, 0x66, 0x88, 0x88, 0x3b, 0x69, 0x1a, 0x2e,
|
||||
0xb0, 0x9a, 0xe1, 0x02, 0x54, 0x7d, 0xd0, 0xa5, 0x23, 0x3f, 0x88, 0x08, 0x2e, 0xbf, 0x7f, 0x4b,
|
||||
0x5f, 0x19, 0x6c, 0x1c, 0xee, 0x0d, 0xe5, 0x5b, 0x30, 0x7c, 0x56, 0xbc, 0x05, 0xf2, 0x9b, 0xcc,
|
||||
0x0f, 0xf3, 0x63, 0x97, 0x72, 0xb8, 0x55, 0x2c, 0x5b, 0x16, 0xb3, 0x2b, 0x0f, 0x50, 0x15, 0x36,
|
||||
0x50, 0x43, 0x96, 0xe7, 0x85, 0xc4, 0xc7, 0xd4, 0x1f, 0x95, 0x79, 0xdd, 0xb7, 0xcb, 0x2b, 0x96,
|
||||
0x35, 0xf3, 0x6a, 0xb0, 0x81, 0x1a, 0x32, 0xf5, 0x77, 0x05, 0x74, 0x65, 0x63, 0x3f, 0x24, 0x24,
|
||||
0x66, 0xd6, 0x19, 0x75, 0xb4, 0x6d, 0xd1, 0x59, 0x7c, 0xc9, 0x61, 0xe7, 0xeb, 0xbc, 0x0a, 0xc1,
|
||||
0x1c, 0x53, 0x33, 0xe5, 0xb0, 0xe3, 0x55, 0x81, 0x32, 0xa4, 0x86, 0x2e, 0x8a, 0x4c, 0x2f, 0xfa,
|
||||
0x0d, 0x79, 0x13, 0x78, 0x39, 0xef, 0xd7, 0x13, 0x50, 0x8d, 0x77, 0xd4, 0xcf, 0x41, 0x3b, 0xf1,
|
||||
0x59, 0x94, 0xc4, 0x8c, 0x60, 0x6d, 0x47, 0x9c, 0x3b, 0x3d, 0x7f, 0x36, 0x4a, 0x30, 0xe3, 0xb0,
|
||||
0x2b, 0x76, 0x50, 0x22, 0x06, 0x5a, 0xb2, 0xe6, 0xf1, 0xf9, 0xab, 0x5e, 0x6b, 0xfe, 0xaa, 0xd7,
|
||||
0x3a, 0xbf, 0xec, 0x29, 0xf3, 0xcb, 0x9e, 0xf2, 0xdb, 0x55, 0xaf, 0xf5, 0xc7, 0x55, 0x4f, 0x99,
|
||||
0x5f, 0xf5, 0x5a, 0xff, 0x5c, 0xf5, 0x5a, 0x27, 0x0f, 0xde, 0xe2, 0xdf, 0x41, 0x16, 0xef, 0xac,
|
||||
0x8a, 0x7f, 0x89, 0x8f, 0xff, 0x0b, 0x00, 0x00, 0xff, 0xff, 0x73, 0xb5, 0x15, 0x0d, 0x4f, 0x08,
|
||||
0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *DeviceConfiguration) Marshal() (dAtA []byte, err error) {
|
||||
@@ -166,6 +169,18 @@ func (m *DeviceConfiguration) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.Untrusted {
|
||||
i--
|
||||
if m.Untrusted {
|
||||
dAtA[i] = 1
|
||||
} else {
|
||||
dAtA[i] = 0
|
||||
}
|
||||
i--
|
||||
dAtA[i] = 0x1
|
||||
i--
|
||||
dAtA[i] = 0x88
|
||||
}
|
||||
if m.MaxRequestKiB != 0 {
|
||||
i = encodeVarintDeviceconfiguration(dAtA, i, uint64(m.MaxRequestKiB))
|
||||
i--
|
||||
@@ -388,6 +403,9 @@ func (m *DeviceConfiguration) ProtoSize() (n int) {
|
||||
if m.MaxRequestKiB != 0 {
|
||||
n += 2 + sovDeviceconfiguration(uint64(m.MaxRequestKiB))
|
||||
}
|
||||
if m.Untrusted {
|
||||
n += 3
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
@@ -844,6 +862,26 @@ func (m *DeviceConfiguration) Unmarshal(dAtA []byte) error {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 17:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Untrusted", wireType)
|
||||
}
|
||||
var v int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowDeviceconfiguration
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
v |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
m.Untrusted = bool(v != 0)
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipDeviceconfiguration(dAtA[iNdEx:])
|
||||
|
||||
@@ -236,13 +236,18 @@ func (f FolderConfiguration) RequiresRestartOnly() FolderConfiguration {
|
||||
return copy
|
||||
}
|
||||
|
||||
func (f *FolderConfiguration) SharedWith(device protocol.DeviceID) bool {
|
||||
func (f *FolderConfiguration) Device(device protocol.DeviceID) (FolderDeviceConfiguration, bool) {
|
||||
for _, dev := range f.Devices {
|
||||
if dev.DeviceID == device {
|
||||
return true
|
||||
return dev, true
|
||||
}
|
||||
}
|
||||
return false
|
||||
return FolderDeviceConfiguration{}, false
|
||||
}
|
||||
|
||||
func (f *FolderConfiguration) SharedWith(device protocol.DeviceID) bool {
|
||||
_, ok := f.Device(device)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (f *FolderConfiguration) CheckAvailableSpace(req uint64) error {
|
||||
|
||||
@@ -27,8 +27,9 @@ var _ = math.Inf
|
||||
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
type FolderDeviceConfiguration struct {
|
||||
DeviceID github_com_syncthing_syncthing_lib_protocol.DeviceID `protobuf:"bytes,1,opt,name=device_id,json=deviceId,proto3,customtype=github.com/syncthing/syncthing/lib/protocol.DeviceID" json:"deviceID" xml:"id,attr"`
|
||||
IntroducedBy github_com_syncthing_syncthing_lib_protocol.DeviceID `protobuf:"bytes,2,opt,name=introduced_by,json=introducedBy,proto3,customtype=github.com/syncthing/syncthing/lib/protocol.DeviceID" json:"introducedBy" xml:"introducedBy,attr"`
|
||||
DeviceID github_com_syncthing_syncthing_lib_protocol.DeviceID `protobuf:"bytes,1,opt,name=device_id,json=deviceId,proto3,customtype=github.com/syncthing/syncthing/lib/protocol.DeviceID" json:"deviceID" xml:"id,attr"`
|
||||
IntroducedBy github_com_syncthing_syncthing_lib_protocol.DeviceID `protobuf:"bytes,2,opt,name=introduced_by,json=introducedBy,proto3,customtype=github.com/syncthing/syncthing/lib/protocol.DeviceID" json:"introducedBy" xml:"introducedBy,attr"`
|
||||
EncryptionPassword string `protobuf:"bytes,3,opt,name=encryption_password,json=encryptionPassword,proto3" json:"encryptionPassword" xml:"encryptionPassword"`
|
||||
}
|
||||
|
||||
func (m *FolderDeviceConfiguration) Reset() { *m = FolderDeviceConfiguration{} }
|
||||
@@ -148,131 +149,134 @@ func init() {
|
||||
}
|
||||
|
||||
var fileDescriptor_44a9785876ed3afa = []byte{
|
||||
// 1983 bytes of a gzipped FileDescriptorProto
|
||||
// 2018 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x58, 0xcd, 0x6f, 0x1c, 0x49,
|
||||
0x15, 0x77, 0x3b, 0x5f, 0x76, 0xf9, 0xbb, 0x12, 0x27, 0x15, 0x67, 0xd7, 0xe5, 0x6d, 0x86, 0xc5,
|
||||
0x15, 0x77, 0x3b, 0x5f, 0x76, 0xf9, 0xbb, 0x1c, 0x27, 0x15, 0x67, 0xd7, 0xe5, 0x6d, 0x86, 0xc5,
|
||||
0xbb, 0xda, 0x38, 0x89, 0x17, 0x71, 0x88, 0x76, 0x17, 0x76, 0xe2, 0xb5, 0x08, 0x21, 0x9b, 0x51,
|
||||
0x3b, 0x10, 0x11, 0x90, 0x9a, 0x9e, 0xee, 0x9a, 0x99, 0x5a, 0xf7, 0x17, 0x55, 0x3d, 0xb1, 0x27,
|
||||
0xa7, 0x70, 0x41, 0x20, 0xf6, 0x80, 0xcc, 0x81, 0x2b, 0x12, 0x08, 0xc1, 0xfe, 0x03, 0x48, 0xfc,
|
||||
0x05, 0xb9, 0x20, 0xcf, 0x11, 0x71, 0x28, 0x69, 0x9d, 0xdb, 0xdc, 0xe8, 0x63, 0x4e, 0xa8, 0xaa,
|
||||
0xba, 0x7b, 0xba, 0x7b, 0x66, 0x11, 0xd2, 0xde, 0xa6, 0x7e, 0xbf, 0x5f, 0xbd, 0xf7, 0xfa, 0xf5,
|
||||
0x7b, 0xaf, 0xaa, 0x07, 0x34, 0x7c, 0xda, 0xbe, 0xe5, 0x46, 0x61, 0x87, 0x76, 0x6f, 0x75, 0x22,
|
||||
0xdf, 0x23, 0x4c, 0x2f, 0xfa, 0xcc, 0x49, 0x68, 0x14, 0xee, 0xc4, 0x2c, 0x4a, 0x22, 0x78, 0x51,
|
||||
0x83, 0x1b, 0x37, 0x26, 0xd4, 0xc9, 0x20, 0x26, 0x5a, 0xb4, 0xb1, 0x5e, 0x22, 0x39, 0x7d, 0x9e,
|
||||
0xc3, 0x1b, 0x25, 0x38, 0xee, 0xfb, 0x7e, 0xc4, 0x3c, 0xc2, 0x32, 0x6e, 0xbb, 0xc4, 0x3d, 0x23,
|
||||
0x8c, 0xd3, 0x28, 0xa4, 0x61, 0x77, 0x4a, 0x04, 0x1b, 0xb8, 0xa4, 0x6c, 0xfb, 0x91, 0x7b, 0x58,
|
||||
0x37, 0x05, 0xa5, 0xa0, 0xc3, 0x6f, 0xc9, 0x80, 0x78, 0x86, 0xbd, 0x91, 0x61, 0x6e, 0x14, 0x0f,
|
||||
0x98, 0x13, 0x76, 0x49, 0x40, 0x92, 0x5e, 0xe4, 0x65, 0xec, 0x3c, 0x39, 0x4e, 0xf4, 0x4f, 0xf3,
|
||||
0x3f, 0xb3, 0xe0, 0xfa, 0xbe, 0x7a, 0x9e, 0x3d, 0xf2, 0x8c, 0xba, 0xe4, 0x5e, 0x39, 0x02, 0xf8,
|
||||
0x85, 0x01, 0xe6, 0x3d, 0x85, 0xdb, 0xd4, 0x43, 0xc6, 0x96, 0xb1, 0xbd, 0xd8, 0xfc, 0xdc, 0x78,
|
||||
0x29, 0xf0, 0xcc, 0xbf, 0x05, 0xfe, 0x76, 0x97, 0x26, 0xbd, 0x7e, 0x7b, 0xc7, 0x8d, 0x82, 0x5b,
|
||||
0x7c, 0x10, 0xba, 0x49, 0x8f, 0x86, 0xdd, 0xd2, 0x2f, 0x19, 0x82, 0x72, 0xe2, 0x46, 0xfe, 0x8e,
|
||||
0xb6, 0x7e, 0x7f, 0xef, 0x4c, 0xe0, 0xb9, 0xfc, 0xf7, 0x48, 0xe0, 0x39, 0x2f, 0xfb, 0x9d, 0x0a,
|
||||
0xbc, 0x74, 0x1c, 0xf8, 0x77, 0x4d, 0xea, 0xbd, 0xe7, 0x24, 0x09, 0x33, 0x47, 0xa7, 0x8d, 0x4b,
|
||||
0xd9, 0xef, 0xf4, 0xb4, 0x51, 0xe8, 0x7e, 0x3d, 0x6c, 0x18, 0x27, 0xc3, 0x46, 0x61, 0xc3, 0xca,
|
||||
0x19, 0x0f, 0xfe, 0xc5, 0x00, 0x4b, 0x34, 0x4c, 0x58, 0xe4, 0xf5, 0x5d, 0xe2, 0xd9, 0xed, 0x01,
|
||||
0x9a, 0x55, 0x01, 0xbf, 0xf8, 0x5a, 0x01, 0x8f, 0x04, 0x5e, 0x1c, 0x5b, 0x6d, 0x0e, 0x52, 0x81,
|
||||
0xaf, 0xe9, 0x40, 0x4b, 0x60, 0x11, 0xf2, 0xda, 0x04, 0x2a, 0x03, 0xb6, 0x2a, 0x16, 0xcc, 0x57,
|
||||
0x18, 0x5c, 0xd6, 0x39, 0xaf, 0x66, 0xfb, 0x23, 0x30, 0x9b, 0x65, 0x79, 0xbe, 0xb9, 0x73, 0x26,
|
||||
0xf0, 0xac, 0xf2, 0x3e, 0x4b, 0xbd, 0xff, 0x95, 0x9c, 0x93, 0x61, 0x63, 0xf6, 0xfe, 0x9e, 0x35,
|
||||
0x4b, 0x3d, 0xf8, 0x23, 0x70, 0xc1, 0x77, 0xda, 0xc4, 0x57, 0xcf, 0x3d, 0xdf, 0xfc, 0xee, 0x48,
|
||||
0x60, 0x0d, 0xa4, 0x02, 0x6f, 0xa9, 0xfd, 0x6a, 0xa5, 0x4d, 0x6c, 0x31, 0xc2, 0x13, 0x87, 0x25,
|
||||
0x77, 0xcd, 0x8e, 0xe3, 0x73, 0x22, 0x4d, 0x82, 0x31, 0xfd, 0x62, 0xd8, 0x98, 0xb1, 0xf4, 0x66,
|
||||
0xd8, 0x05, 0x2b, 0x1d, 0xea, 0x13, 0x3e, 0xe0, 0x09, 0x09, 0x6c, 0x59, 0x65, 0xe8, 0xdc, 0x96,
|
||||
0xb1, 0xbd, 0xbc, 0x0b, 0x77, 0x3a, 0x7c, 0x67, 0xbf, 0xa0, 0x1e, 0x0f, 0x62, 0xd2, 0x7c, 0x77,
|
||||
0x24, 0xf0, 0x72, 0xa7, 0x82, 0xa5, 0x02, 0x5f, 0x51, 0xde, 0xab, 0xb0, 0x69, 0xd5, 0x74, 0xf0,
|
||||
0x03, 0x70, 0x3e, 0x76, 0x92, 0x1e, 0x3a, 0xaf, 0xc2, 0xdf, 0x1e, 0x09, 0xac, 0xd6, 0xa9, 0xc0,
|
||||
0x2b, 0x6a, 0xbf, 0x5c, 0x14, 0xcf, 0x3f, 0x5f, 0xac, 0x2c, 0xa5, 0x82, 0x2d, 0x70, 0x5e, 0xc5,
|
||||
0x76, 0x21, 0x8b, 0x4d, 0xb7, 0xcc, 0x8e, 0x4e, 0xb4, 0x8a, 0x4d, 0x59, 0x4c, 0x74, 0x44, 0xda,
|
||||
0xa2, 0x5c, 0x8c, 0x2d, 0x16, 0x2b, 0x4b, 0xa9, 0xe0, 0xcf, 0xc0, 0x25, 0x5d, 0x5c, 0x1c, 0x5d,
|
||||
0xdc, 0x3a, 0xb7, 0xbd, 0xb0, 0xfb, 0x56, 0xd5, 0xe8, 0x94, 0x8e, 0x69, 0x62, 0x59, 0x6b, 0x23,
|
||||
0x81, 0xf3, 0x9d, 0xa9, 0xc0, 0x8b, 0xca, 0x95, 0x5e, 0x9b, 0x56, 0x4e, 0xc0, 0xdf, 0x1b, 0x60,
|
||||
0x8d, 0x11, 0xee, 0x3a, 0xa1, 0x4d, 0xc3, 0x84, 0xb0, 0x67, 0x8e, 0x6f, 0x73, 0x74, 0x69, 0xcb,
|
||||
0xd8, 0xbe, 0xd0, 0xec, 0x8e, 0x04, 0x5e, 0xd1, 0xe4, 0xfd, 0x8c, 0x3b, 0x48, 0x05, 0x7e, 0x47,
|
||||
0x59, 0xaa, 0xe1, 0xd9, 0xeb, 0xf4, 0x48, 0xc7, 0xe9, 0xfb, 0xc9, 0x5d, 0xf3, 0xfd, 0xef, 0xdc,
|
||||
0xbe, 0x6d, 0xbe, 0x16, 0xf8, 0x1c, 0x0d, 0x93, 0xd1, 0x69, 0xe3, 0xca, 0x34, 0xf9, 0xeb, 0xd3,
|
||||
0xc6, 0x79, 0xa9, 0xb3, 0xea, 0x4e, 0xe0, 0x3f, 0x0c, 0x00, 0x3b, 0xdc, 0x3e, 0x72, 0x12, 0xb7,
|
||||
0x47, 0x98, 0x4d, 0x42, 0xa7, 0xed, 0x13, 0x0f, 0xcd, 0x6d, 0x19, 0xdb, 0x73, 0xcd, 0xdf, 0x1a,
|
||||
0x67, 0x02, 0xaf, 0xee, 0x1f, 0x3c, 0xd1, 0xec, 0x27, 0x9a, 0x1c, 0x09, 0xbc, 0xda, 0xe1, 0x55,
|
||||
0x2c, 0x15, 0xf8, 0x5d, 0xfd, 0xce, 0x6b, 0x44, 0x3d, 0xda, 0x84, 0xf5, 0x55, 0xed, 0xad, 0x4f,
|
||||
0x15, 0xca, 0x38, 0xa5, 0xe2, 0x64, 0xd8, 0x98, 0x70, 0x6b, 0x4d, 0x38, 0x85, 0x7f, 0xaf, 0x06,
|
||||
0xef, 0x11, 0xdf, 0x19, 0xd8, 0x1c, 0xcd, 0xab, 0x9c, 0xfe, 0x46, 0x06, 0xbf, 0x52, 0x58, 0xd9,
|
||||
0x93, 0xe4, 0x81, 0xcc, 0x73, 0x61, 0x46, 0x43, 0xa9, 0xc0, 0xdf, 0xaa, 0x86, 0xae, 0xf1, 0x7a,
|
||||
0xe4, 0x77, 0x2a, 0x59, 0x9e, 0x26, 0x7e, 0x7d, 0xda, 0x98, 0xbd, 0x73, 0xfb, 0x64, 0xd8, 0xa8,
|
||||
0x7b, 0xb5, 0xea, 0x3e, 0xe1, 0xcf, 0xc1, 0x22, 0xed, 0x86, 0x11, 0x23, 0x76, 0x4c, 0x58, 0xc0,
|
||||
0x11, 0x50, 0xf9, 0xfe, 0x70, 0x24, 0xf0, 0x82, 0xc6, 0x5b, 0x12, 0x4e, 0x05, 0xbe, 0xaa, 0xe7,
|
||||
0xc0, 0x18, 0x2b, 0xca, 0x77, 0xb5, 0x0e, 0x5a, 0xe5, 0xad, 0xf0, 0x97, 0x06, 0x58, 0x76, 0xfa,
|
||||
0x49, 0x64, 0x87, 0x11, 0x0b, 0x1c, 0x9f, 0x3e, 0x27, 0x68, 0x41, 0x39, 0x79, 0x3a, 0x12, 0x78,
|
||||
0x49, 0x32, 0x9f, 0xe6, 0x44, 0x91, 0x81, 0x0a, 0xfa, 0x55, 0x6f, 0x0e, 0x4e, 0xaa, 0xf2, 0xd7,
|
||||
0x66, 0x55, 0xed, 0xc2, 0xa7, 0x60, 0x29, 0xa0, 0xa1, 0xed, 0x51, 0x7e, 0x68, 0x77, 0x18, 0x21,
|
||||
0x68, 0x71, 0xcb, 0xd8, 0x5e, 0xd8, 0x5d, 0xcc, 0xdb, 0xea, 0x80, 0x3e, 0x27, 0xcd, 0xed, 0xac,
|
||||
0x83, 0x16, 0x02, 0x1a, 0xee, 0x51, 0x7e, 0xb8, 0xcf, 0x88, 0x8c, 0x68, 0x4d, 0x45, 0x54, 0xc2,
|
||||
0x4c, 0xab, 0xac, 0x80, 0x5d, 0x00, 0xc6, 0xe7, 0x28, 0x5a, 0x52, 0x86, 0x71, 0x6e, 0xf8, 0xc7,
|
||||
0x05, 0x53, 0xed, 0xd6, 0xb7, 0x33, 0x5f, 0xa5, 0xad, 0xa9, 0xc0, 0xab, 0xca, 0xd5, 0x18, 0x32,
|
||||
0xad, 0x12, 0x0f, 0x3f, 0x04, 0x97, 0xdc, 0x28, 0xa6, 0x84, 0x71, 0xb4, 0xac, 0x0a, 0xeb, 0x1b,
|
||||
0xb2, 0xdd, 0x33, 0xa8, 0x98, 0xd4, 0xd9, 0x3a, 0x2f, 0x11, 0x2b, 0x17, 0xc0, 0x7f, 0x1a, 0xe0,
|
||||
0xaa, 0x3c, 0xc1, 0x09, 0xb3, 0x03, 0xe7, 0xd8, 0x8e, 0x49, 0xe8, 0xd1, 0xb0, 0x6b, 0x1f, 0xd2,
|
||||
0x36, 0x5a, 0x51, 0xe6, 0xfe, 0x20, 0xeb, 0xf4, 0x72, 0x4b, 0x49, 0x1e, 0x3a, 0xc7, 0x2d, 0x2d,
|
||||
0x78, 0x40, 0x9b, 0x23, 0x81, 0x2f, 0xc7, 0x93, 0x70, 0x2a, 0xf0, 0x75, 0x3d, 0x1e, 0x27, 0xb9,
|
||||
0x52, 0x85, 0x4e, 0xdd, 0x3a, 0x1d, 0x3e, 0x19, 0x36, 0xa6, 0xf9, 0xb7, 0xa6, 0x68, 0xdb, 0x32,
|
||||
0x1d, 0x3d, 0x87, 0xf7, 0x64, 0x3a, 0x56, 0xc7, 0xe9, 0xc8, 0xa0, 0x22, 0x1d, 0xd9, 0x7a, 0x9c,
|
||||
0x8e, 0x0c, 0x80, 0x1f, 0x83, 0x0b, 0xea, 0x2e, 0x83, 0xd6, 0xd4, 0xd8, 0x5e, 0xcb, 0xdf, 0x98,
|
||||
0xf4, 0xff, 0x48, 0x12, 0x4d, 0x24, 0x8f, 0x31, 0xa5, 0x49, 0x05, 0x5e, 0x50, 0xd6, 0xd4, 0xca,
|
||||
0xb4, 0x34, 0x0a, 0x1f, 0x80, 0xa5, 0xac, 0x77, 0x3c, 0xe2, 0x93, 0x84, 0x20, 0xa8, 0xea, 0xfa,
|
||||
0x6d, 0x75, 0x72, 0x2b, 0x62, 0x4f, 0xe1, 0xa9, 0xc0, 0xb0, 0xd4, 0x3d, 0x1a, 0x34, 0xad, 0x8a,
|
||||
0x06, 0x1e, 0x03, 0xa4, 0x46, 0x72, 0xcc, 0xa2, 0x2e, 0x23, 0x9c, 0x97, 0x67, 0xf3, 0x65, 0xf5,
|
||||
0x7c, 0xf2, 0x58, 0x5d, 0x97, 0x9a, 0x56, 0x26, 0x29, 0x4f, 0xe8, 0x1b, 0xca, 0xc1, 0x54, 0xb6,
|
||||
0x78, 0xf6, 0xe9, 0x9b, 0xe1, 0x01, 0x58, 0xce, 0xea, 0x22, 0x76, 0xfa, 0x9c, 0xd8, 0x1c, 0x5d,
|
||||
0x51, 0xfe, 0x6e, 0xca, 0xe7, 0xd0, 0x4c, 0x4b, 0x12, 0x07, 0xc5, 0x73, 0x94, 0xc1, 0xc2, 0x7a,
|
||||
0x45, 0x0a, 0x09, 0x58, 0x92, 0x55, 0x26, 0x93, 0xea, 0x53, 0x37, 0xe1, 0x68, 0x5d, 0xd9, 0xfc,
|
||||
0x9e, 0xb4, 0x19, 0x38, 0xc7, 0xf7, 0x72, 0x3c, 0x15, 0x18, 0xeb, 0x06, 0x2b, 0x81, 0xa5, 0x66,
|
||||
0xbf, 0x79, 0x27, 0x77, 0x20, 0x87, 0xda, 0xcd, 0x3b, 0x56, 0x65, 0x37, 0xf4, 0xc0, 0x15, 0x8f,
|
||||
0x72, 0x39, 0x84, 0x6d, 0x1e, 0x3b, 0x8c, 0x13, 0x5b, 0x1d, 0xed, 0xe8, 0xaa, 0x7a, 0x13, 0xbb,
|
||||
0x23, 0x81, 0x61, 0xc6, 0x1f, 0x28, 0x5a, 0x5d, 0x1a, 0x52, 0x81, 0x91, 0x3e, 0x1a, 0x27, 0x28,
|
||||
0xd3, 0x9a, 0xa2, 0x2f, 0x7b, 0x49, 0x48, 0x10, 0xdb, 0x34, 0xf4, 0xc8, 0x31, 0xe1, 0xe8, 0xda,
|
||||
0x84, 0x97, 0xc7, 0x24, 0x88, 0xef, 0x6b, 0xb6, 0xee, 0xa5, 0x44, 0x8d, 0xbd, 0x94, 0x40, 0xb8,
|
||||
0x0b, 0x2e, 0xaa, 0x17, 0xe0, 0x21, 0xa4, 0xec, 0x6e, 0x8c, 0x04, 0xce, 0x90, 0xe2, 0x30, 0xd7,
|
||||
0x4b, 0xd3, 0xca, 0x70, 0x98, 0x80, 0x6b, 0x47, 0xc4, 0x39, 0xb4, 0x65, 0x55, 0xdb, 0x49, 0x8f,
|
||||
0x11, 0xde, 0x8b, 0x7c, 0xcf, 0x8e, 0xdd, 0x04, 0x5d, 0x57, 0x09, 0x97, 0x93, 0xfc, 0x8a, 0x94,
|
||||
0x7c, 0xdf, 0xe1, 0xbd, 0xc7, 0xb9, 0xa0, 0xe5, 0x26, 0xa9, 0xc0, 0x1b, 0xca, 0xe4, 0x34, 0xb2,
|
||||
0x78, 0xa9, 0x53, 0xb7, 0xc2, 0x7b, 0x60, 0x21, 0x70, 0xd8, 0x21, 0x61, 0x76, 0xe8, 0x04, 0x04,
|
||||
0x6d, 0xa8, 0x6b, 0x93, 0x29, 0xc7, 0x99, 0x86, 0x3f, 0x75, 0x02, 0x52, 0x8c, 0xb3, 0x31, 0x64,
|
||||
0x5a, 0x25, 0x1e, 0x0e, 0xc0, 0x86, 0xfc, 0x48, 0xb0, 0xa3, 0xa3, 0x90, 0x30, 0xde, 0xa3, 0xb1,
|
||||
0xdd, 0x61, 0x51, 0x60, 0xc7, 0x0e, 0x23, 0x61, 0x82, 0x6e, 0xa8, 0x14, 0x7c, 0x30, 0x12, 0xf8,
|
||||
0x9a, 0x54, 0x3d, 0xca, 0x45, 0xfb, 0x2c, 0x0a, 0x5a, 0x4a, 0x92, 0x0a, 0xfc, 0x66, 0x3e, 0xf1,
|
||||
0xa6, 0xf1, 0xa6, 0xf5, 0x55, 0x3b, 0xe1, 0xaf, 0x0c, 0xb0, 0x16, 0x44, 0x9e, 0x9d, 0xd0, 0x80,
|
||||
0xd8, 0x47, 0x34, 0xf4, 0xa2, 0x23, 0x9b, 0xa3, 0x37, 0x54, 0xc2, 0x7e, 0x7a, 0x26, 0xf0, 0x9a,
|
||||
0xe5, 0x1c, 0x3d, 0x8c, 0xbc, 0xc7, 0x34, 0x20, 0x4f, 0x14, 0x2b, 0x8f, 0xeb, 0xe5, 0xa0, 0x82,
|
||||
0x14, 0x97, 0xcb, 0x2a, 0x9c, 0x67, 0xee, 0x64, 0xd8, 0x98, 0xb4, 0x62, 0xd5, 0x6c, 0xc0, 0x17,
|
||||
0x06, 0x58, 0xcf, 0xda, 0xc4, 0xed, 0x33, 0x19, 0x9b, 0x7d, 0xc4, 0x68, 0x42, 0x38, 0x7a, 0x53,
|
||||
0x05, 0xf3, 0x43, 0x39, 0x7a, 0x75, 0xc1, 0x67, 0xfc, 0x13, 0x45, 0xa7, 0x02, 0x7f, 0xb3, 0xd4,
|
||||
0x35, 0x15, 0xae, 0xd4, 0x3c, 0xbb, 0xa5, 0xde, 0x31, 0x76, 0xad, 0x69, 0x96, 0xe4, 0x10, 0xcb,
|
||||
0x6b, 0xbb, 0x23, 0xbf, 0x48, 0xd0, 0xe6, 0x78, 0x88, 0x65, 0xc4, 0xbe, 0xc4, 0x8b, 0xe6, 0x2f,
|
||||
0x83, 0xa6, 0x55, 0xd1, 0x40, 0x1f, 0xac, 0xaa, 0x2f, 0x45, 0x5b, 0xce, 0x02, 0x5b, 0xcf, 0x57,
|
||||
0xac, 0xe6, 0xeb, 0xd5, 0x7c, 0xbe, 0x36, 0x25, 0x3f, 0x1e, 0xb2, 0xea, 0xda, 0xde, 0xae, 0x60,
|
||||
0x45, 0x66, 0xab, 0xb0, 0x69, 0xd5, 0x74, 0xf0, 0x73, 0x03, 0xac, 0xa9, 0x12, 0x52, 0x1f, 0x9a,
|
||||
0xb6, 0xfe, 0xd2, 0x44, 0x5b, 0xca, 0xdf, 0x65, 0xf9, 0x89, 0x70, 0x2f, 0x8a, 0x07, 0x96, 0xe4,
|
||||
0x1e, 0x2a, 0xaa, 0xf9, 0x40, 0xde, 0xba, 0xdc, 0x2a, 0x98, 0x0a, 0xbc, 0x5d, 0x94, 0x51, 0x09,
|
||||
0x2f, 0xa5, 0x91, 0x27, 0x4e, 0xe8, 0x39, 0xcc, 0x33, 0x5f, 0x9f, 0x36, 0xe6, 0xf2, 0x85, 0x55,
|
||||
0x37, 0x04, 0xff, 0x2c, 0xc3, 0x71, 0xe4, 0x00, 0x25, 0x21, 0xa7, 0x09, 0x7d, 0x26, 0x33, 0x8a,
|
||||
0xde, 0x52, 0xe9, 0x3c, 0x96, 0x57, 0xc0, 0x7b, 0x0e, 0x27, 0x07, 0x39, 0xb7, 0xaf, 0xae, 0x80,
|
||||
0x6e, 0x15, 0x4a, 0x05, 0x5e, 0xd7, 0xc1, 0x54, 0x71, 0x79, 0xdd, 0x99, 0xd0, 0x4e, 0x42, 0xf2,
|
||||
0xc6, 0x57, 0x73, 0x62, 0xd5, 0x34, 0x1c, 0xfe, 0xc9, 0x00, 0xab, 0x9d, 0xc8, 0xf7, 0xa3, 0x23,
|
||||
0xfb, 0xb3, 0x7e, 0xe8, 0xca, 0xeb, 0x08, 0x47, 0xe6, 0x38, 0xca, 0x1f, 0xe4, 0xe0, 0xc7, 0x7c,
|
||||
0x8f, 0x32, 0x2e, 0xa3, 0xfc, 0xac, 0x0a, 0x15, 0x51, 0xd6, 0x70, 0x15, 0x65, 0x5d, 0x3b, 0x09,
|
||||
0xc9, 0x28, 0x6b, 0x4e, 0xac, 0x15, 0x1d, 0x51, 0x01, 0xc3, 0x43, 0x30, 0xcf, 0x88, 0xe3, 0xd9,
|
||||
0x51, 0xe8, 0x0f, 0xd0, 0x5f, 0xf7, 0x55, 0x78, 0x0f, 0xcf, 0x04, 0x86, 0x7b, 0x24, 0x66, 0xc4,
|
||||
0x75, 0x12, 0xe2, 0x59, 0xc4, 0xf1, 0x1e, 0x85, 0xfe, 0x60, 0x24, 0xb0, 0x71, 0xb3, 0xf8, 0x3a,
|
||||
0x66, 0x91, 0xba, 0x09, 0xbe, 0x17, 0x05, 0x54, 0xce, 0xea, 0x64, 0xa0, 0xbe, 0x8e, 0x27, 0x50,
|
||||
0x64, 0x58, 0x73, 0x2c, 0x33, 0x00, 0x7f, 0x01, 0xd6, 0x2a, 0xd7, 0x43, 0x35, 0x3f, 0xff, 0x26,
|
||||
0x9d, 0x1a, 0xcd, 0x4f, 0xce, 0x04, 0x46, 0x63, 0xa7, 0x0f, 0xc7, 0x37, 0xbf, 0x96, 0x9b, 0xe4,
|
||||
0xae, 0x37, 0xeb, 0x77, 0xc4, 0x96, 0x9b, 0x94, 0x22, 0x40, 0x86, 0xb5, 0x5c, 0x25, 0xe1, 0x4f,
|
||||
0xc0, 0x25, 0x7d, 0x5e, 0x72, 0xf4, 0xc5, 0xbe, 0xea, 0xf5, 0x8f, 0xe4, 0xe0, 0x19, 0x3b, 0xd2,
|
||||
0xf7, 0x20, 0x5e, 0x7d, 0xb8, 0x6c, 0x4b, 0xc9, 0x74, 0xd6, 0xe0, 0xc8, 0xb0, 0x72, 0x7b, 0xcd,
|
||||
0x07, 0x2f, 0xbf, 0xdc, 0x9c, 0x19, 0x7e, 0xb9, 0x39, 0xf3, 0xf2, 0x6c, 0xd3, 0x18, 0x9e, 0x6d,
|
||||
0x1a, 0xbf, 0x7b, 0xb5, 0x39, 0xf3, 0xc7, 0x57, 0x9b, 0xc6, 0xf0, 0xd5, 0xe6, 0xcc, 0xbf, 0x5e,
|
||||
0x6d, 0xce, 0x3c, 0x7d, 0xe7, 0xff, 0xf8, 0x3f, 0x42, 0xb7, 0x6b, 0xfb, 0xa2, 0xfa, 0x5f, 0xe2,
|
||||
0xfd, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0xde, 0x81, 0xf6, 0x5e, 0xb5, 0x12, 0x00, 0x00,
|
||||
0x3b, 0x10, 0x11, 0x90, 0x9a, 0x76, 0x77, 0xcd, 0x4c, 0xad, 0xfb, 0x8b, 0xaa, 0x9e, 0xd8, 0x93,
|
||||
0x53, 0xb8, 0x20, 0x10, 0x7b, 0x40, 0xe6, 0xc0, 0x15, 0x09, 0x84, 0x60, 0xff, 0x01, 0x24, 0xfe,
|
||||
0x82, 0x5c, 0x90, 0xe7, 0x84, 0x10, 0x87, 0x92, 0xd6, 0xbe, 0xcd, 0xb1, 0x8f, 0x39, 0xa1, 0xaa,
|
||||
0xea, 0xee, 0xe9, 0xee, 0x99, 0x45, 0x48, 0x7b, 0x9b, 0xfa, 0xfd, 0x7e, 0xf5, 0xde, 0xeb, 0x57,
|
||||
0xf5, 0x5e, 0xbf, 0x1e, 0xd0, 0xf0, 0xe9, 0xc1, 0x6d, 0x37, 0x0a, 0xdb, 0xb4, 0x73, 0xbb, 0x1d,
|
||||
0xf9, 0x1e, 0x61, 0x7a, 0xd1, 0x63, 0x4e, 0x42, 0xa3, 0x70, 0x3b, 0x66, 0x51, 0x12, 0xc1, 0xcb,
|
||||
0x1a, 0x5c, 0xbf, 0x39, 0xa6, 0x4e, 0xfa, 0x31, 0xd1, 0xa2, 0xf5, 0xb5, 0x12, 0xc9, 0xe9, 0x8b,
|
||||
0x1c, 0x5e, 0x2f, 0xc1, 0x71, 0xcf, 0xf7, 0x23, 0xe6, 0x11, 0x96, 0x71, 0x5b, 0x25, 0xee, 0x39,
|
||||
0x61, 0x9c, 0x46, 0x21, 0x0d, 0x3b, 0x13, 0x22, 0x58, 0xc7, 0x25, 0xe5, 0x81, 0x1f, 0xb9, 0x87,
|
||||
0x75, 0x53, 0x50, 0x0a, 0xda, 0xfc, 0xb6, 0x0c, 0x88, 0x67, 0xd8, 0x1b, 0x19, 0xe6, 0x46, 0x71,
|
||||
0x9f, 0x39, 0x61, 0x87, 0x04, 0x24, 0xe9, 0x46, 0x5e, 0xc6, 0xce, 0x92, 0xe3, 0x44, 0xff, 0x34,
|
||||
0xff, 0x75, 0x01, 0xdc, 0xd8, 0x53, 0xcf, 0xb3, 0x4b, 0x9e, 0x53, 0x97, 0xdc, 0x2f, 0x47, 0x00,
|
||||
0xbf, 0x30, 0xc0, 0xac, 0xa7, 0x70, 0x9b, 0x7a, 0xc8, 0xd8, 0x34, 0xb6, 0xe6, 0x9b, 0x9f, 0x1b,
|
||||
0xaf, 0x04, 0x9e, 0xfa, 0x8f, 0xc0, 0xdf, 0xee, 0xd0, 0xa4, 0xdb, 0x3b, 0xd8, 0x76, 0xa3, 0xe0,
|
||||
0x36, 0xef, 0x87, 0x6e, 0xd2, 0xa5, 0x61, 0xa7, 0xf4, 0x4b, 0x86, 0xa0, 0x9c, 0xb8, 0x91, 0xbf,
|
||||
0xad, 0xad, 0x3f, 0xd8, 0x3d, 0x13, 0x78, 0x26, 0xff, 0x3d, 0x14, 0x78, 0xc6, 0xcb, 0x7e, 0xa7,
|
||||
0x02, 0x2f, 0x1c, 0x07, 0xfe, 0x3d, 0x93, 0x7a, 0xef, 0x39, 0x49, 0xc2, 0xcc, 0xe1, 0x69, 0xe3,
|
||||
0x4a, 0xf6, 0x3b, 0x3d, 0x6d, 0x14, 0xba, 0x5f, 0x0f, 0x1a, 0xc6, 0xc9, 0xa0, 0x51, 0xd8, 0xb0,
|
||||
0x72, 0xc6, 0x83, 0x7f, 0x31, 0xc0, 0x02, 0x0d, 0x13, 0x16, 0x79, 0x3d, 0x97, 0x78, 0xf6, 0x41,
|
||||
0x1f, 0x4d, 0xab, 0x80, 0x5f, 0x7e, 0xad, 0x80, 0x87, 0x02, 0xcf, 0x8f, 0xac, 0x36, 0xfb, 0xa9,
|
||||
0xc0, 0xd7, 0x75, 0xa0, 0x25, 0xb0, 0x08, 0x79, 0x65, 0x0c, 0x95, 0x01, 0x5b, 0x15, 0x0b, 0xd0,
|
||||
0x05, 0xab, 0x24, 0x74, 0x59, 0x3f, 0x96, 0x39, 0xb6, 0x63, 0x87, 0xf3, 0xa3, 0x88, 0x79, 0xe8,
|
||||
0xc2, 0xa6, 0xb1, 0x35, 0xdb, 0xdc, 0x19, 0x0a, 0x0c, 0x47, 0x74, 0x2b, 0x63, 0x53, 0x81, 0x91,
|
||||
0x72, 0x3b, 0x4e, 0x99, 0xd6, 0x04, 0xbd, 0x79, 0x8e, 0xc1, 0xaa, 0x3e, 0xd8, 0xea, 0x91, 0x7e,
|
||||
0x04, 0xa6, 0xb3, 0xa3, 0x9c, 0x6d, 0x6e, 0x9f, 0x09, 0x3c, 0xad, 0x1e, 0x71, 0x9a, 0x7a, 0xff,
|
||||
0xeb, 0x04, 0x4e, 0x06, 0x8d, 0xe9, 0x07, 0xbb, 0xd6, 0x34, 0xf5, 0xe0, 0x8f, 0xc0, 0x25, 0xdf,
|
||||
0x39, 0x20, 0xbe, 0x4a, 0xee, 0x6c, 0xf3, 0xbb, 0x43, 0x81, 0x35, 0x90, 0x0a, 0xbc, 0xa9, 0xf6,
|
||||
0xab, 0x95, 0x36, 0xb1, 0xc9, 0x08, 0x4f, 0x1c, 0x96, 0xdc, 0x33, 0xdb, 0x8e, 0xcf, 0x89, 0x34,
|
||||
0x09, 0x46, 0xf4, 0xcb, 0x41, 0x63, 0xca, 0xd2, 0x9b, 0x61, 0x07, 0x2c, 0xb5, 0xa9, 0x4f, 0x78,
|
||||
0x9f, 0x27, 0x24, 0xb0, 0xe5, 0x55, 0x56, 0xf9, 0x58, 0xdc, 0x81, 0xdb, 0x6d, 0xbe, 0xbd, 0x57,
|
||||
0x50, 0x4f, 0xfa, 0x31, 0x69, 0xbe, 0x3b, 0x14, 0x78, 0xb1, 0x5d, 0xc1, 0x52, 0x81, 0xaf, 0x2a,
|
||||
0xef, 0x55, 0xd8, 0xb4, 0x6a, 0x3a, 0xf8, 0x01, 0xb8, 0x18, 0x3b, 0x49, 0x17, 0x5d, 0x54, 0xe1,
|
||||
0x6f, 0x0d, 0x05, 0x56, 0xeb, 0x54, 0xe0, 0x25, 0xb5, 0x5f, 0x2e, 0x8a, 0xe7, 0x9f, 0x2d, 0x56,
|
||||
0x96, 0x52, 0xc1, 0x16, 0xb8, 0xa8, 0x62, 0xbb, 0x94, 0xc5, 0xa6, 0xeb, 0x72, 0x5b, 0x27, 0x5a,
|
||||
0xc5, 0xa6, 0x2c, 0x26, 0x3a, 0x22, 0x6d, 0x51, 0x2e, 0x46, 0x16, 0x8b, 0x95, 0xa5, 0x54, 0xf0,
|
||||
0x67, 0xe0, 0x8a, 0xbe, 0xc1, 0x1c, 0x5d, 0xde, 0xbc, 0xb0, 0x35, 0xb7, 0xf3, 0x56, 0xd5, 0xe8,
|
||||
0x84, 0xb2, 0x6c, 0x62, 0x79, 0xa1, 0x87, 0x02, 0xe7, 0x3b, 0x53, 0x81, 0xe7, 0x95, 0x2b, 0xbd,
|
||||
0x36, 0xad, 0x9c, 0x80, 0xbf, 0x37, 0xc0, 0x0a, 0x23, 0xdc, 0x75, 0x42, 0x9b, 0x86, 0x09, 0x61,
|
||||
0xcf, 0x1d, 0xdf, 0xe6, 0xe8, 0xca, 0xa6, 0xb1, 0x75, 0xa9, 0xd9, 0x19, 0x0a, 0xbc, 0xa4, 0xc9,
|
||||
0x07, 0x19, 0xb7, 0x9f, 0x0a, 0xfc, 0x8e, 0xb2, 0x54, 0xc3, 0xb3, 0xe3, 0xf4, 0x48, 0xdb, 0xe9,
|
||||
0xf9, 0xc9, 0x3d, 0xf3, 0xfd, 0xef, 0xdc, 0xb9, 0x63, 0xbe, 0x16, 0xf8, 0x02, 0x0d, 0x93, 0xe1,
|
||||
0x69, 0xe3, 0xea, 0x24, 0xf9, 0xeb, 0xd3, 0xc6, 0x45, 0xa9, 0xb3, 0xea, 0x4e, 0xe0, 0x3f, 0x0c,
|
||||
0x00, 0xdb, 0xdc, 0x3e, 0x72, 0x12, 0xb7, 0x4b, 0x98, 0x4d, 0x42, 0xe7, 0xc0, 0x27, 0x1e, 0x9a,
|
||||
0xd9, 0x34, 0xb6, 0x66, 0x9a, 0xbf, 0x35, 0xce, 0x04, 0x5e, 0xde, 0xdb, 0x7f, 0xaa, 0xd9, 0x4f,
|
||||
0x34, 0x39, 0x14, 0x78, 0xb9, 0xcd, 0xab, 0x58, 0x2a, 0xf0, 0xbb, 0xfa, 0xcc, 0x6b, 0x44, 0x3d,
|
||||
0xda, 0x84, 0xf5, 0xd4, 0xdd, 0x5b, 0x9b, 0x28, 0x94, 0x71, 0x4a, 0xc5, 0xc9, 0xa0, 0x31, 0xe6,
|
||||
0xd6, 0x1a, 0x73, 0x0a, 0xff, 0x5e, 0x0d, 0xde, 0x23, 0xbe, 0xd3, 0xb7, 0x39, 0x9a, 0x55, 0x39,
|
||||
0xfd, 0x8d, 0x0c, 0x7e, 0xa9, 0xb0, 0xb2, 0x2b, 0xc9, 0x7d, 0x99, 0xe7, 0xc2, 0x8c, 0x86, 0x52,
|
||||
0x81, 0xbf, 0x55, 0x0d, 0x5d, 0xe3, 0xf5, 0xc8, 0xef, 0x56, 0xb2, 0x3c, 0x49, 0xfc, 0xfa, 0xb4,
|
||||
0x31, 0x7d, 0xf7, 0xce, 0xc9, 0xa0, 0x51, 0xf7, 0x6a, 0xd5, 0x7d, 0xc2, 0x9f, 0x83, 0x79, 0xda,
|
||||
0x09, 0x23, 0x46, 0xec, 0x98, 0xb0, 0x80, 0x23, 0xa0, 0xf2, 0xfd, 0xe1, 0x50, 0xe0, 0x39, 0x8d,
|
||||
0xb7, 0x24, 0x9c, 0x0a, 0x7c, 0x4d, 0xf7, 0x81, 0x11, 0x56, 0x5c, 0xdf, 0xe5, 0x3a, 0x68, 0x95,
|
||||
0xb7, 0xc2, 0x5f, 0x1a, 0x60, 0xd1, 0xe9, 0x25, 0x91, 0x1d, 0x46, 0x2c, 0x70, 0x7c, 0xfa, 0x82,
|
||||
0xa0, 0x39, 0xe5, 0xe4, 0xd9, 0x50, 0xe0, 0x05, 0xc9, 0x7c, 0x9a, 0x13, 0x45, 0x06, 0x2a, 0xe8,
|
||||
0x57, 0x9d, 0x1c, 0x1c, 0x57, 0xe5, 0xc7, 0x66, 0x55, 0xed, 0xc2, 0x67, 0x60, 0x21, 0xa0, 0xa1,
|
||||
0xed, 0x51, 0x7e, 0x68, 0xb7, 0x19, 0x21, 0x68, 0x7e, 0xd3, 0xd8, 0x9a, 0xdb, 0x99, 0xcf, 0xcb,
|
||||
0x6a, 0x9f, 0xbe, 0x20, 0xcd, 0xad, 0xac, 0x82, 0xe6, 0x02, 0x1a, 0xee, 0x52, 0x7e, 0xb8, 0xc7,
|
||||
0x88, 0x8c, 0x68, 0x45, 0x45, 0x54, 0xc2, 0x4c, 0xab, 0xac, 0x80, 0x1d, 0x00, 0x46, 0x2f, 0x6b,
|
||||
0xb4, 0xa0, 0x0c, 0xe3, 0xdc, 0xf0, 0x8f, 0x0b, 0xa6, 0x5a, 0xad, 0x6f, 0x67, 0xbe, 0x4a, 0x5b,
|
||||
0x53, 0x81, 0x97, 0x95, 0xab, 0x11, 0x64, 0x5a, 0x25, 0x1e, 0x7e, 0x08, 0xae, 0xb8, 0x51, 0x4c,
|
||||
0x09, 0xe3, 0x68, 0x51, 0x5d, 0xac, 0x6f, 0xc8, 0x72, 0xcf, 0xa0, 0xa2, 0x53, 0x67, 0xeb, 0xfc,
|
||||
0x8a, 0x58, 0xb9, 0x00, 0xfe, 0xd3, 0x00, 0xd7, 0xe4, 0x98, 0x40, 0x98, 0x1d, 0x38, 0xc7, 0x76,
|
||||
0x4c, 0x42, 0x8f, 0x86, 0x1d, 0xfb, 0x90, 0x1e, 0xa0, 0x25, 0x65, 0xee, 0x0f, 0xf2, 0x9e, 0xae,
|
||||
0xb6, 0x94, 0xe4, 0x91, 0x73, 0xdc, 0xd2, 0x82, 0x87, 0xb4, 0x39, 0x14, 0x78, 0x35, 0x1e, 0x87,
|
||||
0x53, 0x81, 0x6f, 0xe8, 0xf6, 0x38, 0xce, 0x95, 0x6e, 0xe8, 0xc4, 0xad, 0x93, 0xe1, 0x93, 0x41,
|
||||
0x63, 0x92, 0x7f, 0x6b, 0x82, 0xf6, 0x40, 0xa6, 0xa3, 0xeb, 0xf0, 0xae, 0x4c, 0xc7, 0xf2, 0x28,
|
||||
0x1d, 0x19, 0x54, 0xa4, 0x23, 0x5b, 0x8f, 0xd2, 0x91, 0x01, 0xf0, 0x63, 0x70, 0x49, 0x0d, 0x4c,
|
||||
0x68, 0x45, 0xb5, 0xed, 0x95, 0xfc, 0xc4, 0xa4, 0xff, 0xc7, 0x92, 0x68, 0x22, 0xf9, 0x1a, 0x53,
|
||||
0x9a, 0x54, 0xe0, 0x39, 0x65, 0x4d, 0xad, 0x4c, 0x4b, 0xa3, 0xf0, 0x21, 0x58, 0xc8, 0x6a, 0xc7,
|
||||
0x23, 0x3e, 0x49, 0x08, 0x82, 0xea, 0x5e, 0xbf, 0xad, 0xc6, 0x03, 0x45, 0xec, 0x2a, 0x3c, 0x15,
|
||||
0x18, 0x96, 0xaa, 0x47, 0x83, 0xa6, 0x55, 0xd1, 0xc0, 0x63, 0x80, 0x54, 0x4b, 0x8e, 0x59, 0xd4,
|
||||
0x61, 0x84, 0xf3, 0x72, 0x6f, 0x5e, 0x55, 0xcf, 0x27, 0x5f, 0xab, 0x6b, 0x52, 0xd3, 0xca, 0x24,
|
||||
0xe5, 0x0e, 0x7d, 0x53, 0x39, 0x98, 0xc8, 0x16, 0xcf, 0x3e, 0x79, 0x33, 0xdc, 0x07, 0x8b, 0xd9,
|
||||
0xbd, 0x88, 0x9d, 0x1e, 0x27, 0x36, 0x47, 0x57, 0x95, 0xbf, 0x5b, 0xf2, 0x39, 0x34, 0xd3, 0x92,
|
||||
0xc4, 0x7e, 0xf1, 0x1c, 0x65, 0xb0, 0xb0, 0x5e, 0x91, 0x42, 0x02, 0x16, 0xe4, 0x2d, 0x93, 0x49,
|
||||
0xf5, 0xa9, 0x9b, 0x70, 0xb4, 0xa6, 0x6c, 0x7e, 0x4f, 0xda, 0x0c, 0x9c, 0xe3, 0xfb, 0x39, 0x9e,
|
||||
0x0a, 0x8c, 0x75, 0x81, 0x95, 0xc0, 0x52, 0xb1, 0xdf, 0xba, 0x9b, 0x3b, 0x90, 0x4d, 0xed, 0xd6,
|
||||
0x5d, 0xab, 0xb2, 0x1b, 0x7a, 0xe0, 0xaa, 0x47, 0xb9, 0x6c, 0xc2, 0x36, 0x8f, 0x1d, 0xc6, 0x89,
|
||||
0xad, 0x5e, 0xed, 0xe8, 0x9a, 0x3a, 0x09, 0x35, 0x37, 0x65, 0xfc, 0xbe, 0xa2, 0xd5, 0xd0, 0x50,
|
||||
0xcc, 0x4d, 0xe3, 0x94, 0x69, 0x4d, 0xd0, 0x97, 0xbd, 0x24, 0x24, 0x88, 0x6d, 0x1a, 0x7a, 0xe4,
|
||||
0x98, 0x70, 0x74, 0x7d, 0xcc, 0xcb, 0x13, 0x12, 0xc4, 0x0f, 0x34, 0x5b, 0xf7, 0x52, 0xa2, 0x46,
|
||||
0x5e, 0x4a, 0x20, 0xdc, 0x01, 0x97, 0xd5, 0x01, 0x78, 0x08, 0x29, 0xbb, 0xeb, 0x43, 0x81, 0x33,
|
||||
0xa4, 0x78, 0x99, 0xeb, 0xa5, 0x69, 0x65, 0x38, 0x4c, 0xc0, 0xf5, 0x23, 0xe2, 0x1c, 0xda, 0xf2,
|
||||
0x56, 0xdb, 0x49, 0x97, 0x11, 0xde, 0x8d, 0x7c, 0xcf, 0x8e, 0xdd, 0x04, 0xdd, 0x50, 0x09, 0x97,
|
||||
0x9d, 0xfc, 0xaa, 0x94, 0x7c, 0xdf, 0xe1, 0xdd, 0x27, 0xb9, 0xa0, 0xe5, 0x26, 0xa9, 0xc0, 0xeb,
|
||||
0xca, 0xe4, 0x24, 0xb2, 0x38, 0xd4, 0x89, 0x5b, 0xe1, 0x7d, 0x30, 0x17, 0x38, 0xec, 0x90, 0x30,
|
||||
0x3b, 0x74, 0x02, 0x82, 0xd6, 0xd5, 0xd8, 0x64, 0xca, 0x76, 0xa6, 0xe1, 0x4f, 0x9d, 0x80, 0x14,
|
||||
0xed, 0x6c, 0x04, 0x99, 0x56, 0x89, 0x87, 0x7d, 0xb0, 0x2e, 0xbf, 0x44, 0xec, 0xe8, 0x28, 0x24,
|
||||
0x8c, 0x77, 0x69, 0x6c, 0xb7, 0x59, 0x14, 0xd8, 0xb1, 0xc3, 0x48, 0x98, 0xa0, 0x9b, 0x2a, 0x05,
|
||||
0x1f, 0x0c, 0x05, 0xbe, 0x2e, 0x55, 0x8f, 0x73, 0xd1, 0x1e, 0x8b, 0x82, 0x96, 0x92, 0xa4, 0x02,
|
||||
0xbf, 0x99, 0x77, 0xbc, 0x49, 0xbc, 0x69, 0x7d, 0xd5, 0x4e, 0xf8, 0x2b, 0x03, 0xac, 0x04, 0x91,
|
||||
0x67, 0x27, 0x34, 0x20, 0xf6, 0x11, 0x0d, 0xbd, 0xe8, 0xc8, 0xe6, 0xe8, 0x0d, 0x95, 0xb0, 0x9f,
|
||||
0x9e, 0x09, 0xbc, 0x62, 0x39, 0x47, 0x8f, 0x22, 0xef, 0x09, 0x0d, 0xc8, 0x53, 0xc5, 0xca, 0xd7,
|
||||
0xf5, 0x62, 0x50, 0x41, 0x8a, 0xe1, 0xb2, 0x0a, 0xe7, 0x99, 0x3b, 0x19, 0x34, 0xc6, 0xad, 0x58,
|
||||
0x35, 0x1b, 0xf0, 0xa5, 0x01, 0xd6, 0xb2, 0x32, 0x71, 0x7b, 0x4c, 0xc6, 0x66, 0x1f, 0x31, 0x9a,
|
||||
0x10, 0x8e, 0xde, 0x54, 0xc1, 0xfc, 0x50, 0xb6, 0x5e, 0x7d, 0xe1, 0x33, 0xfe, 0xa9, 0xa2, 0x53,
|
||||
0x81, 0xbf, 0x59, 0xaa, 0x9a, 0x0a, 0x57, 0x2a, 0x9e, 0x9d, 0x52, 0xed, 0x18, 0x3b, 0xd6, 0x24,
|
||||
0x4b, 0xb2, 0x89, 0xe5, 0x77, 0xbb, 0x2d, 0x3f, 0x7b, 0xd0, 0xc6, 0xa8, 0x89, 0x65, 0xc4, 0x9e,
|
||||
0xc4, 0x8b, 0xe2, 0x2f, 0x83, 0xa6, 0x55, 0xd1, 0x40, 0x1f, 0x2c, 0xab, 0xcf, 0x51, 0x5b, 0xf6,
|
||||
0x02, 0x5b, 0xf7, 0x57, 0xac, 0xfa, 0xeb, 0xb5, 0xbc, 0xbf, 0x36, 0x25, 0x3f, 0x6a, 0xb2, 0x6a,
|
||||
0x6c, 0x3f, 0xa8, 0x60, 0x45, 0x66, 0xab, 0xb0, 0x69, 0xd5, 0x74, 0xf0, 0x73, 0x03, 0xac, 0xa8,
|
||||
0x2b, 0xa4, 0xbe, 0x66, 0x6d, 0xfd, 0x39, 0x8b, 0x36, 0x95, 0xbf, 0x55, 0xf9, 0x89, 0x70, 0x3f,
|
||||
0x8a, 0xfb, 0x96, 0xe4, 0x1e, 0x29, 0xaa, 0xf9, 0x50, 0x4e, 0x5d, 0x6e, 0x15, 0x4c, 0x05, 0xde,
|
||||
0x2a, 0xae, 0x51, 0x09, 0x2f, 0xa5, 0x91, 0x27, 0x4e, 0xe8, 0x39, 0xcc, 0x33, 0x5f, 0x9f, 0x36,
|
||||
0x66, 0xf2, 0x85, 0x55, 0x37, 0x04, 0xff, 0x2c, 0xc3, 0x71, 0x64, 0x03, 0x25, 0x21, 0xa7, 0x09,
|
||||
0x7d, 0x2e, 0x33, 0x8a, 0xde, 0x52, 0xe9, 0x3c, 0x96, 0x23, 0xe0, 0x7d, 0x87, 0x93, 0xfd, 0x9c,
|
||||
0xdb, 0x53, 0x23, 0xa0, 0x5b, 0x85, 0x52, 0x81, 0xd7, 0x74, 0x30, 0x55, 0x5c, 0x8e, 0x3b, 0x63,
|
||||
0xda, 0x71, 0x48, 0x4e, 0x7c, 0x35, 0x27, 0x56, 0x4d, 0xc3, 0xe1, 0x9f, 0x0c, 0xb0, 0xdc, 0x8e,
|
||||
0x7c, 0x3f, 0x3a, 0xb2, 0x3f, 0xeb, 0x85, 0xae, 0x1c, 0x47, 0x38, 0x32, 0x47, 0x51, 0xfe, 0x20,
|
||||
0x07, 0x3f, 0xe6, 0xbb, 0x94, 0x71, 0x19, 0xe5, 0x67, 0x55, 0xa8, 0x88, 0xb2, 0x86, 0xab, 0x28,
|
||||
0xeb, 0xda, 0x71, 0x48, 0x46, 0x59, 0x73, 0x62, 0x2d, 0xe9, 0x88, 0x0a, 0x18, 0x1e, 0x82, 0x59,
|
||||
0x46, 0x1c, 0xcf, 0x8e, 0x42, 0xbf, 0x8f, 0xfe, 0xba, 0xa7, 0xc2, 0x7b, 0x74, 0x26, 0x30, 0xdc,
|
||||
0x25, 0x31, 0x23, 0xae, 0x93, 0x10, 0xcf, 0x22, 0x8e, 0xf7, 0x38, 0xf4, 0xfb, 0x43, 0x81, 0x8d,
|
||||
0x5b, 0xc5, 0x27, 0x38, 0x8b, 0xd4, 0x24, 0xf8, 0x5e, 0x14, 0x50, 0xd9, 0xab, 0x93, 0xbe, 0xfa,
|
||||
0x04, 0x1f, 0x43, 0x91, 0x61, 0xcd, 0xb0, 0xcc, 0x00, 0xfc, 0x05, 0x58, 0xa9, 0x8c, 0x87, 0xaa,
|
||||
0x7f, 0xfe, 0x4d, 0x3a, 0x35, 0x9a, 0x9f, 0x9c, 0x09, 0x8c, 0x46, 0x4e, 0x1f, 0x8d, 0x26, 0xbf,
|
||||
0x96, 0x9b, 0xe4, 0xae, 0x37, 0xea, 0x33, 0x62, 0xcb, 0x4d, 0x4a, 0x11, 0x20, 0xc3, 0x5a, 0xac,
|
||||
0x92, 0xf0, 0x27, 0xe0, 0x8a, 0x7e, 0x5f, 0x72, 0xf4, 0xc5, 0x9e, 0xaa, 0xf5, 0x8f, 0x64, 0xe3,
|
||||
0x19, 0x39, 0xd2, 0x73, 0x10, 0xaf, 0x3e, 0x5c, 0xb6, 0xa5, 0x64, 0x3a, 0x2b, 0x70, 0x64, 0x58,
|
||||
0xb9, 0xbd, 0xe6, 0xc3, 0x57, 0x5f, 0x6e, 0x4c, 0x0d, 0xbe, 0xdc, 0x98, 0x7a, 0x75, 0xb6, 0x61,
|
||||
0x0c, 0xce, 0x36, 0x8c, 0xdf, 0x9d, 0x6f, 0x4c, 0xfd, 0xf1, 0x7c, 0xc3, 0x18, 0x9c, 0x6f, 0x4c,
|
||||
0xfd, 0xfb, 0x7c, 0x63, 0xea, 0xd9, 0x3b, 0xff, 0xc7, 0x9f, 0x1e, 0xba, 0x5c, 0x0f, 0x2e, 0xab,
|
||||
0x3f, 0x3f, 0xde, 0xff, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xe5, 0x04, 0x99, 0x1a, 0x13,
|
||||
0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *FolderDeviceConfiguration) Marshal() (dAtA []byte, err error) {
|
||||
@@ -295,6 +299,13 @@ func (m *FolderDeviceConfiguration) MarshalToSizedBuffer(dAtA []byte) (int, erro
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.EncryptionPassword) > 0 {
|
||||
i -= len(m.EncryptionPassword)
|
||||
copy(dAtA[i:], m.EncryptionPassword)
|
||||
i = encodeVarintFolderconfiguration(dAtA, i, uint64(len(m.EncryptionPassword)))
|
||||
i--
|
||||
dAtA[i] = 0x1a
|
||||
}
|
||||
{
|
||||
size := m.IntroducedBy.ProtoSize()
|
||||
i -= size
|
||||
@@ -685,6 +696,10 @@ func (m *FolderDeviceConfiguration) ProtoSize() (n int) {
|
||||
n += 1 + l + sovFolderconfiguration(uint64(l))
|
||||
l = m.IntroducedBy.ProtoSize()
|
||||
n += 1 + l + sovFolderconfiguration(uint64(l))
|
||||
l = len(m.EncryptionPassword)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovFolderconfiguration(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
@@ -914,6 +929,38 @@ func (m *FolderDeviceConfiguration) Unmarshal(dAtA []byte) error {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 3:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field EncryptionPassword", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowFolderconfiguration
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthFolderconfiguration
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthFolderconfiguration
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.EncryptionPassword = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipFolderconfiguration(dAtA[iNdEx:])
|
||||
|
||||
@@ -14,6 +14,8 @@ func (t FolderType) String() string {
|
||||
return "sendonly"
|
||||
case FolderTypeReceiveOnly:
|
||||
return "receiveonly"
|
||||
case FolderTypeReceiveEncrypted:
|
||||
return "receiveencrypted"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
@@ -31,6 +33,8 @@ func (t *FolderType) UnmarshalText(bs []byte) error {
|
||||
*t = FolderTypeSendOnly
|
||||
case "receiveonly":
|
||||
*t = FolderTypeReceiveOnly
|
||||
case "receiveencrypted":
|
||||
*t = FolderTypeReceiveEncrypted
|
||||
default:
|
||||
*t = FolderTypeSendReceive
|
||||
}
|
||||
|
||||
+19
-14
@@ -24,21 +24,24 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
|
||||
type FolderType int32
|
||||
|
||||
const (
|
||||
FolderTypeSendReceive FolderType = 0
|
||||
FolderTypeSendOnly FolderType = 1
|
||||
FolderTypeReceiveOnly FolderType = 2
|
||||
FolderTypeSendReceive FolderType = 0
|
||||
FolderTypeSendOnly FolderType = 1
|
||||
FolderTypeReceiveOnly FolderType = 2
|
||||
FolderTypeReceiveEncrypted FolderType = 3
|
||||
)
|
||||
|
||||
var FolderType_name = map[int32]string{
|
||||
0: "FOLDER_TYPE_SEND_RECEIVE",
|
||||
1: "FOLDER_TYPE_SEND_ONLY",
|
||||
2: "FOLDER_TYPE_RECEIVE_ONLY",
|
||||
3: "FOLDER_TYPE_RECEIVE_ENCRYPTED",
|
||||
}
|
||||
|
||||
var FolderType_value = map[string]int32{
|
||||
"FOLDER_TYPE_SEND_RECEIVE": 0,
|
||||
"FOLDER_TYPE_SEND_ONLY": 1,
|
||||
"FOLDER_TYPE_RECEIVE_ONLY": 2,
|
||||
"FOLDER_TYPE_SEND_RECEIVE": 0,
|
||||
"FOLDER_TYPE_SEND_ONLY": 1,
|
||||
"FOLDER_TYPE_RECEIVE_ONLY": 2,
|
||||
"FOLDER_TYPE_RECEIVE_ENCRYPTED": 3,
|
||||
}
|
||||
|
||||
func (FolderType) EnumDescriptor() ([]byte, []int) {
|
||||
@@ -52,21 +55,23 @@ func init() {
|
||||
func init() { proto.RegisterFile("lib/config/foldertype.proto", fileDescriptor_ea6ddb20c0633575) }
|
||||
|
||||
var fileDescriptor_ea6ddb20c0633575 = []byte{
|
||||
// 254 bytes of a gzipped FileDescriptorProto
|
||||
// 287 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xce, 0xc9, 0x4c, 0xd2,
|
||||
0x4f, 0xce, 0xcf, 0x4b, 0xcb, 0x4c, 0xd7, 0x4f, 0xcb, 0xcf, 0x49, 0x49, 0x2d, 0x2a, 0xa9, 0x2c,
|
||||
0x48, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x83, 0x48, 0x48, 0x29, 0x17, 0xa5, 0x16,
|
||||
0xe4, 0x17, 0xeb, 0x83, 0x05, 0x93, 0x4a, 0xd3, 0xf4, 0xd3, 0xf3, 0xd3, 0xf3, 0xc1, 0x1c, 0x30,
|
||||
0x0b, 0xa2, 0x58, 0x6b, 0x3b, 0x23, 0x17, 0x97, 0x1b, 0xd8, 0x84, 0x90, 0xca, 0x82, 0x54, 0x21,
|
||||
0x0b, 0xa2, 0x58, 0xeb, 0x17, 0x23, 0x17, 0x97, 0x1b, 0xd8, 0x84, 0x90, 0xca, 0x82, 0x54, 0x21,
|
||||
0x73, 0x2e, 0x09, 0x37, 0x7f, 0x1f, 0x17, 0xd7, 0xa0, 0xf8, 0x90, 0xc8, 0x00, 0xd7, 0xf8, 0x60,
|
||||
0x57, 0x3f, 0x97, 0xf8, 0x20, 0x57, 0x67, 0x57, 0xcf, 0x30, 0x57, 0x01, 0x06, 0x29, 0xc9, 0xae,
|
||||
0xb9, 0x0a, 0xa2, 0x08, 0xd5, 0xc1, 0xa9, 0x79, 0x29, 0x41, 0xa9, 0xc9, 0xa9, 0x99, 0x65, 0xa9,
|
||||
0x42, 0x86, 0x5c, 0xa2, 0x18, 0x1a, 0xfd, 0xfd, 0x7c, 0x22, 0x05, 0x18, 0xa5, 0xc4, 0xba, 0xe6,
|
||||
0x2a, 0x08, 0xa1, 0xea, 0xf2, 0xcf, 0xcb, 0xa9, 0x44, 0xb7, 0x0b, 0x6a, 0x0d, 0x44, 0x17, 0x13,
|
||||
0xba, 0x5d, 0x50, 0x7b, 0x40, 0x1a, 0xa5, 0x58, 0x56, 0x2c, 0x91, 0x63, 0x70, 0xf2, 0x3e, 0xf1,
|
||||
0x50, 0x8e, 0xe1, 0xc2, 0x43, 0x39, 0x86, 0x13, 0x8f, 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x9c,
|
||||
0xf0, 0x58, 0x8e, 0x61, 0xc1, 0x63, 0x39, 0xc6, 0x0b, 0x8f, 0xe5, 0x18, 0x6e, 0x3c, 0x96, 0x63,
|
||||
0x88, 0xd2, 0x4c, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x2f, 0xae, 0xcc,
|
||||
0x4b, 0x2e, 0xc9, 0xc8, 0xcc, 0x4b, 0x47, 0x62, 0x21, 0x02, 0x31, 0x89, 0x0d, 0x1c, 0x1a, 0xc6,
|
||||
0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x36, 0x1f, 0xe5, 0x1d, 0x59, 0x01, 0x00, 0x00,
|
||||
0xba, 0x5d, 0x50, 0x7b, 0xc0, 0x1a, 0x1d, 0xb9, 0x64, 0xb1, 0x69, 0x74, 0xf5, 0x73, 0x0e, 0x8a,
|
||||
0x0c, 0x08, 0x71, 0x75, 0x11, 0x60, 0x96, 0x92, 0xeb, 0x9a, 0xab, 0x20, 0x85, 0xa1, 0xdb, 0x35,
|
||||
0x2f, 0xb9, 0xa8, 0xb2, 0xa0, 0x24, 0x35, 0x45, 0x8a, 0x65, 0xc5, 0x12, 0x39, 0x06, 0x27, 0xef,
|
||||
0x13, 0x0f, 0xe5, 0x18, 0x2e, 0x3c, 0x94, 0x63, 0x38, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39,
|
||||
0xc6, 0x09, 0x8f, 0xe5, 0x18, 0x16, 0x3c, 0x96, 0x63, 0xbc, 0xf0, 0x58, 0x8e, 0xe1, 0xc6, 0x63,
|
||||
0x39, 0x86, 0x28, 0xcd, 0xf4, 0xcc, 0x92, 0x8c, 0xd2, 0x24, 0xbd, 0xe4, 0xfc, 0x5c, 0xfd, 0xe2,
|
||||
0xca, 0xbc, 0xe4, 0x92, 0x8c, 0xcc, 0xbc, 0x74, 0x24, 0x16, 0x22, 0x1e, 0x92, 0xd8, 0xc0, 0x01,
|
||||
0x6a, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0xc9, 0x87, 0xbe, 0x2d, 0x9c, 0x01, 0x00, 0x00,
|
||||
}
|
||||
|
||||
@@ -147,3 +147,13 @@ func (opts OptionsConfiguration) MaxConcurrentIncomingRequestKiB() int {
|
||||
func (opts OptionsConfiguration) AutoUpgradeEnabled() bool {
|
||||
return opts.AutoUpgradeIntervalH > 0
|
||||
}
|
||||
|
||||
func (opts OptionsConfiguration) FeatureFlag(name string) bool {
|
||||
for _, flag := range opts.FeatureFlags {
|
||||
if flag == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -73,6 +73,7 @@ type OptionsConfiguration struct {
|
||||
RawMaxCIRequestKiB int `protobuf:"varint,47,opt,name=max_concurrent_incoming_request_kib,json=maxConcurrentIncomingRequestKib,proto3,casttype=int" json:"maxConcurrentIncomingRequestKiB" xml:"maxConcurrentIncomingRequestKiB"`
|
||||
AnnounceLANAddresses bool `protobuf:"varint,48,opt,name=announce_lan_addresses,json=announceLanAddresses,proto3" json:"announceLANAddresses" xml:"announceLANAddresses" default:"true"`
|
||||
SendFullIndexOnUpgrade bool `protobuf:"varint,49,opt,name=send_full_index_on_upgrade,json=sendFullIndexOnUpgrade,proto3" json:"sendFullIndexOnUpgrade" xml:"sendFullIndexOnUpgrade"`
|
||||
FeatureFlags []string `protobuf:"bytes,50,rep,name=feature_flags,json=featureFlags,proto3" json:"featureFlags" xml:"featureFlag"`
|
||||
// Legacy deprecated
|
||||
DeprecatedUPnPEnabled bool `protobuf:"varint,9000,opt,name=upnp_enabled,json=upnpEnabled,proto3" json:"-" xml:"upnpEnabled,omitempty"` // Deprecated: Do not use.
|
||||
DeprecatedUPnPLeaseM int `protobuf:"varint,9001,opt,name=upnp_lease_m,json=upnpLeaseM,proto3,casttype=int" json:"-" xml:"upnpLeaseMinutes,omitempty"` // Deprecated: Do not use.
|
||||
@@ -125,201 +126,204 @@ func init() {
|
||||
}
|
||||
|
||||
var fileDescriptor_d09882599506ca03 = []byte{
|
||||
// 3103 bytes of a gzipped FileDescriptorProto
|
||||
// 3138 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x5a, 0x5b, 0x6c, 0x1d, 0x47,
|
||||
0x19, 0xce, 0x26, 0x4d, 0xda, 0x6c, 0x1c, 0x27, 0x5e, 0x3b, 0xf6, 0x36, 0x49, 0xbd, 0xee, 0xc9,
|
||||
0x49, 0xeb, 0xde, 0xe2, 0x4b, 0xda, 0x10, 0x2c, 0x21, 0xf0, 0xa5, 0xa6, 0x26, 0xb6, 0x63, 0x8d,
|
||||
0x6d, 0x15, 0x15, 0xa1, 0xd5, 0x9c, 0x3d, 0x73, 0xec, 0xc5, 0x7b, 0x66, 0x4f, 0x76, 0x67, 0x7d,
|
||||
0x29, 0xa8, 0x54, 0x45, 0x5c, 0xde, 0x00, 0x8b, 0x8b, 0x04, 0x08, 0x15, 0x01, 0x12, 0xa5, 0x14,
|
||||
0x21, 0x21, 0x21, 0xc1, 0x0b, 0x08, 0x09, 0xa9, 0x82, 0x07, 0xfb, 0x11, 0x89, 0xb2, 0xa8, 0x4e,
|
||||
0x9f, 0xce, 0x03, 0x0f, 0xe7, 0xd1, 0xbc, 0xa0, 0x7f, 0xf6, 0x36, 0xbb, 0x3b, 0xa7, 0xc9, 0xdb,
|
||||
0xd9, 0xff, 0xfb, 0xe7, 0x9f, 0xef, 0x9f, 0xcb, 0x3f, 0xff, 0x3f, 0x73, 0xd4, 0xeb, 0x8e, 0x5d,
|
||||
0x1b, 0xb3, 0x5c, 0xda, 0xb0, 0x37, 0xc6, 0xdc, 0x16, 0xb3, 0x5d, 0xea, 0x47, 0x5f, 0x81, 0x87,
|
||||
0xe1, 0xeb, 0x46, 0xcb, 0x73, 0x99, 0xab, 0x9d, 0x89, 0x84, 0x97, 0x87, 0x04, 0x75, 0x16, 0x50,
|
||||
0x9b, 0x6e, 0x44, 0x0a, 0x97, 0x2f, 0x09, 0x80, 0x6f, 0xbf, 0x4e, 0x62, 0xf1, 0x59, 0xb2, 0xcb,
|
||||
0xa2, 0x9f, 0x95, 0x9f, 0xcc, 0xab, 0x03, 0x77, 0xa3, 0x1e, 0x66, 0xc5, 0x1e, 0xb4, 0x9f, 0x2a,
|
||||
0xea, 0x45, 0xc7, 0xf6, 0x19, 0xa1, 0x26, 0xae, 0xd7, 0x3d, 0xe2, 0xfb, 0xc4, 0xd7, 0x95, 0x91,
|
||||
0x53, 0xa3, 0x67, 0x67, 0xfc, 0xa3, 0xd0, 0xd0, 0x10, 0xde, 0x59, 0xe4, 0xf0, 0x74, 0x82, 0xb6,
|
||||
0x43, 0xe3, 0x82, 0x93, 0x17, 0x75, 0x42, 0xe3, 0xfa, 0x6e, 0xd3, 0x99, 0xaa, 0xe4, 0xe4, 0x95,
|
||||
0x91, 0x3a, 0x69, 0xe0, 0xc0, 0x61, 0x53, 0x95, 0xf8, 0x47, 0xe5, 0xf8, 0xa0, 0xfa, 0x68, 0xfc,
|
||||
0x7b, 0xff, 0xb0, 0x2a, 0x31, 0x8e, 0x8a, 0xa6, 0xb5, 0xff, 0x2a, 0xaa, 0xbe, 0xe1, 0xb8, 0x35,
|
||||
0xec, 0x98, 0x75, 0xdb, 0xb7, 0xdc, 0x6d, 0xe2, 0xed, 0x99, 0x3e, 0xf1, 0xb6, 0x89, 0xe7, 0xeb,
|
||||
0x27, 0x39, 0xd1, 0xdf, 0x2b, 0x47, 0xa1, 0xd1, 0x8f, 0xf0, 0xce, 0x67, 0xb9, 0xde, 0x34, 0xa5,
|
||||
0xab, 0x11, 0xde, 0x0e, 0x8d, 0x4b, 0x1b, 0x89, 0xcc, 0x0d, 0xa8, 0x45, 0x62, 0xa0, 0x13, 0x1a,
|
||||
0xcf, 0x73, 0xc2, 0x32, 0x54, 0xc2, 0xbb, 0x7d, 0x50, 0x1d, 0x90, 0xa9, 0x76, 0x0e, 0xaa, 0xf2,
|
||||
0x0e, 0xf2, 0x8e, 0xca, 0xb8, 0xa1, 0xc1, 0xa8, 0xe1, 0x5c, 0xe2, 0x54, 0x2c, 0xd7, 0x3e, 0x92,
|
||||
0x39, 0x4c, 0x28, 0xae, 0x39, 0xa4, 0xae, 0x9f, 0x1a, 0x51, 0x46, 0x1f, 0x9b, 0x79, 0x07, 0x1c,
|
||||
0xbe, 0x98, 0x5a, 0x7c, 0x39, 0x02, 0xcb, 0xde, 0xc6, 0x40, 0x27, 0x34, 0x9e, 0x95, 0x78, 0x1b,
|
||||
0xa3, 0x82, 0xbb, 0xcc, 0x0b, 0x08, 0xf8, 0xda, 0xc5, 0x4c, 0x37, 0xe0, 0xf8, 0xa0, 0xfa, 0x08,
|
||||
0x34, 0xdd, 0x3f, 0xac, 0x96, 0x48, 0x95, 0xdc, 0x8c, 0xe5, 0xda, 0x07, 0x8a, 0x3a, 0xe4, 0xb8,
|
||||
0x96, 0xd4, 0xcb, 0x47, 0xb8, 0x97, 0x3f, 0x07, 0x2f, 0x2f, 0x2c, 0x82, 0x4e, 0xce, 0xc9, 0x01,
|
||||
0x27, 0x16, 0x15, 0x7c, 0x7c, 0x26, 0x5a, 0x82, 0x12, 0x50, 0xe2, 0xa2, 0xdc, 0x48, 0x17, 0xb9,
|
||||
0xe0, 0x60, 0x91, 0x0f, 0xba, 0xc4, 0x1b, 0x94, 0xdc, 0xfb, 0x87, 0xa2, 0xf6, 0x47, 0xee, 0xe1,
|
||||
0xd8, 0x96, 0xd9, 0x72, 0x3d, 0xa6, 0x9f, 0x1e, 0x51, 0x46, 0x4f, 0xcf, 0xfc, 0x08, 0x5c, 0xeb,
|
||||
0x49, 0x4c, 0xad, 0xb8, 0x1e, 0x6b, 0x87, 0x46, 0x5f, 0xae, 0x6b, 0x10, 0x76, 0x42, 0xe3, 0xe9,
|
||||
0xb2, 0x53, 0x80, 0x08, 0x1e, 0x4d, 0x4e, 0x8c, 0x4f, 0x7e, 0xa2, 0x72, 0x1c, 0x1a, 0xa7, 0x6c,
|
||||
0xca, 0xda, 0x07, 0x55, 0x89, 0x19, 0x99, 0xf0, 0xf8, 0xa0, 0x7a, 0x9a, 0x37, 0xdd, 0x3f, 0xac,
|
||||
0xe6, 0x98, 0xa0, 0xb2, 0xae, 0xf6, 0xb5, 0x93, 0xea, 0x48, 0xc1, 0x9b, 0x66, 0xe0, 0x30, 0xdb,
|
||||
0xc2, 0x3e, 0x4b, 0xe2, 0x86, 0x7e, 0x66, 0x44, 0x19, 0x3d, 0x3b, 0xf3, 0x47, 0x70, 0xad, 0x37,
|
||||
0x31, 0xb8, 0x34, 0x0b, 0x3b, 0xb9, 0x1d, 0x1a, 0xfd, 0x39, 0xa3, 0x91, 0xb8, 0x13, 0x1a, 0xb7,
|
||||
0xca, 0xee, 0x45, 0x98, 0xe0, 0xe0, 0x17, 0x1a, 0x8d, 0x89, 0xc9, 0xa9, 0xa9, 0xdb, 0x37, 0x6f,
|
||||
0xbf, 0xf8, 0xc5, 0xa9, 0xc8, 0xdb, 0xf6, 0x41, 0x55, 0x6a, 0x50, 0x2e, 0x3e, 0x3e, 0xa8, 0x6a,
|
||||
0x65, 0x23, 0xfb, 0x87, 0xd5, 0x02, 0x4d, 0xf4, 0x44, 0xbe, 0x71, 0xe2, 0x61, 0x1c, 0x8c, 0xb4,
|
||||
0xbb, 0xea, 0xf9, 0x26, 0xde, 0x35, 0x7d, 0x42, 0xeb, 0xe6, 0x56, 0xad, 0xe5, 0xeb, 0x8f, 0xf2,
|
||||
0xc9, 0x7c, 0xae, 0x1d, 0x1a, 0xe7, 0x9a, 0x78, 0x77, 0x95, 0xd0, 0xfa, 0x9d, 0x5a, 0x0b, 0x82,
|
||||
0x4b, 0x1f, 0x77, 0x4b, 0x90, 0x25, 0xf3, 0x83, 0x44, 0xc5, 0xc4, 0xa0, 0x47, 0xac, 0xed, 0xc8,
|
||||
0xe0, 0x63, 0x39, 0x83, 0x88, 0x58, 0xdb, 0x45, 0x83, 0x89, 0x2c, 0x67, 0x30, 0x11, 0x6a, 0x7f,
|
||||
0x50, 0xd4, 0x21, 0x8f, 0x58, 0x2e, 0xa5, 0xc4, 0x82, 0xf0, 0x6e, 0xda, 0x94, 0x11, 0x6f, 0x1b,
|
||||
0x3b, 0xa6, 0xaf, 0x9f, 0xe5, 0xb6, 0xdf, 0xe0, 0x41, 0x3d, 0x51, 0x59, 0x88, 0xe1, 0x55, 0x88,
|
||||
0x1d, 0x62, 0xc3, 0x14, 0xe8, 0x84, 0xc6, 0x28, 0xef, 0x5b, 0x8a, 0x0a, 0xb3, 0x74, 0x6b, 0x3c,
|
||||
0xa1, 0x74, 0x7c, 0x50, 0x3d, 0x79, 0x6b, 0x9c, 0xc7, 0xf7, 0x52, 0x3f, 0x48, 0xde, 0x8b, 0xd6,
|
||||
0x50, 0x7b, 0x3d, 0xe2, 0xe0, 0x3d, 0x3f, 0x8d, 0x01, 0x2a, 0x8f, 0x01, 0x9f, 0x6e, 0x87, 0xc6,
|
||||
0xf9, 0x08, 0xc9, 0x36, 0x7a, 0x25, 0x26, 0x24, 0x48, 0x8b, 0x3b, 0x3c, 0xd9, 0xb1, 0x28, 0xdf,
|
||||
0x58, 0x7b, 0xeb, 0xa4, 0x7a, 0x25, 0xee, 0x28, 0x25, 0x92, 0x0d, 0x52, 0x53, 0x3f, 0xc7, 0x07,
|
||||
0xe9, 0xaf, 0xb0, 0x86, 0x87, 0x10, 0xe8, 0x95, 0x5c, 0x58, 0x6a, 0x87, 0xc6, 0x90, 0x27, 0x87,
|
||||
0xd2, 0x40, 0xdb, 0x05, 0x17, 0x58, 0x4e, 0x8c, 0x0b, 0x5b, 0xb6, 0xab, 0xbd, 0xee, 0x10, 0x0c,
|
||||
0xf2, 0x04, 0x0c, 0x72, 0x37, 0x9a, 0x48, 0x8f, 0xfc, 0x2c, 0x23, 0x5a, 0x4d, 0x3d, 0xef, 0x33,
|
||||
0xec, 0x31, 0xb3, 0xe6, 0xb9, 0x3b, 0x3e, 0xf1, 0xf4, 0x1e, 0x3e, 0xd6, 0x9f, 0x6a, 0x87, 0x46,
|
||||
0x0f, 0x07, 0x66, 0x22, 0x79, 0x27, 0x34, 0x9e, 0xe4, 0xee, 0x88, 0xc2, 0xae, 0x23, 0x9d, 0x6b,
|
||||
0xaa, 0xfd, 0x52, 0x51, 0x2f, 0x51, 0xcc, 0x4c, 0xe6, 0x61, 0x38, 0xd5, 0xb0, 0x93, 0x4e, 0x6c,
|
||||
0x2f, 0xef, 0xec, 0xde, 0x51, 0x68, 0xa8, 0xcb, 0xd3, 0x6b, 0x59, 0x58, 0x57, 0x29, 0x66, 0xd9,
|
||||
0x1c, 0x1b, 0xbc, 0xe3, 0x4c, 0x24, 0x09, 0xe1, 0x62, 0x83, 0xdc, 0x97, 0x10, 0xae, 0x85, 0x2e,
|
||||
0x50, 0x3f, 0xc5, 0x6c, 0x2d, 0xa1, 0x93, 0x2c, 0x88, 0x3f, 0x95, 0x78, 0x3a, 0x04, 0xfb, 0xc4,
|
||||
0x6c, 0xea, 0x17, 0xf8, 0x52, 0xf8, 0x06, 0x2c, 0x85, 0xb3, 0xcb, 0xd3, 0x6b, 0x8b, 0x20, 0x86,
|
||||
0xc9, 0xbf, 0x40, 0x31, 0x8b, 0x3e, 0x6c, 0x1a, 0x30, 0x9e, 0xfc, 0x54, 0x12, 0xb2, 0xa2, 0x5c,
|
||||
0xba, 0x37, 0xda, 0x07, 0xd5, 0x52, 0xfb, 0xb2, 0x28, 0xdd, 0x41, 0x59, 0xc7, 0x48, 0x13, 0xd9,
|
||||
0x47, 0x32, 0xed, 0xef, 0x8a, 0x3a, 0x94, 0x27, 0xef, 0x11, 0x4a, 0x76, 0xf8, 0x4a, 0xbe, 0xc8,
|
||||
0xe9, 0xef, 0x03, 0xfd, 0x73, 0xcb, 0xd3, 0x6b, 0x28, 0x02, 0xc0, 0x81, 0x3e, 0x8a, 0x59, 0xf2,
|
||||
0x99, 0xba, 0x50, 0x4d, 0x5c, 0xc8, 0x23, 0x82, 0x13, 0x37, 0x45, 0x27, 0x24, 0x36, 0x64, 0x42,
|
||||
0x70, 0xe4, 0x26, 0x38, 0x22, 0x52, 0x40, 0x03, 0xa2, 0x2b, 0x89, 0x54, 0xe2, 0x0c, 0xb3, 0x9b,
|
||||
0xc4, 0x0d, 0x98, 0xe9, 0xeb, 0x7d, 0x79, 0x67, 0xd6, 0x22, 0x60, 0x35, 0x76, 0x26, 0xf9, 0x84,
|
||||
0x95, 0x5e, 0xcf, 0x39, 0x93, 0x47, 0xba, 0x6d, 0x3f, 0x89, 0x0d, 0x99, 0x30, 0xdd, 0x72, 0x22,
|
||||
0x85, 0xbc, 0x33, 0x89, 0x54, 0xfb, 0xb1, 0xa2, 0xea, 0x81, 0x8f, 0x37, 0x88, 0xe9, 0x11, 0x38,
|
||||
0xf7, 0x6d, 0xba, 0x61, 0x62, 0xcb, 0x22, 0x2d, 0x46, 0xea, 0xba, 0xc6, 0xbd, 0xc1, 0xb0, 0x03,
|
||||
0xd6, 0xd1, 0x74, 0x2c, 0x85, 0x1d, 0x10, 0x78, 0xc9, 0x57, 0x27, 0x34, 0x2e, 0x72, 0x27, 0x32,
|
||||
0x91, 0x40, 0x58, 0x54, 0xcc, 0x7d, 0xc1, 0x8a, 0xcf, 0x4c, 0xa2, 0x41, 0x4e, 0x01, 0x25, 0x0c,
|
||||
0x12, 0xb9, 0xf6, 0x65, 0x75, 0xa0, 0x48, 0xce, 0x27, 0x84, 0xea, 0xfd, 0x9c, 0xd8, 0xc2, 0x51,
|
||||
0x68, 0x9c, 0x59, 0x47, 0xab, 0x84, 0xd0, 0x76, 0x68, 0x9c, 0x09, 0x3c, 0xf8, 0xd5, 0x09, 0x8d,
|
||||
0x9e, 0x98, 0x10, 0x7c, 0x0a, 0x64, 0x12, 0x85, 0xf4, 0xd7, 0xfe, 0x61, 0x35, 0x6e, 0x8e, 0xb4,
|
||||
0x3c, 0x01, 0x90, 0x69, 0xdf, 0x57, 0xd4, 0xc7, 0x8b, 0xbd, 0x07, 0xd4, 0xbe, 0x17, 0x10, 0xd3,
|
||||
0xae, 0xeb, 0x03, 0x3c, 0x89, 0x78, 0x2d, 0x1a, 0x9b, 0x75, 0x2e, 0x5e, 0x98, 0x8b, 0xc6, 0x26,
|
||||
0xfe, 0x12, 0xc7, 0x26, 0x51, 0xa8, 0x44, 0x83, 0x92, 0x7c, 0x76, 0xc4, 0xaf, 0x78, 0x50, 0x12,
|
||||
0xac, 0x38, 0x28, 0x89, 0x96, 0xf6, 0x17, 0x45, 0xed, 0x2f, 0xf1, 0xf2, 0x1c, 0xfd, 0x12, 0x67,
|
||||
0xf4, 0x6d, 0x58, 0x7b, 0xa7, 0xd7, 0xd1, 0x3a, 0x5a, 0x6c, 0x87, 0xc6, 0xe9, 0xc0, 0x5b, 0x47,
|
||||
0x8b, 0x9d, 0xd0, 0xb8, 0x9d, 0x10, 0x41, 0x8b, 0xc2, 0xea, 0xda, 0x64, 0xac, 0xe5, 0x4f, 0x8d,
|
||||
0x8d, 0xd5, 0x31, 0xc3, 0x37, 0xfc, 0x3d, 0x6a, 0xb1, 0x4d, 0x28, 0xd6, 0x28, 0x61, 0x63, 0x94,
|
||||
0xec, 0x80, 0x14, 0x08, 0xc7, 0x46, 0x92, 0x1f, 0xc7, 0x07, 0xd5, 0x87, 0x68, 0xb8, 0x7f, 0x58,
|
||||
0x8d, 0x58, 0xa0, 0xbe, 0x82, 0x1f, 0x9e, 0xa3, 0xfd, 0x47, 0x51, 0x8d, 0xa2, 0x0b, 0x2d, 0xd7,
|
||||
0x87, 0x13, 0xce, 0x27, 0x56, 0xe0, 0x11, 0x67, 0x4f, 0x1f, 0xe4, 0xe1, 0xf7, 0x87, 0xbc, 0x82,
|
||||
0x58, 0x47, 0x2b, 0xae, 0xcf, 0x16, 0x52, 0xb0, 0x1d, 0x1a, 0x17, 0x03, 0x2f, 0x2f, 0xeb, 0x84,
|
||||
0xc6, 0x53, 0xb1, 0x93, 0x79, 0x40, 0xf0, 0xb7, 0x81, 0x1d, 0x9f, 0x87, 0xe4, 0x72, 0x6b, 0x89,
|
||||
0x0c, 0x32, 0x4f, 0xde, 0x02, 0xea, 0x85, 0x22, 0x05, 0x74, 0x35, 0xef, 0x56, 0x1e, 0xd5, 0xfe,
|
||||
0x2d, 0xf1, 0xd0, 0xa6, 0x36, 0xb3, 0xa1, 0x8e, 0x80, 0xf3, 0xce, 0xf4, 0xf5, 0x21, 0xbe, 0x8a,
|
||||
0x7f, 0xc0, 0xab, 0x87, 0x75, 0xb4, 0x10, 0xa1, 0x73, 0x00, 0x42, 0xc0, 0xb8, 0x10, 0x78, 0x39,
|
||||
0x51, 0x1a, 0x2e, 0x0a, 0x72, 0x31, 0x58, 0xdc, 0x1e, 0xcf, 0x05, 0xf0, 0xa2, 0x85, 0xb2, 0x08,
|
||||
0x4e, 0x20, 0x68, 0x05, 0x05, 0x43, 0x81, 0x02, 0xba, 0x92, 0x77, 0x30, 0x07, 0x6a, 0xae, 0xda,
|
||||
0xe7, 0x91, 0xe8, 0x70, 0x76, 0xa9, 0xb9, 0x83, 0xb7, 0x48, 0xd0, 0xd2, 0x75, 0x3e, 0x65, 0xb3,
|
||||
0x40, 0x3e, 0x06, 0xef, 0xd2, 0x57, 0x39, 0x94, 0x92, 0x2f, 0xc8, 0xbb, 0x1e, 0xd2, 0x45, 0x03,
|
||||
0xda, 0x37, 0x15, 0x75, 0x08, 0x07, 0xcc, 0x35, 0x83, 0xd6, 0x86, 0x87, 0xeb, 0x24, 0x4b, 0x86,
|
||||
0x36, 0xf5, 0xc7, 0xf9, 0x40, 0xae, 0x40, 0xc9, 0x05, 0x2a, 0xeb, 0x91, 0x46, 0x92, 0x47, 0xbc,
|
||||
0x92, 0x56, 0x27, 0x32, 0x50, 0x1c, 0xbe, 0x49, 0x31, 0x33, 0x9c, 0x98, 0x44, 0x52, 0x6b, 0x5a,
|
||||
0x53, 0x1d, 0x4a, 0x38, 0x30, 0xd7, 0x6c, 0x79, 0x30, 0xc5, 0xfc, 0x2c, 0xf6, 0xf5, 0xcb, 0x7c,
|
||||
0x00, 0x6e, 0x01, 0x91, 0x58, 0x65, 0xcd, 0x5d, 0xf1, 0x08, 0x8a, 0xf1, 0x4e, 0x68, 0x5c, 0x8e,
|
||||
0xa6, 0x50, 0x02, 0x56, 0x90, 0xb4, 0x8d, 0xb6, 0xad, 0x6a, 0x5b, 0x84, 0xb4, 0x4c, 0x46, 0x9a,
|
||||
0x2d, 0xd7, 0xc3, 0x9e, 0x4d, 0x7c, 0x73, 0x53, 0xbf, 0xc2, 0x5d, 0x7e, 0x05, 0x36, 0x02, 0xa0,
|
||||
0x6b, 0x19, 0x08, 0xee, 0x5e, 0xe3, 0xbd, 0x14, 0x01, 0xb1, 0x16, 0x7b, 0x51, 0x74, 0x75, 0xf2,
|
||||
0x45, 0x54, 0xb2, 0xa2, 0xed, 0xa9, 0xfd, 0x16, 0xb6, 0x36, 0x89, 0x69, 0x6f, 0x50, 0xd7, 0x23,
|
||||
0x75, 0xb3, 0x61, 0x3b, 0xc4, 0xd7, 0xaf, 0x72, 0x17, 0x17, 0xe0, 0x44, 0xe3, 0xf0, 0x42, 0x84,
|
||||
0xce, 0x03, 0x98, 0x0e, 0x74, 0x09, 0x29, 0xed, 0xc1, 0x74, 0x6f, 0xa1, 0xb2, 0x19, 0xed, 0xbb,
|
||||
0x8a, 0x7a, 0xb9, 0xe5, 0xb9, 0x1b, 0x50, 0xcc, 0x98, 0x41, 0xab, 0x8e, 0x19, 0x11, 0x0b, 0x84,
|
||||
0x27, 0xb8, 0xef, 0x6b, 0x90, 0xdf, 0x26, 0x5a, 0xeb, 0x5c, 0x49, 0x2c, 0x06, 0xa2, 0x22, 0xbb,
|
||||
0x0b, 0x2e, 0xd0, 0x79, 0x49, 0x18, 0x08, 0xe5, 0x25, 0xd4, 0xcd, 0xa2, 0xf6, 0x96, 0xa2, 0x0e,
|
||||
0x3a, 0x76, 0xd3, 0x66, 0x66, 0x0d, 0xd3, 0xfa, 0x8e, 0x5d, 0x67, 0x9b, 0xa6, 0x4d, 0x4d, 0x07,
|
||||
0x53, 0x7d, 0x98, 0x0f, 0xc9, 0x12, 0x2f, 0x1e, 0x41, 0x63, 0x26, 0x51, 0x58, 0xa0, 0x8b, 0x98,
|
||||
0x66, 0x05, 0x7f, 0x19, 0xfb, 0x98, 0x61, 0x91, 0x99, 0xd2, 0xde, 0x54, 0x54, 0xad, 0x69, 0x53,
|
||||
0x73, 0xd3, 0x6d, 0x12, 0xb3, 0x6e, 0xfb, 0x5b, 0x66, 0xc3, 0x23, 0x44, 0x37, 0x46, 0x94, 0xd1,
|
||||
0x73, 0x93, 0x3d, 0x37, 0xa2, 0x9b, 0xb5, 0x1b, 0xab, 0xf6, 0xeb, 0x64, 0xe6, 0xe5, 0xf7, 0x43,
|
||||
0xe3, 0x04, 0xec, 0xc4, 0xa6, 0x4d, 0x5f, 0x71, 0x9b, 0x64, 0xce, 0xf6, 0xb7, 0xe6, 0x3d, 0x42,
|
||||
0xd2, 0xd5, 0x51, 0x90, 0x8b, 0xfb, 0x60, 0xe4, 0x3a, 0x10, 0x39, 0x35, 0x31, 0x72, 0x1d, 0x15,
|
||||
0x9b, 0x6b, 0xf7, 0x15, 0xb5, 0x27, 0x59, 0xef, 0xfc, 0xd8, 0x19, 0xe1, 0xc7, 0xce, 0x9f, 0x79,
|
||||
0xca, 0x93, 0x2c, 0xda, 0xe8, 0xf0, 0x39, 0xe7, 0x65, 0x9f, 0x9d, 0xd0, 0x98, 0x4b, 0x2a, 0x8e,
|
||||
0x44, 0x26, 0x39, 0x88, 0xe2, 0x1d, 0xe0, 0x17, 0xce, 0x94, 0x26, 0x61, 0xf8, 0xc6, 0x97, 0x7c,
|
||||
0x97, 0x42, 0xec, 0xce, 0x99, 0xcd, 0x7f, 0x1e, 0x1f, 0x54, 0x47, 0x1f, 0xd6, 0x14, 0xe4, 0x47,
|
||||
0x02, 0x5f, 0x94, 0xd9, 0xf1, 0x1c, 0xed, 0x55, 0xb5, 0x0f, 0x3b, 0x3b, 0x50, 0x7d, 0x45, 0xb7,
|
||||
0x09, 0x94, 0x30, 0x5f, 0x7f, 0x92, 0x5f, 0xe2, 0x41, 0xd1, 0x7b, 0x21, 0x02, 0x79, 0x55, 0xbe,
|
||||
0x4c, 0x18, 0x2c, 0xfc, 0x81, 0x28, 0xc2, 0xe4, 0xe4, 0x15, 0x54, 0x54, 0xd4, 0xfe, 0xa7, 0xa8,
|
||||
0xa3, 0xee, 0x36, 0xf1, 0x76, 0x3c, 0x9b, 0x41, 0xe0, 0x68, 0xba, 0x8c, 0x98, 0x75, 0xb2, 0x6d,
|
||||
0x5b, 0xc4, 0xa4, 0xb8, 0x49, 0x7c, 0x08, 0xa7, 0x71, 0x21, 0xa4, 0x57, 0xb2, 0xeb, 0xa5, 0xa1,
|
||||
0xbb, 0x49, 0x23, 0xc4, 0xdb, 0xcc, 0x91, 0xed, 0x65, 0x50, 0x6f, 0x87, 0xc6, 0x35, 0xb7, 0x04,
|
||||
0xd9, 0x16, 0xe1, 0xe8, 0x5d, 0x3a, 0x1b, 0x99, 0xea, 0x84, 0xc6, 0x27, 0x39, 0xc1, 0x87, 0xd0,
|
||||
0xed, 0xbe, 0x28, 0xa1, 0x8a, 0xeb, 0xc2, 0x03, 0x3d, 0x0c, 0x0b, 0xed, 0xab, 0xea, 0x25, 0x08,
|
||||
0x63, 0xa6, 0x4d, 0xeb, 0x64, 0xd7, 0x84, 0x95, 0x5c, 0x73, 0x5c, 0x6b, 0xcb, 0xd7, 0xaf, 0xf1,
|
||||
0x2d, 0x0d, 0x8b, 0x46, 0x03, 0x85, 0x05, 0xc0, 0x97, 0x6c, 0x3a, 0xc3, 0xd1, 0xf4, 0xd6, 0xb6,
|
||||
0x0c, 0x49, 0x33, 0xe5, 0x28, 0xff, 0x45, 0x12, 0x4b, 0xda, 0xbf, 0x20, 0xdd, 0xa5, 0xd8, 0xda,
|
||||
0x22, 0x75, 0x93, 0xba, 0xcc, 0x6e, 0xd8, 0x16, 0x8e, 0xee, 0x1f, 0xea, 0xbe, 0x5e, 0xe5, 0xf3,
|
||||
0xfb, 0x36, 0x0c, 0xf7, 0xe0, 0x7a, 0xa4, 0xb4, 0x2c, 0xe8, 0x2c, 0xcc, 0xc1, 0x68, 0x0f, 0x06,
|
||||
0x52, 0xa4, 0x13, 0x1a, 0x57, 0xa2, 0xd0, 0x2e, 0x83, 0xf9, 0x5d, 0xa5, 0x14, 0xe9, 0x1c, 0x54,
|
||||
0xbb, 0x58, 0xdc, 0x3f, 0xac, 0x76, 0x61, 0x81, 0xa4, 0x2d, 0xea, 0xbe, 0x86, 0xd4, 0xf3, 0xcc,
|
||||
0xc3, 0x8d, 0x86, 0x6d, 0x99, 0x96, 0x83, 0x7d, 0x5f, 0xbf, 0xce, 0x87, 0xf5, 0x05, 0xa8, 0x97,
|
||||
0x63, 0x60, 0x16, 0xe4, 0x9d, 0xd0, 0xd0, 0xa2, 0x01, 0x15, 0x84, 0xe9, 0x45, 0x4d, 0x4e, 0x55,
|
||||
0xbb, 0xa7, 0xf6, 0xc7, 0x43, 0x6c, 0x36, 0x5c, 0xa7, 0x4e, 0x3c, 0xb3, 0x85, 0xd9, 0xa6, 0xfe,
|
||||
0x14, 0xdf, 0xf5, 0xd3, 0x70, 0x0c, 0xc4, 0xf0, 0x3c, 0x47, 0x57, 0x30, 0xdb, 0x4c, 0x43, 0x4c,
|
||||
0x09, 0x11, 0xa6, 0xeb, 0x0d, 0x58, 0x56, 0xca, 0x1b, 0xa8, 0xdc, 0x5c, 0xdb, 0x52, 0x2f, 0xfa,
|
||||
0x84, 0x99, 0x8e, 0xbb, 0x63, 0xb6, 0x3c, 0xdb, 0xf5, 0x6c, 0xb6, 0xa7, 0x3f, 0xcd, 0xb7, 0x02,
|
||||
0xf4, 0xd7, 0xeb, 0x13, 0xb6, 0xe8, 0xee, 0xac, 0xc4, 0x48, 0xda, 0x59, 0x5e, 0xdc, 0x35, 0xb1,
|
||||
0x28, 0x34, 0xd7, 0xde, 0x51, 0xd4, 0xc1, 0x26, 0xde, 0x4d, 0x9c, 0xb3, 0x5c, 0x6a, 0x05, 0x9e,
|
||||
0x47, 0xa8, 0xb5, 0xa7, 0x8f, 0xf2, 0xd1, 0xf3, 0xf9, 0x15, 0x0b, 0xde, 0x59, 0xc2, 0xbb, 0x11,
|
||||
0xc7, 0xd9, 0x4c, 0x05, 0x0e, 0xfa, 0xa6, 0x44, 0x9e, 0x1e, 0xf4, 0x32, 0x30, 0x19, 0x68, 0x7e,
|
||||
0x27, 0x22, 0xb7, 0x8b, 0xa4, 0x56, 0xb5, 0x0f, 0x14, 0xb5, 0xdf, 0xf2, 0xb0, 0xbf, 0x59, 0xc8,
|
||||
0xfc, 0x9f, 0xe1, 0x93, 0xf1, 0x2e, 0xcf, 0xfc, 0x67, 0x93, 0xcc, 0xdf, 0x8a, 0x33, 0xff, 0xf9,
|
||||
0xe8, 0x44, 0x86, 0x66, 0x59, 0x0e, 0x2e, 0x0d, 0xbe, 0x5c, 0xa7, 0x9c, 0xcd, 0x73, 0x31, 0xac,
|
||||
0xe0, 0xbe, 0x92, 0x11, 0xa8, 0x09, 0xac, 0xb8, 0x26, 0xa8, 0x3e, 0x8c, 0x19, 0xa8, 0x0a, 0x66,
|
||||
0xa3, 0xaa, 0xa0, 0x60, 0xcc, 0x73, 0xb4, 0x9f, 0x29, 0xea, 0x50, 0xd1, 0xbd, 0xe4, 0x32, 0xe6,
|
||||
0x59, 0x3e, 0xff, 0xf6, 0x51, 0x68, 0x9c, 0x9d, 0x45, 0xc2, 0x3b, 0x42, 0xde, 0x4a, 0xf1, 0x1d,
|
||||
0x41, 0x8a, 0x76, 0x5b, 0x1a, 0xfb, 0x87, 0xd5, 0xcc, 0x36, 0x92, 0x5b, 0xd6, 0xbe, 0xae, 0xa8,
|
||||
0x83, 0x3e, 0x0b, 0xa8, 0x09, 0xf9, 0x12, 0x76, 0xec, 0x6d, 0x62, 0x46, 0x59, 0xb0, 0xaf, 0x3f,
|
||||
0x97, 0x66, 0xa1, 0xfd, 0xa0, 0x71, 0x27, 0x51, 0x58, 0x05, 0x7c, 0x35, 0xcd, 0x8d, 0x24, 0x58,
|
||||
0x3e, 0x85, 0x17, 0xc2, 0xd8, 0xa9, 0x89, 0xdb, 0xe3, 0x48, 0x66, 0x0d, 0x2a, 0xe3, 0x02, 0x0d,
|
||||
0x88, 0xa6, 0xbe, 0xfe, 0x3c, 0x27, 0xf1, 0x39, 0xd8, 0x97, 0xb9, 0x66, 0x4b, 0x36, 0xcd, 0x2a,
|
||||
0x88, 0x12, 0x22, 0x66, 0x86, 0xb9, 0x30, 0x3a, 0x39, 0x8e, 0xca, 0x76, 0x20, 0x17, 0xef, 0xe1,
|
||||
0xbd, 0x27, 0xcf, 0x5b, 0x2f, 0xf0, 0xc8, 0x59, 0x3f, 0x0a, 0x8d, 0x5e, 0x84, 0x77, 0x56, 0x59,
|
||||
0x20, 0x3c, 0x6c, 0x9d, 0xf3, 0xb3, 0xcf, 0xf4, 0x0a, 0x2a, 0x93, 0x3d, 0xf0, 0xf1, 0xad, 0x60,
|
||||
0x11, 0x89, 0xf6, 0xb4, 0x6d, 0xf5, 0x02, 0x14, 0x9b, 0x35, 0xec, 0x13, 0x33, 0x7a, 0x69, 0xd4,
|
||||
0x6f, 0x8c, 0x28, 0xa3, 0xbd, 0x93, 0xbd, 0x49, 0x32, 0xb4, 0xc6, 0xa5, 0xfc, 0xce, 0xb0, 0x37,
|
||||
0x51, 0x8d, 0x64, 0x59, 0x98, 0xca, 0x89, 0x2b, 0x23, 0x71, 0xe9, 0x11, 0x2f, 0x8f, 0x37, 0x0f,
|
||||
0xab, 0x0a, 0x2a, 0x34, 0xd5, 0xbe, 0x77, 0x52, 0xbd, 0x06, 0x51, 0x23, 0x0d, 0x17, 0x50, 0xba,
|
||||
0x5a, 0x6e, 0x13, 0x96, 0xac, 0x47, 0xee, 0x05, 0xc4, 0x67, 0xe6, 0x96, 0x5d, 0xd3, 0xc7, 0xf8,
|
||||
0x74, 0xfc, 0x4d, 0x89, 0x5f, 0x28, 0x97, 0xf0, 0xee, 0xec, 0x02, 0x8a, 0xf0, 0x3b, 0xf6, 0x4c,
|
||||
0x3b, 0x34, 0x8c, 0x26, 0xde, 0x4d, 0xb7, 0x38, 0x5b, 0x88, 0x6d, 0x64, 0x2a, 0xe9, 0xd9, 0xf7,
|
||||
0x00, 0x3d, 0xa1, 0xec, 0x7b, 0xa0, 0xc9, 0x07, 0xab, 0xc4, 0x6f, 0x9e, 0x05, 0xba, 0xe8, 0x01,
|
||||
0xcd, 0x6a, 0xda, 0x47, 0x8a, 0x3a, 0x98, 0x3e, 0xbc, 0x38, 0x58, 0x7c, 0xaa, 0x1d, 0xe7, 0x1b,
|
||||
0xf8, 0x3d, 0x18, 0x89, 0x81, 0xe4, 0xe1, 0x62, 0x71, 0x7a, 0x59, 0x7c, 0xad, 0x1d, 0xc0, 0x12,
|
||||
0x79, 0x9a, 0x3e, 0xcb, 0x40, 0xd9, 0x7b, 0x99, 0xd4, 0x48, 0x17, 0xb9, 0xb0, 0xf5, 0xa5, 0xa4,
|
||||
0x50, 0xd6, 0x0a, 0x0b, 0x4f, 0xbd, 0xdb, 0xea, 0x65, 0xfe, 0xb6, 0xd2, 0x08, 0x1c, 0x27, 0xce,
|
||||
0x65, 0x5c, 0x9a, 0x14, 0xa6, 0xfa, 0x04, 0xf7, 0x74, 0x0a, 0x72, 0x05, 0xd0, 0x9a, 0x0f, 0x1c,
|
||||
0x87, 0x67, 0x21, 0x77, 0x69, 0x5c, 0x4a, 0x76, 0x42, 0xe3, 0x6a, 0x7c, 0x64, 0xc9, 0xe0, 0x0a,
|
||||
0xea, 0xd2, 0x4e, 0xfb, 0x8a, 0xda, 0x13, 0xb4, 0x68, 0x2b, 0x0d, 0x8a, 0xbf, 0x9a, 0xe7, 0x5d,
|
||||
0x7d, 0xfe, 0x28, 0x34, 0x2e, 0xcd, 0x91, 0x96, 0x47, 0x2c, 0xcc, 0x48, 0x7d, 0x7d, 0x85, 0xae,
|
||||
0x64, 0x11, 0x52, 0x79, 0x21, 0x4b, 0x4d, 0x5a, 0xb4, 0x15, 0x03, 0xcf, 0xbb, 0x4d, 0x1b, 0xd2,
|
||||
0x23, 0xb6, 0x57, 0xd9, 0x3f, 0xac, 0xca, 0x1b, 0xeb, 0x0a, 0x3a, 0x27, 0x34, 0xd1, 0x7e, 0xa1,
|
||||
0xc4, 0xdd, 0x27, 0x17, 0xcf, 0xef, 0xcc, 0xf3, 0xd5, 0xfd, 0x26, 0x9f, 0xd3, 0xbc, 0x89, 0xf4,
|
||||
0x12, 0x9a, 0x77, 0x3f, 0x92, 0x76, 0x2f, 0x5e, 0x1e, 0x0b, 0x1c, 0xb2, 0xc5, 0x7b, 0xb9, 0xbb,
|
||||
0x16, 0x4c, 0x92, 0xac, 0x17, 0x5d, 0x41, 0x6a, 0xd6, 0x4a, 0xfb, 0x9d, 0xa2, 0xf6, 0x72, 0x9a,
|
||||
0xd9, 0x15, 0xf3, 0xaf, 0x23, 0xa2, 0xdf, 0xe2, 0x99, 0x5d, 0xde, 0x84, 0x70, 0xdd, 0xcc, 0xa9,
|
||||
0x56, 0x52, 0xaa, 0xf9, 0x0b, 0x62, 0x29, 0xd9, 0xab, 0x1f, 0xa7, 0x07, 0xf9, 0x9b, 0xbc, 0x2f,
|
||||
0x5d, 0x41, 0x3d, 0x62, 0xcb, 0x8c, 0x72, 0x76, 0x91, 0xfc, 0x6e, 0x77, 0xca, 0xc2, 0xa5, 0x72,
|
||||
0x81, 0x72, 0xfe, 0x1a, 0xb8, 0x3b, 0xe5, 0x6e, 0x7a, 0x65, 0xca, 0x89, 0x66, 0x42, 0x39, 0xbd,
|
||||
0x37, 0x6e, 0xa8, 0xd1, 0x83, 0x55, 0x7a, 0x04, 0xfc, 0x66, 0x9e, 0x9f, 0x01, 0x9f, 0xc9, 0xf3,
|
||||
0xe5, 0x6f, 0x3e, 0xd9, 0x59, 0x20, 0x2c, 0x46, 0x2f, 0x43, 0x04, 0xa2, 0xd0, 0x8f, 0x80, 0xf8,
|
||||
0xbc, 0xec, 0x2e, 0x57, 0xbc, 0x66, 0xcb, 0x62, 0xfa, 0x7b, 0x30, 0x44, 0xca, 0xcc, 0xd2, 0x51,
|
||||
0x68, 0x5c, 0xcd, 0x7a, 0x5c, 0xca, 0xd7, 0xab, 0x2b, 0x16, 0xcb, 0x8f, 0x53, 0xb3, 0x84, 0xe7,
|
||||
0xbb, 0xd7, 0xca, 0x0a, 0x70, 0xde, 0x0d, 0x14, 0xa2, 0xbd, 0x6f, 0x61, 0xea, 0xeb, 0xbf, 0x8d,
|
||||
0x66, 0x69, 0xad, 0x40, 0x41, 0x8c, 0x92, 0xab, 0xa0, 0x58, 0xa0, 0x50, 0xc2, 0xcb, 0x53, 0xc5,
|
||||
0x99, 0x94, 0xf4, 0x66, 0xee, 0xbc, 0xff, 0xe1, 0xf0, 0x89, 0xc3, 0x0f, 0x87, 0x4f, 0xbc, 0x7f,
|
||||
0x34, 0xac, 0x1c, 0x1e, 0x0d, 0x2b, 0xdf, 0xb9, 0x3f, 0x7c, 0xe2, 0xed, 0xfb, 0xc3, 0xca, 0xe1,
|
||||
0xfd, 0xe1, 0x13, 0xff, 0xbc, 0x3f, 0x7c, 0xe2, 0xb5, 0x67, 0x36, 0x6c, 0xb6, 0x19, 0xd4, 0x6e,
|
||||
0x58, 0x6e, 0x73, 0x2c, 0xcd, 0xc1, 0x84, 0x5f, 0xd9, 0x3f, 0x70, 0x6a, 0x67, 0xf8, 0x5f, 0x6e,
|
||||
0x6e, 0xfe, 0x3f, 0x00, 0x00, 0xff, 0xff, 0x2e, 0x99, 0xf4, 0x6a, 0xde, 0x23, 0x00, 0x00,
|
||||
0xf9, 0xcf, 0x26, 0x4d, 0xda, 0x6c, 0x1c, 0x27, 0x5e, 0x3b, 0xf6, 0x36, 0x49, 0xbd, 0xee, 0xc9,
|
||||
0x49, 0xeb, 0xde, 0xe2, 0x4b, 0xda, 0xfc, 0xf3, 0xb7, 0x84, 0xc0, 0x97, 0x9a, 0xba, 0xb1, 0x1d,
|
||||
0x6b, 0x6c, 0xab, 0xa8, 0x08, 0xad, 0xe6, 0xec, 0x99, 0x63, 0x2f, 0xde, 0x33, 0x7b, 0xb2, 0x3b,
|
||||
0xeb, 0x4b, 0x41, 0xa5, 0x2a, 0xe2, 0xf2, 0x06, 0x58, 0x5c, 0x24, 0x90, 0x50, 0x11, 0x20, 0x51,
|
||||
0x4a, 0x11, 0x12, 0x12, 0x12, 0xbc, 0x80, 0x90, 0x90, 0x2a, 0x78, 0xb0, 0x1f, 0x91, 0x28, 0x8b,
|
||||
0xea, 0xf4, 0x01, 0x9d, 0x07, 0x1e, 0xce, 0xa3, 0x79, 0x41, 0xdf, 0xec, 0x6d, 0x76, 0x77, 0x4e,
|
||||
0x93, 0xb7, 0xb3, 0xdf, 0xef, 0x9b, 0x6f, 0x7e, 0xdf, 0x5c, 0xbe, 0xf9, 0xbe, 0x99, 0xa3, 0x5e,
|
||||
0x77, 0xec, 0xda, 0x98, 0xe5, 0xd2, 0x86, 0xbd, 0x31, 0xe6, 0xb6, 0x98, 0xed, 0x52, 0x3f, 0xfa,
|
||||
0x0a, 0x3c, 0x0c, 0x5f, 0x37, 0x5a, 0x9e, 0xcb, 0x5c, 0xed, 0x4c, 0x24, 0xbc, 0x3c, 0x24, 0xa8,
|
||||
0xb3, 0x80, 0xda, 0x74, 0x23, 0x52, 0xb8, 0x7c, 0x49, 0x00, 0x7c, 0xfb, 0x0d, 0x12, 0x8b, 0xcf,
|
||||
0x92, 0x5d, 0x16, 0xfd, 0xac, 0xfc, 0x7b, 0x5e, 0x1d, 0xb8, 0x1b, 0xf5, 0x30, 0x2b, 0xf6, 0xa0,
|
||||
0xfd, 0x58, 0x51, 0x2f, 0x3a, 0xb6, 0xcf, 0x08, 0x35, 0x71, 0xbd, 0xee, 0x11, 0xdf, 0x27, 0xbe,
|
||||
0xae, 0x8c, 0x9c, 0x1a, 0x3d, 0x3b, 0xe3, 0x1f, 0x85, 0x86, 0x86, 0xf0, 0xce, 0x22, 0x87, 0xa7,
|
||||
0x13, 0xb4, 0x1d, 0x1a, 0x17, 0x9c, 0xbc, 0xa8, 0x13, 0x1a, 0xd7, 0x77, 0x9b, 0xce, 0x54, 0x25,
|
||||
0x27, 0xaf, 0x8c, 0xd4, 0x49, 0x03, 0x07, 0x0e, 0x9b, 0xaa, 0xc4, 0x3f, 0x2a, 0xc7, 0x07, 0xd5,
|
||||
0x47, 0xe3, 0xdf, 0xfb, 0x87, 0x55, 0x89, 0x71, 0x54, 0x34, 0xad, 0xfd, 0x47, 0x51, 0xf5, 0x0d,
|
||||
0xc7, 0xad, 0x61, 0xc7, 0xac, 0xdb, 0xbe, 0xe5, 0x6e, 0x13, 0x6f, 0xcf, 0xf4, 0x89, 0xb7, 0x4d,
|
||||
0x3c, 0x5f, 0x3f, 0xc9, 0x89, 0xfe, 0x56, 0x39, 0x0a, 0x8d, 0x7e, 0x84, 0x77, 0x3e, 0xcb, 0xf5,
|
||||
0xa6, 0x29, 0x5d, 0x8d, 0xf0, 0x76, 0x68, 0x5c, 0xda, 0x48, 0x64, 0x6e, 0x40, 0x2d, 0x12, 0x03,
|
||||
0x9d, 0xd0, 0x78, 0x9e, 0x13, 0x96, 0xa1, 0x12, 0xde, 0xed, 0x83, 0xea, 0x80, 0x4c, 0xb5, 0x73,
|
||||
0x50, 0x95, 0x77, 0x90, 0x77, 0x54, 0xc6, 0x0d, 0x0d, 0x46, 0x0d, 0xe7, 0x12, 0xa7, 0x62, 0xb9,
|
||||
0xf6, 0xb1, 0xcc, 0x61, 0x42, 0x71, 0xcd, 0x21, 0x75, 0xfd, 0xd4, 0x88, 0x32, 0xfa, 0xd8, 0xcc,
|
||||
0xbb, 0xe0, 0xf0, 0xc5, 0xd4, 0xe2, 0xcb, 0x11, 0x58, 0xf6, 0x36, 0x06, 0x3a, 0xa1, 0xf1, 0xac,
|
||||
0xc4, 0xdb, 0x18, 0x15, 0xdc, 0x65, 0x5e, 0x40, 0xc0, 0xd7, 0x2e, 0x66, 0xba, 0x01, 0xc7, 0x07,
|
||||
0xd5, 0x47, 0xa0, 0xe9, 0xfe, 0x61, 0xb5, 0x44, 0xaa, 0xe4, 0x66, 0x2c, 0xd7, 0x3e, 0x54, 0xd4,
|
||||
0x21, 0xc7, 0xb5, 0xa4, 0x5e, 0x3e, 0xc2, 0xbd, 0xfc, 0x29, 0x78, 0x79, 0x61, 0x11, 0x74, 0x72,
|
||||
0x4e, 0x0e, 0x38, 0xb1, 0xa8, 0xe0, 0xe3, 0x33, 0xd1, 0x12, 0x94, 0x80, 0x12, 0x17, 0xe5, 0x46,
|
||||
0xba, 0xc8, 0x05, 0x07, 0x8b, 0x7c, 0xd0, 0x25, 0xde, 0xa0, 0xe4, 0xde, 0xdf, 0x14, 0xb5, 0x3f,
|
||||
0x72, 0x0f, 0xc7, 0xb6, 0xcc, 0x96, 0xeb, 0x31, 0xfd, 0xf4, 0x88, 0x32, 0x7a, 0x7a, 0xe6, 0x87,
|
||||
0xe0, 0x5a, 0x4f, 0x62, 0x6a, 0xc5, 0xf5, 0x58, 0x3b, 0x34, 0xfa, 0x72, 0x5d, 0x83, 0xb0, 0x13,
|
||||
0x1a, 0x4f, 0x97, 0x9d, 0x02, 0x44, 0xf0, 0x68, 0x72, 0x62, 0x7c, 0xf2, 0xff, 0x2a, 0xc7, 0xa1,
|
||||
0x71, 0xca, 0xa6, 0xac, 0x7d, 0x50, 0x95, 0x98, 0x91, 0x09, 0x8f, 0x0f, 0xaa, 0xa7, 0x79, 0xd3,
|
||||
0xfd, 0xc3, 0x6a, 0x8e, 0x09, 0x2a, 0xeb, 0x6a, 0x5f, 0x3d, 0xa9, 0x8e, 0x14, 0xbc, 0x69, 0x06,
|
||||
0x0e, 0xb3, 0x2d, 0xec, 0xb3, 0x24, 0x6e, 0xe8, 0x67, 0x46, 0x94, 0xd1, 0xb3, 0x33, 0xbf, 0x07,
|
||||
0xd7, 0x7a, 0x13, 0x83, 0x4b, 0xb3, 0xb0, 0x93, 0xdb, 0xa1, 0xd1, 0x9f, 0x33, 0x1a, 0x89, 0x3b,
|
||||
0xa1, 0x71, 0xab, 0xec, 0x5e, 0x84, 0x09, 0x0e, 0x7e, 0xbe, 0xd1, 0x98, 0x98, 0x9c, 0x9a, 0xba,
|
||||
0x7d, 0xf3, 0xf6, 0x8b, 0x5f, 0x98, 0x8a, 0xbc, 0x6d, 0x1f, 0x54, 0xa5, 0x06, 0xe5, 0xe2, 0xe3,
|
||||
0x83, 0xaa, 0x56, 0x36, 0xb2, 0x7f, 0x58, 0x2d, 0xd0, 0x44, 0x4f, 0xe4, 0x1b, 0x27, 0x1e, 0xc6,
|
||||
0xc1, 0x48, 0xbb, 0xab, 0x9e, 0x6f, 0xe2, 0x5d, 0xd3, 0x27, 0xb4, 0x6e, 0x6e, 0xd5, 0x5a, 0xbe,
|
||||
0xfe, 0x28, 0x9f, 0xcc, 0xe7, 0xda, 0xa1, 0x71, 0xae, 0x89, 0x77, 0x57, 0x09, 0xad, 0xdf, 0xa9,
|
||||
0xb5, 0x20, 0xb8, 0xf4, 0x71, 0xb7, 0x04, 0x59, 0x32, 0x3f, 0x48, 0x54, 0x4c, 0x0c, 0x7a, 0xc4,
|
||||
0xda, 0x8e, 0x0c, 0x3e, 0x96, 0x33, 0x88, 0x88, 0xb5, 0x5d, 0x34, 0x98, 0xc8, 0x72, 0x06, 0x13,
|
||||
0xa1, 0xf6, 0x3b, 0x45, 0x1d, 0xf2, 0x88, 0xe5, 0x52, 0x4a, 0x2c, 0x08, 0xef, 0xa6, 0x4d, 0x19,
|
||||
0xf1, 0xb6, 0xb1, 0x63, 0xfa, 0xfa, 0x59, 0x6e, 0xfb, 0x4d, 0x1e, 0xd4, 0x13, 0x95, 0x85, 0x18,
|
||||
0x5e, 0x85, 0xd8, 0x21, 0x36, 0x4c, 0x81, 0x4e, 0x68, 0x8c, 0xf2, 0xbe, 0xa5, 0xa8, 0x30, 0x4b,
|
||||
0xb7, 0xc6, 0x13, 0x4a, 0xc7, 0x07, 0xd5, 0x93, 0xb7, 0xc6, 0x79, 0x7c, 0x2f, 0xf5, 0x83, 0xe4,
|
||||
0xbd, 0x68, 0x0d, 0xb5, 0xd7, 0x23, 0x0e, 0xde, 0xf3, 0xd3, 0x18, 0xa0, 0xf2, 0x18, 0xf0, 0xe9,
|
||||
0x76, 0x68, 0x9c, 0x8f, 0x90, 0x6c, 0xa3, 0x57, 0x62, 0x42, 0x82, 0xb4, 0xb8, 0xc3, 0x93, 0x1d,
|
||||
0x8b, 0xf2, 0x8d, 0xb5, 0xb7, 0x4f, 0xaa, 0x57, 0xe2, 0x8e, 0x52, 0x22, 0xd9, 0x20, 0x35, 0xf5,
|
||||
0x73, 0x7c, 0x90, 0xfe, 0x0c, 0x6b, 0x78, 0x08, 0x81, 0x5e, 0xc9, 0x85, 0xa5, 0x76, 0x68, 0x0c,
|
||||
0x79, 0x72, 0x28, 0x0d, 0xb4, 0x5d, 0x70, 0x81, 0xe5, 0xc4, 0xb8, 0xb0, 0x65, 0xbb, 0xda, 0xeb,
|
||||
0x0e, 0xc1, 0x20, 0x4f, 0xc0, 0x20, 0x77, 0xa3, 0x89, 0xf4, 0xc8, 0xcf, 0x32, 0xa2, 0xd5, 0xd4,
|
||||
0xf3, 0x3e, 0xc3, 0x1e, 0x33, 0x6b, 0x9e, 0xbb, 0xe3, 0x13, 0x4f, 0xef, 0xe1, 0x63, 0xfd, 0xa9,
|
||||
0x76, 0x68, 0xf4, 0x70, 0x60, 0x26, 0x92, 0x77, 0x42, 0xe3, 0x49, 0xee, 0x8e, 0x28, 0xec, 0x3a,
|
||||
0xd2, 0xb9, 0xa6, 0xda, 0xcf, 0x15, 0xf5, 0x12, 0xc5, 0xcc, 0x64, 0x1e, 0x86, 0x53, 0x0d, 0x3b,
|
||||
0xe9, 0xc4, 0xf6, 0xf2, 0xce, 0xee, 0x1d, 0x85, 0x86, 0xba, 0x3c, 0xbd, 0x96, 0x85, 0x75, 0x95,
|
||||
0x62, 0x96, 0xcd, 0xb1, 0xc1, 0x3b, 0xce, 0x44, 0x92, 0x10, 0x2e, 0x36, 0xc8, 0x7d, 0x09, 0xe1,
|
||||
0x5a, 0xe8, 0x02, 0xf5, 0x53, 0xcc, 0xd6, 0x12, 0x3a, 0xc9, 0x82, 0xf8, 0x43, 0x89, 0xa7, 0x43,
|
||||
0xb0, 0x4f, 0xcc, 0xa6, 0x7e, 0x81, 0x2f, 0x85, 0xaf, 0xc3, 0x52, 0x38, 0xbb, 0x3c, 0xbd, 0xb6,
|
||||
0x08, 0x62, 0x98, 0xfc, 0x0b, 0x14, 0xb3, 0xe8, 0xc3, 0xa6, 0x01, 0xe3, 0xc9, 0x4f, 0x25, 0x21,
|
||||
0x2b, 0xca, 0xa5, 0x7b, 0xa3, 0x7d, 0x50, 0x2d, 0xb5, 0x2f, 0x8b, 0xd2, 0x1d, 0x94, 0x75, 0x8c,
|
||||
0x34, 0x91, 0x7d, 0x24, 0xd3, 0xfe, 0xaa, 0xa8, 0x43, 0x79, 0xf2, 0x1e, 0xa1, 0x64, 0x87, 0xaf,
|
||||
0xe4, 0x8b, 0x9c, 0xfe, 0x3e, 0xd0, 0x3f, 0xb7, 0x3c, 0xbd, 0x86, 0x22, 0x00, 0x1c, 0xe8, 0xa3,
|
||||
0x98, 0x25, 0x9f, 0xa9, 0x0b, 0xd5, 0xc4, 0x85, 0x3c, 0x22, 0x38, 0x71, 0x53, 0x74, 0x42, 0x62,
|
||||
0x43, 0x26, 0x04, 0x47, 0x6e, 0x82, 0x23, 0x22, 0x05, 0x34, 0x20, 0xba, 0x92, 0x48, 0x25, 0xce,
|
||||
0x30, 0xbb, 0x49, 0xdc, 0x80, 0x99, 0xbe, 0xde, 0x97, 0x77, 0x66, 0x2d, 0x02, 0x56, 0x63, 0x67,
|
||||
0x92, 0x4f, 0x58, 0xe9, 0xf5, 0x9c, 0x33, 0x79, 0xa4, 0xdb, 0xf6, 0x93, 0xd8, 0x90, 0x09, 0xd3,
|
||||
0x2d, 0x27, 0x52, 0xc8, 0x3b, 0x93, 0x48, 0xb5, 0x1f, 0x29, 0xaa, 0x1e, 0xf8, 0x78, 0x83, 0x98,
|
||||
0x1e, 0x81, 0x73, 0xdf, 0xa6, 0x1b, 0x26, 0xb6, 0x2c, 0xd2, 0x62, 0xa4, 0xae, 0x6b, 0xdc, 0x1b,
|
||||
0x0c, 0x3b, 0x60, 0x1d, 0x4d, 0xc7, 0x52, 0xd8, 0x01, 0x81, 0x97, 0x7c, 0x75, 0x42, 0xe3, 0x22,
|
||||
0x77, 0x22, 0x13, 0x09, 0x84, 0x45, 0xc5, 0xdc, 0x17, 0xac, 0xf8, 0xcc, 0x24, 0x1a, 0xe4, 0x14,
|
||||
0x50, 0xc2, 0x20, 0x91, 0x6b, 0x5f, 0x52, 0x07, 0x8a, 0xe4, 0x7c, 0x42, 0xa8, 0xde, 0xcf, 0x89,
|
||||
0x2d, 0x1c, 0x85, 0xc6, 0x99, 0x75, 0xb4, 0x4a, 0x08, 0x6d, 0x87, 0xc6, 0x99, 0xc0, 0x83, 0x5f,
|
||||
0x9d, 0xd0, 0xe8, 0x89, 0x09, 0xc1, 0xa7, 0x40, 0x26, 0x51, 0x48, 0x7f, 0xed, 0x1f, 0x56, 0xe3,
|
||||
0xe6, 0x48, 0xcb, 0x13, 0x00, 0x99, 0xf6, 0x3d, 0x45, 0x7d, 0xbc, 0xd8, 0x7b, 0x40, 0xed, 0x7b,
|
||||
0x01, 0x31, 0xed, 0xba, 0x3e, 0xc0, 0x93, 0x88, 0xd7, 0xa3, 0xb1, 0x59, 0xe7, 0xe2, 0x85, 0xb9,
|
||||
0x68, 0x6c, 0xe2, 0x2f, 0x71, 0x6c, 0x12, 0x85, 0x4a, 0x34, 0x28, 0xc9, 0x67, 0x47, 0xfc, 0x8a,
|
||||
0x07, 0x25, 0xc1, 0x8a, 0x83, 0x92, 0x68, 0x69, 0x7f, 0x52, 0xd4, 0xfe, 0x12, 0x2f, 0xcf, 0xd1,
|
||||
0x2f, 0x71, 0x46, 0xdf, 0x82, 0xb5, 0x77, 0x7a, 0x1d, 0xad, 0xa3, 0xc5, 0x76, 0x68, 0x9c, 0x0e,
|
||||
0xbc, 0x75, 0xb4, 0xd8, 0x09, 0x8d, 0xdb, 0x09, 0x11, 0xb4, 0x28, 0xac, 0xae, 0x4d, 0xc6, 0x5a,
|
||||
0xfe, 0xd4, 0xd8, 0x58, 0x1d, 0x33, 0x7c, 0xc3, 0xdf, 0xa3, 0x16, 0xdb, 0x84, 0x62, 0x8d, 0x12,
|
||||
0x36, 0x46, 0xc9, 0x0e, 0x48, 0x81, 0x70, 0x6c, 0x24, 0xf9, 0x71, 0x7c, 0x50, 0x7d, 0x88, 0x86,
|
||||
0xfb, 0x87, 0xd5, 0x88, 0x05, 0xea, 0x2b, 0xf8, 0xe1, 0x39, 0xda, 0xbf, 0x14, 0xd5, 0x28, 0xba,
|
||||
0xd0, 0x72, 0x7d, 0x38, 0xe1, 0x7c, 0x62, 0x05, 0x1e, 0x71, 0xf6, 0xf4, 0x41, 0x1e, 0x7e, 0x7f,
|
||||
0xc0, 0x2b, 0x88, 0x75, 0xb4, 0xe2, 0xfa, 0x6c, 0x21, 0x05, 0xdb, 0xa1, 0x71, 0x31, 0xf0, 0xf2,
|
||||
0xb2, 0x4e, 0x68, 0x3c, 0x15, 0x3b, 0x99, 0x07, 0x04, 0x7f, 0x1b, 0xd8, 0xf1, 0x79, 0x48, 0x2e,
|
||||
0xb7, 0x96, 0xc8, 0x20, 0xf3, 0xe4, 0x2d, 0xa0, 0x5e, 0x28, 0x52, 0x40, 0x57, 0xf3, 0x6e, 0xe5,
|
||||
0x51, 0xed, 0x9f, 0x12, 0x0f, 0x6d, 0x6a, 0x33, 0x1b, 0xea, 0x08, 0x38, 0xef, 0x4c, 0x5f, 0x1f,
|
||||
0xe2, 0xab, 0xf8, 0xfb, 0xbc, 0x7a, 0x58, 0x47, 0x0b, 0x11, 0x3a, 0x07, 0x20, 0x04, 0x8c, 0x0b,
|
||||
0x81, 0x97, 0x13, 0xa5, 0xe1, 0xa2, 0x20, 0x17, 0x83, 0xc5, 0xed, 0xf1, 0x5c, 0x00, 0x2f, 0x5a,
|
||||
0x28, 0x8b, 0xe0, 0x04, 0x82, 0x56, 0x50, 0x30, 0x14, 0x28, 0xa0, 0x2b, 0x79, 0x07, 0x73, 0xa0,
|
||||
0xe6, 0xaa, 0x7d, 0x1e, 0x89, 0x0e, 0x67, 0x97, 0x9a, 0x3b, 0x78, 0x8b, 0x04, 0x2d, 0x5d, 0xe7,
|
||||
0x53, 0x36, 0x0b, 0xe4, 0x63, 0xf0, 0x2e, 0x7d, 0x8d, 0x43, 0x29, 0xf9, 0x82, 0xbc, 0xeb, 0x21,
|
||||
0x5d, 0x34, 0xa0, 0x7d, 0x43, 0x51, 0x87, 0x70, 0xc0, 0x5c, 0x33, 0x68, 0x6d, 0x78, 0xb8, 0x4e,
|
||||
0xb2, 0x64, 0x68, 0x53, 0x7f, 0x9c, 0x0f, 0xe4, 0x0a, 0x94, 0x5c, 0xa0, 0xb2, 0x1e, 0x69, 0x24,
|
||||
0x79, 0xc4, 0x2b, 0x69, 0x75, 0x22, 0x03, 0xc5, 0xe1, 0x9b, 0x14, 0x33, 0xc3, 0x89, 0x49, 0x24,
|
||||
0xb5, 0xa6, 0x35, 0xd5, 0xa1, 0x84, 0x03, 0x73, 0xcd, 0x96, 0x07, 0x53, 0xcc, 0xcf, 0x62, 0x5f,
|
||||
0xbf, 0xcc, 0x07, 0xe0, 0x16, 0x10, 0x89, 0x55, 0xd6, 0xdc, 0x15, 0x8f, 0xa0, 0x18, 0xef, 0x84,
|
||||
0xc6, 0xe5, 0x68, 0x0a, 0x25, 0x60, 0x05, 0x49, 0xdb, 0x68, 0xdb, 0xaa, 0xb6, 0x45, 0x48, 0xcb,
|
||||
0x64, 0xa4, 0xd9, 0x72, 0x3d, 0xec, 0xd9, 0xc4, 0x37, 0x37, 0xf5, 0x2b, 0xdc, 0xe5, 0x57, 0x60,
|
||||
0x23, 0x00, 0xba, 0x96, 0x81, 0xe0, 0xee, 0x35, 0xde, 0x4b, 0x11, 0x10, 0x6b, 0xb1, 0x17, 0x45,
|
||||
0x57, 0x27, 0x5f, 0x44, 0x25, 0x2b, 0xda, 0x9e, 0xda, 0x6f, 0x61, 0x6b, 0x93, 0x98, 0xf6, 0x06,
|
||||
0x75, 0x3d, 0x52, 0x37, 0x1b, 0xb6, 0x43, 0x7c, 0xfd, 0x2a, 0x77, 0x71, 0x01, 0x4e, 0x34, 0x0e,
|
||||
0x2f, 0x44, 0xe8, 0x3c, 0x80, 0xe9, 0x40, 0x97, 0x90, 0xd2, 0x1e, 0x4c, 0xf7, 0x16, 0x2a, 0x9b,
|
||||
0xd1, 0xbe, 0xa3, 0xa8, 0x97, 0x5b, 0x9e, 0xbb, 0x01, 0xc5, 0x8c, 0x19, 0xb4, 0xea, 0x98, 0x11,
|
||||
0xb1, 0x40, 0x78, 0x82, 0xfb, 0xbe, 0x06, 0xf9, 0x6d, 0xa2, 0xb5, 0xce, 0x95, 0xc4, 0x62, 0x20,
|
||||
0x2a, 0xb2, 0xbb, 0xe0, 0x02, 0x9d, 0x97, 0x84, 0x81, 0x50, 0x5e, 0x42, 0xdd, 0x2c, 0x6a, 0x6f,
|
||||
0x2b, 0xea, 0xa0, 0x63, 0x37, 0x6d, 0x66, 0xd6, 0x30, 0xad, 0xef, 0xd8, 0x75, 0xb6, 0x69, 0xda,
|
||||
0xd4, 0x74, 0x30, 0xd5, 0x87, 0xf9, 0x90, 0x2c, 0xf1, 0xe2, 0x11, 0x34, 0x66, 0x12, 0x85, 0x05,
|
||||
0xba, 0x88, 0x69, 0x56, 0xf0, 0x97, 0xb1, 0x4f, 0x18, 0x16, 0x99, 0x29, 0xed, 0x2d, 0x45, 0xd5,
|
||||
0x9a, 0x36, 0x35, 0x37, 0xdd, 0x26, 0x31, 0xeb, 0xb6, 0xbf, 0x65, 0x36, 0x3c, 0x42, 0x74, 0x63,
|
||||
0x44, 0x19, 0x3d, 0x37, 0xd9, 0x73, 0x23, 0xba, 0x59, 0xbb, 0xb1, 0x6a, 0xbf, 0x41, 0x66, 0x5e,
|
||||
0xfe, 0x20, 0x34, 0x4e, 0xc0, 0x4e, 0x6c, 0xda, 0xf4, 0x15, 0xb7, 0x49, 0xe6, 0x6c, 0x7f, 0x6b,
|
||||
0xde, 0x23, 0x24, 0x5d, 0x1d, 0x05, 0xb9, 0xb8, 0x0f, 0x46, 0xae, 0x03, 0x91, 0x53, 0x13, 0x23,
|
||||
0xd7, 0x51, 0xb1, 0xb9, 0x76, 0x5f, 0x51, 0x7b, 0x92, 0xf5, 0xce, 0x8f, 0x9d, 0x11, 0x7e, 0xec,
|
||||
0xfc, 0x91, 0xa7, 0x3c, 0xc9, 0xa2, 0x8d, 0x0e, 0x9f, 0x73, 0x5e, 0xf6, 0xd9, 0x09, 0x8d, 0xb9,
|
||||
0xa4, 0xe2, 0x48, 0x64, 0x92, 0x83, 0x28, 0xde, 0x01, 0x7e, 0xe1, 0x4c, 0x69, 0x12, 0x86, 0x6f,
|
||||
0x7c, 0xd1, 0x77, 0x29, 0xc4, 0xee, 0x9c, 0xd9, 0xfc, 0xe7, 0xf1, 0x41, 0x75, 0xf4, 0x61, 0x4d,
|
||||
0x41, 0x7e, 0x24, 0xf0, 0x45, 0x99, 0x1d, 0xcf, 0xd1, 0x5e, 0x53, 0xfb, 0xb0, 0xb3, 0x03, 0xd5,
|
||||
0x57, 0x74, 0x9b, 0x40, 0x09, 0xf3, 0xf5, 0x27, 0xf9, 0x25, 0x1e, 0x14, 0xbd, 0x17, 0x22, 0x90,
|
||||
0x57, 0xe5, 0xcb, 0x84, 0xc1, 0xc2, 0x1f, 0x88, 0x22, 0x4c, 0x4e, 0x5e, 0x41, 0x45, 0x45, 0xed,
|
||||
0xbf, 0x8a, 0x3a, 0xea, 0x6e, 0x13, 0x6f, 0xc7, 0xb3, 0x19, 0x04, 0x8e, 0xa6, 0xcb, 0x88, 0x59,
|
||||
0x27, 0xdb, 0xb6, 0x45, 0x4c, 0x8a, 0x9b, 0xc4, 0x87, 0x70, 0x1a, 0x17, 0x42, 0x7a, 0x25, 0xbb,
|
||||
0x5e, 0x1a, 0xba, 0x9b, 0x34, 0x42, 0xbc, 0xcd, 0x1c, 0xd9, 0x5e, 0x06, 0xf5, 0x76, 0x68, 0x5c,
|
||||
0x73, 0x4b, 0x90, 0x6d, 0x11, 0x8e, 0xde, 0xa5, 0xb3, 0x91, 0xa9, 0x4e, 0x68, 0xfc, 0x3f, 0x27,
|
||||
0xf8, 0x10, 0xba, 0xdd, 0x17, 0x25, 0x54, 0x71, 0x5d, 0x78, 0xa0, 0x87, 0x61, 0xa1, 0x7d, 0x45,
|
||||
0xbd, 0x04, 0x61, 0xcc, 0xb4, 0x69, 0x9d, 0xec, 0x9a, 0xb0, 0x92, 0x6b, 0x8e, 0x6b, 0x6d, 0xf9,
|
||||
0xfa, 0x35, 0xbe, 0xa5, 0x61, 0xd1, 0x68, 0xa0, 0xb0, 0x00, 0xf8, 0x92, 0x4d, 0x67, 0x38, 0x9a,
|
||||
0xde, 0xda, 0x96, 0x21, 0x69, 0xa6, 0x1c, 0xe5, 0xbf, 0x48, 0x62, 0x49, 0xfb, 0x07, 0xa4, 0xbb,
|
||||
0x14, 0x5b, 0x5b, 0xa4, 0x6e, 0x52, 0x97, 0xd9, 0x0d, 0xdb, 0xc2, 0xd1, 0xfd, 0x43, 0xdd, 0xd7,
|
||||
0xab, 0x7c, 0x7e, 0xdf, 0x81, 0xe1, 0x1e, 0x5c, 0x8f, 0x94, 0x96, 0x05, 0x9d, 0x85, 0x39, 0x18,
|
||||
0xed, 0xc1, 0x40, 0x8a, 0x74, 0x42, 0xe3, 0x4a, 0x14, 0xda, 0x65, 0x30, 0xbf, 0xab, 0x94, 0x22,
|
||||
0x9d, 0x83, 0x6a, 0x17, 0x8b, 0xfb, 0x87, 0xd5, 0x2e, 0x2c, 0x90, 0xb4, 0x45, 0xdd, 0xd7, 0x90,
|
||||
0x7a, 0x9e, 0x79, 0xb8, 0xd1, 0xb0, 0x2d, 0xd3, 0x72, 0xb0, 0xef, 0xeb, 0xd7, 0xf9, 0xb0, 0xbe,
|
||||
0x00, 0xf5, 0x72, 0x0c, 0xcc, 0x82, 0xbc, 0x13, 0x1a, 0x5a, 0x34, 0xa0, 0x82, 0x30, 0xbd, 0xa8,
|
||||
0xc9, 0xa9, 0x6a, 0xf7, 0xd4, 0xfe, 0x78, 0x88, 0xcd, 0x86, 0xeb, 0xd4, 0x89, 0x67, 0xb6, 0x30,
|
||||
0xdb, 0xd4, 0x9f, 0xe2, 0xbb, 0x7e, 0x1a, 0x8e, 0x81, 0x18, 0x9e, 0xe7, 0xe8, 0x0a, 0x66, 0x9b,
|
||||
0x69, 0x88, 0x29, 0x21, 0xc2, 0x74, 0xbd, 0x09, 0xcb, 0x4a, 0x79, 0x13, 0x95, 0x9b, 0x6b, 0x5b,
|
||||
0xea, 0x45, 0x9f, 0x30, 0xd3, 0x71, 0x77, 0xcc, 0x96, 0x67, 0xbb, 0x9e, 0xcd, 0xf6, 0xf4, 0xa7,
|
||||
0xf9, 0x56, 0x80, 0xfe, 0x7a, 0x7d, 0xc2, 0x16, 0xdd, 0x9d, 0x95, 0x18, 0x49, 0x3b, 0xcb, 0x8b,
|
||||
0xbb, 0x26, 0x16, 0x85, 0xe6, 0xda, 0xbb, 0x8a, 0x3a, 0xd8, 0xc4, 0xbb, 0x89, 0x73, 0x96, 0x4b,
|
||||
0xad, 0xc0, 0xf3, 0x08, 0xb5, 0xf6, 0xf4, 0x51, 0x3e, 0x7a, 0x3e, 0xbf, 0x62, 0xc1, 0x3b, 0x4b,
|
||||
0x78, 0x37, 0xe2, 0x38, 0x9b, 0xa9, 0xc0, 0x41, 0xdf, 0x94, 0xc8, 0xd3, 0x83, 0x5e, 0x06, 0x26,
|
||||
0x03, 0xcd, 0xef, 0x44, 0xe4, 0x76, 0x91, 0xd4, 0xaa, 0xf6, 0xa1, 0xa2, 0xf6, 0x5b, 0x1e, 0xf6,
|
||||
0x37, 0x0b, 0x99, 0xff, 0x33, 0x7c, 0x32, 0xde, 0xe3, 0x99, 0xff, 0x6c, 0x92, 0xf9, 0x5b, 0x71,
|
||||
0xe6, 0x3f, 0x1f, 0x9d, 0xc8, 0xd0, 0x2c, 0xcb, 0xc1, 0xa5, 0xc1, 0x97, 0xeb, 0x94, 0xb3, 0x79,
|
||||
0x2e, 0x86, 0x15, 0xdc, 0x57, 0x32, 0x02, 0x35, 0x81, 0x15, 0xd7, 0x04, 0xd5, 0x87, 0x31, 0x03,
|
||||
0x55, 0xc1, 0x6c, 0x54, 0x15, 0x14, 0x8c, 0x79, 0x8e, 0xf6, 0x13, 0x45, 0x1d, 0x2a, 0xba, 0x97,
|
||||
0x5c, 0xc6, 0x3c, 0xcb, 0xe7, 0xdf, 0x3e, 0x0a, 0x8d, 0xb3, 0xb3, 0x48, 0x78, 0x47, 0xc8, 0x5b,
|
||||
0x29, 0xbe, 0x23, 0x48, 0xd1, 0x6e, 0x4b, 0x63, 0xff, 0xb0, 0x9a, 0xd9, 0x46, 0x72, 0xcb, 0xda,
|
||||
0xd7, 0x14, 0x75, 0xd0, 0x67, 0x01, 0x35, 0x21, 0x5f, 0xc2, 0x8e, 0xbd, 0x4d, 0xcc, 0x28, 0x0b,
|
||||
0xf6, 0xf5, 0xe7, 0xd2, 0x2c, 0xb4, 0x1f, 0x34, 0xee, 0x24, 0x0a, 0xab, 0x80, 0xaf, 0xa6, 0xb9,
|
||||
0x91, 0x04, 0xcb, 0xa7, 0xf0, 0x42, 0x18, 0x3b, 0x35, 0x71, 0x7b, 0x1c, 0xc9, 0xac, 0x41, 0x65,
|
||||
0x5c, 0xa0, 0x01, 0xd1, 0xd4, 0xd7, 0x9f, 0xe7, 0x24, 0x5e, 0x85, 0x7d, 0x99, 0x6b, 0xb6, 0x64,
|
||||
0xd3, 0xac, 0x82, 0x28, 0x21, 0x62, 0x66, 0x98, 0x0b, 0xa3, 0x93, 0xe3, 0xa8, 0x6c, 0x07, 0x72,
|
||||
0xf1, 0x1e, 0xde, 0x7b, 0xf2, 0xbc, 0xf5, 0x02, 0x8f, 0x9c, 0xf5, 0xa3, 0xd0, 0xe8, 0x45, 0x78,
|
||||
0x67, 0x95, 0x05, 0xc2, 0xc3, 0xd6, 0x39, 0x3f, 0xfb, 0x4c, 0xaf, 0xa0, 0x32, 0xd9, 0x03, 0x1f,
|
||||
0xdf, 0x0a, 0x16, 0x91, 0x68, 0x4f, 0xdb, 0x56, 0x2f, 0x40, 0xb1, 0x59, 0xc3, 0x3e, 0x31, 0xa3,
|
||||
0x97, 0x46, 0xfd, 0xc6, 0x88, 0x32, 0xda, 0x3b, 0xd9, 0x9b, 0x24, 0x43, 0x6b, 0x5c, 0xca, 0xef,
|
||||
0x0c, 0x7b, 0x13, 0xd5, 0x48, 0x96, 0x85, 0xa9, 0x9c, 0xb8, 0x32, 0x12, 0x97, 0x1e, 0xf1, 0xf2,
|
||||
0x78, 0xeb, 0xb0, 0xaa, 0xa0, 0x42, 0x53, 0xed, 0xbb, 0x27, 0xd5, 0x6b, 0x10, 0x35, 0xd2, 0x70,
|
||||
0x01, 0xa5, 0xab, 0xe5, 0x36, 0x61, 0xc9, 0x7a, 0xe4, 0x5e, 0x40, 0x7c, 0x66, 0x6e, 0xd9, 0x35,
|
||||
0x7d, 0x8c, 0x4f, 0xc7, 0x5f, 0x94, 0xf8, 0x85, 0x72, 0x09, 0xef, 0xce, 0x2e, 0xa0, 0x08, 0xbf,
|
||||
0x63, 0xcf, 0xb4, 0x43, 0xc3, 0x68, 0xe2, 0xdd, 0x74, 0x8b, 0xb3, 0x85, 0xd8, 0x46, 0xa6, 0x92,
|
||||
0x9e, 0x7d, 0x0f, 0xd0, 0x13, 0xca, 0xbe, 0x07, 0x9a, 0x7c, 0xb0, 0x4a, 0xfc, 0xe6, 0x59, 0xa0,
|
||||
0x8b, 0x1e, 0xd0, 0xac, 0xa6, 0x7d, 0xac, 0xa8, 0x83, 0xe9, 0xc3, 0x8b, 0x83, 0xc5, 0xa7, 0xda,
|
||||
0x71, 0xbe, 0x81, 0xdf, 0x87, 0x91, 0x18, 0x48, 0x1e, 0x2e, 0x16, 0xa7, 0x97, 0xc5, 0xd7, 0xda,
|
||||
0x01, 0x2c, 0x91, 0xa7, 0xe9, 0xb3, 0x0c, 0x94, 0xbd, 0x97, 0x49, 0x8d, 0x74, 0x91, 0x0b, 0x5b,
|
||||
0x5f, 0x4a, 0x0a, 0x65, 0xad, 0xb0, 0xf0, 0xd4, 0xbb, 0xad, 0x5e, 0xe6, 0x6f, 0x2b, 0x8d, 0xc0,
|
||||
0x71, 0xe2, 0x5c, 0xc6, 0xa5, 0x49, 0x61, 0xaa, 0x4f, 0x70, 0x4f, 0xa7, 0x20, 0x57, 0x00, 0xad,
|
||||
0xf9, 0xc0, 0x71, 0x78, 0x16, 0x72, 0x97, 0xc6, 0xa5, 0x64, 0x27, 0x34, 0xae, 0xc6, 0x47, 0x96,
|
||||
0x0c, 0xae, 0xa0, 0x2e, 0xed, 0xb4, 0x57, 0xd5, 0xf3, 0x0d, 0x82, 0x59, 0xe0, 0x11, 0xb3, 0xe1,
|
||||
0xe0, 0x0d, 0x5f, 0x9f, 0xe4, 0xfb, 0xee, 0x3a, 0x9c, 0xef, 0x31, 0x30, 0x0f, 0xf2, 0xf4, 0x1d,
|
||||
0x46, 0x10, 0x56, 0x50, 0x4e, 0x45, 0xfb, 0xb2, 0xda, 0x13, 0xb4, 0x68, 0x2b, 0x0d, 0xb0, 0xbf,
|
||||
0x98, 0xe7, 0xb4, 0x3f, 0x77, 0x14, 0x1a, 0x97, 0xe6, 0x48, 0xcb, 0x23, 0x16, 0x66, 0xa4, 0xbe,
|
||||
0xbe, 0x42, 0x57, 0xb2, 0x68, 0xab, 0xbc, 0x90, 0xa5, 0x39, 0x2d, 0xda, 0x8a, 0x81, 0xe7, 0xdd,
|
||||
0xa6, 0x0d, 0xa9, 0x16, 0xdb, 0xab, 0xec, 0x1f, 0x56, 0xe5, 0x8d, 0x75, 0x05, 0x9d, 0x13, 0x9a,
|
||||
0x68, 0x3f, 0x53, 0xe2, 0xee, 0x93, 0x4b, 0xec, 0x77, 0xe7, 0xf9, 0x4e, 0x79, 0x8b, 0xaf, 0x8f,
|
||||
0xbc, 0x89, 0xf4, 0x42, 0x9b, 0x77, 0x3f, 0x92, 0x76, 0x2f, 0x5e, 0x44, 0x0b, 0x1c, 0xb2, 0x8d,
|
||||
0x70, 0xb9, 0xbb, 0x16, 0x4c, 0xb8, 0xac, 0x17, 0x5d, 0x41, 0x6a, 0xd6, 0x4a, 0xfb, 0x8d, 0xa2,
|
||||
0xf6, 0x72, 0x9a, 0xd9, 0x75, 0xf5, 0x2f, 0x23, 0xa2, 0xdf, 0xe4, 0x59, 0x62, 0xde, 0x84, 0x70,
|
||||
0x75, 0xcd, 0xa9, 0x56, 0x52, 0xaa, 0xf9, 0xcb, 0x66, 0x29, 0xd9, 0xab, 0x9f, 0xa4, 0x07, 0xb9,
|
||||
0xa0, 0xbc, 0x2f, 0x5d, 0x41, 0x3d, 0x62, 0xcb, 0x8c, 0x72, 0x76, 0x29, 0xfd, 0x5e, 0x77, 0xca,
|
||||
0xc2, 0x05, 0x75, 0x81, 0x72, 0xfe, 0x4a, 0xb9, 0x3b, 0xe5, 0x6e, 0x7a, 0x65, 0xca, 0x89, 0x66,
|
||||
0x42, 0x39, 0xbd, 0x83, 0x6e, 0xa8, 0xd1, 0xe3, 0x57, 0x7a, 0x9c, 0xfc, 0x6a, 0x9e, 0xaf, 0xeb,
|
||||
0xcf, 0xe4, 0xf9, 0xf2, 0xf7, 0xa3, 0xec, 0x5c, 0x11, 0x16, 0xa3, 0x97, 0x21, 0x02, 0x51, 0xe8,
|
||||
0x47, 0x40, 0x7c, 0x5e, 0xc2, 0x97, 0xab, 0x67, 0xb3, 0x65, 0x31, 0xfd, 0x7d, 0x18, 0x22, 0x65,
|
||||
0x66, 0xe9, 0x28, 0x34, 0xae, 0x66, 0x3d, 0x2e, 0xe5, 0x6b, 0xdf, 0x15, 0x8b, 0xe5, 0xc7, 0xa9,
|
||||
0x59, 0xc2, 0xf3, 0xdd, 0x6b, 0x65, 0x05, 0x38, 0x3b, 0x07, 0x0a, 0x27, 0x87, 0x6f, 0x61, 0xea,
|
||||
0xeb, 0xbf, 0x8e, 0x66, 0x69, 0xad, 0x40, 0x41, 0x8c, 0xb8, 0xab, 0xa0, 0x58, 0xa0, 0x50, 0xc2,
|
||||
0xcb, 0x53, 0xc5, 0x99, 0x94, 0xf4, 0x66, 0xee, 0x7c, 0xf0, 0xd1, 0xf0, 0x89, 0xc3, 0x8f, 0x86,
|
||||
0x4f, 0x7c, 0x70, 0x34, 0xac, 0x1c, 0x1e, 0x0d, 0x2b, 0xdf, 0xbe, 0x3f, 0x7c, 0xe2, 0x9d, 0xfb,
|
||||
0xc3, 0xca, 0xe1, 0xfd, 0xe1, 0x13, 0x7f, 0xbf, 0x3f, 0x7c, 0xe2, 0xf5, 0x67, 0x36, 0x6c, 0xb6,
|
||||
0x19, 0xd4, 0x6e, 0x58, 0x6e, 0x73, 0x2c, 0xcd, 0xe7, 0x84, 0x5f, 0xd9, 0xbf, 0x79, 0x6a, 0x67,
|
||||
0xf8, 0xdf, 0x77, 0x6e, 0xfe, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x64, 0xe8, 0xf8, 0x5e, 0x2a, 0x24,
|
||||
0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *OptionsConfiguration) Marshal() (dAtA []byte, err error) {
|
||||
@@ -415,6 +419,17 @@ func (m *OptionsConfiguration) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i--
|
||||
dAtA[i] = 0xc0
|
||||
}
|
||||
if len(m.FeatureFlags) > 0 {
|
||||
for iNdEx := len(m.FeatureFlags) - 1; iNdEx >= 0; iNdEx-- {
|
||||
i -= len(m.FeatureFlags[iNdEx])
|
||||
copy(dAtA[i:], m.FeatureFlags[iNdEx])
|
||||
i = encodeVarintOptionsconfiguration(dAtA, i, uint64(len(m.FeatureFlags[iNdEx])))
|
||||
i--
|
||||
dAtA[i] = 0x3
|
||||
i--
|
||||
dAtA[i] = 0x92
|
||||
}
|
||||
}
|
||||
if m.SendFullIndexOnUpgrade {
|
||||
i--
|
||||
if m.SendFullIndexOnUpgrade {
|
||||
@@ -1019,6 +1034,12 @@ func (m *OptionsConfiguration) ProtoSize() (n int) {
|
||||
if m.SendFullIndexOnUpgrade {
|
||||
n += 3
|
||||
}
|
||||
if len(m.FeatureFlags) > 0 {
|
||||
for _, s := range m.FeatureFlags {
|
||||
l = len(s)
|
||||
n += 2 + l + sovOptionsconfiguration(uint64(l))
|
||||
}
|
||||
}
|
||||
if m.DeprecatedUPnPEnabled {
|
||||
n += 4
|
||||
}
|
||||
@@ -2165,6 +2186,38 @@ func (m *OptionsConfiguration) Unmarshal(dAtA []byte) error {
|
||||
}
|
||||
}
|
||||
m.SendFullIndexOnUpgrade = bool(v != 0)
|
||||
case 50:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field FeatureFlags", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowOptionsconfiguration
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthOptionsconfiguration
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthOptionsconfiguration
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.FeatureFlags = append(m.FeatureFlags, string(dAtA[iNdEx:postIndex]))
|
||||
iNdEx = postIndex
|
||||
case 9000:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field DeprecatedUPnPEnabled", wireType)
|
||||
|
||||
+1
@@ -45,5 +45,6 @@
|
||||
<stunServer>foo</stunServer>
|
||||
<unackedNotificationID>asdfasdf</unackedNotificationID>
|
||||
<announceLANAddresses>false</announceLANAddresses>
|
||||
<featureFlag>feature</featureFlag>
|
||||
</options>
|
||||
</configuration>
|
||||
|
||||
@@ -75,6 +75,7 @@ type Wrapper interface {
|
||||
RemoveFolder(id string) (Waiter, error)
|
||||
SetFolder(fld FolderConfiguration) (Waiter, error)
|
||||
SetFolders(folders []FolderConfiguration) (Waiter, error)
|
||||
FolderPasswords(device protocol.DeviceID) map[string]string
|
||||
|
||||
Device(id protocol.DeviceID) (DeviceConfiguration, bool)
|
||||
Devices() map[protocol.DeviceID]DeviceConfiguration
|
||||
@@ -353,6 +354,14 @@ func (w *wrapper) RemoveFolder(id string) (Waiter, error) {
|
||||
return noopWaiter{}, nil
|
||||
}
|
||||
|
||||
// FolderPasswords returns the folder passwords set for this device, for
|
||||
// folders that have an encryption password set.
|
||||
func (w *wrapper) FolderPasswords(device protocol.DeviceID) map[string]string {
|
||||
w.mut.Lock()
|
||||
defer w.mut.Unlock()
|
||||
return w.cfg.FolderPasswords(device)
|
||||
}
|
||||
|
||||
// Options returns the current options configuration object.
|
||||
func (w *wrapper) Options() OptionsConfiguration {
|
||||
w.mut.Lock()
|
||||
|
||||
@@ -324,7 +324,13 @@ func (s *service) handle(ctx context.Context) {
|
||||
isLAN := s.isLAN(c.RemoteAddr())
|
||||
rd, wr := s.limiter.getLimiters(remoteID, c, isLAN)
|
||||
|
||||
protoConn := protocol.NewConnection(remoteID, rd, wr, s.model, c.String(), deviceCfg.Compression)
|
||||
var protoConn protocol.Connection
|
||||
passwords := s.cfg.FolderPasswords(remoteID)
|
||||
if len(passwords) > 0 {
|
||||
protoConn = protocol.NewEncryptedConnection(passwords, remoteID, rd, wr, s.model, c.String(), deviceCfg.Compression)
|
||||
} else {
|
||||
protoConn = protocol.NewConnection(remoteID, rd, wr, s.model, c.String(), deviceCfg.Compression)
|
||||
}
|
||||
modelConn := completeConn{c, protoConn}
|
||||
|
||||
l.Infof("Established secure connection to %s at %s", remoteID, c)
|
||||
|
||||
+130
-81
@@ -113,6 +113,7 @@ type FileInfoTruncated struct {
|
||||
// repeated BlockInfo Blocks = 16
|
||||
SymlinkTarget string `protobuf:"bytes,17,opt,name=symlink_target,json=symlinkTarget,proto3" json:"symlinkTarget" xml:"symlinkTarget"`
|
||||
BlocksHash []byte `protobuf:"bytes,18,opt,name=blocks_hash,json=blocksHash,proto3" json:"blocksHash" xml:"blocksHash"`
|
||||
Encrypted []byte `protobuf:"bytes,19,opt,name=encrypted,proto3" json:"encrypted" xml:"encrypted"`
|
||||
Type protocol.FileInfoType `protobuf:"varint,2,opt,name=type,proto3,enum=protocol.FileInfoType" json:"type" xml:"type"`
|
||||
Permissions uint32 `protobuf:"varint,4,opt,name=permissions,proto3" json:"permissions" xml:"permissions"`
|
||||
ModifiedNs int `protobuf:"varint,11,opt,name=modified_ns,json=modifiedNs,proto3,casttype=int" json:"modifiedNs" xml:"modifiedNs"`
|
||||
@@ -409,87 +410,88 @@ func init() {
|
||||
func init() { proto.RegisterFile("lib/db/structs.proto", fileDescriptor_5465d80e8cba02e3) }
|
||||
|
||||
var fileDescriptor_5465d80e8cba02e3 = []byte{
|
||||
// 1267 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xcf, 0x6f, 0x13, 0xc7,
|
||||
0x17, 0xf7, 0xc6, 0x3f, 0x62, 0x8f, 0x9d, 0x40, 0x96, 0x2f, 0x68, 0xbf, 0xb4, 0xf5, 0xb8, 0x43,
|
||||
0x90, 0xdc, 0x56, 0x72, 0xa4, 0x20, 0x50, 0x85, 0x54, 0x21, 0x96, 0x08, 0x08, 0xa2, 0x50, 0x4d,
|
||||
0x10, 0xad, 0x7a, 0xb1, 0xbc, 0xeb, 0x49, 0xb2, 0x62, 0xb3, 0xeb, 0xee, 0x6c, 0x08, 0xe6, 0xd6,
|
||||
0x4b, 0xa5, 0xde, 0x2a, 0xd4, 0x43, 0x55, 0x55, 0x15, 0xa7, 0xfe, 0x09, 0x55, 0xff, 0x04, 0x8e,
|
||||
0x39, 0x56, 0x3d, 0xac, 0x84, 0x73, 0x69, 0x7d, 0xf4, 0xb1, 0xa7, 0x6a, 0xde, 0xcc, 0xce, 0x8e,
|
||||
0x89, 0xa8, 0x80, 0x72, 0xdb, 0xf7, 0x79, 0x9f, 0xf7, 0xbc, 0xfb, 0xde, 0xe7, 0x3d, 0x3f, 0xf4,
|
||||
0xbf, 0x30, 0xf0, 0xd6, 0x86, 0xde, 0x1a, 0x4f, 0x93, 0x7d, 0x3f, 0xe5, 0xbd, 0x51, 0x12, 0xa7,
|
||||
0xb1, 0xbd, 0x30, 0xf4, 0xce, 0x9e, 0x4b, 0xd8, 0x28, 0xe6, 0x6b, 0x00, 0x78, 0xfb, 0xdb, 0x6b,
|
||||
0x3b, 0xf1, 0x4e, 0x0c, 0x06, 0x3c, 0x49, 0xe2, 0xd9, 0x33, 0x22, 0x1c, 0x1e, 0xfd, 0x38, 0x5c,
|
||||
0xf3, 0xd8, 0x48, 0xe1, 0x0d, 0xf6, 0x28, 0x95, 0x8f, 0xe4, 0xe7, 0x05, 0xd4, 0xbc, 0x1e, 0x84,
|
||||
0xec, 0x3e, 0x4b, 0x78, 0x10, 0x47, 0xf6, 0x6d, 0xb4, 0xf8, 0x50, 0x3e, 0x3a, 0x56, 0xc7, 0xea,
|
||||
0x36, 0xd7, 0x4f, 0xf6, 0xf2, 0x04, 0xbd, 0xfb, 0xcc, 0x4f, 0xe3, 0xc4, 0xed, 0x3c, 0xcb, 0x70,
|
||||
0x69, 0x9a, 0xe1, 0x9c, 0x38, 0xcb, 0xf0, 0xd2, 0xa3, 0xbd, 0xf0, 0x32, 0x51, 0x36, 0xa1, 0xb9,
|
||||
0xc7, 0xbe, 0x84, 0x16, 0x87, 0x2c, 0x64, 0x29, 0x1b, 0x3a, 0x0b, 0x1d, 0xab, 0x5b, 0x77, 0xdf,
|
||||
0x15, 0x71, 0x0a, 0xd2, 0x71, 0xca, 0x26, 0x34, 0xf7, 0xd8, 0x17, 0x45, 0xdc, 0xc3, 0xc0, 0x67,
|
||||
0xdc, 0x29, 0x77, 0xca, 0xdd, 0x96, 0xfb, 0x8e, 0x8c, 0x03, 0x68, 0x96, 0xe1, 0x96, 0x8a, 0x13,
|
||||
0x36, 0x84, 0x81, 0xc3, 0xa6, 0xe8, 0x44, 0x10, 0x3d, 0x1c, 0x84, 0xc1, 0xb0, 0x9f, 0x87, 0x57,
|
||||
0x20, 0xfc, 0x83, 0x69, 0x86, 0x97, 0x95, 0x6b, 0x43, 0x67, 0x39, 0x05, 0x59, 0xe6, 0x60, 0x42,
|
||||
0x5f, 0xa0, 0x91, 0xaf, 0x2d, 0xd4, 0x54, 0xc5, 0xb9, 0x1d, 0xf0, 0xd4, 0x0e, 0x51, 0x5d, 0x7d,
|
||||
0x1d, 0x77, 0xac, 0x4e, 0xb9, 0xdb, 0x5c, 0x3f, 0xd1, 0x1b, 0x7a, 0x3d, 0xa3, 0x86, 0xee, 0x15,
|
||||
0x51, 0xa0, 0x49, 0x86, 0x9b, 0x74, 0x70, 0xa0, 0x30, 0x3e, 0xcd, 0xb0, 0x8e, 0x3b, 0x56, 0xb0,
|
||||
0x27, 0x87, 0xab, 0x26, 0x97, 0x6a, 0xe6, 0xe5, 0xca, 0x0f, 0x4f, 0x71, 0x89, 0xfc, 0x86, 0xd0,
|
||||
0x8a, 0xf8, 0x81, 0xcd, 0x68, 0x3b, 0xbe, 0x97, 0xec, 0x47, 0xfe, 0x40, 0x14, 0xe9, 0x43, 0x54,
|
||||
0x89, 0x06, 0x7b, 0x0c, 0xfa, 0xd4, 0x70, 0xcf, 0x4c, 0x33, 0x0c, 0xf6, 0x2c, 0xc3, 0x08, 0xb2,
|
||||
0x0b, 0x83, 0x50, 0xc0, 0x04, 0x97, 0x07, 0x8f, 0x99, 0x53, 0xee, 0x58, 0xdd, 0xb2, 0xe4, 0x0a,
|
||||
0x5b, 0x73, 0x85, 0x41, 0x28, 0x60, 0xf6, 0x15, 0x84, 0xf6, 0xe2, 0x61, 0xb0, 0x1d, 0xb0, 0x61,
|
||||
0x9f, 0x3b, 0x55, 0x88, 0xe8, 0x4c, 0x33, 0xdc, 0xc8, 0xd1, 0xad, 0x59, 0x86, 0x4f, 0x40, 0x98,
|
||||
0x46, 0x08, 0x2d, 0xbc, 0xf6, 0xaf, 0x16, 0x6a, 0xea, 0x0c, 0xde, 0xd8, 0x69, 0x75, 0xac, 0x6e,
|
||||
0xc5, 0xfd, 0xde, 0x12, 0x65, 0xf9, 0x23, 0xc3, 0x17, 0x76, 0x82, 0x74, 0x77, 0xdf, 0xeb, 0xf9,
|
||||
0xf1, 0xde, 0x1a, 0x1f, 0x47, 0x7e, 0xba, 0x1b, 0x44, 0x3b, 0xc6, 0x93, 0x29, 0xda, 0xde, 0xd6,
|
||||
0x6e, 0x9c, 0xa4, 0x9b, 0x1b, 0xd3, 0x0c, 0xeb, 0x97, 0x72, 0xc7, 0xb3, 0x0c, 0x9f, 0x9c, 0xfb,
|
||||
0x7d, 0x77, 0x4c, 0x7e, 0x3c, 0x5c, 0x7d, 0x93, 0xc4, 0xd4, 0x48, 0x6b, 0x8a, 0xbf, 0xf1, 0xdf,
|
||||
0xc5, 0x7f, 0x19, 0xd5, 0x39, 0xfb, 0x6a, 0x9f, 0x45, 0x3e, 0x73, 0x10, 0x54, 0xb1, 0x2d, 0x54,
|
||||
0x90, 0x63, 0xb3, 0x0c, 0x2f, 0xcb, 0xda, 0x2b, 0x80, 0x50, 0xed, 0xb3, 0xef, 0xa2, 0x65, 0x3e,
|
||||
0xde, 0x0b, 0x83, 0xe8, 0x41, 0x3f, 0x1d, 0x24, 0x3b, 0x2c, 0x75, 0x56, 0xa0, 0xcb, 0xdd, 0x69,
|
||||
0x86, 0x97, 0x94, 0xe7, 0x1e, 0x38, 0xb4, 0x8e, 0xe7, 0x50, 0x42, 0xe7, 0x59, 0xf6, 0x35, 0xd4,
|
||||
0xf4, 0xc2, 0xd8, 0x7f, 0xc0, 0xfb, 0xbb, 0x03, 0xbe, 0xeb, 0xd8, 0x1d, 0xab, 0xdb, 0x72, 0x89,
|
||||
0x28, 0xab, 0x84, 0x6f, 0x0e, 0xf8, 0xae, 0x2e, 0x6b, 0x01, 0x11, 0x6a, 0xf8, 0x6d, 0x17, 0x55,
|
||||
0xd2, 0xf1, 0x88, 0xc1, 0x2c, 0x2f, 0xaf, 0x9f, 0x29, 0x8a, 0xa3, 0xc5, 0x39, 0x1e, 0x31, 0xa9,
|
||||
0x2e, 0xc1, 0xd3, 0xea, 0x12, 0x06, 0xa1, 0x80, 0xd9, 0xd7, 0x51, 0x73, 0xc4, 0x92, 0xbd, 0x80,
|
||||
0xcb, 0x11, 0xaa, 0x74, 0xac, 0xee, 0x92, 0xbb, 0x3a, 0xcd, 0xb0, 0x09, 0xcf, 0x32, 0xbc, 0x02,
|
||||
0x91, 0x06, 0x46, 0xa8, 0xc9, 0xb0, 0x6f, 0x19, 0x1a, 0x8b, 0xb8, 0xd3, 0xec, 0x58, 0xdd, 0x2a,
|
||||
0xcc, 0xb9, 0x6e, 0xe8, 0x1d, 0x7e, 0x4c, 0x27, 0x77, 0x38, 0xf9, 0x3b, 0xc3, 0xe5, 0x20, 0x4a,
|
||||
0xa9, 0x41, 0xb3, 0xb7, 0x91, 0xfc, 0xca, 0x3e, 0xcc, 0xc8, 0x12, 0xa4, 0xba, 0x31, 0xc9, 0x70,
|
||||
0x8b, 0x0e, 0x0e, 0x5c, 0xe1, 0xd8, 0x0a, 0x1e, 0x33, 0x31, 0x01, 0x5e, 0x6e, 0xe8, 0x09, 0xd0,
|
||||
0x48, 0x9e, 0xf8, 0xc9, 0xe1, 0xea, 0x5c, 0x18, 0x2d, 0x82, 0xec, 0x0d, 0xd4, 0x0c, 0x63, 0x7f,
|
||||
0x10, 0xf6, 0xb7, 0xc3, 0xc1, 0x0e, 0x77, 0xfe, 0x5c, 0x84, 0x8f, 0x87, 0x2e, 0x00, 0x7e, 0x5d,
|
||||
0xc0, 0xfa, 0xa5, 0x0b, 0x88, 0x50, 0xc3, 0x6f, 0xdf, 0x44, 0x2d, 0x25, 0x31, 0xd9, 0xcb, 0xbf,
|
||||
0x16, 0xa1, 0x99, 0x50, 0x43, 0xe5, 0x50, 0xdd, 0x5c, 0x31, 0x95, 0x29, 0xdb, 0x69, 0x32, 0xcc,
|
||||
0xf5, 0x5c, 0x7b, 0x9d, 0xf5, 0x4c, 0xd1, 0xa2, 0xda, 0x92, 0xce, 0x22, 0xc4, 0x7d, 0x3c, 0xc9,
|
||||
0x30, 0xa2, 0x83, 0x83, 0x4d, 0x89, 0x8a, 0x2c, 0x8a, 0xa0, 0xb3, 0x28, 0x5b, 0xec, 0x3a, 0x83,
|
||||
0x49, 0x73, 0x9e, 0x50, 0x7c, 0x14, 0xf7, 0x4d, 0x69, 0xd4, 0x21, 0x35, 0x28, 0x3e, 0x8a, 0x3f,
|
||||
0x9b, 0x13, 0x87, 0x54, 0xfc, 0x1c, 0x4a, 0xe8, 0x3c, 0x4b, 0xad, 0xce, 0xcf, 0x51, 0x03, 0x5a,
|
||||
0x01, 0xbb, 0xfb, 0x16, 0xaa, 0x49, 0x35, 0xab, 0xcd, 0x7d, 0xaa, 0x50, 0x30, 0x90, 0x84, 0x84,
|
||||
0xdd, 0xf7, 0xd4, 0x84, 0x2b, 0xea, 0x2c, 0xc3, 0xcd, 0xa2, 0xd3, 0x84, 0x2a, 0x98, 0xfc, 0x62,
|
||||
0xa1, 0xd3, 0x9b, 0xd1, 0x30, 0x48, 0x98, 0x9f, 0xaa, 0x7a, 0x32, 0x7e, 0x37, 0x0a, 0xc7, 0x6f,
|
||||
0x67, 0xd4, 0xde, 0x5a, 0x93, 0xc9, 0x4f, 0x15, 0x54, 0xbb, 0x16, 0xef, 0x47, 0x29, 0xb7, 0x2f,
|
||||
0xa2, 0xea, 0x76, 0x10, 0x32, 0x0e, 0x7f, 0x19, 0x55, 0x17, 0x4f, 0x33, 0x2c, 0x01, 0xfd, 0x91,
|
||||
0x60, 0xe9, 0x19, 0x91, 0x4e, 0xfb, 0x53, 0xd4, 0x94, 0xdf, 0x19, 0x27, 0x01, 0xe3, 0x30, 0xfd,
|
||||
0x55, 0xf7, 0x23, 0xf1, 0x26, 0x06, 0xac, 0xdf, 0xc4, 0xc0, 0x74, 0x22, 0x93, 0x68, 0x5f, 0x45,
|
||||
0x75, 0xb5, 0x9b, 0x38, 0xfc, 0x1f, 0x55, 0xdd, 0xf3, 0xb0, 0x17, 0x15, 0x56, 0xec, 0x45, 0x05,
|
||||
0xe8, 0x2c, 0x9a, 0x62, 0x7f, 0x52, 0x08, 0xb7, 0x02, 0x19, 0xce, 0xfd, 0x9b, 0x70, 0xf3, 0x78,
|
||||
0xad, 0xdf, 0x1e, 0xaa, 0x7a, 0xe3, 0x94, 0xe5, 0x7f, 0x6e, 0x8e, 0xa8, 0x03, 0x00, 0x45, 0xb3,
|
||||
0x85, 0x45, 0xa8, 0x44, 0xe7, 0x36, 0x79, 0xed, 0x35, 0x37, 0xf9, 0x16, 0x6a, 0xc8, 0x5b, 0xa4,
|
||||
0x1f, 0x0c, 0x61, 0x89, 0xb7, 0xdc, 0x4b, 0x93, 0x0c, 0xd7, 0xe5, 0x7d, 0x01, 0xff, 0x6c, 0x75,
|
||||
0x49, 0xd8, 0x1c, 0xea, 0x44, 0x39, 0x20, 0xa6, 0x45, 0x33, 0xa9, 0xe6, 0x09, 0x89, 0x99, 0x8b,
|
||||
0xc4, 0x7e, 0x93, 0x3d, 0xa2, 0x06, 0xe4, 0x1b, 0x0b, 0x35, 0xa4, 0x3c, 0xb6, 0x58, 0x6a, 0x5f,
|
||||
0x45, 0x35, 0x1f, 0x0c, 0x35, 0x21, 0x48, 0xdc, 0x36, 0xd2, 0x5d, 0x0c, 0x86, 0x64, 0xe8, 0x5a,
|
||||
0x81, 0x49, 0xa8, 0x82, 0xc5, 0x52, 0xf1, 0x13, 0x36, 0xc8, 0x6f, 0xbe, 0xb2, 0x5c, 0x2a, 0x0a,
|
||||
0xd2, 0xbd, 0x51, 0x36, 0xa1, 0xb9, 0x87, 0x7c, 0xbb, 0x80, 0x4e, 0x1b, 0x57, 0xd4, 0x06, 0x1b,
|
||||
0x25, 0x4c, 0x1e, 0x3a, 0x6f, 0xf7, 0x26, 0x5d, 0x47, 0x35, 0x59, 0x47, 0x78, 0xbd, 0x96, 0x7b,
|
||||
0x56, 0x7c, 0x92, 0x44, 0x8e, 0x5d, 0x96, 0x0a, 0x17, 0xdf, 0x94, 0x2f, 0xbc, 0x72, 0xb1, 0x28,
|
||||
0x5f, 0xb6, 0xe2, 0x8a, 0xa5, 0x76, 0x69, 0x5e, 0xa7, 0xaf, 0xba, 0x60, 0xc9, 0x01, 0x3a, 0x6d,
|
||||
0xdc, 0x9c, 0x46, 0x29, 0xbe, 0x38, 0x76, 0x7d, 0xfe, 0xff, 0x85, 0xeb, 0xb3, 0x20, 0xbb, 0xef,
|
||||
0xab, 0xa2, 0xbc, 0xfc, 0xf0, 0x7c, 0xf1, 0xd2, 0x74, 0x6f, 0x3c, 0x7b, 0xde, 0x2e, 0x1d, 0x3e,
|
||||
0x6f, 0x97, 0x9e, 0x4d, 0xda, 0xd6, 0xe1, 0xa4, 0x6d, 0x7d, 0x77, 0xd4, 0x2e, 0x3d, 0x3d, 0x6a,
|
||||
0x5b, 0x87, 0x47, 0xed, 0xd2, 0xef, 0x47, 0xed, 0xd2, 0x97, 0xe7, 0x5f, 0xe1, 0xc8, 0x1a, 0x7a,
|
||||
0x5e, 0x0d, 0x3a, 0x74, 0xe1, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x62, 0x5e, 0x6e, 0xcc, 0xc2,
|
||||
0x0c, 0x00, 0x00,
|
||||
// 1289 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xcf, 0x6f, 0xdc, 0x44,
|
||||
0x14, 0x5e, 0x67, 0x7f, 0x64, 0x77, 0x76, 0x93, 0x36, 0x2e, 0xad, 0x4c, 0x81, 0x9d, 0x65, 0x9a,
|
||||
0x4a, 0x0b, 0x48, 0x1b, 0x29, 0x55, 0x2b, 0x54, 0x09, 0xaa, 0xba, 0x51, 0xdb, 0x54, 0xa5, 0x45,
|
||||
0x93, 0xaa, 0x20, 0x2e, 0xab, 0xb5, 0x77, 0x92, 0x58, 0x75, 0xec, 0xc5, 0xe3, 0x34, 0xdd, 0xde,
|
||||
0xb8, 0x20, 0x71, 0x43, 0x15, 0x07, 0x84, 0x10, 0xea, 0x89, 0x3f, 0x81, 0xbf, 0xa1, 0xc7, 0x1c,
|
||||
0x11, 0x07, 0x4b, 0x4d, 0x2e, 0xb0, 0xc7, 0x3d, 0x21, 0x4e, 0x68, 0xde, 0x8c, 0xc7, 0xb3, 0x8d,
|
||||
0x8a, 0xda, 0x92, 0x9b, 0xdf, 0xf7, 0xbe, 0xf7, 0x6c, 0xbf, 0xf9, 0xde, 0x9b, 0x87, 0xde, 0x0a,
|
||||
0x03, 0x6f, 0x65, 0xe8, 0xad, 0xf0, 0x34, 0xd9, 0xf5, 0x53, 0xde, 0x1b, 0x25, 0x71, 0x1a, 0xdb,
|
||||
0x73, 0x43, 0xef, 0xec, 0xb9, 0x84, 0x8d, 0x62, 0xbe, 0x02, 0x80, 0xb7, 0xbb, 0xb9, 0xb2, 0x15,
|
||||
0x6f, 0xc5, 0x60, 0xc0, 0x93, 0x24, 0x9e, 0x3d, 0x23, 0xc2, 0xe1, 0xd1, 0x8f, 0xc3, 0x15, 0x8f,
|
||||
0x8d, 0x14, 0xde, 0x60, 0x8f, 0x52, 0xf9, 0x48, 0x7e, 0x99, 0x43, 0xcd, 0xeb, 0x41, 0xc8, 0xee,
|
||||
0xb3, 0x84, 0x07, 0x71, 0x64, 0xdf, 0x46, 0xf3, 0x0f, 0xe5, 0xa3, 0x63, 0x75, 0xac, 0x6e, 0x73,
|
||||
0xf5, 0x64, 0x2f, 0x4f, 0xd0, 0xbb, 0xcf, 0xfc, 0x34, 0x4e, 0xdc, 0xce, 0xb3, 0x0c, 0x97, 0x26,
|
||||
0x19, 0xce, 0x89, 0xd3, 0x0c, 0x2f, 0x3c, 0xda, 0x09, 0x2f, 0x13, 0x65, 0x13, 0x9a, 0x7b, 0xec,
|
||||
0x4b, 0x68, 0x7e, 0xc8, 0x42, 0x96, 0xb2, 0xa1, 0x33, 0xd7, 0xb1, 0xba, 0x75, 0xf7, 0x5d, 0x11,
|
||||
0xa7, 0x20, 0x1d, 0xa7, 0x6c, 0x42, 0x73, 0x8f, 0x7d, 0x51, 0xc4, 0x3d, 0x0c, 0x7c, 0xc6, 0x9d,
|
||||
0x72, 0xa7, 0xdc, 0x6d, 0xb9, 0xef, 0xc8, 0x38, 0x80, 0xa6, 0x19, 0x6e, 0xa9, 0x38, 0x61, 0x43,
|
||||
0x18, 0x38, 0x6c, 0x8a, 0x4e, 0x04, 0xd1, 0xc3, 0x41, 0x18, 0x0c, 0xfb, 0x79, 0x78, 0x05, 0xc2,
|
||||
0x3f, 0x98, 0x64, 0x78, 0x51, 0xb9, 0xd6, 0x74, 0x96, 0x53, 0x90, 0x65, 0x06, 0x26, 0xf4, 0x05,
|
||||
0x1a, 0xf9, 0xc6, 0x42, 0x4d, 0x55, 0x9c, 0xdb, 0x01, 0x4f, 0xed, 0x10, 0xd5, 0xd5, 0xdf, 0x71,
|
||||
0xc7, 0xea, 0x94, 0xbb, 0xcd, 0xd5, 0x13, 0xbd, 0xa1, 0xd7, 0x33, 0x6a, 0xe8, 0x5e, 0x11, 0x05,
|
||||
0x3a, 0xc8, 0x70, 0x93, 0x0e, 0xf6, 0x14, 0xc6, 0x27, 0x19, 0xd6, 0x71, 0x47, 0x0a, 0xf6, 0x64,
|
||||
0x7f, 0xd9, 0xe4, 0x52, 0xcd, 0xbc, 0x5c, 0xf9, 0xf1, 0x29, 0x2e, 0x91, 0xbf, 0x11, 0x5a, 0x12,
|
||||
0x2f, 0x58, 0x8f, 0x36, 0xe3, 0x7b, 0xc9, 0x6e, 0xe4, 0x0f, 0x44, 0x91, 0x3e, 0x44, 0x95, 0x68,
|
||||
0xb0, 0xc3, 0xe0, 0x9c, 0x1a, 0xee, 0x99, 0x49, 0x86, 0xc1, 0x9e, 0x66, 0x18, 0x41, 0x76, 0x61,
|
||||
0x10, 0x0a, 0x98, 0xe0, 0xf2, 0xe0, 0x31, 0x73, 0xca, 0x1d, 0xab, 0x5b, 0x96, 0x5c, 0x61, 0x6b,
|
||||
0xae, 0x30, 0x08, 0x05, 0xcc, 0xbe, 0x82, 0xd0, 0x4e, 0x3c, 0x0c, 0x36, 0x03, 0x36, 0xec, 0x73,
|
||||
0xa7, 0x0a, 0x11, 0x9d, 0x49, 0x86, 0x1b, 0x39, 0xba, 0x31, 0xcd, 0xf0, 0x09, 0x08, 0xd3, 0x08,
|
||||
0xa1, 0x85, 0xd7, 0xfe, 0xcd, 0x42, 0x4d, 0x9d, 0xc1, 0x1b, 0x3b, 0xad, 0x8e, 0xd5, 0xad, 0xb8,
|
||||
0x3f, 0x58, 0xa2, 0x2c, 0x7f, 0x64, 0xf8, 0xc2, 0x56, 0x90, 0x6e, 0xef, 0x7a, 0x3d, 0x3f, 0xde,
|
||||
0x59, 0xe1, 0xe3, 0xc8, 0x4f, 0xb7, 0x83, 0x68, 0xcb, 0x78, 0x32, 0x45, 0xdb, 0xdb, 0xd8, 0x8e,
|
||||
0x93, 0x74, 0x7d, 0x6d, 0x92, 0x61, 0xfd, 0x51, 0xee, 0x78, 0x9a, 0xe1, 0x93, 0x33, 0xef, 0x77,
|
||||
0xc7, 0xe4, 0xa7, 0xfd, 0xe5, 0x37, 0x49, 0x4c, 0x8d, 0xb4, 0xa6, 0xf8, 0x1b, 0xff, 0x5f, 0xfc,
|
||||
0x97, 0x51, 0x9d, 0xb3, 0xaf, 0x77, 0x59, 0xe4, 0x33, 0x07, 0x41, 0x15, 0xdb, 0x42, 0x05, 0x39,
|
||||
0x36, 0xcd, 0xf0, 0xa2, 0xac, 0xbd, 0x02, 0x08, 0xd5, 0x3e, 0xfb, 0x2e, 0x5a, 0xe4, 0xe3, 0x9d,
|
||||
0x30, 0x88, 0x1e, 0xf4, 0xd3, 0x41, 0xb2, 0xc5, 0x52, 0x67, 0x09, 0x4e, 0xb9, 0x3b, 0xc9, 0xf0,
|
||||
0x82, 0xf2, 0xdc, 0x03, 0x87, 0xd6, 0xf1, 0x0c, 0x4a, 0xe8, 0x2c, 0xcb, 0xbe, 0x86, 0x9a, 0x5e,
|
||||
0x18, 0xfb, 0x0f, 0x78, 0x7f, 0x7b, 0xc0, 0xb7, 0x1d, 0xbb, 0x63, 0x75, 0x5b, 0x2e, 0x11, 0x65,
|
||||
0x95, 0xf0, 0xcd, 0x01, 0xdf, 0xd6, 0x65, 0x2d, 0x20, 0x42, 0x0d, 0xbf, 0xfd, 0x29, 0x6a, 0xb0,
|
||||
0xc8, 0x4f, 0xc6, 0x23, 0xd1, 0xd0, 0xa7, 0x20, 0x05, 0x08, 0x43, 0x83, 0x5a, 0x18, 0x1a, 0x21,
|
||||
0xb4, 0xf0, 0xda, 0x2e, 0xaa, 0xa4, 0xe3, 0x11, 0x83, 0x59, 0xb0, 0xb8, 0x7a, 0xa6, 0x28, 0xae,
|
||||
0x16, 0xf7, 0x78, 0xc4, 0xa4, 0x3a, 0x05, 0x4f, 0xab, 0x53, 0x18, 0x84, 0x02, 0x66, 0x5f, 0x47,
|
||||
0xcd, 0x11, 0x4b, 0x76, 0x02, 0x2e, 0x5b, 0xb0, 0xd2, 0xb1, 0xba, 0x0b, 0xee, 0xf2, 0x24, 0xc3,
|
||||
0x26, 0x3c, 0xcd, 0xf0, 0x12, 0x44, 0x1a, 0x18, 0xa1, 0x26, 0xc3, 0xbe, 0x65, 0x68, 0x34, 0xe2,
|
||||
0x4e, 0xb3, 0x63, 0x75, 0xab, 0x30, 0x27, 0xb4, 0x20, 0xee, 0xf0, 0x23, 0x3a, 0xbb, 0xc3, 0xc9,
|
||||
0x3f, 0x19, 0x2e, 0x07, 0x51, 0x4a, 0x0d, 0x9a, 0xbd, 0x89, 0x64, 0x95, 0xfa, 0xd0, 0x63, 0x0b,
|
||||
0x90, 0xea, 0xc6, 0x41, 0x86, 0x5b, 0x74, 0xb0, 0xe7, 0x0a, 0xc7, 0x46, 0xf0, 0x98, 0x89, 0x42,
|
||||
0x79, 0xb9, 0xa1, 0x0b, 0xa5, 0x91, 0x3c, 0xf1, 0x93, 0xfd, 0xe5, 0x99, 0x30, 0x5a, 0x04, 0xd9,
|
||||
0x6b, 0xa8, 0x19, 0xc6, 0xfe, 0x20, 0xec, 0x6f, 0x86, 0x83, 0x2d, 0xee, 0xfc, 0x39, 0x0f, 0x3f,
|
||||
0x0f, 0xa7, 0x08, 0xf8, 0x75, 0x01, 0xeb, 0x8f, 0x2e, 0x20, 0x42, 0x0d, 0xbf, 0x7d, 0x13, 0xb5,
|
||||
0x94, 0x44, 0xa5, 0x16, 0xfe, 0x9a, 0x87, 0x93, 0x84, 0x1a, 0x2a, 0x87, 0x52, 0xc3, 0x92, 0xa9,
|
||||
0x6c, 0x29, 0x07, 0x93, 0x61, 0x8e, 0xf7, 0xda, 0xeb, 0x8c, 0x77, 0x8a, 0xe6, 0xd5, 0x94, 0x75,
|
||||
0xe6, 0x21, 0xee, 0xe3, 0x83, 0x0c, 0x23, 0x3a, 0xd8, 0x5b, 0x97, 0xa8, 0xc8, 0xa2, 0x08, 0x3a,
|
||||
0x8b, 0xb2, 0xc5, 0xac, 0x34, 0x98, 0x34, 0xe7, 0x89, 0x8e, 0x89, 0xe2, 0xbe, 0x29, 0x8d, 0x3a,
|
||||
0xa4, 0x86, 0x8e, 0x89, 0xe2, 0xcf, 0x67, 0xc4, 0x21, 0x3b, 0x66, 0x06, 0x25, 0x74, 0x96, 0xa5,
|
||||
0x46, 0xef, 0x17, 0xa8, 0x01, 0x47, 0x01, 0xb3, 0xff, 0x16, 0xaa, 0xc9, 0x6e, 0x50, 0x93, 0xff,
|
||||
0x54, 0xa1, 0x60, 0x20, 0x09, 0x09, 0xbb, 0xef, 0xa9, 0x09, 0xa1, 0xa8, 0xd3, 0x0c, 0x37, 0x8b,
|
||||
0x93, 0x26, 0x54, 0xc1, 0xe4, 0x57, 0x0b, 0x9d, 0x5e, 0x8f, 0x86, 0x41, 0xc2, 0xfc, 0x54, 0xd5,
|
||||
0x93, 0xf1, 0xbb, 0x51, 0x38, 0x3e, 0x9e, 0x56, 0x3d, 0xb6, 0x43, 0x26, 0x3f, 0x57, 0x50, 0xed,
|
||||
0x5a, 0xbc, 0x1b, 0xa5, 0xdc, 0xbe, 0x88, 0xaa, 0x9b, 0x41, 0xc8, 0x38, 0x5c, 0x39, 0x55, 0x17,
|
||||
0x4f, 0x32, 0x2c, 0x01, 0xfd, 0x93, 0x60, 0xe9, 0x1e, 0x91, 0x4e, 0xfb, 0x33, 0xd4, 0x94, 0xff,
|
||||
0x19, 0x27, 0x01, 0xe3, 0xd0, 0xfd, 0x55, 0xf7, 0x23, 0xf1, 0x25, 0x06, 0xac, 0xbf, 0xc4, 0xc0,
|
||||
0x74, 0x22, 0x93, 0x68, 0x5f, 0x45, 0x75, 0x35, 0xdb, 0x38, 0xdc, 0x67, 0x55, 0xf7, 0x3c, 0xcc,
|
||||
0x55, 0x85, 0x15, 0x73, 0x55, 0x01, 0x3a, 0x8b, 0xa6, 0xd8, 0x9f, 0x14, 0xc2, 0xad, 0x40, 0x86,
|
||||
0x73, 0xff, 0x25, 0xdc, 0x3c, 0x5e, 0xeb, 0xb7, 0x87, 0xaa, 0xde, 0x38, 0x65, 0xf9, 0xe5, 0xe8,
|
||||
0x88, 0x3a, 0x00, 0x50, 0x1c, 0xb6, 0xb0, 0x08, 0x95, 0xe8, 0xcc, 0x4d, 0x50, 0x7b, 0xcd, 0x9b,
|
||||
0x60, 0x03, 0x35, 0xe4, 0x2e, 0xd3, 0x0f, 0x86, 0x70, 0x09, 0xb4, 0xdc, 0x4b, 0x07, 0x19, 0xae,
|
||||
0xcb, 0xfd, 0x04, 0x6e, 0xc6, 0xba, 0x24, 0xac, 0x0f, 0x75, 0xa2, 0x1c, 0x10, 0xdd, 0xa2, 0x99,
|
||||
0x54, 0xf3, 0x84, 0xc4, 0xcc, 0x41, 0x62, 0xbf, 0xc9, 0x1c, 0x51, 0x0d, 0xf2, 0xad, 0x85, 0x1a,
|
||||
0x52, 0x1e, 0x1b, 0x2c, 0xb5, 0xaf, 0xa2, 0x9a, 0x0f, 0x86, 0xea, 0x10, 0x24, 0x76, 0x23, 0xe9,
|
||||
0x2e, 0x1a, 0x43, 0x32, 0x74, 0xad, 0xc0, 0x24, 0x54, 0xc1, 0x62, 0xa8, 0xf8, 0x09, 0x1b, 0xe4,
|
||||
0x3b, 0x63, 0x59, 0x0e, 0x15, 0x05, 0xe9, 0xb3, 0x51, 0x36, 0xa1, 0xb9, 0x87, 0x7c, 0x37, 0x87,
|
||||
0x4e, 0x1b, 0x5b, 0xd8, 0x1a, 0x1b, 0x25, 0x4c, 0x2e, 0x4a, 0xc7, 0xbb, 0xd3, 0xae, 0xa2, 0x9a,
|
||||
0xac, 0x23, 0x7c, 0x5e, 0xcb, 0x3d, 0x2b, 0x7e, 0x49, 0x22, 0x47, 0x36, 0x53, 0x85, 0x8b, 0x7f,
|
||||
0xca, 0x07, 0x5e, 0xb9, 0x18, 0x94, 0x2f, 0x1b, 0x71, 0xc5, 0x50, 0xbb, 0x34, 0xab, 0xd3, 0x57,
|
||||
0x1d, 0xb0, 0x64, 0x0f, 0x9d, 0x36, 0x76, 0x56, 0xa3, 0x14, 0x5f, 0x1e, 0xd9, 0x5e, 0xdf, 0x7e,
|
||||
0x61, 0x7b, 0x2d, 0xc8, 0xee, 0xfb, 0xaa, 0x28, 0x2f, 0x5f, 0x5c, 0x5f, 0xdc, 0x54, 0xdd, 0x1b,
|
||||
0xcf, 0x9e, 0xb7, 0x4b, 0xfb, 0xcf, 0xdb, 0xa5, 0x67, 0x07, 0x6d, 0x6b, 0xff, 0xa0, 0x6d, 0x7d,
|
||||
0x7f, 0xd8, 0x2e, 0x3d, 0x3d, 0x6c, 0x5b, 0xfb, 0x87, 0xed, 0xd2, 0xef, 0x87, 0xed, 0xd2, 0x57,
|
||||
0xe7, 0x5f, 0x61, 0x49, 0x1b, 0x7a, 0x5e, 0x0d, 0x4e, 0xe8, 0xc2, 0xbf, 0x01, 0x00, 0x00, 0xff,
|
||||
0xff, 0xfc, 0x01, 0x79, 0xc2, 0x02, 0x0d, 0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *FileVersion) Marshal() (dAtA []byte, err error) {
|
||||
@@ -626,6 +628,15 @@ func (m *FileInfoTruncated) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i--
|
||||
dAtA[i] = 0xc0
|
||||
}
|
||||
if len(m.Encrypted) > 0 {
|
||||
i -= len(m.Encrypted)
|
||||
copy(dAtA[i:], m.Encrypted)
|
||||
i = encodeVarintStructs(dAtA, i, uint64(len(m.Encrypted)))
|
||||
i--
|
||||
dAtA[i] = 0x1
|
||||
i--
|
||||
dAtA[i] = 0x9a
|
||||
}
|
||||
if len(m.BlocksHash) > 0 {
|
||||
i -= len(m.BlocksHash)
|
||||
copy(dAtA[i:], m.BlocksHash)
|
||||
@@ -1125,6 +1136,10 @@ func (m *FileInfoTruncated) ProtoSize() (n int) {
|
||||
if l > 0 {
|
||||
n += 2 + l + sovStructs(uint64(l))
|
||||
}
|
||||
l = len(m.Encrypted)
|
||||
if l > 0 {
|
||||
n += 2 + l + sovStructs(uint64(l))
|
||||
}
|
||||
if m.LocalFlags != 0 {
|
||||
n += 2 + sovStructs(uint64(m.LocalFlags))
|
||||
}
|
||||
@@ -1890,6 +1905,40 @@ func (m *FileInfoTruncated) Unmarshal(dAtA []byte) error {
|
||||
m.BlocksHash = []byte{}
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 19:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Encrypted", wireType)
|
||||
}
|
||||
var byteLen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowStructs
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
byteLen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if byteLen < 0 {
|
||||
return ErrInvalidLengthStructs
|
||||
}
|
||||
postIndex := iNdEx + byteLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthStructs
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Encrypted = append(m.Encrypted[:0], dAtA[iNdEx:postIndex]...)
|
||||
if m.Encrypted == nil {
|
||||
m.Encrypted = []byte{}
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 1000:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field LocalFlags", wireType)
|
||||
|
||||
@@ -83,7 +83,7 @@ func (f *fakeConnection) IndexUpdate(ctx context.Context, folder string, fs []pr
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeConnection) Request(ctx context.Context, folder, name string, offset int64, size int, hash []byte, weakHash uint32, fromTemporary bool) ([]byte, error) {
|
||||
func (f *fakeConnection) Request(ctx context.Context, folder, name string, blockNo int, offset int64, size int, hash []byte, weakHash uint32, fromTemporary bool) ([]byte, error) {
|
||||
f.mut.Lock()
|
||||
defer f.mut.Unlock()
|
||||
if f.requestFn != nil {
|
||||
|
||||
+45
-18
@@ -459,7 +459,8 @@ func (f *folder) scanSubdirs(subDirs []string) error {
|
||||
scanCtx, scanCancel := context.WithCancel(f.ctx)
|
||||
defer scanCancel()
|
||||
mtimefs := f.fset.MtimeFS()
|
||||
fchan := scanner.Walk(scanCtx, scanner.Config{
|
||||
|
||||
scanConfig := scanner.Config{
|
||||
Folder: f.ID,
|
||||
Subs: subDirs,
|
||||
Matcher: f.ignores,
|
||||
@@ -474,7 +475,13 @@ func (f *folder) scanSubdirs(subDirs []string) error {
|
||||
LocalFlags: f.localFlags,
|
||||
ModTimeWindow: f.modTimeWindow,
|
||||
EventLogger: f.evLogger,
|
||||
})
|
||||
}
|
||||
var fchan chan scanner.ScanResult
|
||||
if f.Type == config.FolderTypeReceiveEncrypted {
|
||||
fchan = scanner.WalkWithoutHashing(scanCtx, scanConfig)
|
||||
} else {
|
||||
fchan = scanner.Walk(scanCtx, scanConfig)
|
||||
}
|
||||
|
||||
batch := newFileInfoBatch(func(fs []protocol.FileInfo) error {
|
||||
if err := f.getHealthErrorWithoutIgnores(); err != nil {
|
||||
@@ -485,13 +492,19 @@ func (f *folder) scanSubdirs(subDirs []string) error {
|
||||
return nil
|
||||
})
|
||||
|
||||
// Schedule a pull after scanning, but only if we actually detected any
|
||||
// changes.
|
||||
changes := 0
|
||||
defer func() {
|
||||
if changes > 0 {
|
||||
f.SchedulePull()
|
||||
}
|
||||
}()
|
||||
|
||||
var batchAppend func(protocol.FileInfo, *db.Snapshot)
|
||||
// Resolve items which are identical with the global state.
|
||||
if f.localFlags&protocol.FlagLocalReceiveOnly == 0 {
|
||||
batchAppend = func(fi protocol.FileInfo, _ *db.Snapshot) {
|
||||
batch.append(fi)
|
||||
}
|
||||
} else {
|
||||
switch f.Type {
|
||||
case config.FolderTypeReceiveOnly:
|
||||
batchAppend = func(fi protocol.FileInfo, snap *db.Snapshot) {
|
||||
switch gf, ok := snap.GetGlobal(fi.Name); {
|
||||
case !ok:
|
||||
@@ -509,16 +522,28 @@ func (f *folder) scanSubdirs(subDirs []string) error {
|
||||
}
|
||||
batch.append(fi)
|
||||
}
|
||||
}
|
||||
|
||||
// Schedule a pull after scanning, but only if we actually detected any
|
||||
// changes.
|
||||
changes := 0
|
||||
defer func() {
|
||||
if changes > 0 {
|
||||
f.SchedulePull()
|
||||
case config.FolderTypeReceiveEncrypted:
|
||||
batchAppend = func(fi protocol.FileInfo, _ *db.Snapshot) {
|
||||
// This is a "virtual" parent directory of encrypted files.
|
||||
// We don't track it, but check if anything still exists
|
||||
// within and delete it otherwise.
|
||||
if fi.IsDirectory() && protocol.IsEncryptedParent(fi.Name) {
|
||||
if names, err := mtimefs.DirNames(fi.Name); err == nil && len(names) == 0 {
|
||||
mtimefs.Remove(fi.Name)
|
||||
}
|
||||
changes--
|
||||
return
|
||||
}
|
||||
// Any local change must not be sent as index entry to
|
||||
// remotes and show up as an error in the UI.
|
||||
fi.LocalFlags = protocol.FlagLocalReceiveOnly
|
||||
batch.append(fi)
|
||||
}
|
||||
}()
|
||||
default:
|
||||
batchAppend = func(fi protocol.FileInfo, _ *db.Snapshot) {
|
||||
batch.append(fi)
|
||||
}
|
||||
}
|
||||
|
||||
f.clearScanErrors(subDirs)
|
||||
alreadyUsed := make(map[string]struct{})
|
||||
@@ -540,7 +565,9 @@ func (f *folder) scanSubdirs(subDirs []string) error {
|
||||
batchAppend(res.File, snap)
|
||||
changes++
|
||||
|
||||
if f.localFlags&protocol.FlagLocalReceiveOnly == 0 {
|
||||
switch f.Type {
|
||||
case config.FolderTypeReceiveOnly, config.FolderTypeReceiveEncrypted:
|
||||
default:
|
||||
if nf, ok := f.findRename(snap, mtimefs, res.File, alreadyUsed); ok {
|
||||
batchAppend(nf, snap)
|
||||
changes++
|
||||
@@ -648,7 +675,7 @@ func (f *folder) scanSubdirs(subDirs []string) error {
|
||||
l.Debugln("marking file as deleted", nf)
|
||||
batchAppend(nf, snap)
|
||||
changes++
|
||||
case file.IsDeleted() && file.IsReceiveOnlyChanged() && f.localFlags&protocol.FlagLocalReceiveOnly != 0 && len(snap.Availability(file.Name)) == 0:
|
||||
case file.IsDeleted() && file.IsReceiveOnlyChanged() && f.Type == config.FolderTypeReceiveOnly && len(snap.Availability(file.Name)) == 0:
|
||||
file.Version = protocol.Vector{}
|
||||
file.LocalFlags &^= protocol.FlagLocalReceiveOnly
|
||||
l.Debugln("marking deleted item that doesn't exist anywhere as not receive-only", file)
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
// Copyright (C) 2018 The Syncthing Authors.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/config"
|
||||
"github.com/syncthing/syncthing/lib/db"
|
||||
"github.com/syncthing/syncthing/lib/events"
|
||||
"github.com/syncthing/syncthing/lib/fs"
|
||||
"github.com/syncthing/syncthing/lib/ignore"
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
"github.com/syncthing/syncthing/lib/versioner"
|
||||
)
|
||||
|
||||
func init() {
|
||||
folderFactories[config.FolderTypeReceiveEncrypted] = newReceiveEncryptedFolder
|
||||
}
|
||||
|
||||
type receiveEncryptedFolder struct {
|
||||
*sendReceiveFolder
|
||||
}
|
||||
|
||||
func newReceiveEncryptedFolder(model *model, fset *db.FileSet, ignores *ignore.Matcher, cfg config.FolderConfiguration, ver versioner.Versioner, fs fs.Filesystem, evLogger events.Logger, ioLimiter *byteSemaphore) service {
|
||||
return &receiveEncryptedFolder{newSendReceiveFolder(model, fset, ignores, cfg, ver, fs, evLogger, ioLimiter).(*sendReceiveFolder)}
|
||||
}
|
||||
|
||||
func (f *receiveEncryptedFolder) Revert() {
|
||||
f.doInSync(func() error { f.revert(); return nil })
|
||||
}
|
||||
|
||||
func (f *receiveEncryptedFolder) revert() {
|
||||
l.Infof("Reverting unexpected items in folder %v (receive-encrypted)", f.Description())
|
||||
|
||||
f.setState(FolderScanning)
|
||||
defer f.setState(FolderIdle)
|
||||
|
||||
batch := newFileInfoBatch(func(fs []protocol.FileInfo) error {
|
||||
f.updateLocalsFromScanning(fs)
|
||||
return nil
|
||||
})
|
||||
|
||||
snap := f.fset.Snapshot()
|
||||
defer snap.Release()
|
||||
var iterErr error
|
||||
var dirs []string
|
||||
snap.WithHaveTruncated(protocol.LocalDeviceID, func(intf protocol.FileIntf) bool {
|
||||
if iterErr = batch.flushIfFull(); iterErr != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
fit := intf.(db.FileInfoTruncated)
|
||||
if !fit.IsReceiveOnlyChanged() || intf.IsDeleted() {
|
||||
return true
|
||||
}
|
||||
|
||||
if fit.IsDirectory() {
|
||||
dirs = append(dirs, fit.Name)
|
||||
return true
|
||||
}
|
||||
|
||||
if err := f.inWritableDir(f.fs.Remove, fit.Name); err != nil && !fs.IsNotExist(err) {
|
||||
f.newScanError(fit.Name, fmt.Errorf("deleting unexpected item: %w", err))
|
||||
}
|
||||
|
||||
fi := fit.ConvertToDeletedFileInfo(f.shortID)
|
||||
// Set version to zero, such that we pull the global version in case
|
||||
// this is a valid filename that was erroneously changed locally.
|
||||
// Should already be zero from scanning, but lets be safe.
|
||||
fi.Version = protocol.Vector{}
|
||||
// Purposely not removing FlagLocalReceiveOnly as the deleted
|
||||
// item should still not be sent in index updates. However being
|
||||
// deleted, it will not show up as an unexpected file in the UI
|
||||
// anymore.
|
||||
batch.append(fi)
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
f.revertHandleDirs(dirs, snap)
|
||||
|
||||
if iterErr == nil {
|
||||
iterErr = batch.flush()
|
||||
}
|
||||
if iterErr != nil {
|
||||
l.Infoln("Failed to delete unexpected items:", iterErr)
|
||||
}
|
||||
}
|
||||
|
||||
func (f *receiveEncryptedFolder) revertHandleDirs(dirs []string, snap *db.Snapshot) {
|
||||
if len(dirs) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
scanChan := make(chan string)
|
||||
go f.pullScannerRoutine(scanChan)
|
||||
defer close(scanChan)
|
||||
|
||||
sort.Sort(sort.Reverse(sort.StringSlice(dirs)))
|
||||
for _, dir := range dirs {
|
||||
if err := f.deleteDirOnDisk(dir, snap, scanChan); err != nil {
|
||||
f.newScanError(dir, fmt.Errorf("deleting unexpected dir: %w", err))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -686,16 +686,22 @@ func (f *sendReceiveFolder) checkParent(file string, scanChan chan<- string) boo
|
||||
// user can then clean up as they like...
|
||||
// This can also occur if an entire tree structure was deleted, but only
|
||||
// a leave has been scanned.
|
||||
//
|
||||
// And if this is an encrypted folder:
|
||||
// Encrypted files have made-up filenames with two synthetic parent
|
||||
// directories which don't have any meaning. Create those if necessary.
|
||||
if _, err := f.fs.Lstat(parent); !fs.IsNotExist(err) {
|
||||
l.Debugf("%v parent not missing %v", f, file)
|
||||
return true
|
||||
}
|
||||
l.Debugf("%v resurrecting parent directory of %v", f, file)
|
||||
l.Debugf("%v creating parent directory of %v", f, file)
|
||||
if err := f.fs.MkdirAll(parent, 0755); err != nil {
|
||||
f.newPullError(file, errors.Wrap(err, "resurrecting parent dir"))
|
||||
f.newPullError(file, errors.Wrap(err, "creating parent dir"))
|
||||
return false
|
||||
}
|
||||
scanChan <- parent
|
||||
if f.Type != config.FolderTypeReceiveEncrypted {
|
||||
scanChan <- parent
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -1248,38 +1254,11 @@ func (f *sendReceiveFolder) copierRoutine(in <-chan copyBlocksState, pullChan ch
|
||||
continue
|
||||
}
|
||||
|
||||
f.model.progressEmitter.Register(state.sharedPullerState)
|
||||
|
||||
var file fs.File
|
||||
var weakHashFinder *weakhash.Finder
|
||||
|
||||
blocksPercentChanged := 0
|
||||
if tot := len(state.file.Blocks); tot > 0 {
|
||||
blocksPercentChanged = (tot - state.have) * 100 / tot
|
||||
if f.Type != config.FolderTypeReceiveEncrypted {
|
||||
f.model.progressEmitter.Register(state.sharedPullerState)
|
||||
}
|
||||
|
||||
if blocksPercentChanged >= f.WeakHashThresholdPct {
|
||||
hashesToFind := make([]uint32, 0, len(state.blocks))
|
||||
for _, block := range state.blocks {
|
||||
if block.WeakHash != 0 {
|
||||
hashesToFind = append(hashesToFind, block.WeakHash)
|
||||
}
|
||||
}
|
||||
|
||||
if len(hashesToFind) > 0 {
|
||||
file, err = f.fs.Open(state.file.Name)
|
||||
if err == nil {
|
||||
weakHashFinder, err = weakhash.NewFinder(f.ctx, file, state.file.BlockSize(), hashesToFind)
|
||||
if err != nil {
|
||||
l.Debugln("weak hasher", err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
l.Debugf("not weak hashing %s. file did not contain any weak hashes", state.file.Name)
|
||||
}
|
||||
} else {
|
||||
l.Debugf("not weak hashing %s. not enough changed %.02f < %d", state.file.Name, blocksPercentChanged, f.WeakHashThresholdPct)
|
||||
}
|
||||
weakHashFinder, file := f.initWeakHashFinder(state)
|
||||
|
||||
blocks:
|
||||
for _, block := range state.blocks {
|
||||
@@ -1305,25 +1284,28 @@ func (f *sendReceiveFolder) copierRoutine(in <-chan copyBlocksState, pullChan ch
|
||||
|
||||
buf = protocol.BufferPool.Upgrade(buf, int(block.Size))
|
||||
|
||||
found, err := weakHashFinder.Iterate(block.WeakHash, buf, func(offset int64) bool {
|
||||
if verifyBuffer(buf, block) != nil {
|
||||
return true
|
||||
}
|
||||
var found bool
|
||||
if f.Type != config.FolderTypeReceiveEncrypted {
|
||||
found, err = weakHashFinder.Iterate(block.WeakHash, buf, func(offset int64) bool {
|
||||
if f.verifyBuffer(buf, block) != nil {
|
||||
return true
|
||||
}
|
||||
|
||||
err = f.limitedWriteAt(dstFd, buf, block.Offset)
|
||||
err = f.limitedWriteAt(dstFd, buf, block.Offset)
|
||||
if err != nil {
|
||||
state.fail(errors.Wrap(err, "dst write"))
|
||||
}
|
||||
if offset == block.Offset {
|
||||
state.copiedFromOrigin()
|
||||
} else {
|
||||
state.copiedFromOriginShifted()
|
||||
}
|
||||
|
||||
return false
|
||||
})
|
||||
if err != nil {
|
||||
state.fail(errors.Wrap(err, "dst write"))
|
||||
l.Debugln("weak hasher iter", err)
|
||||
}
|
||||
if offset == block.Offset {
|
||||
state.copiedFromOrigin()
|
||||
} else {
|
||||
state.copiedFromOriginShifted()
|
||||
}
|
||||
|
||||
return false
|
||||
})
|
||||
if err != nil {
|
||||
l.Debugln("weak hasher iter", err)
|
||||
}
|
||||
|
||||
if !found {
|
||||
@@ -1341,9 +1323,14 @@ func (f *sendReceiveFolder) copierRoutine(in <-chan copyBlocksState, pullChan ch
|
||||
return false
|
||||
}
|
||||
|
||||
if err := verifyBuffer(buf, block); err != nil {
|
||||
l.Debugln("Finder failed to verify buffer", err)
|
||||
return false
|
||||
// Hash is not SHA256 as it's an encrypted hash token. In that
|
||||
// case we can't verify the block integrity so we'll take it on
|
||||
// trust. (The other side can and will verify.)
|
||||
if f.Type != config.FolderTypeReceiveEncrypted {
|
||||
if err := f.verifyBuffer(buf, block); err != nil {
|
||||
l.Debugln("Finder failed to verify buffer", err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if f.CopyRangeMethod != fs.CopyRangeMethodStandard {
|
||||
@@ -1390,7 +1377,49 @@ func (f *sendReceiveFolder) copierRoutine(in <-chan copyBlocksState, pullChan ch
|
||||
}
|
||||
}
|
||||
|
||||
func verifyBuffer(buf []byte, block protocol.BlockInfo) error {
|
||||
func (f *sendReceiveFolder) initWeakHashFinder(state copyBlocksState) (*weakhash.Finder, fs.File) {
|
||||
if f.Type == config.FolderTypeReceiveEncrypted {
|
||||
l.Debugln("not weak hashing due to folder type", f.Type)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
blocksPercentChanged := 0
|
||||
if tot := len(state.file.Blocks); tot > 0 {
|
||||
blocksPercentChanged = (tot - state.have) * 100 / tot
|
||||
}
|
||||
|
||||
if blocksPercentChanged < f.WeakHashThresholdPct {
|
||||
l.Debugf("not weak hashing %s. not enough changed %.02f < %d", state.file.Name, blocksPercentChanged, f.WeakHashThresholdPct)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
hashesToFind := make([]uint32, 0, len(state.blocks))
|
||||
for _, block := range state.blocks {
|
||||
if block.WeakHash != 0 {
|
||||
hashesToFind = append(hashesToFind, block.WeakHash)
|
||||
}
|
||||
}
|
||||
|
||||
if len(hashesToFind) == 0 {
|
||||
l.Debugf("not weak hashing %s. file did not contain any weak hashes", state.file.Name)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
file, err := f.fs.Open(state.file.Name)
|
||||
if err != nil {
|
||||
l.Debugln("weak hasher", err)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
weakHashFinder, err := weakhash.NewFinder(f.ctx, file, state.file.BlockSize(), hashesToFind)
|
||||
if err != nil {
|
||||
l.Debugln("weak hasher", err)
|
||||
return nil, file
|
||||
}
|
||||
return weakHashFinder, file
|
||||
}
|
||||
|
||||
func (f *sendReceiveFolder) verifyBuffer(buf []byte, block protocol.BlockInfo) error {
|
||||
if len(buf) != int(block.Size) {
|
||||
return fmt.Errorf("length mismatch %d != %d", len(buf), block.Size)
|
||||
}
|
||||
@@ -1487,7 +1516,8 @@ func (f *sendReceiveFolder) pullBlock(state pullBlockState, out chan<- *sharedPu
|
||||
// leastBusy can select another device when someone else asks.
|
||||
activity.using(selected)
|
||||
var buf []byte
|
||||
buf, lastError = f.model.requestGlobal(f.ctx, selected.ID, f.folderID, state.file.Name, state.block.Offset, int(state.block.Size), state.block.Hash, state.block.WeakHash, selected.FromTemporary)
|
||||
blockNo := int(state.block.Offset / int64(state.file.BlockSize()))
|
||||
buf, lastError = f.model.requestGlobal(f.ctx, selected.ID, f.folderID, state.file.Name, blockNo, state.block.Offset, int(state.block.Size), state.block.Hash, state.block.WeakHash, selected.FromTemporary)
|
||||
activity.done(selected)
|
||||
if lastError != nil {
|
||||
l.Debugln("request:", f.folderID, state.file.Name, state.block.Offset, state.block.Size, "returned error:", lastError)
|
||||
@@ -1496,7 +1526,13 @@ func (f *sendReceiveFolder) pullBlock(state pullBlockState, out chan<- *sharedPu
|
||||
|
||||
// Verify that the received block matches the desired hash, if not
|
||||
// try pulling it from another device.
|
||||
lastError = verifyBuffer(buf, state.block)
|
||||
// For receive-only folders, the hash is not SHA256 as it's an
|
||||
// encrypted hash token. In that case we can't verify the block
|
||||
// integrity so we'll take it on trust. (The other side can and
|
||||
// will verify.)
|
||||
if f.Type != config.FolderTypeReceiveEncrypted {
|
||||
lastError = f.verifyBuffer(buf, state.block)
|
||||
}
|
||||
if lastError != nil {
|
||||
l.Debugln("request:", f.folderID, state.file.Name, state.block.Offset, state.block.Size, "hash mismatch")
|
||||
continue
|
||||
@@ -1595,7 +1631,9 @@ func (f *sendReceiveFolder) finisherRoutine(snap *db.Snapshot, in <-chan *shared
|
||||
blockStatsMut.Unlock()
|
||||
}
|
||||
|
||||
f.model.progressEmitter.Deregister(state)
|
||||
if f.Type != config.FolderTypeReceiveEncrypted {
|
||||
f.model.progressEmitter.Deregister(state)
|
||||
}
|
||||
|
||||
f.evLogger.Log(events.ItemFinished, map[string]interface{}{
|
||||
"folder": f.folderID,
|
||||
|
||||
@@ -123,9 +123,9 @@ func (c *folderSummaryService) Summary(folder string) (map[string]interface{}, e
|
||||
}
|
||||
res["needFiles"], res["needDirectories"], res["needSymlinks"], res["needDeletes"], res["needBytes"], res["needTotalItems"] = need.Files, need.Directories, need.Symlinks, need.Deleted, need.Bytes, need.TotalItems()
|
||||
|
||||
if haveFcfg && fcfg.Type == config.FolderTypeReceiveOnly {
|
||||
if haveFcfg && (fcfg.Type == config.FolderTypeReceiveOnly || fcfg.Type == config.FolderTypeReceiveEncrypted) {
|
||||
// Add statistics for things that have changed locally in a receive
|
||||
// only folder.
|
||||
// only or receive encrypted folder.
|
||||
res["receiveOnlyChangedFiles"] = ro.Files
|
||||
res["receiveOnlyChangedDirectories"] = ro.Directories
|
||||
res["receiveOnlyChangedSymlinks"] = ro.Symlinks
|
||||
|
||||
@@ -23,15 +23,17 @@ import (
|
||||
|
||||
type indexSender struct {
|
||||
suture.Service
|
||||
conn protocol.Connection
|
||||
folder string
|
||||
fset *db.FileSet
|
||||
prevSequence int64
|
||||
evLogger events.Logger
|
||||
connClosed chan struct{}
|
||||
token suture.ServiceToken
|
||||
pauseChan chan struct{}
|
||||
resumeChan chan *db.FileSet
|
||||
conn protocol.Connection
|
||||
folder string
|
||||
folderIsReceiveEncrypted bool
|
||||
dev string
|
||||
fset *db.FileSet
|
||||
prevSequence int64
|
||||
evLogger events.Logger
|
||||
connClosed chan struct{}
|
||||
token suture.ServiceToken
|
||||
pauseChan chan struct{}
|
||||
resumeChan chan *db.FileSet
|
||||
}
|
||||
|
||||
func (s *indexSender) serve(ctx context.Context) {
|
||||
@@ -169,6 +171,13 @@ func (s *indexSender) sendIndexTo(ctx context.Context) error {
|
||||
|
||||
f = fi.(protocol.FileInfo)
|
||||
|
||||
// If this is a folder receiving encrypted files only, we
|
||||
// mustn't ever send locally changed file infos. Those aren't
|
||||
// encrypted and thus would be a protocol error at the remote.
|
||||
if s.folderIsReceiveEncrypted && fi.IsReceiveOnlyChanged() {
|
||||
return true
|
||||
}
|
||||
|
||||
// Mark the file as invalid if any of the local bad stuff flags are set.
|
||||
f.RawInvalid = f.IsInvalid()
|
||||
// If the file is marked LocalReceive (i.e., changed locally on a
|
||||
|
||||
+365
-125
@@ -11,6 +11,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
@@ -131,15 +132,17 @@ type model struct {
|
||||
folderIOLimiter *byteSemaphore
|
||||
|
||||
// fields protected by fmut
|
||||
fmut sync.RWMutex
|
||||
folderCfgs map[string]config.FolderConfiguration // folder -> cfg
|
||||
folderFiles map[string]*db.FileSet // folder -> files
|
||||
deviceStatRefs map[protocol.DeviceID]*stats.DeviceStatisticsReference // deviceID -> statsRef
|
||||
folderIgnores map[string]*ignore.Matcher // folder -> matcher object
|
||||
folderRunners map[string]service // folder -> puller or scanner
|
||||
folderRunnerToken map[string]suture.ServiceToken // folder -> token for folder runner
|
||||
folderRestartMuts syncMutexMap // folder -> restart mutex
|
||||
folderVersioners map[string]versioner.Versioner // folder -> versioner (may be nil)
|
||||
fmut sync.RWMutex
|
||||
folderCfgs map[string]config.FolderConfiguration // folder -> cfg
|
||||
folderFiles map[string]*db.FileSet // folder -> files
|
||||
deviceStatRefs map[protocol.DeviceID]*stats.DeviceStatisticsReference // deviceID -> statsRef
|
||||
folderIgnores map[string]*ignore.Matcher // folder -> matcher object
|
||||
folderRunners map[string]service // folder -> puller or scanner
|
||||
folderRunnerToken map[string]suture.ServiceToken // folder -> token for folder runner
|
||||
folderRestartMuts syncMutexMap // folder -> restart mutex
|
||||
folderVersioners map[string]versioner.Versioner // folder -> versioner (may be nil)
|
||||
folderEncryptionPasswordTokens map[string][]byte // folder -> encryption token (may be missing, and only for encryption type folders)
|
||||
folderEncryptionFailures map[string]map[protocol.DeviceID]error // folder -> device -> error regarding encryption consistency (may be missing)
|
||||
|
||||
// fields protected by pmut
|
||||
pmut sync.RWMutex
|
||||
@@ -171,11 +174,18 @@ var (
|
||||
errNetworkNotAllowed = errors.New("network not allowed")
|
||||
errNoVersioner = errors.New("folder has no versioner")
|
||||
// errors about why a connection is closed
|
||||
errIgnoredFolderRemoved = errors.New("folder no longer ignored")
|
||||
errReplacingConnection = errors.New("replacing connection")
|
||||
errStopped = errors.New("Syncthing is being stopped")
|
||||
errMissingRemoteInClusterConfig = errors.New("remote device missing in cluster config")
|
||||
errMissingLocalInClusterConfig = errors.New("local device missing in cluster config")
|
||||
errIgnoredFolderRemoved = errors.New("folder no longer ignored")
|
||||
errReplacingConnection = errors.New("replacing connection")
|
||||
errStopped = errors.New("Syncthing is being stopped")
|
||||
errEncryptionInvConfigLocal = errors.New("can't encrypt data for a device when the folder type is receiveEncrypted")
|
||||
errEncryptionInvConfigRemote = errors.New("remote has encrypted data and encrypts that data for us - this is impossible")
|
||||
errEncryptionNotEncryptedLocal = errors.New("folder is announced as encrypted, but not configured thus")
|
||||
errEncryptionNotEncryptedRemote = errors.New("folder is configured to be encrypted but not announced thus")
|
||||
errEncryptionNotEncryptedUntrusted = errors.New("device is untrusted, but configured to receive not encrypted data")
|
||||
errEncryptionPassword = errors.New("different encryption passwords used")
|
||||
errEncryptionReceivedToken = errors.New("resetting connection to send info on new encrypted folder (new cluster config)")
|
||||
errMissingRemoteInClusterConfig = errors.New("remote device missing in cluster config")
|
||||
errMissingLocalInClusterConfig = errors.New("local device missing in cluster config")
|
||||
)
|
||||
|
||||
// NewModel creates and starts a new model. The model starts in read-only mode,
|
||||
@@ -207,14 +217,16 @@ func NewModel(cfg config.Wrapper, id protocol.DeviceID, clientName, clientVersio
|
||||
folderIOLimiter: newByteSemaphore(cfg.Options().MaxFolderConcurrency()),
|
||||
|
||||
// fields protected by fmut
|
||||
fmut: sync.NewRWMutex(),
|
||||
folderCfgs: make(map[string]config.FolderConfiguration),
|
||||
folderFiles: make(map[string]*db.FileSet),
|
||||
deviceStatRefs: make(map[protocol.DeviceID]*stats.DeviceStatisticsReference),
|
||||
folderIgnores: make(map[string]*ignore.Matcher),
|
||||
folderRunners: make(map[string]service),
|
||||
folderRunnerToken: make(map[string]suture.ServiceToken),
|
||||
folderVersioners: make(map[string]versioner.Versioner),
|
||||
fmut: sync.NewRWMutex(),
|
||||
folderCfgs: make(map[string]config.FolderConfiguration),
|
||||
folderFiles: make(map[string]*db.FileSet),
|
||||
deviceStatRefs: make(map[protocol.DeviceID]*stats.DeviceStatisticsReference),
|
||||
folderIgnores: make(map[string]*ignore.Matcher),
|
||||
folderRunners: make(map[string]service),
|
||||
folderRunnerToken: make(map[string]suture.ServiceToken),
|
||||
folderVersioners: make(map[string]versioner.Versioner),
|
||||
folderEncryptionPasswordTokens: make(map[string][]byte),
|
||||
folderEncryptionFailures: make(map[string]map[protocol.DeviceID]error),
|
||||
|
||||
// fields protected by pmut
|
||||
pmut: sync.NewRWMutex(),
|
||||
@@ -339,6 +351,14 @@ func (m *model) addAndStartFolderLockedWithIgnores(cfg config.FolderConfiguratio
|
||||
|
||||
ffs := fset.MtimeFS()
|
||||
|
||||
if cfg.Type == config.FolderTypeReceiveEncrypted {
|
||||
if encryptionToken, err := readEncryptionToken(cfg); err == nil {
|
||||
m.folderEncryptionPasswordTokens[folder] = encryptionToken
|
||||
} else if !fs.IsNotExist(err) {
|
||||
l.Warnf("Failed to read encryption token: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// These are our metadata files, and they should always be hidden.
|
||||
_ = ffs.Hide(config.DefaultMarkerName)
|
||||
_ = ffs.Hide(".stversions")
|
||||
@@ -1026,8 +1046,6 @@ func (m *model) ClusterConfig(deviceID protocol.DeviceID, cm protocol.ClusterCon
|
||||
// Also, collect a list of folders we do share, and if he's interested in
|
||||
// temporary indexes, subscribe the connection.
|
||||
|
||||
tempIndexFolders := make([]string, 0, len(cm.Folders))
|
||||
|
||||
m.pmut.RLock()
|
||||
indexSenderRegistry, ok := m.indexSenders[deviceID]
|
||||
m.pmut.RUnlock()
|
||||
@@ -1042,11 +1060,37 @@ func (m *model) ClusterConfig(deviceID protocol.DeviceID, cm protocol.ClusterCon
|
||||
return errDeviceUnknown
|
||||
}
|
||||
|
||||
// Assemble the device information from the connected device about
|
||||
// themselves and us for all folders.
|
||||
ccDeviceInfos := make(map[string]*indexSenderStartInfo, len(cm.Folders))
|
||||
for _, folder := range cm.Folders {
|
||||
info := &indexSenderStartInfo{}
|
||||
for _, dev := range folder.Devices {
|
||||
if dev.ID == m.id {
|
||||
info.local = dev
|
||||
} else if dev.ID == deviceID {
|
||||
info.remote = dev
|
||||
}
|
||||
if info.local.ID != protocol.EmptyDeviceID && info.remote.ID != protocol.EmptyDeviceID {
|
||||
break
|
||||
}
|
||||
}
|
||||
if info.remote.ID == protocol.EmptyDeviceID {
|
||||
l.Infof("Device %v sent cluster-config without the device info for the remote on folder %v", deviceID, folder.Description())
|
||||
return errMissingRemoteInClusterConfig
|
||||
}
|
||||
if info.local.ID == protocol.EmptyDeviceID {
|
||||
l.Infof("Device %v sent cluster-config without the device info for us locally on folder %v", deviceID, folder.Description())
|
||||
return errMissingLocalInClusterConfig
|
||||
}
|
||||
ccDeviceInfos[folder.ID] = info
|
||||
}
|
||||
|
||||
// Needs to happen outside of the fmut, as can cause CommitConfiguration
|
||||
if deviceCfg.AutoAcceptFolders {
|
||||
changedFolders := make([]config.FolderConfiguration, 0, len(cm.Folders))
|
||||
for _, folder := range cm.Folders {
|
||||
if fcfg, fchanged := m.handleAutoAccepts(deviceCfg, folder); fchanged {
|
||||
if fcfg, fchanged := m.handleAutoAccepts(deviceID, folder, ccDeviceInfos[folder.ID]); fchanged {
|
||||
changedFolders = append(changedFolders, fcfg)
|
||||
}
|
||||
}
|
||||
@@ -1061,91 +1105,16 @@ func (m *model) ClusterConfig(deviceID protocol.DeviceID, cm protocol.ClusterCon
|
||||
}
|
||||
}
|
||||
|
||||
paused := make(map[string]struct{}, len(cm.Folders))
|
||||
seenFolders := make(map[string]struct{}, len(cm.Folders))
|
||||
for _, folder := range cm.Folders {
|
||||
seenFolders[folder.ID] = struct{}{}
|
||||
|
||||
cfg, ok := m.cfg.Folder(folder.ID)
|
||||
if !ok || !cfg.SharedWith(deviceID) {
|
||||
indexSenderRegistry.remove(folder.ID)
|
||||
if deviceCfg.IgnoredFolder(folder.ID) {
|
||||
l.Infof("Ignoring folder %s from device %s since we are configured to", folder.Description(), deviceID)
|
||||
continue
|
||||
}
|
||||
m.cfg.AddOrUpdatePendingFolder(folder.ID, folder.Label, deviceID)
|
||||
changed = true
|
||||
m.evLogger.Log(events.FolderRejected, map[string]string{
|
||||
"folder": folder.ID,
|
||||
"folderLabel": folder.Label,
|
||||
"device": deviceID.String(),
|
||||
})
|
||||
l.Infof("Unexpected folder %s sent from device %q; ensure that the folder exists and that this device is selected under \"Share With\" in the folder configuration.", folder.Description(), deviceID)
|
||||
continue
|
||||
}
|
||||
|
||||
deviceInfos := &indexSenderStartInfo{}
|
||||
for _, dev := range folder.Devices {
|
||||
if dev.ID == m.id {
|
||||
deviceInfos.local = dev
|
||||
} else if dev.ID == deviceID {
|
||||
deviceInfos.remote = dev
|
||||
}
|
||||
if deviceInfos.local.ID != protocol.EmptyDeviceID && deviceInfos.remote.ID != protocol.EmptyDeviceID {
|
||||
break
|
||||
}
|
||||
}
|
||||
if deviceInfos.remote.ID == protocol.EmptyDeviceID {
|
||||
l.Infof("Device %v sent cluster-config without the device info for the remote on folder %v", deviceID, folder.Description())
|
||||
return errMissingRemoteInClusterConfig
|
||||
}
|
||||
if deviceInfos.local.ID == protocol.EmptyDeviceID {
|
||||
l.Infof("Device %v sent cluster-config without the device info for us locally on folder %v", deviceID, folder.Description())
|
||||
return errMissingLocalInClusterConfig
|
||||
}
|
||||
|
||||
if folder.Paused {
|
||||
indexSenderRegistry.remove(folder.ID)
|
||||
paused[cfg.ID] = struct{}{}
|
||||
continue
|
||||
}
|
||||
|
||||
if cfg.Paused {
|
||||
indexSenderRegistry.addPaused(cfg, deviceInfos)
|
||||
continue
|
||||
}
|
||||
|
||||
m.fmut.RLock()
|
||||
fs, ok := m.folderFiles[folder.ID]
|
||||
m.fmut.RUnlock()
|
||||
if !ok {
|
||||
// Shouldn't happen because !cfg.Paused, but might happen
|
||||
// if the folder is about to be unpaused, but not yet.
|
||||
continue
|
||||
}
|
||||
|
||||
if !folder.DisableTempIndexes {
|
||||
tempIndexFolders = append(tempIndexFolders, folder.ID)
|
||||
}
|
||||
|
||||
indexSenderRegistry.add(cfg, fs, deviceInfos)
|
||||
|
||||
// We might already have files that we need to pull so let the
|
||||
// folder runner know that it should recheck the index data.
|
||||
m.fmut.RLock()
|
||||
if runner := m.folderRunners[folder.ID]; runner != nil {
|
||||
defer runner.SchedulePull()
|
||||
}
|
||||
m.fmut.RUnlock()
|
||||
changedHere, tempIndexFolders, paused, err := m.ccHandleFolders(cm.Folders, deviceCfg, ccDeviceInfos, indexSenderRegistry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
indexSenderRegistry.removeAllExcept(seenFolders)
|
||||
changed = changed || changedHere
|
||||
|
||||
m.pmut.Lock()
|
||||
m.remotePausedFolders[deviceID] = paused
|
||||
m.pmut.Unlock()
|
||||
|
||||
// This breaks if we send multiple CM messages during the same connection.
|
||||
if len(tempIndexFolders) > 0 {
|
||||
m.pmut.RLock()
|
||||
conn, ok := m.conn[deviceID]
|
||||
@@ -1184,6 +1153,212 @@ func (m *model) ClusterConfig(deviceID protocol.DeviceID, cm protocol.ClusterCon
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *model) ccHandleFolders(folders []protocol.Folder, deviceCfg config.DeviceConfiguration, ccDeviceInfos map[string]*indexSenderStartInfo, indexSenders *indexSenderRegistry) (bool, []string, map[string]struct{}, error) {
|
||||
var changed bool
|
||||
var folderDevice config.FolderDeviceConfiguration
|
||||
tempIndexFolders := make([]string, 0, len(folders))
|
||||
paused := make(map[string]struct{}, len(folders))
|
||||
seenFolders := make(map[string]struct{}, len(folders))
|
||||
deviceID := deviceCfg.DeviceID
|
||||
for _, folder := range folders {
|
||||
seenFolders[folder.ID] = struct{}{}
|
||||
|
||||
cfg, ok := m.cfg.Folder(folder.ID)
|
||||
if ok {
|
||||
folderDevice, ok = cfg.Device(deviceID)
|
||||
}
|
||||
if !ok {
|
||||
indexSenders.remove(folder.ID)
|
||||
if deviceCfg.IgnoredFolder(folder.ID) {
|
||||
l.Infof("Ignoring folder %s from device %s since we are configured to", folder.Description(), deviceID)
|
||||
continue
|
||||
}
|
||||
m.cfg.AddOrUpdatePendingFolder(folder.ID, folder.Label, deviceID)
|
||||
changed = true
|
||||
m.evLogger.Log(events.FolderRejected, map[string]string{
|
||||
"folder": folder.ID,
|
||||
"folderLabel": folder.Label,
|
||||
"device": deviceID.String(),
|
||||
})
|
||||
l.Infof("Unexpected folder %s sent from device %q; ensure that the folder exists and that this device is selected under \"Share With\" in the folder configuration.", folder.Description(), deviceID)
|
||||
continue
|
||||
}
|
||||
|
||||
if folder.Paused {
|
||||
indexSenders.remove(folder.ID)
|
||||
paused[cfg.ID] = struct{}{}
|
||||
continue
|
||||
}
|
||||
|
||||
if cfg.Paused {
|
||||
indexSenders.addPaused(cfg, ccDeviceInfos[folder.ID])
|
||||
continue
|
||||
}
|
||||
|
||||
m.fmut.RLock()
|
||||
fs, ok := m.folderFiles[folder.ID]
|
||||
m.fmut.RUnlock()
|
||||
if !ok {
|
||||
// Shouldn't happen because !cfg.Paused, but might happen
|
||||
// if the folder is about to be unpaused, but not yet.
|
||||
l.Debugln("ccH: no fset", folder.ID)
|
||||
continue
|
||||
}
|
||||
|
||||
if err := m.ccCheckEncryption(cfg, folderDevice, ccDeviceInfos[folder.ID], deviceCfg.Untrusted); err != nil {
|
||||
sameError := false
|
||||
if devs, ok := m.folderEncryptionFailures[folder.ID]; ok {
|
||||
sameError = devs[deviceID] == err
|
||||
} else {
|
||||
m.folderEncryptionFailures[folder.ID] = make(map[protocol.DeviceID]error)
|
||||
}
|
||||
m.folderEncryptionFailures[folder.ID][deviceID] = err
|
||||
msg := fmt.Sprintf("Failure checking encryption consistency with device %v for folder %v: %v", deviceID, cfg.Description(), err)
|
||||
if sameError || err == errEncryptionReceivedToken {
|
||||
l.Debugln(msg)
|
||||
} else {
|
||||
l.Warnln(msg)
|
||||
}
|
||||
|
||||
return changed, tempIndexFolders, paused, err
|
||||
}
|
||||
if devErrs, ok := m.folderEncryptionFailures[folder.ID]; ok {
|
||||
if len(devErrs) == 1 {
|
||||
delete(m.folderEncryptionFailures, folder.ID)
|
||||
} else {
|
||||
delete(m.folderEncryptionFailures[folder.ID], deviceID)
|
||||
}
|
||||
}
|
||||
|
||||
// Handle indexes
|
||||
|
||||
if !folder.DisableTempIndexes {
|
||||
tempIndexFolders = append(tempIndexFolders, folder.ID)
|
||||
}
|
||||
|
||||
indexSenders.add(cfg, fs, ccDeviceInfos[folder.ID])
|
||||
|
||||
// We might already have files that we need to pull so let the
|
||||
// folder runner know that it should recheck the index data.
|
||||
m.fmut.RLock()
|
||||
if runner := m.folderRunners[folder.ID]; runner != nil {
|
||||
defer runner.SchedulePull()
|
||||
}
|
||||
m.fmut.RUnlock()
|
||||
}
|
||||
|
||||
indexSenders.removeAllExcept(seenFolders)
|
||||
|
||||
return changed, tempIndexFolders, paused, nil
|
||||
}
|
||||
|
||||
func (m *model) ccCheckEncryption(fcfg config.FolderConfiguration, folderDevice config.FolderDeviceConfiguration, ccDeviceInfos *indexSenderStartInfo, deviceUntrusted bool) error {
|
||||
hasTokenRemote := len(ccDeviceInfos.remote.EncryptionPasswordToken) > 0
|
||||
hasTokenLocal := len(ccDeviceInfos.local.EncryptionPasswordToken) > 0
|
||||
isEncryptedRemote := folderDevice.EncryptionPassword != ""
|
||||
isEncryptedLocal := fcfg.Type == config.FolderTypeReceiveEncrypted
|
||||
|
||||
if !isEncryptedRemote && !isEncryptedLocal && deviceUntrusted {
|
||||
return errEncryptionNotEncryptedUntrusted
|
||||
}
|
||||
|
||||
if !(hasTokenRemote || hasTokenLocal || isEncryptedRemote || isEncryptedLocal) {
|
||||
// Noone cares about encryption here
|
||||
return nil
|
||||
}
|
||||
|
||||
if isEncryptedRemote && isEncryptedLocal {
|
||||
// Should never happen, but config racyness and be safe.
|
||||
return errEncryptionInvConfigLocal
|
||||
}
|
||||
|
||||
if hasTokenRemote && hasTokenLocal {
|
||||
return errEncryptionInvConfigRemote
|
||||
}
|
||||
|
||||
if !(hasTokenRemote || hasTokenLocal) {
|
||||
return errEncryptionNotEncryptedRemote
|
||||
}
|
||||
|
||||
if !(isEncryptedRemote || isEncryptedLocal) {
|
||||
return errEncryptionNotEncryptedLocal
|
||||
}
|
||||
|
||||
if isEncryptedRemote {
|
||||
passwordToken := protocol.PasswordToken(fcfg.ID, folderDevice.EncryptionPassword)
|
||||
match := false
|
||||
if hasTokenLocal {
|
||||
match = bytes.Equal(passwordToken, ccDeviceInfos.local.EncryptionPasswordToken)
|
||||
} else {
|
||||
// hasTokenRemote == true
|
||||
match = bytes.Equal(passwordToken, ccDeviceInfos.remote.EncryptionPasswordToken)
|
||||
}
|
||||
if !match {
|
||||
return errEncryptionPassword
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// isEncryptedLocal == true
|
||||
|
||||
var ccToken []byte
|
||||
if hasTokenLocal {
|
||||
ccToken = ccDeviceInfos.local.EncryptionPasswordToken
|
||||
} else {
|
||||
// hasTokenRemote == true
|
||||
ccToken = ccDeviceInfos.remote.EncryptionPasswordToken
|
||||
}
|
||||
m.fmut.RLock()
|
||||
token, ok := m.folderEncryptionPasswordTokens[fcfg.ID]
|
||||
m.fmut.RUnlock()
|
||||
if !ok {
|
||||
var err error
|
||||
token, err = readEncryptionToken(fcfg)
|
||||
if err != nil && !fs.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
if err == nil {
|
||||
m.fmut.Lock()
|
||||
m.folderEncryptionPasswordTokens[fcfg.ID] = token
|
||||
m.fmut.Unlock()
|
||||
} else {
|
||||
if err := writeEncryptionToken(ccToken, fcfg); err != nil {
|
||||
return err
|
||||
}
|
||||
m.fmut.Lock()
|
||||
m.folderEncryptionPasswordTokens[fcfg.ID] = ccToken
|
||||
m.fmut.Unlock()
|
||||
// We can only announce ourselfs once we have the token,
|
||||
// thus we need to resend CCs now that we have it.
|
||||
m.resendClusterConfig(fcfg.DeviceIDs())
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if !bytes.Equal(token, ccToken) {
|
||||
return errEncryptionPassword
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *model) resendClusterConfig(ids []protocol.DeviceID) {
|
||||
if len(ids) == 0 {
|
||||
return
|
||||
}
|
||||
ccConns := make([]protocol.Connection, 0, len(ids))
|
||||
m.pmut.RLock()
|
||||
for _, id := range ids {
|
||||
if conn, ok := m.conn[id]; ok {
|
||||
ccConns = append(ccConns, conn)
|
||||
}
|
||||
}
|
||||
m.pmut.RUnlock()
|
||||
// Generating cluster-configs acquires fmut -> must happen outside of pmut.
|
||||
for _, conn := range ccConns {
|
||||
cm := m.generateClusterConfig(conn.ID())
|
||||
go conn.ClusterConfig(cm)
|
||||
}
|
||||
}
|
||||
|
||||
// handleIntroductions handles adding devices/folders that are shared by an introducer device
|
||||
func (m *model) handleIntroductions(introducerCfg config.DeviceConfiguration, cm protocol.ClusterConfig) (map[string]config.FolderConfiguration, map[protocol.DeviceID]config.DeviceConfiguration, folderDeviceSet, bool) {
|
||||
changed := false
|
||||
@@ -1295,7 +1470,7 @@ func (m *model) handleDeintroductions(introducerCfg config.DeviceConfiguration,
|
||||
|
||||
// handleAutoAccepts handles adding and sharing folders for devices that have
|
||||
// AutoAcceptFolders set to true.
|
||||
func (m *model) handleAutoAccepts(deviceCfg config.DeviceConfiguration, folder protocol.Folder) (config.FolderConfiguration, bool) {
|
||||
func (m *model) handleAutoAccepts(deviceID protocol.DeviceID, folder protocol.Folder, ccDeviceInfos *indexSenderStartInfo) (config.FolderConfiguration, bool) {
|
||||
if cfg, ok := m.cfg.Folder(folder.ID); !ok {
|
||||
defaultPath := m.cfg.Options().DefaultFolderPath
|
||||
defaultPathFs := fs.NewFilesystem(fs.FilesystemTypeBasic, defaultPath)
|
||||
@@ -1310,25 +1485,40 @@ func (m *model) handleAutoAccepts(deviceCfg config.DeviceConfiguration, folder p
|
||||
|
||||
fcfg := config.NewFolderConfiguration(m.id, folder.ID, folder.Label, fs.FilesystemTypeBasic, filepath.Join(defaultPath, path))
|
||||
fcfg.Devices = append(fcfg.Devices, config.FolderDeviceConfiguration{
|
||||
DeviceID: deviceCfg.DeviceID,
|
||||
DeviceID: deviceID,
|
||||
})
|
||||
|
||||
l.Infof("Auto-accepted %s folder %s at path %s", deviceCfg.DeviceID, folder.Description(), fcfg.Path)
|
||||
if len(ccDeviceInfos.remote.EncryptionPasswordToken) > 0 || len(ccDeviceInfos.local.EncryptionPasswordToken) > 0 {
|
||||
fcfg.Type = config.FolderTypeReceiveEncrypted
|
||||
}
|
||||
|
||||
l.Infof("Auto-accepted %s folder %s at path %s", deviceID, folder.Description(), fcfg.Path)
|
||||
return fcfg, true
|
||||
}
|
||||
l.Infof("Failed to auto-accept folder %s from %s due to path conflict", folder.Description(), deviceCfg.DeviceID)
|
||||
l.Infof("Failed to auto-accept folder %s from %s due to path conflict", folder.Description(), deviceID)
|
||||
return config.FolderConfiguration{}, false
|
||||
} else {
|
||||
for _, device := range cfg.DeviceIDs() {
|
||||
if device == deviceCfg.DeviceID {
|
||||
if device == deviceID {
|
||||
// Already shared nothing todo.
|
||||
return config.FolderConfiguration{}, false
|
||||
}
|
||||
}
|
||||
if cfg.Type == config.FolderTypeReceiveEncrypted {
|
||||
if len(ccDeviceInfos.remote.EncryptionPasswordToken) == 0 && len(ccDeviceInfos.local.EncryptionPasswordToken) == 0 {
|
||||
l.Infof("Failed to auto-accept device %s on existing folder %s as the remote wants to send us unencrypted data, but the folder type is receive-encrypted", folder.Description(), deviceID)
|
||||
return config.FolderConfiguration{}, false
|
||||
}
|
||||
} else {
|
||||
if len(ccDeviceInfos.remote.EncryptionPasswordToken) > 0 || len(ccDeviceInfos.local.EncryptionPasswordToken) > 0 {
|
||||
l.Infof("Failed to auto-accept device %s on existing folder %s as the remote wants to send us encrypted data, but the folder type is not receive-encrypted", folder.Description(), deviceID)
|
||||
return config.FolderConfiguration{}, false
|
||||
}
|
||||
}
|
||||
cfg.Devices = append(cfg.Devices, config.FolderDeviceConfiguration{
|
||||
DeviceID: deviceCfg.DeviceID,
|
||||
DeviceID: deviceID,
|
||||
})
|
||||
l.Infof("Shared %s with %s due to auto-accept", folder.ID, deviceCfg.DeviceID)
|
||||
l.Infof("Shared %s with %s due to auto-accept", folder.ID, deviceID)
|
||||
return cfg, true
|
||||
}
|
||||
}
|
||||
@@ -1422,7 +1612,7 @@ func (r *requestResponse) Wait() {
|
||||
|
||||
// Request returns the specified data segment by reading it from local disk.
|
||||
// Implements the protocol.Model interface.
|
||||
func (m *model) Request(deviceID protocol.DeviceID, folder, name string, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (out protocol.RequestResponse, err error) {
|
||||
func (m *model) Request(deviceID protocol.DeviceID, folder, name string, blockNo, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (out protocol.RequestResponse, err error) {
|
||||
if size < 0 || offset < 0 {
|
||||
return nil, protocol.ErrInvalid
|
||||
}
|
||||
@@ -1520,12 +1710,15 @@ func (m *model) Request(deviceID protocol.DeviceID, folder, name string, size in
|
||||
if err := readOffsetIntoBuf(folderFs, name, offset, res.data); fs.IsNotExist(err) {
|
||||
l.Debugf("%v REQ(in) file doesn't exist: %s: %q / %q o=%d s=%d", m, deviceID, folder, name, offset, size)
|
||||
return nil, protocol.ErrNoSuchFile
|
||||
} else if err == io.EOF && len(hash) == 0 {
|
||||
// Read beyond end of file when we can't verify the hash -- this is
|
||||
// a padded read for an encrypted file. It's fine.
|
||||
} else if err != nil {
|
||||
l.Debugf("%v REQ(in) failed reading file (%v): %s: %q / %q o=%d s=%d", m, err, deviceID, folder, name, offset, size)
|
||||
return nil, protocol.ErrGeneric
|
||||
}
|
||||
|
||||
if !scanner.Validate(res.data, hash, weakHash) {
|
||||
if len(hash) > 0 && !scanner.Validate(res.data, hash, weakHash) {
|
||||
m.recheckFile(deviceID, folder, name, offset, hash, weakHash)
|
||||
l.Debugf("%v REQ(in) failed validating data: %s: %q / %q o=%d s=%d", m, deviceID, folder, name, offset, size)
|
||||
return nil, protocol.ErrNoSuchFile
|
||||
@@ -1862,7 +2055,7 @@ func (m *model) deviceWasSeen(deviceID protocol.DeviceID) {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *model) requestGlobal(ctx context.Context, deviceID protocol.DeviceID, folder, name string, offset int64, size int, hash []byte, weakHash uint32, fromTemporary bool) ([]byte, error) {
|
||||
func (m *model) requestGlobal(ctx context.Context, deviceID protocol.DeviceID, folder, name string, blockNo int, offset int64, size int, hash []byte, weakHash uint32, fromTemporary bool) ([]byte, error) {
|
||||
m.pmut.RLock()
|
||||
nc, ok := m.conn[deviceID]
|
||||
m.pmut.RUnlock()
|
||||
@@ -1871,9 +2064,9 @@ func (m *model) requestGlobal(ctx context.Context, deviceID protocol.DeviceID, f
|
||||
return nil, fmt.Errorf("requestGlobal: no such device: %s", deviceID)
|
||||
}
|
||||
|
||||
l.Debugf("%v REQ(out): %s: %q / %q o=%d s=%d h=%x wh=%x ft=%t", m, deviceID, folder, name, offset, size, hash, weakHash, fromTemporary)
|
||||
l.Debugf("%v REQ(out): %s: %q / %q b=%d o=%d s=%d h=%x wh=%x ft=%t", m, deviceID, folder, name, blockNo, offset, size, hash, weakHash, fromTemporary)
|
||||
|
||||
return nc.Request(ctx, folder, name, offset, size, hash, weakHash, fromTemporary)
|
||||
return nc.Request(ctx, folder, name, blockNo, offset, size, hash, weakHash, fromTemporary)
|
||||
}
|
||||
|
||||
func (m *model) ScanFolders() map[string]error {
|
||||
@@ -1974,6 +2167,17 @@ func (m *model) generateClusterConfig(device protocol.DeviceID) protocol.Cluster
|
||||
continue
|
||||
}
|
||||
|
||||
var encryptionToken []byte
|
||||
var hasEncryptionToken bool
|
||||
if folderCfg.Type == config.FolderTypeReceiveEncrypted {
|
||||
if encryptionToken, hasEncryptionToken = m.folderEncryptionPasswordTokens[folderCfg.ID]; !hasEncryptionToken {
|
||||
// We haven't gotten a token for us yet and without
|
||||
// one the other side can't validate us - pretend
|
||||
// we don't have the folder yet.
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
protocolFolder := protocol.Folder{
|
||||
ID: folderCfg.ID,
|
||||
Label: folderCfg.Label,
|
||||
@@ -2001,6 +2205,12 @@ func (m *model) generateClusterConfig(device protocol.DeviceID) protocol.Cluster
|
||||
Introducer: deviceCfg.Introducer,
|
||||
}
|
||||
|
||||
if deviceCfg.DeviceID == m.id && hasEncryptionToken {
|
||||
protocolDevice.EncryptionPasswordToken = encryptionToken
|
||||
} else if device.EncryptionPassword != "" {
|
||||
protocolDevice.EncryptionPasswordToken = protocol.PasswordToken(folderCfg.ID, device.EncryptionPassword)
|
||||
}
|
||||
|
||||
if fs != nil {
|
||||
if deviceCfg.DeviceID == m.id {
|
||||
protocolDevice.IndexID = fs.IndexID(protocol.LocalDeviceID)
|
||||
@@ -2375,18 +2585,13 @@ func (m *model) CommitConfiguration(from, to config.Configuration) bool {
|
||||
go conn.Close(errDeviceRemoved)
|
||||
}
|
||||
}
|
||||
ccConns := make([]protocol.Connection, 0, len(clusterConfigDevices))
|
||||
for id := range clusterConfigDevices {
|
||||
if conn, ok := m.conn[id]; ok {
|
||||
ccConns = append(ccConns, conn)
|
||||
}
|
||||
}
|
||||
m.pmut.RUnlock()
|
||||
// Generating cluster-configs acquires fmut -> must happen outside of pmut.
|
||||
for _, conn := range ccConns {
|
||||
cm := m.generateClusterConfig(conn.ID())
|
||||
go conn.ClusterConfig(cm)
|
||||
ids := make([]protocol.DeviceID, 0, len(clusterConfigDevices))
|
||||
for id := range clusterConfigDevices {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
m.resendClusterConfig(ids)
|
||||
|
||||
m.globalRequestLimiter.setCapacity(1024 * to.Options.MaxConcurrentIncomingRequestKiB())
|
||||
m.folderIOLimiter.setCapacity(to.Options.MaxFolderConcurrency())
|
||||
@@ -2600,3 +2805,38 @@ func addDeviceIDsToMap(m map[protocol.DeviceID]struct{}, s []protocol.DeviceID)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func encryptionTokenPath(cfg config.FolderConfiguration) string {
|
||||
return filepath.Join(cfg.MarkerName, "syncthing-encryption_password_token")
|
||||
}
|
||||
|
||||
type storedEncryptionToken struct {
|
||||
FolderID string
|
||||
Token []byte
|
||||
}
|
||||
|
||||
func readEncryptionToken(cfg config.FolderConfiguration) ([]byte, error) {
|
||||
fd, err := cfg.Filesystem().Open(encryptionTokenPath(cfg))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer fd.Close()
|
||||
var stored storedEncryptionToken
|
||||
if err := json.NewDecoder(fd).Decode(&stored); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return stored.Token, nil
|
||||
}
|
||||
|
||||
func writeEncryptionToken(token []byte, cfg config.FolderConfiguration) error {
|
||||
tokenName := encryptionTokenPath(cfg)
|
||||
fd, err := cfg.Filesystem().OpenFile(tokenName, fs.OptReadWrite|fs.OptCreate, 0666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fd.Close()
|
||||
return json.NewEncoder(fd).Encode(storedEncryptionToken{
|
||||
FolderID: cfg.ID,
|
||||
Token: token,
|
||||
})
|
||||
}
|
||||
|
||||
+309
-129
@@ -132,12 +132,35 @@ func newState(cfg config.Configuration) *model {
|
||||
return m
|
||||
}
|
||||
|
||||
func createClusterConfig(remote protocol.DeviceID, ids ...string) protocol.ClusterConfig {
|
||||
cc := protocol.ClusterConfig{
|
||||
Folders: make([]protocol.Folder, len(ids)),
|
||||
}
|
||||
for i, id := range ids {
|
||||
cc.Folders[i] = protocol.Folder{
|
||||
ID: id,
|
||||
Label: id,
|
||||
}
|
||||
}
|
||||
return addFolderDevicesToClusterConfig(cc, remote)
|
||||
}
|
||||
|
||||
func addFolderDevicesToClusterConfig(cc protocol.ClusterConfig, remote protocol.DeviceID) protocol.ClusterConfig {
|
||||
for i := range cc.Folders {
|
||||
cc.Folders[i].Devices = []protocol.Device{
|
||||
{ID: myID},
|
||||
{ID: remote},
|
||||
}
|
||||
}
|
||||
return cc
|
||||
}
|
||||
|
||||
func TestRequest(t *testing.T) {
|
||||
m := setupModel(defaultCfgWrapper)
|
||||
defer cleanupModel(m)
|
||||
|
||||
// Existing, shared file
|
||||
res, err := m.Request(device1, "default", "foo", 6, 0, nil, 0, false)
|
||||
res, err := m.Request(device1, "default", "foo", 0, 6, 0, nil, 0, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -147,33 +170,37 @@ func TestRequest(t *testing.T) {
|
||||
}
|
||||
|
||||
// Existing, nonshared file
|
||||
_, err = m.Request(device2, "default", "foo", 6, 0, nil, 0, false)
|
||||
_, err = m.Request(device2, "default", "foo", 0, 6, 0, nil, 0, false)
|
||||
if err == nil {
|
||||
t.Error("Unexpected nil error on insecure file read")
|
||||
}
|
||||
|
||||
// Nonexistent file
|
||||
_, err = m.Request(device1, "default", "nonexistent", 6, 0, nil, 0, false)
|
||||
_, err = m.Request(device1, "default", "nonexistent", 0, 6, 0, nil, 0, false)
|
||||
if err == nil {
|
||||
t.Error("Unexpected nil error on insecure file read")
|
||||
}
|
||||
|
||||
// Shared folder, but disallowed file name
|
||||
_, err = m.Request(device1, "default", "../walk.go", 6, 0, nil, 0, false)
|
||||
_, err = m.Request(device1, "default", "../walk.go", 0, 6, 0, nil, 0, false)
|
||||
if err == nil {
|
||||
t.Error("Unexpected nil error on insecure file read")
|
||||
}
|
||||
|
||||
// Negative offset
|
||||
_, err = m.Request(device1, "default", "foo", -4, 0, nil, 0, false)
|
||||
_, err = m.Request(device1, "default", "foo", 0, -4, 0, nil, 0, false)
|
||||
if err == nil {
|
||||
t.Error("Unexpected nil error on insecure file read")
|
||||
}
|
||||
|
||||
// Larger block than available
|
||||
_, err = m.Request(device1, "default", "foo", 42, 0, nil, 0, false)
|
||||
_, err = m.Request(device1, "default", "foo", 0, 42, 0, []byte("hash necessary but not checked"), 0, false)
|
||||
if err == nil {
|
||||
t.Error("Unexpected nil error on insecure file read")
|
||||
t.Error("Unexpected nil error on read past end of file")
|
||||
}
|
||||
_, err = m.Request(device1, "default", "foo", 0, 42, 0, nil, 0, false)
|
||||
if err != nil {
|
||||
t.Error("Unexpected error when large read should be permitted")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,7 +286,7 @@ func BenchmarkRequestOut(b *testing.B) {
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
data, err := m.requestGlobal(context.Background(), device1, "default", files[i%n].Name, 0, 32, nil, 0, false)
|
||||
data, err := m.requestGlobal(context.Background(), device1, "default", files[i%n].Name, 0, 0, 32, nil, 0, false)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
@@ -283,7 +310,7 @@ func BenchmarkRequestInSingleFile(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := m.Request(device1, "default", "request/for/a/file/in/a/couple/of/dirs/128k", 128<<10, 0, nil, 0, false); err != nil {
|
||||
if _, err := m.Request(device1, "default", "request/for/a/file/in/a/couple/of/dirs/128k", 0, 128<<10, 0, nil, 0, false); err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
}
|
||||
@@ -854,14 +881,7 @@ func TestIssue5063(t *testing.T) {
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
addAndVerify := func(id string) {
|
||||
m.ClusterConfig(device1, protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{
|
||||
{
|
||||
ID: id,
|
||||
Label: id,
|
||||
},
|
||||
},
|
||||
})
|
||||
m.ClusterConfig(device1, createClusterConfig(device1, id))
|
||||
if fcfg, ok := m.cfg.Folder(id); !ok || !fcfg.SharedWith(device1) {
|
||||
t.Error("expected shared", id)
|
||||
}
|
||||
@@ -904,14 +924,7 @@ func TestAutoAcceptRejected(t *testing.T) {
|
||||
defer cleanupModel(m)
|
||||
id := srand.String(8)
|
||||
defer os.RemoveAll(id)
|
||||
m.ClusterConfig(device1, protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{
|
||||
{
|
||||
ID: id,
|
||||
Label: id,
|
||||
},
|
||||
},
|
||||
})
|
||||
m.ClusterConfig(device1, createClusterConfig(device1, id))
|
||||
|
||||
if cfg, ok := m.cfg.Folder(id); ok && cfg.SharedWith(device1) {
|
||||
t.Error("unexpected shared", id)
|
||||
@@ -924,14 +937,7 @@ func TestAutoAcceptNewFolder(t *testing.T) {
|
||||
defer cleanupModel(m)
|
||||
id := srand.String(8)
|
||||
defer os.RemoveAll(id)
|
||||
m.ClusterConfig(device1, protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{
|
||||
{
|
||||
ID: id,
|
||||
Label: id,
|
||||
},
|
||||
},
|
||||
})
|
||||
m.ClusterConfig(device1, createClusterConfig(device1, id))
|
||||
if fcfg, ok := m.cfg.Folder(id); !ok || !fcfg.SharedWith(device1) {
|
||||
t.Error("expected shared", id)
|
||||
}
|
||||
@@ -942,28 +948,14 @@ func TestAutoAcceptNewFolderFromTwoDevices(t *testing.T) {
|
||||
defer cleanupModel(m)
|
||||
id := srand.String(8)
|
||||
defer os.RemoveAll(id)
|
||||
m.ClusterConfig(device1, protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{
|
||||
{
|
||||
ID: id,
|
||||
Label: id,
|
||||
},
|
||||
},
|
||||
})
|
||||
m.ClusterConfig(device1, createClusterConfig(device1, id))
|
||||
if fcfg, ok := m.cfg.Folder(id); !ok || !fcfg.SharedWith(device1) {
|
||||
t.Error("expected shared", id)
|
||||
}
|
||||
if fcfg, ok := m.cfg.Folder(id); !ok || fcfg.SharedWith(device2) {
|
||||
t.Error("unexpected expected shared", id)
|
||||
}
|
||||
m.ClusterConfig(device2, protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{
|
||||
{
|
||||
ID: id,
|
||||
Label: id,
|
||||
},
|
||||
},
|
||||
})
|
||||
m.ClusterConfig(device2, createClusterConfig(device2, id))
|
||||
if fcfg, ok := m.cfg.Folder(id); !ok || !fcfg.SharedWith(device2) {
|
||||
t.Error("expected shared", id)
|
||||
}
|
||||
@@ -976,28 +968,14 @@ func TestAutoAcceptNewFolderFromOnlyOneDevice(t *testing.T) {
|
||||
id := srand.String(8)
|
||||
defer os.RemoveAll(id)
|
||||
defer cleanupModel(m)
|
||||
m.ClusterConfig(device1, protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{
|
||||
{
|
||||
ID: id,
|
||||
Label: id,
|
||||
},
|
||||
},
|
||||
})
|
||||
m.ClusterConfig(device1, createClusterConfig(device1, id))
|
||||
if fcfg, ok := m.cfg.Folder(id); !ok || !fcfg.SharedWith(device1) {
|
||||
t.Error("expected shared", id)
|
||||
}
|
||||
if fcfg, ok := m.cfg.Folder(id); !ok || fcfg.SharedWith(device2) {
|
||||
t.Error("unexpected expected shared", id)
|
||||
}
|
||||
m.ClusterConfig(device2, protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{
|
||||
{
|
||||
ID: id,
|
||||
Label: id,
|
||||
},
|
||||
},
|
||||
})
|
||||
m.ClusterConfig(device2, createClusterConfig(device2, id))
|
||||
if fcfg, ok := m.cfg.Folder(id); !ok || fcfg.SharedWith(device2) {
|
||||
t.Error("unexpected shared", id)
|
||||
}
|
||||
@@ -1053,18 +1031,7 @@ func TestAutoAcceptMultipleFolders(t *testing.T) {
|
||||
defer os.RemoveAll(id2)
|
||||
m := newState(defaultAutoAcceptCfg)
|
||||
defer cleanupModel(m)
|
||||
m.ClusterConfig(device1, protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{
|
||||
{
|
||||
ID: id1,
|
||||
Label: id1,
|
||||
},
|
||||
{
|
||||
ID: id2,
|
||||
Label: id2,
|
||||
},
|
||||
},
|
||||
})
|
||||
m.ClusterConfig(device1, createClusterConfig(device1, id1, id2))
|
||||
if fcfg, ok := m.cfg.Folder(id1); !ok || !fcfg.SharedWith(device1) {
|
||||
t.Error("expected shared", id1)
|
||||
}
|
||||
@@ -1092,14 +1059,7 @@ func TestAutoAcceptExistingFolder(t *testing.T) {
|
||||
if fcfg, ok := m.cfg.Folder(id); !ok || fcfg.SharedWith(device1) {
|
||||
t.Error("missing folder, or shared", id)
|
||||
}
|
||||
m.ClusterConfig(device1, protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{
|
||||
{
|
||||
ID: id,
|
||||
Label: id,
|
||||
},
|
||||
},
|
||||
})
|
||||
m.ClusterConfig(device1, createClusterConfig(device1, id))
|
||||
|
||||
if fcfg, ok := m.cfg.Folder(id); !ok || !fcfg.SharedWith(device1) || fcfg.Path != idOther {
|
||||
t.Error("missing folder, or unshared, or path changed", id)
|
||||
@@ -1125,18 +1085,7 @@ func TestAutoAcceptNewAndExistingFolder(t *testing.T) {
|
||||
if fcfg, ok := m.cfg.Folder(id1); !ok || fcfg.SharedWith(device1) {
|
||||
t.Error("missing folder, or shared", id1)
|
||||
}
|
||||
m.ClusterConfig(device1, protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{
|
||||
{
|
||||
ID: id1,
|
||||
Label: id1,
|
||||
},
|
||||
{
|
||||
ID: id2,
|
||||
Label: id2,
|
||||
},
|
||||
},
|
||||
})
|
||||
m.ClusterConfig(device1, createClusterConfig(device1, id1, id2))
|
||||
|
||||
for i, id := range []string{id1, id2} {
|
||||
if fcfg, ok := m.cfg.Folder(id); !ok || !fcfg.SharedWith(device1) {
|
||||
@@ -1166,14 +1115,7 @@ func TestAutoAcceptAlreadyShared(t *testing.T) {
|
||||
if fcfg, ok := m.cfg.Folder(id); !ok || !fcfg.SharedWith(device1) {
|
||||
t.Error("missing folder, or not shared", id)
|
||||
}
|
||||
m.ClusterConfig(device1, protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{
|
||||
{
|
||||
ID: id,
|
||||
Label: id,
|
||||
},
|
||||
},
|
||||
})
|
||||
m.ClusterConfig(device1, createClusterConfig(device1, id))
|
||||
|
||||
if fcfg, ok := m.cfg.Folder(id); !ok || !fcfg.SharedWith(device1) {
|
||||
t.Error("missing folder, or not shared", id)
|
||||
@@ -1212,14 +1154,14 @@ func TestAutoAcceptPrefersLabel(t *testing.T) {
|
||||
defer os.RemoveAll(id)
|
||||
defer os.RemoveAll(label)
|
||||
defer cleanupModel(m)
|
||||
m.ClusterConfig(device1, protocol.ClusterConfig{
|
||||
m.ClusterConfig(device1, addFolderDevicesToClusterConfig(protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{
|
||||
{
|
||||
ID: id,
|
||||
Label: label,
|
||||
},
|
||||
},
|
||||
})
|
||||
}, device1))
|
||||
if fcfg, ok := m.cfg.Folder(id); !ok || !fcfg.SharedWith(device1) || !strings.HasSuffix(fcfg.Path, label) {
|
||||
t.Error("expected shared, or wrong path", id, label, fcfg.Path)
|
||||
}
|
||||
@@ -1237,14 +1179,14 @@ func TestAutoAcceptFallsBackToID(t *testing.T) {
|
||||
defer os.RemoveAll(label)
|
||||
defer os.RemoveAll(id)
|
||||
defer cleanupModel(m)
|
||||
m.ClusterConfig(device1, protocol.ClusterConfig{
|
||||
m.ClusterConfig(device1, addFolderDevicesToClusterConfig(protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{
|
||||
{
|
||||
ID: id,
|
||||
Label: label,
|
||||
},
|
||||
},
|
||||
})
|
||||
}, device1))
|
||||
if fcfg, ok := m.cfg.Folder(id); !ok || !fcfg.SharedWith(device1) || !strings.HasSuffix(fcfg.Path, id) {
|
||||
t.Error("expected shared, or wrong path", id, label, fcfg.Path)
|
||||
}
|
||||
@@ -1276,14 +1218,7 @@ func TestAutoAcceptPausedWhenFolderConfigChanged(t *testing.T) {
|
||||
t.Fatal("folder running?")
|
||||
}
|
||||
|
||||
m.ClusterConfig(device1, protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{
|
||||
{
|
||||
ID: id,
|
||||
Label: id,
|
||||
},
|
||||
},
|
||||
})
|
||||
m.ClusterConfig(device1, createClusterConfig(device1, id))
|
||||
m.generateClusterConfig(device1)
|
||||
|
||||
if fcfg, ok := m.cfg.Folder(id); !ok {
|
||||
@@ -1333,14 +1268,7 @@ func TestAutoAcceptPausedWhenFolderConfigNotChanged(t *testing.T) {
|
||||
t.Fatal("folder running?")
|
||||
}
|
||||
|
||||
m.ClusterConfig(device1, protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{
|
||||
{
|
||||
ID: id,
|
||||
Label: id,
|
||||
},
|
||||
},
|
||||
})
|
||||
m.ClusterConfig(device1, createClusterConfig(device1, id))
|
||||
m.generateClusterConfig(device1)
|
||||
|
||||
if fcfg, ok := m.cfg.Folder(id); !ok {
|
||||
@@ -1361,6 +1289,113 @@ func TestAutoAcceptPausedWhenFolderConfigNotChanged(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAutoAcceptEnc(t *testing.T) {
|
||||
tcfg := defaultAutoAcceptCfg.Copy()
|
||||
m := newState(tcfg)
|
||||
defer cleanupModel(m)
|
||||
|
||||
id := srand.String(8)
|
||||
defer os.RemoveAll(id)
|
||||
|
||||
token := []byte("token")
|
||||
basicCC := func() protocol.ClusterConfig {
|
||||
return protocol.ClusterConfig{
|
||||
Folders: []protocol.Folder{{
|
||||
ID: id,
|
||||
Label: id,
|
||||
}}}
|
||||
}
|
||||
|
||||
// Earlier tests might cause the connection to get closed, thus ClusterConfig
|
||||
// would panic.
|
||||
clusterConfig := func(deviceID protocol.DeviceID, cm protocol.ClusterConfig) {
|
||||
m.AddConnection(&fakeConnection{id: deviceID, model: m}, protocol.Hello{})
|
||||
m.ClusterConfig(deviceID, cm)
|
||||
}
|
||||
|
||||
clusterConfig(device1, basicCC())
|
||||
if _, ok := m.cfg.Folder(id); ok {
|
||||
t.Fatal("unexpected added")
|
||||
}
|
||||
cc := basicCC()
|
||||
cc.Folders[0].Devices = []protocol.Device{{ID: device1}}
|
||||
clusterConfig(device1, cc)
|
||||
if _, ok := m.cfg.Folder(id); ok {
|
||||
t.Fatal("unexpected added")
|
||||
}
|
||||
cc = basicCC()
|
||||
cc.Folders[0].Devices = []protocol.Device{{ID: myID}}
|
||||
clusterConfig(device1, cc)
|
||||
if _, ok := m.cfg.Folder(id); ok {
|
||||
t.Fatal("unexpected added")
|
||||
}
|
||||
|
||||
// New folder, encrypted -> add as enc
|
||||
|
||||
cc = createClusterConfig(device1, id)
|
||||
cc.Folders[0].Devices[1].EncryptionPasswordToken = token
|
||||
clusterConfig(device1, cc)
|
||||
if cfg, ok := m.cfg.Folder(id); !ok {
|
||||
t.Fatal("unexpected unadded")
|
||||
} else {
|
||||
if !cfg.SharedWith(device1) {
|
||||
t.Fatal("unexpected unshared")
|
||||
}
|
||||
if cfg.Type != config.FolderTypeReceiveEncrypted {
|
||||
t.Fatal("Folder not added as receiveEncrypted")
|
||||
}
|
||||
}
|
||||
|
||||
// New device, unencrypted on encrypted folder -> reject
|
||||
|
||||
clusterConfig(device2, createClusterConfig(device2, id))
|
||||
if cfg, _ := m.cfg.Folder(id); cfg.SharedWith(device2) {
|
||||
t.Fatal("unexpected shared")
|
||||
}
|
||||
|
||||
// New device, encrypted on encrypted folder -> share
|
||||
|
||||
cc = createClusterConfig(device2, id)
|
||||
cc.Folders[0].Devices[1].EncryptionPasswordToken = token
|
||||
clusterConfig(device2, cc)
|
||||
if cfg, _ := m.cfg.Folder(id); !cfg.SharedWith(device2) {
|
||||
t.Fatal("unexpected unshared")
|
||||
}
|
||||
|
||||
// New folder, no encrypted -> add "normal"
|
||||
|
||||
id = srand.String(8)
|
||||
defer os.RemoveAll(id)
|
||||
|
||||
clusterConfig(device1, createClusterConfig(device1, id))
|
||||
if cfg, ok := m.cfg.Folder(id); !ok {
|
||||
t.Fatal("unexpected unadded")
|
||||
} else {
|
||||
if !cfg.SharedWith(device1) {
|
||||
t.Fatal("unexpected unshared")
|
||||
}
|
||||
if cfg.Type != config.FolderTypeSendReceive {
|
||||
t.Fatal("Folder not added as send-receive")
|
||||
}
|
||||
}
|
||||
|
||||
// New device, encrypted on unencrypted folder -> reject
|
||||
|
||||
cc = createClusterConfig(device2, id)
|
||||
cc.Folders[0].Devices[1].EncryptionPasswordToken = token
|
||||
clusterConfig(device2, cc)
|
||||
if cfg, _ := m.cfg.Folder(id); cfg.SharedWith(device2) {
|
||||
t.Fatal("unexpected shared")
|
||||
}
|
||||
|
||||
// New device, unencrypted on unencrypted folder -> share
|
||||
|
||||
clusterConfig(device2, createClusterConfig(device2, id))
|
||||
if cfg, _ := m.cfg.Folder(id); !cfg.SharedWith(device2) {
|
||||
t.Fatal("unexpected unshared")
|
||||
}
|
||||
}
|
||||
|
||||
func changeIgnores(t *testing.T, m *model, expected []string) {
|
||||
arrEqual := func(a, b []string) bool {
|
||||
if len(a) != len(b) {
|
||||
@@ -3220,14 +3255,14 @@ func TestRequestLimit(t *testing.T) {
|
||||
|
||||
file := "tmpfile"
|
||||
befReq := time.Now()
|
||||
first, err := m.Request(device1, "default", file, 2000, 0, nil, 0, false)
|
||||
first, err := m.Request(device1, "default", file, 0, 2000, 0, nil, 0, false)
|
||||
if err != nil {
|
||||
t.Fatalf("First request failed: %v", err)
|
||||
}
|
||||
reqDur := time.Since(befReq)
|
||||
returned := make(chan struct{})
|
||||
go func() {
|
||||
second, err := m.Request(device1, "default", file, 2000, 0, nil, 0, false)
|
||||
second, err := m.Request(device1, "default", file, 0, 2000, 0, nil, 0, false)
|
||||
if err != nil {
|
||||
t.Errorf("Second request failed: %v", err)
|
||||
}
|
||||
@@ -3829,7 +3864,10 @@ func TestClusterConfigOnFolderAdd(t *testing.T) {
|
||||
fcfg := testFolderConfigTmp()
|
||||
fcfg.ID = "second"
|
||||
fcfg.Label = "second"
|
||||
fcfg.Devices = []config.FolderDeviceConfiguration{{device2, protocol.EmptyDeviceID}}
|
||||
fcfg.Devices = []config.FolderDeviceConfiguration{{
|
||||
DeviceID: device2,
|
||||
IntroducedBy: protocol.EmptyDeviceID,
|
||||
}}
|
||||
if w, err := cfg.SetFolder(fcfg); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
@@ -3841,7 +3879,10 @@ func TestClusterConfigOnFolderAdd(t *testing.T) {
|
||||
func TestClusterConfigOnFolderShare(t *testing.T) {
|
||||
testConfigChangeTriggersClusterConfigs(t, true, true, nil, func(cfg config.Wrapper) {
|
||||
fcfg := cfg.FolderList()[0]
|
||||
fcfg.Devices = []config.FolderDeviceConfiguration{{device2, protocol.EmptyDeviceID}}
|
||||
fcfg.Devices = []config.FolderDeviceConfiguration{{
|
||||
DeviceID: device2,
|
||||
IntroducedBy: protocol.EmptyDeviceID,
|
||||
}}
|
||||
if w, err := cfg.SetFolder(fcfg); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
@@ -4161,6 +4202,145 @@ func TestNeedMetaAfterIndexReset(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCcCheckEncryption(t *testing.T) {
|
||||
w, fcfg := tmpDefaultWrapper()
|
||||
m := setupModel(w)
|
||||
m.Stop()
|
||||
defer cleanupModel(m)
|
||||
|
||||
pw := "foo"
|
||||
token := protocol.PasswordToken(fcfg.ID, pw)
|
||||
m.folderEncryptionPasswordTokens[fcfg.ID] = token
|
||||
|
||||
testCases := []struct {
|
||||
tokenRemote, tokenLocal []byte
|
||||
isEncryptedRemote, isEncryptedLocal bool
|
||||
expectedErr error
|
||||
}{
|
||||
{
|
||||
tokenRemote: token,
|
||||
tokenLocal: token,
|
||||
expectedErr: errEncryptionInvConfigRemote,
|
||||
},
|
||||
{
|
||||
isEncryptedRemote: true,
|
||||
isEncryptedLocal: true,
|
||||
expectedErr: errEncryptionInvConfigLocal,
|
||||
},
|
||||
{
|
||||
tokenRemote: token,
|
||||
tokenLocal: nil,
|
||||
isEncryptedRemote: false,
|
||||
isEncryptedLocal: false,
|
||||
expectedErr: errEncryptionNotEncryptedLocal,
|
||||
},
|
||||
{
|
||||
tokenRemote: token,
|
||||
tokenLocal: nil,
|
||||
isEncryptedRemote: true,
|
||||
isEncryptedLocal: false,
|
||||
expectedErr: nil,
|
||||
},
|
||||
{
|
||||
tokenRemote: token,
|
||||
tokenLocal: nil,
|
||||
isEncryptedRemote: false,
|
||||
isEncryptedLocal: true,
|
||||
expectedErr: nil,
|
||||
},
|
||||
{
|
||||
tokenRemote: nil,
|
||||
tokenLocal: token,
|
||||
isEncryptedRemote: true,
|
||||
isEncryptedLocal: false,
|
||||
expectedErr: nil,
|
||||
},
|
||||
{
|
||||
tokenRemote: nil,
|
||||
tokenLocal: token,
|
||||
isEncryptedRemote: false,
|
||||
isEncryptedLocal: true,
|
||||
expectedErr: nil,
|
||||
},
|
||||
{
|
||||
tokenRemote: nil,
|
||||
tokenLocal: token,
|
||||
isEncryptedRemote: false,
|
||||
isEncryptedLocal: false,
|
||||
expectedErr: errEncryptionNotEncryptedLocal,
|
||||
},
|
||||
{
|
||||
tokenRemote: nil,
|
||||
tokenLocal: nil,
|
||||
isEncryptedRemote: true,
|
||||
isEncryptedLocal: false,
|
||||
expectedErr: errEncryptionNotEncryptedRemote,
|
||||
},
|
||||
{
|
||||
tokenRemote: nil,
|
||||
tokenLocal: nil,
|
||||
isEncryptedRemote: false,
|
||||
isEncryptedLocal: true,
|
||||
expectedErr: errEncryptionNotEncryptedRemote,
|
||||
},
|
||||
{
|
||||
tokenRemote: nil,
|
||||
tokenLocal: nil,
|
||||
isEncryptedRemote: false,
|
||||
isEncryptedLocal: false,
|
||||
expectedErr: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
tfcfg := fcfg.Copy()
|
||||
if tc.isEncryptedLocal {
|
||||
tfcfg.Type = config.FolderTypeReceiveEncrypted
|
||||
m.folderEncryptionPasswordTokens[fcfg.ID] = token
|
||||
}
|
||||
dcfg := config.FolderDeviceConfiguration{DeviceID: device1}
|
||||
if tc.isEncryptedRemote {
|
||||
dcfg.EncryptionPassword = pw
|
||||
}
|
||||
|
||||
deviceInfos := &indexSenderStartInfo{
|
||||
remote: protocol.Device{ID: device1, EncryptionPasswordToken: tc.tokenRemote},
|
||||
local: protocol.Device{ID: myID, EncryptionPasswordToken: tc.tokenLocal},
|
||||
}
|
||||
err := m.ccCheckEncryption(tfcfg, dcfg, deviceInfos, false)
|
||||
if err != tc.expectedErr {
|
||||
t.Errorf("Testcase %v: Expected error %v, got %v", i, tc.expectedErr, err)
|
||||
}
|
||||
|
||||
if tc.expectedErr == nil {
|
||||
err := m.ccCheckEncryption(tfcfg, dcfg, deviceInfos, true)
|
||||
if tc.isEncryptedRemote || tc.isEncryptedLocal {
|
||||
if err != nil {
|
||||
t.Errorf("Testcase %v: Expected no error, got %v", i, err)
|
||||
}
|
||||
} else {
|
||||
if err != errEncryptionNotEncryptedUntrusted {
|
||||
t.Errorf("Testcase %v: Expected error %v, got %v", i, errEncryptionNotEncryptedUntrusted, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil || (!tc.isEncryptedRemote && !tc.isEncryptedLocal) {
|
||||
continue
|
||||
}
|
||||
|
||||
if tc.isEncryptedLocal {
|
||||
m.folderEncryptionPasswordTokens[fcfg.ID] = []byte("notAMatch")
|
||||
} else {
|
||||
dcfg.EncryptionPassword = "notAMatch"
|
||||
}
|
||||
err = m.ccCheckEncryption(tfcfg, dcfg, deviceInfos, false)
|
||||
if err != errEncryptionPassword {
|
||||
t.Errorf("Testcase %v: Expected error %v, got %v", i, errEncryptionPassword, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func equalStringsInAnyOrder(a, b []string) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
|
||||
@@ -101,7 +101,7 @@ func TestSymlinkTraversalRead(t *testing.T) {
|
||||
<-done
|
||||
|
||||
// Request a file by traversing the symlink
|
||||
res, err := m.Request(device1, "default", "symlink/requests_test.go", 10, 0, nil, 0, false)
|
||||
res, err := m.Request(device1, "default", "symlink/requests_test.go", 0, 10, 0, nil, 0, false)
|
||||
if err == nil || res != nil {
|
||||
t.Error("Managed to traverse symlink")
|
||||
}
|
||||
@@ -499,7 +499,7 @@ func TestRescanIfHaveInvalidContent(t *testing.T) {
|
||||
t.Fatalf("unexpected weak hash: %d != 103547413", f.Blocks[0].WeakHash)
|
||||
}
|
||||
|
||||
res, err := m.Request(device1, "default", "foo", int32(len(payload)), 0, f.Blocks[0].Hash, f.Blocks[0].WeakHash, false)
|
||||
res, err := m.Request(device1, "default", "foo", 0, int32(len(payload)), 0, f.Blocks[0].Hash, f.Blocks[0].WeakHash, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -513,7 +513,7 @@ func TestRescanIfHaveInvalidContent(t *testing.T) {
|
||||
|
||||
must(t, writeFile(tfs, "foo", payload, 0777))
|
||||
|
||||
_, err = m.Request(device1, "default", "foo", int32(len(payload)), 0, f.Blocks[0].Hash, f.Blocks[0].WeakHash, false)
|
||||
_, err = m.Request(device1, "default", "foo", 0, int32(len(payload)), 0, f.Blocks[0].Hash, f.Blocks[0].WeakHash, false)
|
||||
if err == nil {
|
||||
t.Fatalf("expected failure")
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
@@ -131,7 +132,7 @@ func (s *sharedPullerState) tempFile() (*lockedWriterAt, error) {
|
||||
return s.writer, nil
|
||||
}
|
||||
|
||||
if err := inWritableDir(s.tempFileInWritableDir, s.fs, s.tempName, s.ignorePerms); err != nil {
|
||||
if err := s.addWriterLocked(); err != nil {
|
||||
s.failLocked(err)
|
||||
return nil, err
|
||||
}
|
||||
@@ -139,6 +140,10 @@ func (s *sharedPullerState) tempFile() (*lockedWriterAt, error) {
|
||||
return s.writer, nil
|
||||
}
|
||||
|
||||
func (s *sharedPullerState) addWriterLocked() error {
|
||||
return inWritableDir(s.tempFileInWritableDir, s.fs, s.tempName, s.ignorePerms)
|
||||
}
|
||||
|
||||
// tempFileInWritableDir should only be called from tempFile.
|
||||
func (s *sharedPullerState) tempFileInWritableDir(_ string) error {
|
||||
// The permissions to use for the temporary file should be those of the
|
||||
@@ -184,9 +189,14 @@ func (s *sharedPullerState) tempFileInWritableDir(_ string) error {
|
||||
// Don't truncate symlink files, as that will mean that the path will
|
||||
// contain a bunch of nulls.
|
||||
if s.sparse && !s.file.IsSymlink() {
|
||||
size := s.file.Size
|
||||
// Trailer added to encrypted files
|
||||
if len(s.file.Encrypted) > 0 {
|
||||
size += int64(s.file.ProtoSize() + 4)
|
||||
}
|
||||
// Truncate sets the size of the file. This creates a sparse file or a
|
||||
// space reservation, depending on the underlying filesystem.
|
||||
if err := fd.Truncate(s.file.Size); err != nil {
|
||||
if err := fd.Truncate(size); err != nil {
|
||||
// The truncate call failed. That can happen in some cases when
|
||||
// space reservation isn't possible or over some network
|
||||
// filesystems... This generally doesn't matter.
|
||||
@@ -305,6 +315,13 @@ func (s *sharedPullerState) finalClose() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if len(s.file.Encrypted) > 0 {
|
||||
if err := s.finalizeEncrypted(); err != nil && s.err == nil {
|
||||
// This is our error as we weren't errored before.
|
||||
s.err = err
|
||||
}
|
||||
}
|
||||
|
||||
if s.writer != nil {
|
||||
if err := s.writer.SyncClose(s.fsync); err != nil && s.err == nil {
|
||||
// This is our error as we weren't errored before.
|
||||
@@ -324,6 +341,34 @@ func (s *sharedPullerState) finalClose() (bool, error) {
|
||||
return true, s.err
|
||||
}
|
||||
|
||||
// finalizeEncrypted adds a trailer to the encrypted file containing the
|
||||
// serialized FileInfo and the length of that FileInfo. When initializing a
|
||||
// folder from encrypted data we can extract this FileInfo from the end of
|
||||
// the file and regain the original metadata.
|
||||
func (s *sharedPullerState) finalizeEncrypted() error {
|
||||
size := s.file.ProtoSize()
|
||||
bs := make([]byte, 4+size)
|
||||
n, err := s.file.MarshalTo(bs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
binary.BigEndian.PutUint32(bs[n:], uint32(n))
|
||||
bs = bs[:n+4]
|
||||
|
||||
if s.writer == nil {
|
||||
if err := s.addWriterLocked(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if _, err := s.writer.WriteAt(bs, s.file.Size); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.file.Size += int64(len(bs))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Progress returns the momentarily progress for the puller
|
||||
func (s *sharedPullerState) Progress() *pullerProgress {
|
||||
s.mut.RLock()
|
||||
|
||||
@@ -49,6 +49,7 @@ func init() {
|
||||
defaultCfg = defaultCfgWrapper.RawCopy()
|
||||
|
||||
defaultAutoAcceptCfg = config.Configuration{
|
||||
Version: config.CurrentVersion,
|
||||
Devices: []config.DeviceConfiguration{
|
||||
{
|
||||
DeviceID: myID, // self
|
||||
|
||||
@@ -81,9 +81,9 @@ func benchmarkRequestsConnPair(b *testing.B, conn0, conn1 net.Conn) {
|
||||
// Use c0 and c1 for each alternating request, so we get as much
|
||||
// data flowing in both directions.
|
||||
if i%2 == 0 {
|
||||
buf, err = c0.Request(context.Background(), "folder", "file", int64(i), 128<<10, nil, 0, false)
|
||||
buf, err = c0.Request(context.Background(), "folder", "file", i, int64(i), 128<<10, nil, 0, false)
|
||||
} else {
|
||||
buf, err = c1.Request(context.Background(), "folder", "file", int64(i), 128<<10, nil, 0, false)
|
||||
buf, err = c1.Request(context.Background(), "folder", "file", i, int64(i), 128<<10, nil, 0, false)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
@@ -174,7 +174,7 @@ func (m *fakeModel) IndexUpdate(deviceID DeviceID, folder string, files []FileIn
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *fakeModel) Request(deviceID DeviceID, folder, name string, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (RequestResponse, error) {
|
||||
func (m *fakeModel) Request(deviceID DeviceID, folder, name string, blockNo, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (RequestResponse, error) {
|
||||
// We write the offset to the end of the buffer, so the receiver
|
||||
// can verify that it did in fact get some data back over the
|
||||
// connection.
|
||||
|
||||
+291
-163
@@ -378,6 +378,7 @@ type Device struct {
|
||||
Introducer bool `protobuf:"varint,7,opt,name=introducer,proto3" json:"introducer" xml:"introducer"`
|
||||
IndexID IndexID `protobuf:"varint,8,opt,name=index_id,json=indexId,proto3,customtype=IndexID" json:"indexId" xml:"indexId"`
|
||||
SkipIntroductionRemovals bool `protobuf:"varint,9,opt,name=skip_introduction_removals,json=skipIntroductionRemovals,proto3" json:"skipIntroductionRemovals" xml:"skipIntroductionRemovals"`
|
||||
EncryptionPasswordToken []byte `protobuf:"bytes,10,opt,name=encryption_password_token,json=encryptionPasswordToken,proto3" json:"encryptionPasswordToken" xml:"encryptionPasswordToken"`
|
||||
}
|
||||
|
||||
func (m *Device) Reset() { *m = Device{} }
|
||||
@@ -499,6 +500,7 @@ type FileInfo struct {
|
||||
Blocks []BlockInfo `protobuf:"bytes,16,rep,name=blocks,proto3" json:"blocks" xml:"block"`
|
||||
SymlinkTarget string `protobuf:"bytes,17,opt,name=symlink_target,json=symlinkTarget,proto3" json:"symlinkTarget" xml:"symlinkTarget"`
|
||||
BlocksHash []byte `protobuf:"bytes,18,opt,name=blocks_hash,json=blocksHash,proto3" json:"blocksHash" xml:"blocksHash"`
|
||||
Encrypted []byte `protobuf:"bytes,19,opt,name=encrypted,proto3" json:"encrypted" xml:"encrypted"`
|
||||
Type FileInfoType `protobuf:"varint,2,opt,name=type,proto3,enum=protocol.FileInfoType" json:"type" xml:"type"`
|
||||
Permissions uint32 `protobuf:"varint,4,opt,name=permissions,proto3" json:"permissions" xml:"permissions"`
|
||||
ModifiedNs int `protobuf:"varint,11,opt,name=modified_ns,json=modifiedNs,proto3,casttype=int" json:"modifiedNs" xml:"modifiedNs"`
|
||||
@@ -671,6 +673,7 @@ type Request struct {
|
||||
Hash []byte `protobuf:"bytes,6,opt,name=hash,proto3" json:"hash" xml:"hash"`
|
||||
FromTemporary bool `protobuf:"varint,7,opt,name=from_temporary,json=fromTemporary,proto3" json:"fromTemporary" xml:"fromTemporary"`
|
||||
WeakHash uint32 `protobuf:"varint,8,opt,name=weak_hash,json=weakHash,proto3" json:"weakHash" xml:"weakHash"`
|
||||
BlockNo int `protobuf:"varint,9,opt,name=block_no,json=blockNo,proto3,casttype=int" json:"blockNo" xml:"blockNo"`
|
||||
}
|
||||
|
||||
func (m *Request) Reset() { *m = Request{} }
|
||||
@@ -926,169 +929,175 @@ func init() {
|
||||
func init() { proto.RegisterFile("lib/protocol/bep.proto", fileDescriptor_311ef540e10d9705) }
|
||||
|
||||
var fileDescriptor_311ef540e10d9705 = []byte{
|
||||
// 2584 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x59, 0x4d, 0x6c, 0xe3, 0xc6,
|
||||
0xf5, 0x17, 0xf5, 0x61, 0xcb, 0x63, 0x7b, 0x23, 0xcf, 0x7e, 0x29, 0xda, 0x8d, 0xa8, 0xff, 0xfc,
|
||||
0x37, 0xad, 0xe3, 0x34, 0xde, 0xc4, 0x49, 0xda, 0x34, 0x49, 0x13, 0xe8, 0x83, 0xb6, 0x95, 0xd8,
|
||||
0x92, 0x3b, 0xf2, 0x6e, 0xba, 0x8b, 0x16, 0x04, 0x2d, 0x8e, 0x6d, 0x62, 0x29, 0x52, 0x25, 0x65,
|
||||
0xef, 0x3a, 0xe8, 0xa9, 0xbd, 0x04, 0x3a, 0x14, 0x45, 0x4e, 0x45, 0x51, 0xa1, 0x69, 0x2f, 0xbd,
|
||||
0x15, 0xe8, 0xa1, 0x97, 0xdc, 0x7a, 0x29, 0x72, 0x5c, 0x04, 0x28, 0x50, 0xf4, 0x40, 0x20, 0xbb,
|
||||
0x97, 0x56, 0x47, 0x1d, 0x7b, 0x2a, 0xe6, 0x83, 0xe4, 0xd0, 0xb2, 0x03, 0x27, 0x39, 0xf4, 0xc6,
|
||||
0xf7, 0x7b, 0x1f, 0x1c, 0xce, 0xfb, 0xbd, 0x37, 0x6f, 0x24, 0x70, 0xcd, 0xb6, 0xf6, 0x6e, 0xf7,
|
||||
0x3d, 0x77, 0xe0, 0x76, 0x5d, 0xfb, 0xf6, 0x1e, 0xe9, 0xaf, 0x32, 0x01, 0xe6, 0x43, 0xac, 0x34,
|
||||
0x47, 0x1e, 0x0d, 0x38, 0x58, 0xfa, 0x7f, 0x8f, 0xf4, 0x5d, 0x9f, 0x9b, 0xef, 0x1d, 0xed, 0xdf,
|
||||
0x3e, 0x70, 0x0f, 0x5c, 0x26, 0xb0, 0x27, 0x6e, 0x84, 0x9e, 0x28, 0x20, 0xb7, 0x49, 0x6c, 0xdb,
|
||||
0x85, 0x75, 0x30, 0x6f, 0x92, 0x63, 0xab, 0x4b, 0x74, 0xc7, 0xe8, 0x91, 0xa2, 0x52, 0x51, 0x96,
|
||||
0xe7, 0x6a, 0x68, 0x1c, 0xa8, 0x80, 0xc3, 0x2d, 0xa3, 0x47, 0x26, 0x81, 0x5a, 0x78, 0xd4, 0xb3,
|
||||
0xdf, 0x44, 0x31, 0x84, 0xb0, 0xa4, 0xa7, 0x41, 0xba, 0xb6, 0x45, 0x9c, 0x01, 0x0f, 0x92, 0x8e,
|
||||
0x83, 0x70, 0x38, 0x11, 0x24, 0x86, 0x10, 0x96, 0xf4, 0xb0, 0x0d, 0x2e, 0x89, 0x20, 0xc7, 0xc4,
|
||||
0xf3, 0x2d, 0xd7, 0x29, 0x66, 0x58, 0x9c, 0xe5, 0x71, 0xa0, 0x2e, 0x72, 0xcd, 0x5d, 0xae, 0x98,
|
||||
0x04, 0xea, 0x65, 0x29, 0x94, 0x40, 0x11, 0x4e, 0x5a, 0xa1, 0x3f, 0x2b, 0x60, 0x66, 0x93, 0x18,
|
||||
0x26, 0xf1, 0x60, 0x15, 0x64, 0x07, 0x27, 0x7d, 0xfe, 0x79, 0x97, 0xd6, 0xae, 0xae, 0x86, 0x1b,
|
||||
0xb7, 0xba, 0x4d, 0x7c, 0xdf, 0x38, 0x20, 0xbb, 0x27, 0x7d, 0x52, 0xbb, 0x36, 0x0e, 0x54, 0x66,
|
||||
0x36, 0x09, 0x54, 0xc0, 0xe2, 0x53, 0x01, 0x61, 0x86, 0x41, 0x13, 0xcc, 0x77, 0xdd, 0x5e, 0xdf,
|
||||
0x23, 0x3e, 0x5b, 0x5b, 0x9a, 0x45, 0xba, 0x39, 0x15, 0xa9, 0x1e, 0xdb, 0xd4, 0x6e, 0x8d, 0x03,
|
||||
0x55, 0x76, 0x9a, 0x04, 0xea, 0x12, 0x5f, 0x77, 0x8c, 0x21, 0x2c, 0x5b, 0xa0, 0x1f, 0x83, 0xc5,
|
||||
0xba, 0x7d, 0xe4, 0x0f, 0x88, 0x57, 0x77, 0x9d, 0x7d, 0xeb, 0x00, 0xbe, 0x0f, 0x66, 0xf7, 0x5d,
|
||||
0xdb, 0x24, 0x9e, 0x5f, 0x54, 0x2a, 0x99, 0xe5, 0xf9, 0xb5, 0x42, 0xfc, 0xca, 0x75, 0xa6, 0xa8,
|
||||
0xa9, 0x9f, 0x05, 0x6a, 0x6a, 0x1c, 0xa8, 0xa1, 0xe1, 0x24, 0x50, 0x17, 0xd8, 0x6b, 0xb8, 0x8c,
|
||||
0x70, 0xa8, 0x40, 0x9f, 0x66, 0xc1, 0x0c, 0x77, 0x82, 0xab, 0x20, 0x6d, 0x99, 0x22, 0xdd, 0xe5,
|
||||
0x27, 0x81, 0x9a, 0x6e, 0x36, 0xc6, 0x81, 0x9a, 0xb6, 0xcc, 0x49, 0xa0, 0xe6, 0x99, 0xb7, 0x65,
|
||||
0xa2, 0x8f, 0x1f, 0xdf, 0x4a, 0x37, 0x1b, 0x38, 0x6d, 0x99, 0x70, 0x15, 0xe4, 0x6c, 0x63, 0x8f,
|
||||
0xd8, 0x22, 0xb9, 0xc5, 0x71, 0xa0, 0x72, 0x60, 0x12, 0xa8, 0xf3, 0xcc, 0x9e, 0x49, 0x08, 0x73,
|
||||
0x14, 0xbe, 0x05, 0xe6, 0x3c, 0x62, 0x98, 0xba, 0xeb, 0xd8, 0x27, 0x2c, 0x91, 0xf9, 0x5a, 0x79,
|
||||
0x1c, 0xa8, 0x79, 0x0a, 0xb6, 0x1d, 0xfb, 0x64, 0x12, 0xa8, 0x97, 0x98, 0x5b, 0x08, 0x20, 0x1c,
|
||||
0xe9, 0xa0, 0x0e, 0xa0, 0x75, 0xe0, 0xb8, 0x1e, 0xd1, 0xfb, 0xc4, 0xeb, 0x59, 0x6c, 0x6b, 0xfc,
|
||||
0x62, 0x96, 0x45, 0x79, 0x79, 0x1c, 0xa8, 0x4b, 0x5c, 0xbb, 0x13, 0x2b, 0x27, 0x81, 0x7a, 0x9d,
|
||||
0xaf, 0xfa, 0xb4, 0x06, 0xe1, 0x69, 0x6b, 0xf8, 0x3e, 0x58, 0x14, 0x2f, 0x30, 0x89, 0x4d, 0x06,
|
||||
0xa4, 0x98, 0x63, 0xb1, 0xbf, 0x35, 0x0e, 0xd4, 0x05, 0xae, 0x68, 0x30, 0x7c, 0x12, 0xa8, 0x50,
|
||||
0x0a, 0xcb, 0x41, 0x84, 0x13, 0x36, 0xd0, 0x04, 0x57, 0x4c, 0xcb, 0x37, 0xf6, 0x6c, 0xa2, 0x0f,
|
||||
0x48, 0xaf, 0xaf, 0x5b, 0x8e, 0x49, 0x1e, 0x11, 0xbf, 0x38, 0xc3, 0x62, 0xae, 0x8d, 0x03, 0x15,
|
||||
0x0a, 0xfd, 0x2e, 0xe9, 0xf5, 0x9b, 0x5c, 0x3b, 0x09, 0xd4, 0x22, 0xaf, 0xa9, 0x29, 0x15, 0xc2,
|
||||
0x67, 0xd8, 0xc3, 0x35, 0x30, 0xd3, 0x37, 0x8e, 0x7c, 0x62, 0x16, 0x67, 0x59, 0xdc, 0xd2, 0x38,
|
||||
0x50, 0x05, 0x12, 0x25, 0x9c, 0x8b, 0x08, 0x0b, 0x9c, 0x92, 0x87, 0x57, 0xa9, 0x5f, 0x2c, 0x9c,
|
||||
0x26, 0x4f, 0x83, 0x29, 0x62, 0xf2, 0x08, 0xc3, 0x28, 0x16, 0x97, 0x11, 0x0e, 0x15, 0xe8, 0x6f,
|
||||
0x39, 0x30, 0xc3, 0x9d, 0x60, 0x2d, 0x22, 0xcf, 0x42, 0x6d, 0x8d, 0x06, 0xf8, 0x67, 0xa0, 0xe6,
|
||||
0xb9, 0xae, 0xd9, 0x38, 0x8f, 0x4c, 0x1f, 0x3d, 0xbe, 0xa5, 0x48, 0x84, 0x5a, 0x01, 0x59, 0xa9,
|
||||
0x59, 0xb0, 0xda, 0x73, 0x78, 0x9b, 0xe0, 0xb5, 0xe7, 0xb0, 0x06, 0xc1, 0x30, 0xf8, 0x36, 0x98,
|
||||
0x33, 0x4c, 0x93, 0xd6, 0x08, 0xf1, 0x8b, 0x99, 0x4a, 0x86, 0x72, 0x76, 0x1c, 0xa8, 0x31, 0x38,
|
||||
0x09, 0xd4, 0x45, 0xe6, 0x25, 0x10, 0x84, 0x63, 0x1d, 0xfc, 0x49, 0xb2, 0x72, 0xb3, 0xa7, 0x7b,
|
||||
0xc0, 0x37, 0x2b, 0x59, 0xca, 0xf4, 0x2e, 0xf1, 0x44, 0xeb, 0xcb, 0xf1, 0x82, 0xa2, 0x4c, 0xa7,
|
||||
0xa0, 0x68, 0x7c, 0x9c, 0xe9, 0x21, 0x80, 0x70, 0xa4, 0x83, 0x1b, 0x60, 0xa1, 0x67, 0x3c, 0xd2,
|
||||
0x7d, 0xf2, 0xd3, 0x23, 0xe2, 0x74, 0x09, 0xe3, 0x4c, 0x86, 0xaf, 0xa2, 0x67, 0x3c, 0xea, 0x08,
|
||||
0x38, 0x5a, 0x85, 0x84, 0x21, 0x2c, 0x5b, 0xc0, 0x1a, 0x00, 0x96, 0x33, 0xf0, 0x5c, 0xf3, 0xa8,
|
||||
0x4b, 0x3c, 0x41, 0x11, 0xd6, 0x81, 0x63, 0x34, 0xea, 0xc0, 0x31, 0x84, 0xb0, 0xa4, 0x87, 0x07,
|
||||
0x20, 0xcf, 0xb8, 0xab, 0x5b, 0x66, 0x31, 0x5f, 0x51, 0x96, 0xb3, 0xb5, 0x2d, 0x91, 0xdc, 0x59,
|
||||
0xc6, 0x42, 0x96, 0xdb, 0xf0, 0x91, 0x72, 0x86, 0x59, 0x37, 0xcd, 0x68, 0xf7, 0x85, 0x4c, 0xfb,
|
||||
0x46, 0x68, 0xf6, 0x9b, 0xf8, 0x11, 0x87, 0xf6, 0xf0, 0x67, 0xa0, 0xe4, 0x3f, 0xb0, 0x68, 0xa5,
|
||||
0xf0, 0x77, 0x0f, 0x2c, 0xd7, 0xd1, 0x3d, 0xd2, 0x73, 0x8f, 0x0d, 0xdb, 0x2f, 0xce, 0xb1, 0xc5,
|
||||
0xbf, 0x33, 0x0e, 0xd4, 0x22, 0xb5, 0x6a, 0x4a, 0x46, 0x58, 0xd8, 0x4c, 0x02, 0xb5, 0xcc, 0xde,
|
||||
0x78, 0x9e, 0x01, 0xc2, 0xe7, 0xfa, 0xa2, 0x9f, 0x2b, 0x20, 0xc7, 0x96, 0x44, 0x6b, 0x8a, 0xb7,
|
||||
0x46, 0xd1, 0x08, 0x59, 0x4d, 0x71, 0x64, 0xaa, 0x89, 0x0a, 0x1c, 0x6a, 0x20, 0xb7, 0x6f, 0xd9,
|
||||
0xc4, 0x2f, 0xa6, 0x59, 0x45, 0x41, 0xa9, 0x1d, 0x5b, 0x36, 0x69, 0x3a, 0xfb, 0x6e, 0xed, 0x86,
|
||||
0xa8, 0x29, 0x6e, 0x18, 0x31, 0x9a, 0x4a, 0x08, 0x73, 0x10, 0x7d, 0xa4, 0x80, 0x79, 0xb6, 0x88,
|
||||
0x3b, 0x7d, 0xd3, 0x18, 0x90, 0xff, 0xe5, 0x52, 0x7e, 0x0f, 0x40, 0x3e, 0x74, 0x88, 0xca, 0x52,
|
||||
0xb9, 0x40, 0x59, 0xae, 0x80, 0xac, 0x6f, 0x7d, 0x48, 0x58, 0x7b, 0xcf, 0x70, 0x5b, 0x2a, 0x47,
|
||||
0xb6, 0x54, 0x40, 0x98, 0x61, 0xf0, 0x5d, 0x00, 0x7a, 0xae, 0x69, 0xed, 0x5b, 0xc4, 0xd4, 0x7d,
|
||||
0x56, 0x26, 0x99, 0x5a, 0x85, 0xd6, 0x70, 0x88, 0x76, 0x26, 0x81, 0xfa, 0x0c, 0x27, 0x79, 0x88,
|
||||
0x20, 0x1c, 0x6b, 0x69, 0x15, 0x47, 0x01, 0xf6, 0x4e, 0x8a, 0x0b, 0x8c, 0x9f, 0x6f, 0x87, 0xfc,
|
||||
0xec, 0x1c, 0xba, 0xde, 0x80, 0x91, 0x32, 0x7a, 0x4d, 0xed, 0x24, 0x22, 0x7c, 0x0c, 0x21, 0xca,
|
||||
0x47, 0x61, 0x8c, 0x25, 0x53, 0xb8, 0x05, 0x66, 0xc3, 0xb1, 0x83, 0xf2, 0x2f, 0xd1, 0x2a, 0xef,
|
||||
0x92, 0xee, 0xc0, 0xf5, 0x6a, 0x95, 0xb0, 0x55, 0x1e, 0x47, 0x63, 0x08, 0xa7, 0xfd, 0x71, 0x38,
|
||||
0x80, 0x84, 0x1a, 0xf8, 0x26, 0xc8, 0x47, 0x25, 0x0d, 0xd8, 0xb7, 0xb2, 0x96, 0xe0, 0xc7, 0xf5,
|
||||
0xcc, 0x5b, 0x82, 0x1f, 0x15, 0x73, 0xa4, 0x83, 0xef, 0x81, 0x99, 0x3d, 0xdb, 0xed, 0x3e, 0x08,
|
||||
0x7b, 0xf6, 0xe5, 0x78, 0x21, 0x35, 0x8a, 0xb3, 0xbc, 0x3e, 0x27, 0xd6, 0x22, 0x4c, 0xa3, 0x43,
|
||||
0x98, 0x89, 0x08, 0x0b, 0x98, 0xce, 0x54, 0xfe, 0x49, 0xcf, 0xb6, 0x9c, 0x07, 0xfa, 0xc0, 0xf0,
|
||||
0x0e, 0xc8, 0xa0, 0xb8, 0x14, 0xcf, 0x54, 0x42, 0xb3, 0xcb, 0x14, 0xd1, 0x4c, 0x95, 0x40, 0x11,
|
||||
0x4e, 0x5a, 0xd1, 0x49, 0x8f, 0x87, 0xd6, 0x0f, 0x0d, 0xff, 0xb0, 0x08, 0xd9, 0x11, 0xc0, 0xfa,
|
||||
0x0c, 0x87, 0x37, 0x0d, 0xff, 0x30, 0xda, 0xf6, 0x18, 0x42, 0x58, 0xd2, 0xc3, 0x9a, 0x98, 0xc6,
|
||||
0xf8, 0x0c, 0x75, 0x6d, 0x9a, 0xb6, 0x17, 0x18, 0xc7, 0xd6, 0xc1, 0xfc, 0xe9, 0xd9, 0x60, 0x91,
|
||||
0xf7, 0xcd, 0x7e, 0x62, 0x2a, 0xe0, 0x7d, 0xb3, 0x2f, 0xcf, 0x03, 0xb2, 0x05, 0x7c, 0x4f, 0xa2,
|
||||
0x95, 0xe3, 0x17, 0xe7, 0x2b, 0xca, 0x72, 0xae, 0xf6, 0x82, 0xcc, 0xa3, 0x96, 0x3f, 0xc5, 0xa3,
|
||||
0x96, 0x8f, 0xfe, 0x13, 0xa8, 0x19, 0xcb, 0x19, 0x60, 0xc9, 0x0c, 0xee, 0x03, 0xfe, 0x95, 0x3a,
|
||||
0xab, 0x8a, 0x45, 0x16, 0x6a, 0xe3, 0x49, 0xa0, 0x2e, 0x60, 0xe3, 0x21, 0x4b, 0x5d, 0xc7, 0xfa,
|
||||
0x90, 0x50, 0xce, 0xef, 0x85, 0x42, 0xc4, 0xf9, 0x08, 0x09, 0x03, 0x7f, 0xfc, 0xf8, 0x56, 0xc2,
|
||||
0x0d, 0xc7, 0x4e, 0xb0, 0x01, 0xe6, 0x6d, 0xb7, 0x6b, 0xd8, 0xfa, 0xbe, 0x6d, 0x1c, 0xf8, 0xc5,
|
||||
0x7f, 0xcd, 0xb2, 0x8f, 0x67, 0x59, 0x60, 0xf8, 0x3a, 0x85, 0xa3, 0x45, 0xc7, 0x10, 0xc2, 0x92,
|
||||
0x1e, 0x6e, 0x82, 0x05, 0x41, 0x57, 0x9e, 0xcb, 0x7f, 0xcf, 0xb2, 0x64, 0xb2, 0x3d, 0x14, 0x0a,
|
||||
0x91, 0xcd, 0x25, 0x99, 0xe5, 0x3c, 0x9d, 0xb2, 0x05, 0xfc, 0x2e, 0x1d, 0x33, 0xe8, 0x28, 0x64,
|
||||
0x8a, 0x99, 0xe7, 0x26, 0x1f, 0x28, 0x18, 0x14, 0x55, 0x89, 0x90, 0xd9, 0x44, 0xc1, 0x9e, 0x20,
|
||||
0x06, 0xb3, 0x96, 0x73, 0x6c, 0xd8, 0x56, 0x38, 0xd3, 0xbc, 0xf1, 0x24, 0x50, 0x01, 0x36, 0x1e,
|
||||
0x36, 0x39, 0xca, 0x8f, 0x18, 0xf6, 0x28, 0x1d, 0x31, 0x4c, 0xa6, 0x47, 0x8c, 0x64, 0x89, 0x43,
|
||||
0x3b, 0xca, 0x78, 0xc7, 0x4d, 0x8c, 0x8d, 0x79, 0x16, 0x9a, 0x31, 0xde, 0x71, 0x93, 0x23, 0x23,
|
||||
0x67, 0x7c, 0x02, 0x45, 0x38, 0x69, 0xf5, 0x66, 0xf6, 0xd7, 0x9f, 0xa8, 0x29, 0xf4, 0x85, 0x02,
|
||||
0xe6, 0xa2, 0xea, 0xa3, 0x8d, 0x8f, 0x6d, 0x59, 0x86, 0xed, 0x18, 0x23, 0xea, 0x21, 0xdf, 0x2a,
|
||||
0x4e, 0xd4, 0x43, 0xb6, 0x47, 0x0c, 0xa3, 0x8d, 0xdd, 0xdd, 0xdf, 0xf7, 0xc9, 0x80, 0xb5, 0xd4,
|
||||
0x0c, 0x6f, 0xec, 0x1c, 0x89, 0x1a, 0x3b, 0x17, 0x11, 0x16, 0x38, 0x7c, 0x45, 0x34, 0xd6, 0x34,
|
||||
0xa3, 0xd0, 0x73, 0x67, 0x37, 0xd6, 0x90, 0x81, 0xbc, 0xbf, 0xbe, 0x05, 0xe6, 0x1e, 0x12, 0xe3,
|
||||
0x01, 0x4f, 0x25, 0xaf, 0x06, 0xd6, 0x72, 0x28, 0x28, 0xd2, 0xc8, 0x5b, 0x4e, 0x08, 0x20, 0x1c,
|
||||
0xe9, 0xc4, 0x37, 0xde, 0x07, 0x33, 0xbc, 0xd3, 0xc1, 0x1d, 0x90, 0xef, 0xba, 0x47, 0xce, 0x20,
|
||||
0xbe, 0x75, 0x2c, 0xc9, 0xe3, 0x12, 0xd3, 0xd4, 0xfe, 0x4f, 0xb4, 0xa0, 0xc8, 0x34, 0xca, 0x91,
|
||||
0x00, 0xe8, 0x9c, 0x23, 0x54, 0xe8, 0x17, 0x0a, 0x98, 0x15, 0x8e, 0x70, 0x33, 0x9a, 0x1e, 0xb3,
|
||||
0xb5, 0x37, 0x4e, 0x35, 0xf0, 0x2f, 0xbf, 0x89, 0xc8, 0xcd, 0x5b, 0x5c, 0x4a, 0x8e, 0x0d, 0xfb,
|
||||
0x88, 0x6f, 0x54, 0x96, 0x5f, 0x4a, 0x18, 0x10, 0xf5, 0x43, 0x26, 0x21, 0xcc, 0x51, 0xf4, 0xd7,
|
||||
0x0c, 0x98, 0xc5, 0xb4, 0xcf, 0xfa, 0x03, 0xf8, 0x7a, 0xb4, 0x8a, 0x5c, 0xed, 0xf9, 0xf3, 0x5e,
|
||||
0x1b, 0x17, 0x63, 0x38, 0xb6, 0xc6, 0xe7, 0x74, 0xfa, 0xc2, 0xe7, 0x74, 0x78, 0xa6, 0x66, 0x2e,
|
||||
0x70, 0xa6, 0xc6, 0x74, 0xc9, 0x7e, 0x65, 0xba, 0xe4, 0x2e, 0x4e, 0x97, 0x90, 0xc1, 0x33, 0x17,
|
||||
0x60, 0x70, 0x1b, 0x5c, 0xda, 0xf7, 0xdc, 0x1e, 0xbb, 0xdc, 0xb8, 0x9e, 0xe1, 0x9d, 0x88, 0x6a,
|
||||
0x65, 0x25, 0x45, 0x35, 0xbb, 0xa1, 0x22, 0x2a, 0xa9, 0x04, 0x8a, 0x70, 0xd2, 0x2a, 0xc9, 0xd5,
|
||||
0xfc, 0x57, 0xe3, 0x2a, 0xfa, 0x93, 0x02, 0xf2, 0x98, 0xf8, 0x7d, 0xd7, 0xf1, 0xc9, 0xd7, 0x4d,
|
||||
0xe2, 0x0a, 0xc8, 0x9a, 0xc6, 0xc0, 0x60, 0x29, 0x14, 0x5f, 0x4f, 0xe5, 0xe8, 0xeb, 0xa9, 0x80,
|
||||
0x30, 0xc3, 0xe0, 0xbb, 0x20, 0xdb, 0x75, 0x4d, 0x9e, 0xbc, 0x4b, 0xf2, 0x61, 0xac, 0x79, 0x9e,
|
||||
0xeb, 0xd5, 0x5d, 0x53, 0x9c, 0x54, 0xd4, 0x28, 0x0a, 0x40, 0x05, 0x84, 0x19, 0x86, 0xfe, 0xa8,
|
||||
0x80, 0x42, 0xc3, 0x7d, 0xe8, 0xd8, 0xae, 0x61, 0xee, 0x78, 0xee, 0x01, 0xbd, 0x37, 0x7c, 0xad,
|
||||
0x71, 0x4f, 0x07, 0xb3, 0x47, 0x6c, 0x58, 0x0c, 0x07, 0xbe, 0x5b, 0xc9, 0x93, 0xf3, 0xf4, 0x4b,
|
||||
0xf8, 0x64, 0x19, 0xdf, 0xf0, 0x84, 0x73, 0x14, 0x9f, 0xcb, 0x08, 0x87, 0x0a, 0xf4, 0x87, 0x0c,
|
||||
0x28, 0x9d, 0x1f, 0x08, 0xf6, 0xc0, 0x3c, 0xb7, 0xd4, 0xa5, 0xdf, 0x52, 0x96, 0x2f, 0xb2, 0x06,
|
||||
0x76, 0x9e, 0xb3, 0xf3, 0xe9, 0x28, 0x92, 0xa3, 0xf3, 0x29, 0x86, 0x10, 0x96, 0xf4, 0x5f, 0xe9,
|
||||
0x82, 0x28, 0x4d, 0x6f, 0x99, 0x6f, 0x3e, 0xbd, 0x75, 0xc0, 0x22, 0x3f, 0xc7, 0xc3, 0x9b, 0x7c,
|
||||
0xb6, 0x92, 0x59, 0xce, 0xd5, 0x56, 0xc7, 0x81, 0xba, 0xb0, 0xc7, 0x0f, 0x81, 0xf0, 0x0e, 0xbf,
|
||||
0x14, 0x9f, 0xde, 0x1c, 0x0c, 0xd9, 0x56, 0x48, 0xe1, 0x84, 0x2d, 0x5c, 0x4f, 0x0c, 0x07, 0xbc,
|
||||
0x54, 0xbf, 0x7d, 0xc1, 0x61, 0x40, 0x3a, 0xfc, 0xd1, 0x0c, 0xc8, 0xee, 0x58, 0xce, 0x01, 0x7a,
|
||||
0x0b, 0xe4, 0xea, 0xb6, 0xeb, 0xb3, 0x8e, 0xe1, 0x11, 0xc3, 0x77, 0x1d, 0x99, 0x4a, 0x1c, 0x89,
|
||||
0x52, 0xcd, 0x45, 0x84, 0x05, 0xbe, 0xf2, 0x69, 0x06, 0xcc, 0x4b, 0x3f, 0x7d, 0xc1, 0x1f, 0x80,
|
||||
0x1b, 0xdb, 0x5a, 0xa7, 0x53, 0xdd, 0xd0, 0xf4, 0xdd, 0x7b, 0x3b, 0x9a, 0x5e, 0xdf, 0xba, 0xd3,
|
||||
0xd9, 0xd5, 0xb0, 0x5e, 0x6f, 0xb7, 0xd6, 0x9b, 0x1b, 0x85, 0x54, 0xe9, 0xe6, 0x70, 0x54, 0x29,
|
||||
0x4a, 0x1e, 0xc9, 0x1f, 0xa9, 0xbe, 0x03, 0x60, 0xc2, 0xbd, 0xd9, 0x6a, 0x68, 0x3f, 0x2a, 0x28,
|
||||
0xa5, 0x2b, 0xc3, 0x51, 0xa5, 0x20, 0x79, 0xf1, 0x5b, 0xd7, 0xf7, 0xc1, 0xb3, 0xd3, 0xd6, 0xfa,
|
||||
0x9d, 0x9d, 0x46, 0x75, 0x57, 0x2b, 0xa4, 0x4b, 0xa5, 0xe1, 0xa8, 0x72, 0xed, 0xb4, 0x93, 0xa0,
|
||||
0xe0, 0xcb, 0xe0, 0x4a, 0xc2, 0x15, 0x6b, 0x3f, 0xbc, 0xa3, 0x75, 0x76, 0x0b, 0x99, 0xd2, 0xb5,
|
||||
0xe1, 0xa8, 0x02, 0x25, 0xaf, 0xb0, 0xcd, 0xaf, 0x81, 0xab, 0xa7, 0x3c, 0x3a, 0x3b, 0xed, 0x56,
|
||||
0x47, 0x2b, 0x64, 0x4b, 0xd7, 0x87, 0xa3, 0xca, 0xe5, 0x84, 0x8b, 0xe8, 0x2a, 0x75, 0x50, 0x4e,
|
||||
0xf8, 0x34, 0xda, 0x1f, 0xb4, 0xb6, 0xda, 0xd5, 0x86, 0xbe, 0x83, 0xdb, 0x1b, 0x58, 0xeb, 0x74,
|
||||
0x0a, 0xb9, 0x92, 0x3a, 0x1c, 0x55, 0x6e, 0x48, 0xce, 0x53, 0x15, 0xbe, 0x02, 0x96, 0x12, 0x41,
|
||||
0x76, 0x9a, 0xad, 0x8d, 0xc2, 0x4c, 0xe9, 0xf2, 0x70, 0x54, 0x79, 0x46, 0xf2, 0xa3, 0xb9, 0x9c,
|
||||
0xda, 0xbf, 0xfa, 0x56, 0xbb, 0xa3, 0x15, 0x66, 0xa7, 0xf6, 0x8f, 0x25, 0x7c, 0xe5, 0x77, 0x0a,
|
||||
0x80, 0xd3, 0xbf, 0x36, 0xc2, 0x37, 0x40, 0x31, 0x0c, 0x52, 0x6f, 0x6f, 0xef, 0xd0, 0x75, 0x36,
|
||||
0xdb, 0x2d, 0xbd, 0xd5, 0x6e, 0x69, 0x85, 0x54, 0x62, 0x57, 0x25, 0xaf, 0x96, 0xeb, 0x10, 0xd8,
|
||||
0x06, 0xd7, 0xcf, 0xf2, 0xdc, 0xba, 0xff, 0x5a, 0x41, 0x29, 0xad, 0x0d, 0x47, 0x95, 0xab, 0xd3,
|
||||
0x8e, 0x5b, 0xf7, 0x5f, 0xfb, 0xfc, 0x97, 0xcf, 0x9f, 0xad, 0x58, 0xf9, 0xad, 0x02, 0xe6, 0xe5,
|
||||
0xa5, 0xbd, 0x02, 0xae, 0xc8, 0x81, 0xb7, 0xb5, 0xdd, 0x6a, 0xa3, 0xba, 0x5b, 0x2d, 0xa4, 0x78,
|
||||
0x0e, 0x24, 0xd3, 0x6d, 0x32, 0x30, 0x58, 0xdb, 0x7d, 0x11, 0x2c, 0x25, 0xbe, 0x42, 0xbb, 0xab,
|
||||
0xe1, 0x90, 0x51, 0xf2, 0xfa, 0xc9, 0x31, 0xf1, 0xe0, 0x4b, 0x00, 0xca, 0xc6, 0xd5, 0xad, 0x0f,
|
||||
0xaa, 0xf7, 0x3a, 0x85, 0x74, 0xe9, 0xea, 0x70, 0x54, 0x59, 0x92, 0xac, 0xab, 0xf6, 0x43, 0xe3,
|
||||
0xc4, 0x5f, 0xf9, 0x4b, 0x1a, 0x2c, 0xc8, 0x57, 0x0d, 0xf8, 0x12, 0xb8, 0xbc, 0xde, 0xdc, 0xa2,
|
||||
0x4c, 0x5c, 0x6f, 0xf3, 0x0c, 0x50, 0xb1, 0x90, 0xe2, 0xaf, 0x93, 0x4d, 0xe9, 0x33, 0xfc, 0x1e,
|
||||
0x28, 0x9e, 0x32, 0x6f, 0x34, 0xb1, 0x56, 0xdf, 0x6d, 0xe3, 0x7b, 0x05, 0xa5, 0xf4, 0x2c, 0xdd,
|
||||
0x30, 0xd9, 0xa7, 0x61, 0x79, 0xac, 0x05, 0x9d, 0xc0, 0x77, 0xc0, 0x8d, 0x53, 0x8e, 0x9d, 0x7b,
|
||||
0xdb, 0x5b, 0xcd, 0xd6, 0xfb, 0xfc, 0x7d, 0xe9, 0xd2, 0x73, 0xc3, 0x51, 0xe5, 0xba, 0xec, 0xdb,
|
||||
0xe1, 0xb7, 0x2f, 0x0a, 0xe5, 0x15, 0xb8, 0x09, 0x2a, 0xe7, 0xf8, 0xc7, 0x0b, 0xc8, 0x94, 0xd0,
|
||||
0x70, 0x54, 0xb9, 0x79, 0x46, 0x90, 0x68, 0x1d, 0x79, 0x05, 0xbe, 0x0a, 0xae, 0x9d, 0x1d, 0x29,
|
||||
0xac, 0x8b, 0x33, 0xfc, 0x57, 0xfe, 0xae, 0x80, 0xb9, 0xe8, 0xd4, 0xa3, 0x9b, 0xa6, 0x61, 0xdc,
|
||||
0xa6, 0x4d, 0xa2, 0xa1, 0xe9, 0xad, 0xb6, 0xce, 0xa4, 0x70, 0xd3, 0x22, 0xbb, 0x96, 0xcb, 0x1e,
|
||||
0x29, 0xc7, 0x25, 0xf3, 0x0d, 0xad, 0xa5, 0xe1, 0x66, 0x3d, 0xcc, 0x68, 0x64, 0xbd, 0x41, 0x1c,
|
||||
0xe2, 0x59, 0x5d, 0xf8, 0x1a, 0xb8, 0x9e, 0x0c, 0xde, 0xb9, 0x53, 0xdf, 0x0c, 0x77, 0x89, 0x2d,
|
||||
0x50, 0x7a, 0x41, 0xe7, 0xa8, 0x7b, 0xc8, 0x12, 0xf3, 0x7a, 0xc2, 0xab, 0xd9, 0xba, 0x5b, 0xdd,
|
||||
0x6a, 0x36, 0xb8, 0x57, 0xa6, 0x54, 0x1c, 0x8e, 0x2a, 0x57, 0x22, 0x2f, 0x71, 0x71, 0xa0, 0x6e,
|
||||
0x2b, 0x9f, 0x2b, 0xa0, 0xfc, 0xe5, 0x87, 0x17, 0xfc, 0x00, 0xbc, 0xc0, 0xf6, 0x6b, 0xaa, 0x15,
|
||||
0x88, 0xbe, 0xc5, 0xf7, 0xb0, 0xba, 0xb3, 0xa3, 0xb5, 0x1a, 0x85, 0x54, 0x69, 0x79, 0x38, 0xaa,
|
||||
0xdc, 0xfa, 0xf2, 0x90, 0xd5, 0x7e, 0x9f, 0x38, 0xe6, 0x05, 0x03, 0xaf, 0xb7, 0xf1, 0x86, 0xb6,
|
||||
0x5b, 0x50, 0x2e, 0x12, 0x78, 0xdd, 0xa5, 0x37, 0xf5, 0xda, 0xf6, 0x67, 0x5f, 0x94, 0x53, 0x8f,
|
||||
0xbf, 0x28, 0xa7, 0x3e, 0x7b, 0x52, 0x56, 0x1e, 0x3f, 0x29, 0x2b, 0xbf, 0x7a, 0x5a, 0x4e, 0x7d,
|
||||
0xf2, 0xb4, 0xac, 0x3c, 0x7e, 0x5a, 0x4e, 0xfd, 0xe3, 0x69, 0x39, 0x75, 0xff, 0xc5, 0x03, 0x6b,
|
||||
0x70, 0x78, 0xb4, 0xb7, 0xda, 0x75, 0x7b, 0xb7, 0xfd, 0x13, 0xa7, 0x3b, 0x38, 0xb4, 0x9c, 0x03,
|
||||
0xe9, 0x49, 0xfe, 0xd7, 0x69, 0x6f, 0x86, 0x3d, 0xbd, 0xfa, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff,
|
||||
0xf3, 0xce, 0x28, 0x00, 0x8c, 0x1a, 0x00, 0x00,
|
||||
// 2681 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x59, 0x4d, 0x6c, 0x1b, 0xc7,
|
||||
0xf5, 0xd7, 0x92, 0x94, 0x44, 0x8d, 0x24, 0x87, 0x1a, 0x7f, 0x6d, 0x68, 0x9b, 0xcb, 0xff, 0xc4,
|
||||
0xf9, 0x57, 0x51, 0x1a, 0x39, 0x51, 0x92, 0x36, 0x4d, 0x52, 0x07, 0xfc, 0x92, 0xc4, 0x44, 0x22,
|
||||
0xd9, 0x21, 0xed, 0xd4, 0x46, 0x0b, 0x62, 0xc5, 0x1d, 0x51, 0x0b, 0x2f, 0x77, 0xd9, 0x5d, 0x4a,
|
||||
0xb6, 0x82, 0x5e, 0xda, 0x5e, 0x02, 0x1e, 0x8a, 0x22, 0xa7, 0xa2, 0x28, 0xd1, 0xa0, 0x97, 0xde,
|
||||
0x0a, 0xf4, 0xd0, 0x4b, 0x4e, 0x3d, 0xe6, 0x68, 0x04, 0x28, 0x50, 0xf4, 0xb0, 0x80, 0xed, 0x4b,
|
||||
0xcb, 0x23, 0x8f, 0x3d, 0x15, 0xf3, 0xb1, 0xbb, 0xb3, 0xa2, 0x14, 0xc8, 0xc9, 0xa1, 0xb7, 0x7d,
|
||||
0xbf, 0xf7, 0x7b, 0x6f, 0x86, 0x6f, 0xde, 0x7b, 0xf3, 0x76, 0x09, 0xae, 0x58, 0xe6, 0xde, 0xad,
|
||||
0xbe, 0xeb, 0x0c, 0x9c, 0x8e, 0x63, 0xdd, 0xda, 0x23, 0xfd, 0x75, 0x26, 0xc0, 0x74, 0x80, 0x65,
|
||||
0x17, 0xc8, 0xa3, 0x01, 0x07, 0xb3, 0x2f, 0xb9, 0xa4, 0xef, 0x78, 0x9c, 0xbe, 0x77, 0xb8, 0x7f,
|
||||
0xab, 0xeb, 0x74, 0x1d, 0x26, 0xb0, 0x27, 0x4e, 0x42, 0x4f, 0x15, 0x30, 0xbb, 0x4d, 0x2c, 0xcb,
|
||||
0x81, 0x25, 0xb0, 0x68, 0x90, 0x23, 0xb3, 0x43, 0xda, 0xb6, 0xde, 0x23, 0xaa, 0x92, 0x57, 0x56,
|
||||
0x17, 0x8a, 0x68, 0xec, 0x6b, 0x80, 0xc3, 0x35, 0xbd, 0x47, 0x26, 0xbe, 0x96, 0x79, 0xd4, 0xb3,
|
||||
0xde, 0x45, 0x11, 0x84, 0xb0, 0xa4, 0xa7, 0x4e, 0x3a, 0x96, 0x49, 0xec, 0x01, 0x77, 0x92, 0x88,
|
||||
0x9c, 0x70, 0x38, 0xe6, 0x24, 0x82, 0x10, 0x96, 0xf4, 0xb0, 0x0e, 0x2e, 0x08, 0x27, 0x47, 0xc4,
|
||||
0xf5, 0x4c, 0xc7, 0x56, 0x93, 0xcc, 0xcf, 0xea, 0xd8, 0xd7, 0x96, 0xb9, 0xe6, 0x2e, 0x57, 0x4c,
|
||||
0x7c, 0xed, 0xa2, 0xe4, 0x4a, 0xa0, 0x08, 0xc7, 0x59, 0xe8, 0x2f, 0x0a, 0x98, 0xdb, 0x26, 0xba,
|
||||
0x41, 0x5c, 0x58, 0x00, 0xa9, 0xc1, 0x71, 0x9f, 0xff, 0xbc, 0x0b, 0x1b, 0x97, 0xd7, 0x83, 0xc0,
|
||||
0xad, 0xef, 0x12, 0xcf, 0xd3, 0xbb, 0xa4, 0x75, 0xdc, 0x27, 0xc5, 0x2b, 0x63, 0x5f, 0x63, 0xb4,
|
||||
0x89, 0xaf, 0x01, 0xe6, 0x9f, 0x0a, 0x08, 0x33, 0x0c, 0x1a, 0x60, 0xb1, 0xe3, 0xf4, 0xfa, 0x2e,
|
||||
0xf1, 0xd8, 0xde, 0x12, 0xcc, 0xd3, 0xf5, 0x29, 0x4f, 0xa5, 0x88, 0x53, 0xbc, 0x39, 0xf6, 0x35,
|
||||
0xd9, 0x68, 0xe2, 0x6b, 0x2b, 0x7c, 0xdf, 0x11, 0x86, 0xb0, 0xcc, 0x40, 0x3f, 0x01, 0xcb, 0x25,
|
||||
0xeb, 0xd0, 0x1b, 0x10, 0xb7, 0xe4, 0xd8, 0xfb, 0x66, 0x17, 0x7e, 0x04, 0xe6, 0xf7, 0x1d, 0xcb,
|
||||
0x20, 0xae, 0xa7, 0x2a, 0xf9, 0xe4, 0xea, 0xe2, 0x46, 0x26, 0x5a, 0x72, 0x93, 0x29, 0x8a, 0xda,
|
||||
0x97, 0xbe, 0x36, 0x33, 0xf6, 0xb5, 0x80, 0x38, 0xf1, 0xb5, 0x25, 0xb6, 0x0c, 0x97, 0x11, 0x0e,
|
||||
0x14, 0xe8, 0x8b, 0x14, 0x98, 0xe3, 0x46, 0x70, 0x1d, 0x24, 0x4c, 0x43, 0x1c, 0x77, 0xee, 0xa9,
|
||||
0xaf, 0x25, 0xaa, 0xe5, 0xb1, 0xaf, 0x25, 0x4c, 0x63, 0xe2, 0x6b, 0x69, 0x66, 0x6d, 0x1a, 0xe8,
|
||||
0xb3, 0xc7, 0x37, 0x13, 0xd5, 0x32, 0x4e, 0x98, 0x06, 0x5c, 0x07, 0xb3, 0x96, 0xbe, 0x47, 0x2c,
|
||||
0x71, 0xb8, 0xea, 0xd8, 0xd7, 0x38, 0x30, 0xf1, 0xb5, 0x45, 0xc6, 0x67, 0x12, 0xc2, 0x1c, 0x85,
|
||||
0xef, 0x81, 0x05, 0x97, 0xe8, 0x46, 0xdb, 0xb1, 0xad, 0x63, 0x76, 0x90, 0xe9, 0x62, 0x6e, 0xec,
|
||||
0x6b, 0x69, 0x0a, 0xd6, 0x6d, 0xeb, 0x78, 0xe2, 0x6b, 0x17, 0x98, 0x59, 0x00, 0x20, 0x1c, 0xea,
|
||||
0x60, 0x1b, 0x40, 0xb3, 0x6b, 0x3b, 0x2e, 0x69, 0xf7, 0x89, 0xdb, 0x33, 0x59, 0x68, 0x3c, 0x35,
|
||||
0xc5, 0xbc, 0xbc, 0x3e, 0xf6, 0xb5, 0x15, 0xae, 0x6d, 0x44, 0xca, 0x89, 0xaf, 0x5d, 0xe5, 0xbb,
|
||||
0x3e, 0xa9, 0x41, 0x78, 0x9a, 0x0d, 0x3f, 0x02, 0xcb, 0x62, 0x01, 0x83, 0x58, 0x64, 0x40, 0xd4,
|
||||
0x59, 0xe6, 0xfb, 0xff, 0xc7, 0xbe, 0xb6, 0xc4, 0x15, 0x65, 0x86, 0x4f, 0x7c, 0x0d, 0x4a, 0x6e,
|
||||
0x39, 0x88, 0x70, 0x8c, 0x03, 0x0d, 0x70, 0xc9, 0x30, 0x3d, 0x7d, 0xcf, 0x22, 0xed, 0x01, 0xe9,
|
||||
0xf5, 0xdb, 0xa6, 0x6d, 0x90, 0x47, 0xc4, 0x53, 0xe7, 0x98, 0xcf, 0x8d, 0xb1, 0xaf, 0x41, 0xa1,
|
||||
0x6f, 0x91, 0x5e, 0xbf, 0xca, 0xb5, 0x13, 0x5f, 0x53, 0x79, 0x4d, 0x4d, 0xa9, 0x10, 0x3e, 0x85,
|
||||
0x0f, 0x37, 0xc0, 0x5c, 0x5f, 0x3f, 0xf4, 0x88, 0xa1, 0xce, 0x33, 0xbf, 0xd9, 0xb1, 0xaf, 0x09,
|
||||
0x24, 0x3c, 0x70, 0x2e, 0x22, 0x2c, 0x70, 0x9a, 0x3c, 0xbc, 0x4a, 0x3d, 0x35, 0x73, 0x32, 0x79,
|
||||
0xca, 0x4c, 0x11, 0x25, 0x8f, 0x20, 0x86, 0xbe, 0xb8, 0x8c, 0x70, 0xa0, 0x40, 0x7f, 0x9b, 0x03,
|
||||
0x73, 0xdc, 0x08, 0x16, 0xc3, 0xe4, 0x59, 0x2a, 0x6e, 0x50, 0x07, 0xff, 0xf4, 0xb5, 0x34, 0xd7,
|
||||
0x55, 0xcb, 0x67, 0x25, 0xd3, 0xa7, 0x8f, 0x6f, 0x2a, 0x52, 0x42, 0xad, 0x81, 0x94, 0xd4, 0x2c,
|
||||
0x58, 0xed, 0xd9, 0xbc, 0x4d, 0xf0, 0xda, 0xb3, 0x59, 0x83, 0x60, 0x18, 0x7c, 0x1f, 0x2c, 0xe8,
|
||||
0x86, 0x41, 0x6b, 0x84, 0x78, 0x6a, 0x32, 0x9f, 0xa4, 0x39, 0x3b, 0xf6, 0xb5, 0x08, 0x9c, 0xf8,
|
||||
0xda, 0x32, 0xb3, 0x12, 0x08, 0xc2, 0x91, 0x0e, 0xfe, 0x34, 0x5e, 0xb9, 0xa9, 0x93, 0x3d, 0xe0,
|
||||
0xdb, 0x95, 0x2c, 0xcd, 0xf4, 0x0e, 0x71, 0x45, 0xeb, 0x9b, 0xe5, 0x05, 0x45, 0x33, 0x9d, 0x82,
|
||||
0xa2, 0xf1, 0xf1, 0x4c, 0x0f, 0x00, 0x84, 0x43, 0x1d, 0xdc, 0x02, 0x4b, 0x3d, 0xfd, 0x51, 0xdb,
|
||||
0x23, 0x3f, 0x3b, 0x24, 0x76, 0x87, 0xb0, 0x9c, 0x49, 0xf2, 0x5d, 0xf4, 0xf4, 0x47, 0x4d, 0x01,
|
||||
0x87, 0xbb, 0x90, 0x30, 0x84, 0x65, 0x06, 0x2c, 0x02, 0x60, 0xda, 0x03, 0xd7, 0x31, 0x0e, 0x3b,
|
||||
0xc4, 0x15, 0x29, 0xc2, 0x3a, 0x70, 0x84, 0x86, 0x1d, 0x38, 0x82, 0x10, 0x96, 0xf4, 0xb0, 0x0b,
|
||||
0xd2, 0x2c, 0x77, 0xdb, 0xa6, 0xa1, 0xa6, 0xf3, 0xca, 0x6a, 0xaa, 0xb8, 0x23, 0x0e, 0x77, 0x9e,
|
||||
0x65, 0x21, 0x3b, 0xdb, 0xe0, 0x91, 0xe6, 0x0c, 0x63, 0x57, 0x8d, 0x30, 0xfa, 0x42, 0xa6, 0x7d,
|
||||
0x23, 0xa0, 0xfd, 0x2e, 0x7a, 0xc4, 0x01, 0x1f, 0xfe, 0x1c, 0x64, 0xbd, 0x07, 0x26, 0xad, 0x14,
|
||||
0xbe, 0xf6, 0xc0, 0x74, 0xec, 0xb6, 0x4b, 0x7a, 0xce, 0x91, 0x6e, 0x79, 0xea, 0x02, 0xdb, 0xfc,
|
||||
0xed, 0xb1, 0xaf, 0xa9, 0x94, 0x55, 0x95, 0x48, 0x58, 0x70, 0x26, 0xbe, 0x96, 0x63, 0x2b, 0x9e,
|
||||
0x45, 0x40, 0xf8, 0x4c, 0x5b, 0xf8, 0x08, 0xbc, 0x48, 0xec, 0x8e, 0x7b, 0xdc, 0x67, 0xcb, 0xf6,
|
||||
0x75, 0xcf, 0x7b, 0xe8, 0xb8, 0x46, 0x7b, 0xe0, 0x3c, 0x20, 0xb6, 0x0a, 0x58, 0x52, 0xbf, 0x3f,
|
||||
0xf6, 0xb5, 0xab, 0x11, 0xa9, 0x21, 0x38, 0x2d, 0x4a, 0x99, 0xf8, 0xda, 0x0d, 0xb6, 0xf6, 0x19,
|
||||
0x7a, 0x84, 0xcf, 0xb2, 0x44, 0xbf, 0x54, 0xc0, 0x2c, 0x0b, 0x06, 0xad, 0x66, 0xde, 0x94, 0x45,
|
||||
0x0b, 0x66, 0xd5, 0xcc, 0x91, 0xa9, 0xf6, 0x2d, 0x70, 0x58, 0x01, 0xb3, 0xfb, 0xa6, 0x45, 0x3c,
|
||||
0x35, 0xc1, 0x6a, 0x19, 0x4a, 0x17, 0x81, 0x69, 0x91, 0xaa, 0xbd, 0xef, 0x14, 0xaf, 0x89, 0x6a,
|
||||
0xe6, 0xc4, 0xb0, 0x96, 0xa8, 0x84, 0x30, 0x07, 0xd1, 0xa7, 0x0a, 0x58, 0x64, 0x9b, 0xb8, 0xd3,
|
||||
0x37, 0xf4, 0x01, 0xf9, 0x5f, 0x6e, 0xe5, 0x09, 0x00, 0xe9, 0xc0, 0x20, 0x6c, 0x08, 0xca, 0x39,
|
||||
0x1a, 0xc2, 0x1a, 0x48, 0x79, 0xe6, 0x27, 0x84, 0x5d, 0x2c, 0x49, 0xce, 0xa5, 0x72, 0xc8, 0xa5,
|
||||
0x02, 0xc2, 0x0c, 0x83, 0x1f, 0x00, 0xd0, 0x73, 0x0c, 0x73, 0xdf, 0x24, 0x46, 0xdb, 0x63, 0x05,
|
||||
0x9a, 0x2c, 0xe6, 0x69, 0xf7, 0x08, 0xd0, 0xe6, 0xc4, 0xd7, 0x5e, 0xe0, 0xe5, 0x15, 0x20, 0x08,
|
||||
0x47, 0x5a, 0xda, 0x3f, 0x42, 0x07, 0x7b, 0xc7, 0xea, 0x12, 0xab, 0x8c, 0xf7, 0x83, 0xca, 0x68,
|
||||
0x1e, 0x38, 0xee, 0x80, 0x95, 0x43, 0xb8, 0x4c, 0xf1, 0x38, 0x2c, 0xb5, 0x08, 0x42, 0xb4, 0x12,
|
||||
0x04, 0x19, 0x4b, 0x54, 0xb8, 0x03, 0xe6, 0x83, 0x81, 0x87, 0x66, 0x7e, 0xac, 0x49, 0xdf, 0x25,
|
||||
0x9d, 0x81, 0xe3, 0x16, 0xf3, 0x41, 0x93, 0x3e, 0x0a, 0x07, 0x20, 0x5e, 0x70, 0x47, 0xc1, 0xe8,
|
||||
0x13, 0x68, 0xe0, 0xbb, 0x20, 0x1d, 0x36, 0x13, 0xc0, 0x7e, 0x2b, 0x6b, 0x46, 0x5e, 0xd4, 0x49,
|
||||
0x78, 0x33, 0xf2, 0xc2, 0x36, 0x12, 0xea, 0xe0, 0x87, 0x60, 0x6e, 0xcf, 0x72, 0x3a, 0x0f, 0x82,
|
||||
0xdb, 0xe2, 0x62, 0xb4, 0x91, 0x22, 0xc5, 0xd9, 0xb9, 0xde, 0x10, 0x7b, 0x11, 0xd4, 0xf0, 0xfa,
|
||||
0x67, 0x22, 0xc2, 0x02, 0xa6, 0xd3, 0x9c, 0x77, 0xdc, 0xb3, 0x4c, 0xfb, 0x41, 0x7b, 0xa0, 0xbb,
|
||||
0x5d, 0x32, 0x50, 0x57, 0xa2, 0x69, 0x4e, 0x68, 0x5a, 0x4c, 0x11, 0x4e, 0x73, 0x31, 0x14, 0xe1,
|
||||
0x38, 0x8b, 0xce, 0x98, 0xdc, 0x75, 0xfb, 0x40, 0xf7, 0x0e, 0x54, 0xc8, 0xea, 0x94, 0x75, 0x38,
|
||||
0x0e, 0x6f, 0xeb, 0xde, 0x41, 0x18, 0xf6, 0x08, 0x42, 0x58, 0xd2, 0xc3, 0xdb, 0x60, 0x41, 0xd4,
|
||||
0x26, 0x31, 0xd4, 0x8b, 0xcc, 0x05, 0x4b, 0x85, 0x10, 0x0c, 0x53, 0x21, 0x44, 0x10, 0x8e, 0xb4,
|
||||
0xb0, 0x28, 0xe6, 0x48, 0x3e, 0xfd, 0x5d, 0x99, 0x4e, 0xfb, 0x73, 0x0c, 0x92, 0x9b, 0x60, 0xf1,
|
||||
0xe4, 0x54, 0xb3, 0xcc, 0x3b, 0x7e, 0x3f, 0x36, 0xcf, 0xf0, 0x8e, 0xdf, 0x97, 0x27, 0x19, 0x99,
|
||||
0x01, 0x3f, 0x94, 0xd2, 0xd2, 0xf6, 0xd4, 0xc5, 0xbc, 0xb2, 0x3a, 0x5b, 0x7c, 0x45, 0xce, 0xc3,
|
||||
0x9a, 0x37, 0x95, 0x87, 0x35, 0x0f, 0xfd, 0xc7, 0xd7, 0x92, 0xa6, 0x3d, 0xc0, 0x12, 0x0d, 0xee,
|
||||
0x03, 0x1e, 0xa5, 0x36, 0xab, 0xaa, 0x65, 0xe6, 0x6a, 0xeb, 0xa9, 0xaf, 0x2d, 0x61, 0xfd, 0x21,
|
||||
0x3b, 0xfa, 0xa6, 0xf9, 0x09, 0xa1, 0x81, 0xda, 0x0b, 0x84, 0x30, 0x50, 0x21, 0x12, 0x38, 0xfe,
|
||||
0xec, 0xf1, 0xcd, 0x98, 0x19, 0x8e, 0x8c, 0x60, 0x19, 0x2c, 0x5a, 0x4e, 0x47, 0xb7, 0xda, 0xfb,
|
||||
0x96, 0xde, 0xf5, 0xd4, 0x7f, 0xcd, 0xb3, 0x1f, 0xcf, 0x4e, 0x91, 0xe1, 0x9b, 0x14, 0x0e, 0x37,
|
||||
0x1d, 0x41, 0x08, 0x4b, 0x7a, 0xb8, 0x0d, 0x96, 0x44, 0xba, 0xf3, 0x5c, 0xf8, 0xf7, 0x3c, 0x3b,
|
||||
0x49, 0x16, 0x43, 0xa1, 0x10, 0xd9, 0xb0, 0x22, 0x57, 0x09, 0x4f, 0x07, 0x99, 0x01, 0xbf, 0x47,
|
||||
0x07, 0x24, 0x3a, 0xc4, 0x19, 0x62, 0x5a, 0xbb, 0xce, 0x47, 0x21, 0x06, 0x85, 0x55, 0x26, 0x64,
|
||||
0x36, 0x0b, 0xb1, 0x27, 0x88, 0xc1, 0xbc, 0x69, 0x1f, 0xe9, 0x96, 0x19, 0x4c, 0x63, 0xef, 0x3c,
|
||||
0xf5, 0x35, 0x80, 0xf5, 0x87, 0x55, 0x8e, 0xf2, 0xcb, 0x91, 0x3d, 0x4a, 0x97, 0x23, 0x93, 0xe9,
|
||||
0xe5, 0x28, 0x31, 0x71, 0xc0, 0xa3, 0x15, 0x63, 0x3b, 0xb1, 0x81, 0x37, 0xcd, 0x5c, 0xb3, 0x8a,
|
||||
0xb1, 0x9d, 0xf8, 0xb0, 0xcb, 0x2b, 0x26, 0x86, 0x22, 0x1c, 0x67, 0xbd, 0x9b, 0xfa, 0xed, 0xe7,
|
||||
0xda, 0x0c, 0x7a, 0xa2, 0x80, 0x85, 0xb0, 0x7a, 0x69, 0xe3, 0x64, 0x21, 0x4b, 0xb2, 0x88, 0xb1,
|
||||
0x44, 0x3d, 0xe0, 0xa1, 0xe2, 0x89, 0x7a, 0xc0, 0x62, 0xc4, 0x30, 0x7a, 0x31, 0x38, 0xfb, 0xfb,
|
||||
0x1e, 0x19, 0xb0, 0x96, 0x9c, 0xe4, 0x17, 0x03, 0x47, 0xc2, 0x8b, 0x81, 0x8b, 0x08, 0x0b, 0x1c,
|
||||
0xbe, 0x21, 0x1a, 0x73, 0x82, 0xa5, 0xd0, 0x8d, 0xd3, 0x1b, 0x73, 0x90, 0x81, 0xbc, 0x3f, 0xbf,
|
||||
0x07, 0x16, 0x1e, 0x12, 0xfd, 0x01, 0x3f, 0x4a, 0x5e, 0x0d, 0xac, 0x65, 0x51, 0x50, 0x1c, 0x23,
|
||||
0x6f, 0x59, 0x01, 0x80, 0x70, 0xa8, 0x13, 0xbf, 0xf1, 0x3e, 0x98, 0xe3, 0x9d, 0x12, 0x36, 0x40,
|
||||
0xba, 0xe3, 0x1c, 0xda, 0x83, 0xe8, 0x7d, 0x69, 0x45, 0x1e, 0xf4, 0x98, 0xa6, 0xf8, 0x7f, 0xa2,
|
||||
0x85, 0x85, 0xd4, 0xf0, 0x8c, 0x04, 0x40, 0x27, 0x34, 0xa1, 0x42, 0xbf, 0x52, 0xc0, 0xbc, 0x30,
|
||||
0x84, 0xdb, 0xe1, 0xdc, 0x9b, 0x2a, 0xbe, 0x73, 0xe2, 0x02, 0xf8, 0xfa, 0x77, 0x28, 0xb9, 0xf9,
|
||||
0x8b, 0xd7, 0xa9, 0x23, 0xdd, 0x3a, 0xe4, 0x81, 0x4a, 0xf1, 0xd7, 0x29, 0x06, 0x84, 0xfd, 0x94,
|
||||
0x49, 0x08, 0x73, 0x14, 0xfd, 0x22, 0x05, 0xe6, 0x31, 0xed, 0xd3, 0xde, 0x00, 0xbe, 0x1d, 0xee,
|
||||
0x62, 0xb6, 0xf8, 0xf2, 0x59, 0xcb, 0x46, 0xc5, 0x18, 0x0c, 0xdc, 0xd1, 0x3d, 0x9f, 0x38, 0xf7,
|
||||
0x3d, 0x1f, 0xdc, 0xc9, 0xc9, 0x73, 0xdc, 0xc9, 0x51, 0xba, 0xa4, 0x9e, 0x3b, 0x5d, 0x66, 0xcf,
|
||||
0x9f, 0x2e, 0x41, 0x06, 0xcf, 0x9d, 0x23, 0x83, 0xeb, 0xe0, 0xc2, 0xbe, 0xeb, 0xf4, 0xd8, 0x6b,
|
||||
0x99, 0xe3, 0xea, 0xee, 0xb1, 0xa8, 0x56, 0x56, 0x52, 0x54, 0xd3, 0x0a, 0x14, 0x61, 0x49, 0xc5,
|
||||
0x50, 0x84, 0xe3, 0xac, 0x78, 0xae, 0xa6, 0x9f, 0x2f, 0x57, 0xe1, 0x6d, 0x90, 0xe6, 0x4d, 0xd6,
|
||||
0x76, 0xd8, 0x4d, 0x3f, 0x5b, 0x7c, 0x89, 0xf6, 0x09, 0x86, 0xd5, 0x9c, 0x30, 0x07, 0x85, 0x1c,
|
||||
0xfe, 0xec, 0x80, 0x80, 0xfe, 0xac, 0x80, 0x34, 0x26, 0x5e, 0xdf, 0xb1, 0x3d, 0xf2, 0x4d, 0x93,
|
||||
0x60, 0x0d, 0xa4, 0x0c, 0x7d, 0xa0, 0xb3, 0x14, 0x10, 0xd1, 0xa3, 0x72, 0x18, 0x3d, 0x2a, 0x20,
|
||||
0xcc, 0x30, 0xf8, 0x01, 0x48, 0x75, 0x1c, 0x83, 0x1f, 0xfe, 0x05, 0x79, 0x18, 0xa8, 0xb8, 0xae,
|
||||
0xe3, 0x96, 0x1c, 0x43, 0xdc, 0x74, 0x94, 0x14, 0x3a, 0xa0, 0x02, 0xc2, 0x0c, 0x43, 0x7f, 0x52,
|
||||
0x40, 0xa6, 0xec, 0x3c, 0xb4, 0x2d, 0x47, 0x37, 0x1a, 0xae, 0xd3, 0xa5, 0x6f, 0x4c, 0xdf, 0x68,
|
||||
0xdc, 0x6c, 0x83, 0xf9, 0x43, 0x36, 0xac, 0x06, 0x03, 0xe7, 0xcd, 0xf8, 0xcd, 0x7b, 0x72, 0x11,
|
||||
0x3e, 0xd9, 0x46, 0xef, 0xb6, 0xc2, 0x38, 0xf4, 0xcf, 0x65, 0x84, 0x03, 0x05, 0xfa, 0x63, 0x12,
|
||||
0x64, 0xcf, 0x76, 0x04, 0x7b, 0x60, 0x91, 0x33, 0xdb, 0xd2, 0x57, 0xa4, 0xd5, 0xf3, 0xec, 0x81,
|
||||
0xcd, 0x03, 0xec, 0x7e, 0x3b, 0x0c, 0xe5, 0xf0, 0x7e, 0x8b, 0x20, 0x84, 0x25, 0xfd, 0x73, 0xbd,
|
||||
0x1a, 0x4b, 0xd3, 0x63, 0xf2, 0xdb, 0x4f, 0x8f, 0x4d, 0xb0, 0xcc, 0x53, 0x34, 0xf8, 0x86, 0x91,
|
||||
0xca, 0x27, 0x57, 0x67, 0x8b, 0xeb, 0x63, 0x5f, 0x5b, 0xda, 0xe3, 0x97, 0x48, 0xf0, 0xf5, 0x62,
|
||||
0x25, 0x4a, 0x56, 0x0e, 0x06, 0xd9, 0x96, 0x99, 0xc1, 0x31, 0x2e, 0xdc, 0x8c, 0x0d, 0x17, 0xbc,
|
||||
0xd4, 0xbf, 0x73, 0xce, 0x61, 0x42, 0x1a, 0x1e, 0xd0, 0x1c, 0x48, 0x35, 0x4c, 0xbb, 0x8b, 0xde,
|
||||
0x03, 0xb3, 0x25, 0xcb, 0xf1, 0x58, 0xc7, 0x71, 0x89, 0xee, 0x39, 0xb6, 0x9c, 0x4a, 0x1c, 0x09,
|
||||
0x8f, 0x9a, 0x8b, 0x08, 0x0b, 0x7c, 0xed, 0x8b, 0x24, 0x58, 0x94, 0x3e, 0xfa, 0xc1, 0x1f, 0x82,
|
||||
0x6b, 0xbb, 0x95, 0x66, 0xb3, 0xb0, 0x55, 0x69, 0xb7, 0xee, 0x35, 0x2a, 0xed, 0xd2, 0xce, 0x9d,
|
||||
0x66, 0xab, 0x82, 0xdb, 0xa5, 0x7a, 0x6d, 0xb3, 0xba, 0x95, 0x99, 0xc9, 0x5e, 0x1f, 0x8e, 0xf2,
|
||||
0xaa, 0x64, 0x11, 0xff, 0x3c, 0xf7, 0x5d, 0x00, 0x63, 0xe6, 0xd5, 0x5a, 0xb9, 0xf2, 0xe3, 0x8c,
|
||||
0x92, 0xbd, 0x34, 0x1c, 0xe5, 0x33, 0x92, 0x15, 0x7f, 0xeb, 0xfb, 0x01, 0x78, 0x71, 0x9a, 0xdd,
|
||||
0xbe, 0xd3, 0x28, 0x17, 0x5a, 0x95, 0x4c, 0x22, 0x9b, 0x1d, 0x8e, 0xf2, 0x57, 0x4e, 0x1a, 0x89,
|
||||
0x14, 0x7c, 0x1d, 0x5c, 0x8a, 0x99, 0xe2, 0xca, 0x8f, 0xee, 0x54, 0x9a, 0xad, 0x4c, 0x32, 0x7b,
|
||||
0x65, 0x38, 0xca, 0x43, 0xc9, 0x2a, 0xb8, 0x26, 0x36, 0xc0, 0xe5, 0x13, 0x16, 0xcd, 0x46, 0xbd,
|
||||
0xd6, 0xac, 0x64, 0x52, 0xd9, 0xab, 0xc3, 0x51, 0xfe, 0x62, 0xcc, 0x44, 0x74, 0x95, 0x12, 0xc8,
|
||||
0xc5, 0x6c, 0xca, 0xf5, 0x8f, 0x6b, 0x3b, 0xf5, 0x42, 0xb9, 0xdd, 0xc0, 0xf5, 0x2d, 0x5c, 0x69,
|
||||
0x36, 0x33, 0xb3, 0x59, 0x6d, 0x38, 0xca, 0x5f, 0x93, 0x8c, 0xa7, 0x2a, 0x7c, 0x0d, 0xac, 0xc4,
|
||||
0x9c, 0x34, 0xaa, 0xb5, 0xad, 0xcc, 0x5c, 0xf6, 0xe2, 0x70, 0x94, 0x7f, 0x41, 0xb2, 0xa3, 0x67,
|
||||
0x39, 0x15, 0xbf, 0xd2, 0x4e, 0xbd, 0x59, 0xc9, 0xcc, 0x4f, 0xc5, 0x8f, 0x1d, 0xf8, 0xda, 0x1f,
|
||||
0x14, 0x00, 0xa7, 0xbf, 0xb3, 0xc2, 0x77, 0x80, 0x1a, 0x38, 0x29, 0xd5, 0x77, 0x1b, 0x74, 0x9f,
|
||||
0xd5, 0x7a, 0xad, 0x5d, 0xab, 0xd7, 0x2a, 0x99, 0x99, 0x58, 0x54, 0x25, 0xab, 0x9a, 0x63, 0x13,
|
||||
0x58, 0x07, 0x57, 0x4f, 0xb3, 0xdc, 0xb9, 0xff, 0x56, 0x46, 0xc9, 0x6e, 0x0c, 0x47, 0xf9, 0xcb,
|
||||
0xd3, 0x86, 0x3b, 0xf7, 0xdf, 0xfa, 0xea, 0xd7, 0x2f, 0x9f, 0xae, 0x58, 0xfb, 0xbd, 0x02, 0x16,
|
||||
0xe5, 0xad, 0xbd, 0x01, 0x2e, 0xc9, 0x8e, 0x77, 0x2b, 0xad, 0x42, 0xb9, 0xd0, 0x2a, 0x64, 0x66,
|
||||
0xf8, 0x19, 0x48, 0xd4, 0x5d, 0x32, 0xd0, 0x59, 0xdb, 0x7d, 0x15, 0xac, 0xc4, 0x7e, 0x45, 0xe5,
|
||||
0x6e, 0x05, 0x07, 0x19, 0x25, 0xef, 0x9f, 0x1c, 0x11, 0x17, 0xbe, 0x06, 0xa0, 0x4c, 0x2e, 0xec,
|
||||
0x7c, 0x5c, 0xb8, 0xd7, 0xcc, 0x24, 0xb2, 0x97, 0x87, 0xa3, 0xfc, 0x8a, 0xc4, 0x2e, 0x58, 0x0f,
|
||||
0xf5, 0x63, 0x6f, 0xed, 0xaf, 0x09, 0xb0, 0x24, 0xbf, 0xaa, 0xc0, 0xd7, 0xc0, 0xc5, 0xcd, 0xea,
|
||||
0x0e, 0xcd, 0xc4, 0xcd, 0x3a, 0x3f, 0x01, 0x2a, 0x66, 0x66, 0xf8, 0x72, 0x32, 0x95, 0x3e, 0xc3,
|
||||
0xef, 0x03, 0xf5, 0x04, 0xbd, 0x5c, 0xc5, 0x95, 0x52, 0xab, 0x8e, 0xef, 0x65, 0x94, 0xec, 0x8b,
|
||||
0x34, 0x60, 0xb2, 0x4d, 0xd9, 0x74, 0x59, 0x0b, 0x3a, 0x86, 0xb7, 0xc1, 0xb5, 0x13, 0x86, 0xcd,
|
||||
0x7b, 0xbb, 0x3b, 0xd5, 0xda, 0x47, 0x7c, 0xbd, 0x44, 0xf6, 0xc6, 0x70, 0x94, 0xbf, 0x2a, 0xdb,
|
||||
0x36, 0xf9, 0xdb, 0x1f, 0x85, 0xd2, 0x0a, 0xdc, 0x06, 0xf9, 0x33, 0xec, 0xa3, 0x0d, 0x24, 0xb3,
|
||||
0x68, 0x38, 0xca, 0x5f, 0x3f, 0xc5, 0x49, 0xb8, 0x8f, 0xb4, 0x02, 0xdf, 0x04, 0x57, 0x4e, 0xf7,
|
||||
0x14, 0xd4, 0xc5, 0x29, 0xf6, 0x6b, 0x7f, 0x57, 0xc0, 0x42, 0x78, 0xeb, 0xd1, 0xa0, 0x55, 0x30,
|
||||
0xae, 0xd3, 0x26, 0x51, 0xae, 0xb4, 0x6b, 0xf5, 0x36, 0x93, 0x82, 0xa0, 0x85, 0xbc, 0x9a, 0xc3,
|
||||
0x1e, 0x69, 0x8e, 0x4b, 0xf4, 0xad, 0x4a, 0xad, 0x82, 0xab, 0xa5, 0xe0, 0x44, 0x43, 0xf6, 0x16,
|
||||
0xb1, 0x89, 0x6b, 0x76, 0xe0, 0x5b, 0xe0, 0x6a, 0xdc, 0x79, 0xf3, 0x4e, 0x69, 0x3b, 0x88, 0x12,
|
||||
0xdb, 0xa0, 0xb4, 0x40, 0xf3, 0xb0, 0x73, 0xc0, 0x0e, 0xe6, 0xed, 0x98, 0x55, 0xb5, 0x76, 0xb7,
|
||||
0xb0, 0x53, 0x2d, 0x73, 0xab, 0x64, 0x56, 0x1d, 0x8e, 0xf2, 0x97, 0x42, 0x2b, 0xf1, 0xe2, 0x41,
|
||||
0xcd, 0xd6, 0xbe, 0x52, 0x40, 0xee, 0xeb, 0x2f, 0x2f, 0xf8, 0x31, 0x78, 0x85, 0xc5, 0x6b, 0xaa,
|
||||
0x15, 0x88, 0xbe, 0xc5, 0x63, 0x58, 0x68, 0x34, 0x2a, 0xb5, 0x72, 0x66, 0x26, 0xbb, 0x3a, 0x1c,
|
||||
0xe5, 0x6f, 0x7e, 0xbd, 0xcb, 0x42, 0xbf, 0x4f, 0x6c, 0xe3, 0x9c, 0x8e, 0x37, 0xeb, 0x78, 0xab,
|
||||
0xd2, 0xca, 0x28, 0xe7, 0x71, 0xbc, 0xe9, 0xb8, 0x5d, 0x32, 0x28, 0xee, 0x7e, 0xf9, 0x24, 0x37,
|
||||
0xf3, 0xf8, 0x49, 0x6e, 0xe6, 0xcb, 0xa7, 0x39, 0xe5, 0xf1, 0xd3, 0x9c, 0xf2, 0x9b, 0x67, 0xb9,
|
||||
0x99, 0xcf, 0x9f, 0xe5, 0x94, 0xc7, 0xcf, 0x72, 0x33, 0xff, 0x78, 0x96, 0x9b, 0xb9, 0xff, 0x6a,
|
||||
0xd7, 0x1c, 0x1c, 0x1c, 0xee, 0xad, 0x77, 0x9c, 0xde, 0x2d, 0xef, 0xd8, 0xee, 0x0c, 0x0e, 0x4c,
|
||||
0xbb, 0x2b, 0x3d, 0xc9, 0xff, 0xb7, 0xed, 0xcd, 0xb1, 0xa7, 0x37, 0xff, 0x1b, 0x00, 0x00, 0xff,
|
||||
0xff, 0xf7, 0xe3, 0xa9, 0xd7, 0x86, 0x1b, 0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *Hello) Marshal() (dAtA []byte, err error) {
|
||||
@@ -1328,6 +1337,13 @@ func (m *Device) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.EncryptionPasswordToken) > 0 {
|
||||
i -= len(m.EncryptionPasswordToken)
|
||||
copy(dAtA[i:], m.EncryptionPasswordToken)
|
||||
i = encodeVarintBep(dAtA, i, uint64(len(m.EncryptionPasswordToken)))
|
||||
i--
|
||||
dAtA[i] = 0x52
|
||||
}
|
||||
if m.SkipIntroductionRemovals {
|
||||
i--
|
||||
if m.SkipIntroductionRemovals {
|
||||
@@ -1523,6 +1539,15 @@ func (m *FileInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i--
|
||||
dAtA[i] = 0xc0
|
||||
}
|
||||
if len(m.Encrypted) > 0 {
|
||||
i -= len(m.Encrypted)
|
||||
copy(dAtA[i:], m.Encrypted)
|
||||
i = encodeVarintBep(dAtA, i, uint64(len(m.Encrypted)))
|
||||
i--
|
||||
dAtA[i] = 0x1
|
||||
i--
|
||||
dAtA[i] = 0x9a
|
||||
}
|
||||
if len(m.BlocksHash) > 0 {
|
||||
i -= len(m.BlocksHash)
|
||||
copy(dAtA[i:], m.BlocksHash)
|
||||
@@ -1782,6 +1807,11 @@ func (m *Request) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.BlockNo != 0 {
|
||||
i = encodeVarintBep(dAtA, i, uint64(m.BlockNo))
|
||||
i--
|
||||
dAtA[i] = 0x48
|
||||
}
|
||||
if m.WeakHash != 0 {
|
||||
i = encodeVarintBep(dAtA, i, uint64(m.WeakHash))
|
||||
i--
|
||||
@@ -2167,6 +2197,10 @@ func (m *Device) ProtoSize() (n int) {
|
||||
if m.SkipIntroductionRemovals {
|
||||
n += 2
|
||||
}
|
||||
l = len(m.EncryptionPasswordToken)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovBep(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
@@ -2267,6 +2301,10 @@ func (m *FileInfo) ProtoSize() (n int) {
|
||||
if l > 0 {
|
||||
n += 2 + l + sovBep(uint64(l))
|
||||
}
|
||||
l = len(m.Encrypted)
|
||||
if l > 0 {
|
||||
n += 2 + l + sovBep(uint64(l))
|
||||
}
|
||||
if m.LocalFlags != 0 {
|
||||
n += 2 + sovBep(uint64(m.LocalFlags))
|
||||
}
|
||||
@@ -2362,6 +2400,9 @@ func (m *Request) ProtoSize() (n int) {
|
||||
if m.WeakHash != 0 {
|
||||
n += 1 + sovBep(uint64(m.WeakHash))
|
||||
}
|
||||
if m.BlockNo != 0 {
|
||||
n += 1 + sovBep(uint64(m.BlockNo))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
@@ -3290,6 +3331,40 @@ func (m *Device) Unmarshal(dAtA []byte) error {
|
||||
}
|
||||
}
|
||||
m.SkipIntroductionRemovals = bool(v != 0)
|
||||
case 10:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field EncryptionPasswordToken", wireType)
|
||||
}
|
||||
var byteLen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowBep
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
byteLen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if byteLen < 0 {
|
||||
return ErrInvalidLengthBep
|
||||
}
|
||||
postIndex := iNdEx + byteLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthBep
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.EncryptionPasswordToken = append(m.EncryptionPasswordToken[:0], dAtA[iNdEx:postIndex]...)
|
||||
if m.EncryptionPasswordToken == nil {
|
||||
m.EncryptionPasswordToken = []byte{}
|
||||
}
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipBep(dAtA[iNdEx:])
|
||||
@@ -3958,6 +4033,40 @@ func (m *FileInfo) Unmarshal(dAtA []byte) error {
|
||||
m.BlocksHash = []byte{}
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 19:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Encrypted", wireType)
|
||||
}
|
||||
var byteLen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowBep
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
byteLen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if byteLen < 0 {
|
||||
return ErrInvalidLengthBep
|
||||
}
|
||||
postIndex := iNdEx + byteLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthBep
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Encrypted = append(m.Encrypted[:0], dAtA[iNdEx:postIndex]...)
|
||||
if m.Encrypted == nil {
|
||||
m.Encrypted = []byte{}
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 1000:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field LocalFlags", wireType)
|
||||
@@ -4580,6 +4689,25 @@ func (m *Request) Unmarshal(dAtA []byte) error {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 9:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field BlockNo", wireType)
|
||||
}
|
||||
m.BlockNo = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowBep
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.BlockNo |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipBep(dAtA[iNdEx:])
|
||||
|
||||
@@ -36,7 +36,7 @@ func (t *TestModel) IndexUpdate(deviceID DeviceID, folder string, files []FileIn
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *TestModel) Request(deviceID DeviceID, folder, name string, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (RequestResponse, error) {
|
||||
func (t *TestModel) Request(deviceID DeviceID, folder, name string, blockNo, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (RequestResponse, error) {
|
||||
t.folder = folder
|
||||
t.name = name
|
||||
t.offset = offset
|
||||
|
||||
@@ -0,0 +1,547 @@
|
||||
// Copyright (C) 2019 The Syncthing Authors.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/base32"
|
||||
"errors"
|
||||
"io"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/miscreant/miscreant.go"
|
||||
"golang.org/x/crypto/chacha20poly1305"
|
||||
"golang.org/x/crypto/hkdf"
|
||||
"golang.org/x/crypto/scrypt"
|
||||
)
|
||||
|
||||
const (
|
||||
nonceSize = 24 // chacha20poly1305.NonceSizeX
|
||||
tagSize = 16 // chacha20poly1305.Overhead()
|
||||
keySize = 32 // fits both chacha20poly1305 and AES-SIV
|
||||
minPaddedSize = 1024 // smallest block we'll allow
|
||||
blockOverhead = tagSize + nonceSize
|
||||
maxPathComponent = 200 // characters
|
||||
encryptedDirExtension = ".syncthing-enc" // for top level dirs
|
||||
miscreantAlgo = "AES-SIV"
|
||||
)
|
||||
|
||||
// The encryptedModel sits between the encrypted device and the model. It
|
||||
// receives encrypted metadata and requests from the untrusted device, so it
|
||||
// must decrypt those and answer requests by encrypting the data.
|
||||
type encryptedModel struct {
|
||||
model Model
|
||||
folderKeys map[string]*[keySize]byte // folder ID -> key
|
||||
}
|
||||
|
||||
func (e encryptedModel) Index(deviceID DeviceID, folder string, files []FileInfo) error {
|
||||
if folderKey, ok := e.folderKeys[folder]; ok {
|
||||
// incoming index data to be decrypted
|
||||
if err := decryptFileInfos(files, folderKey); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return e.model.Index(deviceID, folder, files)
|
||||
}
|
||||
|
||||
func (e encryptedModel) IndexUpdate(deviceID DeviceID, folder string, files []FileInfo) error {
|
||||
if folderKey, ok := e.folderKeys[folder]; ok {
|
||||
// incoming index data to be decrypted
|
||||
if err := decryptFileInfos(files, folderKey); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return e.model.IndexUpdate(deviceID, folder, files)
|
||||
}
|
||||
|
||||
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]
|
||||
if !ok {
|
||||
return e.model.Request(deviceID, folder, name, blockNo, size, offset, hash, weakHash, fromTemporary)
|
||||
}
|
||||
|
||||
// Figure out the real file name, offset and size from the encrypted /
|
||||
// tweaked values.
|
||||
|
||||
realName, err := decryptName(name, folderKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
realSize := size - blockOverhead
|
||||
realOffset := offset - int64(blockNo*blockOverhead)
|
||||
|
||||
if size < minPaddedSize {
|
||||
return nil, errors.New("short request")
|
||||
}
|
||||
|
||||
// Perform that request and grab the data. Explicitly zero out the
|
||||
// hashes which are meaningless.
|
||||
|
||||
resp, err := e.model.Request(deviceID, folder, realName, blockNo, realSize, realOffset, nil, 0, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Encrypt the response. Blocks smaller than minPaddedSize are padded
|
||||
// with random data.
|
||||
|
||||
data := resp.Data()
|
||||
if len(data) < minPaddedSize {
|
||||
nd := make([]byte, minPaddedSize)
|
||||
copy(nd, data)
|
||||
if _, err := rand.Read(nd[len(data):]); err != nil {
|
||||
panic("catastrophic randomness failure")
|
||||
}
|
||||
data = nd
|
||||
}
|
||||
fileKey := FileKey(realName, folderKey)
|
||||
enc := encryptBytes(data, fileKey)
|
||||
resp.Close()
|
||||
return rawResponse{enc}, nil
|
||||
}
|
||||
|
||||
func (e encryptedModel) DownloadProgress(deviceID DeviceID, folder string, updates []FileDownloadProgressUpdate) error {
|
||||
if _, ok := e.folderKeys[folder]; !ok {
|
||||
return e.model.DownloadProgress(deviceID, folder, updates)
|
||||
}
|
||||
|
||||
// Encrypted devices shouldn't send these - ignore them.
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e encryptedModel) ClusterConfig(deviceID DeviceID, config ClusterConfig) error {
|
||||
return e.model.ClusterConfig(deviceID, config)
|
||||
}
|
||||
|
||||
func (e encryptedModel) Closed(conn Connection, err error) {
|
||||
e.model.Closed(conn, err)
|
||||
}
|
||||
|
||||
// The encryptedConnection sits between the model and the encrypted device. It
|
||||
// encrypts outgoing metadata and decrypts incoming responses.
|
||||
type encryptedConnection struct {
|
||||
conn Connection
|
||||
folderKeys map[string]*[keySize]byte // folder ID -> key
|
||||
}
|
||||
|
||||
func (e encryptedConnection) Start() {
|
||||
e.conn.Start()
|
||||
}
|
||||
|
||||
func (e encryptedConnection) ID() DeviceID {
|
||||
return e.conn.ID()
|
||||
}
|
||||
|
||||
func (e encryptedConnection) Name() string {
|
||||
return e.conn.Name()
|
||||
}
|
||||
|
||||
func (e encryptedConnection) Index(ctx context.Context, folder string, files []FileInfo) error {
|
||||
if folderKey, ok := e.folderKeys[folder]; ok {
|
||||
encryptFileInfos(files, folderKey)
|
||||
}
|
||||
return e.conn.Index(ctx, folder, files)
|
||||
}
|
||||
|
||||
func (e encryptedConnection) IndexUpdate(ctx context.Context, folder string, files []FileInfo) error {
|
||||
if folderKey, ok := e.folderKeys[folder]; ok {
|
||||
encryptFileInfos(files, folderKey)
|
||||
}
|
||||
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) {
|
||||
folderKey, ok := e.folderKeys[folder]
|
||||
if !ok {
|
||||
return e.conn.Request(ctx, folder, name, blockNo, offset, size, hash, weakHash, fromTemporary)
|
||||
}
|
||||
|
||||
// Encrypt / adjust the request parameters.
|
||||
|
||||
origSize := size
|
||||
if size < minPaddedSize {
|
||||
// Make a request for minPaddedSize data instead of the smaller
|
||||
// block. We'll chop of the extra data later.
|
||||
size = minPaddedSize
|
||||
}
|
||||
encName := encryptName(name, folderKey)
|
||||
encOffset := offset + int64(blockNo*blockOverhead)
|
||||
encSize := size + blockOverhead
|
||||
|
||||
// Perform that request, getting back and encrypted block.
|
||||
|
||||
bs, err := e.conn.Request(ctx, folder, encName, blockNo, encOffset, encSize, nil, 0, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Return the decrypted block (or an error if it fails decryption)
|
||||
|
||||
fileKey := FileKey(name, folderKey)
|
||||
bs, err = DecryptBytes(bs, fileKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bs[:origSize], nil
|
||||
}
|
||||
|
||||
func (e encryptedConnection) DownloadProgress(ctx context.Context, folder string, updates []FileDownloadProgressUpdate) {
|
||||
if _, ok := e.folderKeys[folder]; !ok {
|
||||
e.conn.DownloadProgress(ctx, folder, updates)
|
||||
}
|
||||
|
||||
// No need to send these
|
||||
}
|
||||
|
||||
func (e encryptedConnection) ClusterConfig(config ClusterConfig) {
|
||||
e.conn.ClusterConfig(config)
|
||||
}
|
||||
|
||||
func (e encryptedConnection) Close(err error) {
|
||||
e.conn.Close(err)
|
||||
}
|
||||
|
||||
func (e encryptedConnection) Closed() bool {
|
||||
return e.conn.Closed()
|
||||
}
|
||||
|
||||
func (e encryptedConnection) Statistics() Statistics {
|
||||
return e.conn.Statistics()
|
||||
}
|
||||
|
||||
func encryptFileInfos(files []FileInfo, folderKey *[keySize]byte) {
|
||||
for i, fi := range files {
|
||||
files[i] = encryptFileInfo(fi, folderKey)
|
||||
}
|
||||
}
|
||||
|
||||
// encryptFileInfo encrypts a FileInfo and wraps it into a new fake FileInfo
|
||||
// with an encrypted name.
|
||||
func encryptFileInfo(fi FileInfo, folderKey *[keySize]byte) FileInfo {
|
||||
fileKey := FileKey(fi.Name, folderKey)
|
||||
|
||||
// The entire FileInfo is encrypted with a random nonce, and concatenated
|
||||
// with that nonce.
|
||||
|
||||
bs, err := proto.Marshal(&fi)
|
||||
if err != nil {
|
||||
panic("impossible serialization mishap: " + err.Error())
|
||||
}
|
||||
encryptedFI := encryptBytes(bs, fileKey)
|
||||
|
||||
// The vector is set to something that is higher than any other version sent
|
||||
// previously, assuming people's clocks are correct. We do this because
|
||||
// there is no way for the insecure device on the other end to do proper
|
||||
// conflict resolution, so they will simply accept and keep whatever is the
|
||||
// latest version they see. The secure devices will decrypt the real
|
||||
// FileInfo, see the real Version, and act appropriately regardless of what
|
||||
// this fake version happens to be.
|
||||
|
||||
version := Vector{
|
||||
Counters: []Counter{
|
||||
{
|
||||
ID: 1,
|
||||
Value: uint64(time.Now().UnixNano()),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Construct the fake block list. Each block will be blockOverhead bytes
|
||||
// larger than the corresponding real one and have an encrypted hash.
|
||||
// Very small blocks will be padded upwards to minPaddedSize.
|
||||
//
|
||||
// The encrypted hash becomes just a "token" for the data -- it doesn't
|
||||
// help verifying it, but it lets the encrypted device do block level
|
||||
// diffs and data reuse properly when it gets a new version of a file.
|
||||
|
||||
var offset int64
|
||||
blocks := make([]BlockInfo, len(fi.Blocks))
|
||||
for i, b := range fi.Blocks {
|
||||
if b.Size < minPaddedSize {
|
||||
b.Size = minPaddedSize
|
||||
}
|
||||
size := b.Size + blockOverhead
|
||||
blocks[i] = BlockInfo{
|
||||
Offset: offset,
|
||||
Size: size,
|
||||
Hash: encryptDeterministic(b.Hash, fileKey),
|
||||
}
|
||||
offset += int64(size)
|
||||
}
|
||||
|
||||
// Construct the fake FileInfo. This is mostly just a wrapper around the
|
||||
// encrypted FileInfo and fake block list. We'll represent symlinks as
|
||||
// directories, because they need some sort of on disk representation
|
||||
// but have no data outside of the metadata. Deletion and sequence
|
||||
// numbering are handled as usual.
|
||||
|
||||
typ := FileInfoTypeFile
|
||||
if fi.Type != FileInfoTypeFile {
|
||||
typ = FileInfoTypeDirectory
|
||||
}
|
||||
enc := FileInfo{
|
||||
Name: encryptName(fi.Name, folderKey),
|
||||
Type: typ,
|
||||
Size: offset, // new total file size
|
||||
Permissions: 0644,
|
||||
ModifiedS: 1234567890, // Sat Feb 14 00:31:30 CET 2009
|
||||
Deleted: fi.Deleted,
|
||||
Version: version,
|
||||
Sequence: fi.Sequence,
|
||||
RawBlockSize: fi.RawBlockSize + blockOverhead,
|
||||
Blocks: blocks,
|
||||
Encrypted: encryptedFI,
|
||||
}
|
||||
|
||||
return enc
|
||||
}
|
||||
|
||||
func decryptFileInfos(files []FileInfo, folderKey *[keySize]byte) error {
|
||||
for i, fi := range files {
|
||||
decFI, err := DecryptFileInfo(fi, folderKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
files[i] = decFI
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DecryptFileInfo extracts the encrypted portion of a FileInfo, decrypts it
|
||||
// and returns that.
|
||||
func DecryptFileInfo(fi FileInfo, folderKey *[keySize]byte) (FileInfo, error) {
|
||||
realName, err := decryptName(fi.Name, folderKey)
|
||||
if err != nil {
|
||||
return FileInfo{}, err
|
||||
}
|
||||
|
||||
fileKey := FileKey(realName, folderKey)
|
||||
dec, err := DecryptBytes(fi.Encrypted, fileKey)
|
||||
if err != nil {
|
||||
return FileInfo{}, err
|
||||
}
|
||||
|
||||
var decFI FileInfo
|
||||
if err := proto.Unmarshal(dec, &decFI); err != nil {
|
||||
return FileInfo{}, err
|
||||
}
|
||||
return decFI, nil
|
||||
}
|
||||
|
||||
// encryptName encrypts the given string in a deterministic manner (the
|
||||
// result is always the same for any given string) and encodes it in a
|
||||
// filesystem-friendly manner.
|
||||
func encryptName(name string, key *[keySize]byte) string {
|
||||
enc := encryptDeterministic([]byte(name), key)
|
||||
b32enc := base32.HexEncoding.WithPadding(base32.NoPadding).EncodeToString(enc)
|
||||
return slashify(b32enc)
|
||||
}
|
||||
|
||||
// decryptName decrypts a string from encryptName
|
||||
func decryptName(name string, key *[keySize]byte) (string, error) {
|
||||
name = deslashify(name)
|
||||
bs, err := base32.HexEncoding.WithPadding(base32.NoPadding).DecodeString(name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
dec, err := decryptDeterministic(bs, key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(dec), nil
|
||||
}
|
||||
|
||||
// encryptBytes encrypts bytes with a random nonce
|
||||
func encryptBytes(data []byte, key *[keySize]byte) []byte {
|
||||
nonce := randomNonce()
|
||||
return encrypt(data, nonce, key)
|
||||
}
|
||||
|
||||
// encryptDeterministic encrypts bytes using AES-SIV
|
||||
func encryptDeterministic(data []byte, key *[keySize]byte) []byte {
|
||||
aead, err := miscreant.NewAEAD(miscreantAlgo, key[:], 0)
|
||||
if err != nil {
|
||||
panic("cipher failure: " + err.Error())
|
||||
}
|
||||
return aead.Seal(nil, nil, data, nil)
|
||||
}
|
||||
|
||||
// decryptDeterministic decrypts bytes using AES-SIV
|
||||
func decryptDeterministic(data []byte, key *[keySize]byte) ([]byte, error) {
|
||||
aead, err := miscreant.NewAEAD(miscreantAlgo, key[:], 0)
|
||||
if err != nil {
|
||||
panic("cipher failure: " + err.Error())
|
||||
}
|
||||
return aead.Open(nil, nil, data, nil)
|
||||
}
|
||||
|
||||
func encrypt(data []byte, nonce *[nonceSize]byte, key *[keySize]byte) []byte {
|
||||
aead, err := chacha20poly1305.NewX(key[:])
|
||||
if err != nil {
|
||||
// Can only fail if the key is the wrong length
|
||||
panic("cipher failure: " + err.Error())
|
||||
}
|
||||
|
||||
if aead.NonceSize() != nonceSize || aead.Overhead() != tagSize {
|
||||
// We want these values to be constant for our type declarations so
|
||||
// we don't use the values returned by the GCM, but we verify them
|
||||
// here.
|
||||
panic("crypto parameter mismatch")
|
||||
}
|
||||
|
||||
// Data is appended to the nonce
|
||||
return aead.Seal(nonce[:], nonce[:], data, nil)
|
||||
}
|
||||
|
||||
// DecryptBytes returns the decrypted bytes, or an error if decryption
|
||||
// failed.
|
||||
func DecryptBytes(data []byte, key *[keySize]byte) ([]byte, error) {
|
||||
if len(data) < blockOverhead {
|
||||
return nil, errors.New("data too short")
|
||||
}
|
||||
|
||||
aead, err := chacha20poly1305.NewX(key[:])
|
||||
if err != nil {
|
||||
// Can only fail if the key is the wrong length
|
||||
panic("cipher failure: " + err.Error())
|
||||
}
|
||||
|
||||
if aead.NonceSize() != nonceSize || aead.Overhead() != tagSize {
|
||||
// We want these values to be constant for our type declarations so
|
||||
// we don't use the values returned by the GCM, but we verify them
|
||||
// here.
|
||||
panic("crypto parameter mismatch")
|
||||
}
|
||||
|
||||
return aead.Open(nil, data[:nonceSize], data[nonceSize:], nil)
|
||||
}
|
||||
|
||||
// randomNonce is a normal, cryptographically random nonce
|
||||
func randomNonce() *[nonceSize]byte {
|
||||
var nonce [nonceSize]byte
|
||||
if _, err := rand.Read(nonce[:]); err != nil {
|
||||
panic("catastrophic randomness failure: " + err.Error())
|
||||
}
|
||||
return &nonce
|
||||
}
|
||||
|
||||
// keysFromPasswords converts a set of folder ID to password into a set of
|
||||
// folder ID to encryption key, using our key derivation function.
|
||||
func keysFromPasswords(passwords map[string]string) map[string]*[keySize]byte {
|
||||
res := make(map[string]*[keySize]byte, len(passwords))
|
||||
for folder, password := range passwords {
|
||||
res[folder] = KeyFromPassword(folder, password)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func knownBytes(folderID string) []byte {
|
||||
return []byte("syncthing" + folderID)
|
||||
}
|
||||
|
||||
// KeyFromPassword uses key derivation to generate a stronger key from a
|
||||
// probably weak password.
|
||||
func KeyFromPassword(folderID, password string) *[keySize]byte {
|
||||
bs, err := scrypt.Key([]byte(password), knownBytes(folderID), 32768, 8, 1, keySize)
|
||||
if err != nil {
|
||||
panic("key derivation failure: " + err.Error())
|
||||
}
|
||||
if len(bs) != keySize {
|
||||
panic("key derivation failure: wrong number of bytes")
|
||||
}
|
||||
var key [keySize]byte
|
||||
copy(key[:], bs)
|
||||
return &key
|
||||
}
|
||||
|
||||
func FileKey(filename string, folderKey *[keySize]byte) *[keySize]byte {
|
||||
kdf := hkdf.New(sha256.New, append(folderKey[:], filename...), []byte("syncthing"), nil)
|
||||
var fileKey [keySize]byte
|
||||
n, err := io.ReadFull(kdf, fileKey[:])
|
||||
if err != nil || n != keySize {
|
||||
panic("hkdf failure")
|
||||
}
|
||||
return &fileKey
|
||||
}
|
||||
|
||||
func PasswordToken(folderID, password string) []byte {
|
||||
return encryptDeterministic(knownBytes(folderID), KeyFromPassword(folderID, password))
|
||||
}
|
||||
|
||||
// slashify inserts slashes (and file extension) in the string to create an
|
||||
// appropriate tree. ABCDEFGH... => A.syncthing-enc/BC/DEFGH... We can use
|
||||
// forward slashes here because we're on the outside of native path formats,
|
||||
// the slash is the wire format.
|
||||
func slashify(s string) string {
|
||||
// We somewhat sloppily assume bytes == characters here, but the only
|
||||
// file names we should deal with are those that come from our base32
|
||||
// encoding.
|
||||
|
||||
comps := make([]string, 0, len(s)/maxPathComponent+3)
|
||||
comps = append(comps, s[:1]+encryptedDirExtension)
|
||||
s = s[1:]
|
||||
comps = append(comps, s[:2])
|
||||
s = s[2:]
|
||||
|
||||
for len(s) > maxPathComponent {
|
||||
comps = append(comps, s[:maxPathComponent])
|
||||
s = s[maxPathComponent:]
|
||||
}
|
||||
if len(s) > 0 {
|
||||
comps = append(comps, s)
|
||||
}
|
||||
return strings.Join(comps, "/")
|
||||
}
|
||||
|
||||
// deslashify removes slashes and encrypted file extensions from the string.
|
||||
// This is the inverse of slashify().
|
||||
func deslashify(s string) string {
|
||||
s = strings.ReplaceAll(s, encryptedDirExtension, "")
|
||||
return strings.ReplaceAll(s, "/", "")
|
||||
}
|
||||
|
||||
type rawResponse struct {
|
||||
data []byte
|
||||
}
|
||||
|
||||
func (r rawResponse) Data() []byte {
|
||||
return r.data
|
||||
}
|
||||
|
||||
func (r rawResponse) Close() {}
|
||||
func (r rawResponse) Wait() {}
|
||||
|
||||
// IsEncryptedPath returns true if the path points at encrypted data. This is
|
||||
// determined by checking for a sentinel string in the path.
|
||||
func IsEncryptedPath(path string) bool {
|
||||
pathComponents := strings.Split(path, "/")
|
||||
if len(pathComponents) != 3 {
|
||||
return false
|
||||
}
|
||||
return isEncryptedParentFromComponents(pathComponents[:2])
|
||||
}
|
||||
|
||||
// IsEncryptedParent returns true if the path points at a parent directory of
|
||||
// encrypted data, i.e. is not a "real" directory. This is determined by
|
||||
// checking for a sentinel string in the path.
|
||||
func IsEncryptedParent(path string) bool {
|
||||
return isEncryptedParentFromComponents(strings.Split(path, "/"))
|
||||
}
|
||||
|
||||
func isEncryptedParentFromComponents(pathComponents []string) bool {
|
||||
if l := len(pathComponents); l > 2 {
|
||||
return false
|
||||
} else if l == 2 && len(pathComponents[1]) != 2 {
|
||||
return false
|
||||
}
|
||||
return pathComponents[0][1:1+len(encryptedDirExtension)] == encryptedDirExtension
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
// Copyright (C) 2019 The Syncthing Authors.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestEnDecryptName(t *testing.T) {
|
||||
var key [32]byte
|
||||
cases := []string{
|
||||
"",
|
||||
"foo",
|
||||
"a longer name/with/slashes and spaces",
|
||||
}
|
||||
for _, tc := range cases {
|
||||
var prev string
|
||||
for i := 0; i < 5; i++ {
|
||||
enc := encryptName(tc, &key)
|
||||
if prev != "" && prev != enc {
|
||||
t.Error("name should always encrypt the same")
|
||||
}
|
||||
prev = enc
|
||||
if tc != "" && strings.Contains(enc, tc) {
|
||||
t.Error("shouldn't contain plaintext")
|
||||
}
|
||||
dec, err := decryptName(enc, &key)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if dec != tc {
|
||||
t.Error("mismatch after decryption")
|
||||
}
|
||||
t.Log(enc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnDecryptBytes(t *testing.T) {
|
||||
var key [32]byte
|
||||
cases := [][]byte{
|
||||
{},
|
||||
{1, 2, 3, 4, 5},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
var prev []byte
|
||||
for i := 0; i < 5; i++ {
|
||||
enc := encryptBytes(tc, &key)
|
||||
if bytes.Equal(enc, prev) {
|
||||
t.Error("encryption should not repeat")
|
||||
}
|
||||
prev = enc
|
||||
if len(tc) > 0 && bytes.Contains(enc, tc) {
|
||||
t.Error("shouldn't contain plaintext")
|
||||
}
|
||||
dec, err := DecryptBytes(enc, &key)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if !bytes.Equal(dec, tc) {
|
||||
t.Error("mismatch after decryption")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnDecryptFileInfo(t *testing.T) {
|
||||
var key [32]byte
|
||||
fi := FileInfo{
|
||||
Name: "hello",
|
||||
Size: 45,
|
||||
Permissions: 0755,
|
||||
ModifiedS: 8080,
|
||||
Blocks: []BlockInfo{
|
||||
{
|
||||
Size: 45,
|
||||
Hash: []byte{1, 2, 3},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
enc := encryptFileInfo(fi, &key)
|
||||
dec, err := DecryptFileInfo(enc, &key)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if !reflect.DeepEqual(fi, dec) {
|
||||
t.Error("mismatch after decryption")
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ func (m nativeModel) IndexUpdate(deviceID DeviceID, folder string, files []FileI
|
||||
return m.Model.IndexUpdate(deviceID, folder, files)
|
||||
}
|
||||
|
||||
func (m nativeModel) Request(deviceID DeviceID, folder, name string, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (RequestResponse, error) {
|
||||
func (m nativeModel) Request(deviceID DeviceID, folder, name string, blockNo, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (RequestResponse, error) {
|
||||
name = norm.NFD.String(name)
|
||||
return m.Model.Request(deviceID, folder, name, size, offset, hash, weakHash, fromTemporary)
|
||||
return m.Model.Request(deviceID, folder, name, blockNo, size, offset, hash, weakHash, fromTemporary)
|
||||
}
|
||||
|
||||
@@ -26,14 +26,14 @@ func (m nativeModel) IndexUpdate(deviceID DeviceID, folder string, files []FileI
|
||||
return m.Model.IndexUpdate(deviceID, folder, files)
|
||||
}
|
||||
|
||||
func (m nativeModel) Request(deviceID DeviceID, folder, name string, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (RequestResponse, error) {
|
||||
func (m nativeModel) Request(deviceID DeviceID, folder, name string, blockNo, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (RequestResponse, error) {
|
||||
if strings.Contains(name, `\`) {
|
||||
l.Warnf("Dropping request for %s, contains invalid path separator", name)
|
||||
return nil, ErrNoSuchFile
|
||||
}
|
||||
|
||||
name = filepath.FromSlash(name)
|
||||
return m.Model.Request(deviceID, folder, name, size, offset, hash, weakHash, fromTemporary)
|
||||
return m.Model.Request(deviceID, folder, name, blockNo, size, offset, hash, weakHash, fromTemporary)
|
||||
}
|
||||
|
||||
func fixupFiles(files []FileInfo) []FileInfo {
|
||||
|
||||
@@ -115,7 +115,7 @@ type Model interface {
|
||||
// An index update was received from the peer device
|
||||
IndexUpdate(deviceID DeviceID, folder string, files []FileInfo) error
|
||||
// A request was made by the peer device
|
||||
Request(deviceID DeviceID, folder, name string, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (RequestResponse, error)
|
||||
Request(deviceID DeviceID, folder, name string, blockNo, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (RequestResponse, error)
|
||||
// A cluster configuration message was received
|
||||
ClusterConfig(deviceID DeviceID, config ClusterConfig) error
|
||||
// The peer device closed the connection
|
||||
@@ -137,7 +137,7 @@ type Connection interface {
|
||||
Name() string
|
||||
Index(ctx context.Context, folder string, files []FileInfo) error
|
||||
IndexUpdate(ctx context.Context, folder string, files []FileInfo) error
|
||||
Request(ctx context.Context, folder string, name string, offset int64, size int, hash []byte, weakHash uint32, fromTemporary bool) ([]byte, error)
|
||||
Request(ctx context.Context, folder string, name string, blockNo int, offset int64, size int, hash []byte, weakHash uint32, fromTemporary bool) ([]byte, error)
|
||||
ClusterConfig(config ClusterConfig)
|
||||
DownloadProgress(ctx context.Context, folder string, updates []FileDownloadProgressUpdate)
|
||||
Statistics() Statistics
|
||||
@@ -204,13 +204,36 @@ const (
|
||||
var CloseTimeout = 10 * time.Second
|
||||
|
||||
func NewConnection(deviceID DeviceID, reader io.Reader, writer io.Writer, receiver Model, name string, compress Compression) Connection {
|
||||
receiver = nativeModel{receiver}
|
||||
rc := newRawConnection(deviceID, reader, writer, receiver, name, compress)
|
||||
return wireFormatConnection{rc}
|
||||
}
|
||||
|
||||
func NewEncryptedConnection(passwords map[string]string, deviceID DeviceID, reader io.Reader, writer io.Writer, receiver Model, name string, compress Compression) Connection {
|
||||
keys := keysFromPasswords(passwords)
|
||||
|
||||
// Encryption / decryption is first (outermost) before conversion to
|
||||
// native path formats.
|
||||
nm := nativeModel{receiver}
|
||||
em := encryptedModel{model: nm, folderKeys: keys}
|
||||
|
||||
// We do the wire format conversion first (outermost) so that the
|
||||
// metadata is in wire format when it reaches the encryption step.
|
||||
rc := newRawConnection(deviceID, reader, writer, em, name, compress)
|
||||
ec := encryptedConnection{conn: rc, folderKeys: keys}
|
||||
wc := wireFormatConnection{ec}
|
||||
|
||||
return wc
|
||||
}
|
||||
|
||||
func newRawConnection(deviceID DeviceID, reader io.Reader, writer io.Writer, receiver Model, name string, compress Compression) *rawConnection {
|
||||
cr := &countingReader{Reader: reader}
|
||||
cw := &countingWriter{Writer: writer}
|
||||
|
||||
c := rawConnection{
|
||||
return &rawConnection{
|
||||
id: deviceID,
|
||||
name: name,
|
||||
receiver: nativeModel{receiver},
|
||||
receiver: receiver,
|
||||
cr: cr,
|
||||
cw: cw,
|
||||
awaiting: make(map[int]chan asyncResult),
|
||||
@@ -222,8 +245,6 @@ func NewConnection(deviceID DeviceID, reader io.Reader, writer io.Writer, receiv
|
||||
closed: make(chan struct{}),
|
||||
compression: compress,
|
||||
}
|
||||
|
||||
return wireFormatConnection{&c}
|
||||
}
|
||||
|
||||
// Start creates the goroutines for sending and receiving of messages. It must
|
||||
@@ -281,7 +302,7 @@ func (c *rawConnection) IndexUpdate(ctx context.Context, folder string, idx []Fi
|
||||
}
|
||||
|
||||
// Request returns the bytes for the specified block after fetching them from the connected peer.
|
||||
func (c *rawConnection) Request(ctx context.Context, folder string, name string, offset int64, size int, hash []byte, weakHash uint32, fromTemporary bool) ([]byte, error) {
|
||||
func (c *rawConnection) Request(ctx context.Context, folder string, name string, blockNo int, offset int64, size int, hash []byte, weakHash uint32, fromTemporary bool) ([]byte, error) {
|
||||
c.nextIDMut.Lock()
|
||||
id := c.nextID
|
||||
c.nextID++
|
||||
@@ -302,6 +323,7 @@ func (c *rawConnection) Request(ctx context.Context, folder string, name string,
|
||||
Name: name,
|
||||
Offset: offset,
|
||||
Size: size,
|
||||
BlockNo: blockNo,
|
||||
Hash: hash,
|
||||
WeakHash: weakHash,
|
||||
FromTemporary: fromTemporary,
|
||||
@@ -622,7 +644,7 @@ func checkFilename(name string) error {
|
||||
}
|
||||
|
||||
func (c *rawConnection) handleRequest(req Request) {
|
||||
res, err := c.receiver.Request(c.id, req.Folder, req.Name, int32(req.Size), req.Offset, req.Hash, req.WeakHash, req.FromTemporary)
|
||||
res, err := c.receiver.Request(c.id, req.Folder, req.Name, int32(req.BlockNo), int32(req.Size), req.Offset, req.Hash, req.WeakHash, req.FromTemporary)
|
||||
if err != nil {
|
||||
c.send(context.Background(), &Response{
|
||||
ID: req.ID,
|
||||
|
||||
@@ -80,7 +80,7 @@ func TestClose(t *testing.T) {
|
||||
c0.Index(ctx, "default", nil)
|
||||
c0.Index(ctx, "default", nil)
|
||||
|
||||
if _, err := c0.Request(ctx, "default", "foo", 0, 0, nil, 0, false); err == nil {
|
||||
if _, err := c0.Request(ctx, "default", "foo", 0, 0, 0, nil, 0, false); err == nil {
|
||||
t.Error("Request should return an error")
|
||||
}
|
||||
}
|
||||
@@ -279,6 +279,9 @@ func TestMarshalIndexMessage(t *testing.T) {
|
||||
if len(f.Version.Counters) == 0 {
|
||||
m1.Files[i].Version.Counters = nil
|
||||
}
|
||||
if len(f.Encrypted) == 0 {
|
||||
m1.Files[i].Encrypted = nil
|
||||
}
|
||||
}
|
||||
|
||||
return testMarshal(t, "index", &m1, &Index{})
|
||||
@@ -340,6 +343,9 @@ func TestMarshalClusterConfigMessage(t *testing.T) {
|
||||
if len(m1.Folders[i].Devices[j].Addresses) == 0 {
|
||||
m1.Folders[i].Devices[j].Addresses = nil
|
||||
}
|
||||
if len(m1.Folders[i].Devices[j].EncryptionPasswordToken) == 0 {
|
||||
m1.Folders[i].Devices[j].EncryptionPasswordToken = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ func (c wireFormatConnection) IndexUpdate(ctx context.Context, folder string, fs
|
||||
return c.Connection.IndexUpdate(ctx, folder, myFs)
|
||||
}
|
||||
|
||||
func (c wireFormatConnection) Request(ctx context.Context, folder string, name string, offset int64, size int, hash []byte, weakHash uint32, fromTemporary bool) ([]byte, error) {
|
||||
func (c wireFormatConnection) Request(ctx context.Context, folder string, name string, blockNo int, offset int64, size int, hash []byte, weakHash uint32, fromTemporary bool) ([]byte, error) {
|
||||
name = norm.NFC.String(filepath.ToSlash(name))
|
||||
return c.Connection.Request(ctx, folder, name, offset, size, hash, weakHash, fromTemporary)
|
||||
return c.Connection.Request(ctx, folder, name, blockNo, offset, size, hash, weakHash, fromTemporary)
|
||||
}
|
||||
|
||||
+47
-17
@@ -73,7 +73,15 @@ type ScanResult struct {
|
||||
}
|
||||
|
||||
func Walk(ctx context.Context, cfg Config) chan ScanResult {
|
||||
w := walker{cfg}
|
||||
return newWalker(cfg).walk(ctx)
|
||||
}
|
||||
|
||||
func WalkWithoutHashing(ctx context.Context, cfg Config) chan ScanResult {
|
||||
return newWalker(cfg).walkWithoutHashing(ctx)
|
||||
}
|
||||
|
||||
func newWalker(cfg Config) *walker {
|
||||
w := &walker{cfg}
|
||||
|
||||
if w.CurrentFiler == nil {
|
||||
w.CurrentFiler = noCurrentFiler{}
|
||||
@@ -85,7 +93,7 @@ func Walk(ctx context.Context, cfg Config) chan ScanResult {
|
||||
w.Matcher = ignore.New(w.Filesystem)
|
||||
}
|
||||
|
||||
return w.walk(ctx)
|
||||
return w
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -108,21 +116,7 @@ func (w *walker) walk(ctx context.Context) chan ScanResult {
|
||||
|
||||
// A routine which walks the filesystem tree, and sends files which have
|
||||
// been modified to the counter routine.
|
||||
go func() {
|
||||
hashFiles := w.walkAndHashFiles(ctx, toHashChan, finishedChan)
|
||||
if len(w.Subs) == 0 {
|
||||
w.Filesystem.Walk(".", hashFiles)
|
||||
} else {
|
||||
for _, sub := range w.Subs {
|
||||
if err := osutil.TraversesSymlink(w.Filesystem, filepath.Dir(sub)); err != nil {
|
||||
l.Debugf("Skip walking %v as it is below a symlink", sub)
|
||||
continue
|
||||
}
|
||||
w.Filesystem.Walk(sub, hashFiles)
|
||||
}
|
||||
}
|
||||
close(toHashChan)
|
||||
}()
|
||||
go w.scan(ctx, toHashChan, finishedChan)
|
||||
|
||||
// We're not required to emit scan progress events, just kick off hashers,
|
||||
// and feed inputs directly from the walker.
|
||||
@@ -203,6 +197,42 @@ func (w *walker) walk(ctx context.Context) chan ScanResult {
|
||||
return finishedChan
|
||||
}
|
||||
|
||||
func (w *walker) walkWithoutHashing(ctx context.Context) chan ScanResult {
|
||||
l.Debugln("Walk without hashing", w.Subs, w.Matcher)
|
||||
|
||||
toHashChan := make(chan protocol.FileInfo)
|
||||
finishedChan := make(chan ScanResult)
|
||||
|
||||
// A routine which walks the filesystem tree, and sends files which have
|
||||
// been modified to the counter routine.
|
||||
go w.scan(ctx, toHashChan, finishedChan)
|
||||
|
||||
go func() {
|
||||
for file := range toHashChan {
|
||||
finishedChan <- ScanResult{File: file}
|
||||
}
|
||||
close(finishedChan)
|
||||
}()
|
||||
|
||||
return finishedChan
|
||||
}
|
||||
|
||||
func (w *walker) scan(ctx context.Context, toHashChan chan<- protocol.FileInfo, finishedChan chan<- ScanResult) {
|
||||
hashFiles := w.walkAndHashFiles(ctx, toHashChan, finishedChan)
|
||||
if len(w.Subs) == 0 {
|
||||
w.Filesystem.Walk(".", hashFiles)
|
||||
} else {
|
||||
for _, sub := range w.Subs {
|
||||
if err := osutil.TraversesSymlink(w.Filesystem, filepath.Dir(sub)); err != nil {
|
||||
l.Debugf("Skip walking %v as it is below a symlink", sub)
|
||||
continue
|
||||
}
|
||||
w.Filesystem.Walk(sub, hashFiles)
|
||||
}
|
||||
}
|
||||
close(toHashChan)
|
||||
}
|
||||
|
||||
func (w *walker) walkAndHashFiles(ctx context.Context, toHashChan chan<- protocol.FileInfo, finishedChan chan<- ScanResult) fs.WalkFunc {
|
||||
now := time.Now()
|
||||
ignoredParent := ""
|
||||
|
||||
@@ -131,6 +131,10 @@ type Report struct {
|
||||
CaseSensitiveFS int `json:"caseSensitiveFS,omitempty" since:"3"`
|
||||
} `json:"folderUsesV3,omitempty" since:"3"`
|
||||
|
||||
DeviceUsesV3 struct {
|
||||
Untrusted int `json:"untrusted,omitempty" since:"3"`
|
||||
} `json:"deviceUsesV3,omitempty" since:"3"`
|
||||
|
||||
GUIStats struct {
|
||||
Enabled int `json:"enabled,omitempty" since:"3"`
|
||||
UseTLS int `json:"useTLS,omitempty" since:"3"`
|
||||
|
||||
@@ -275,6 +275,12 @@ func (s *Service) reportData(ctx context.Context, urVersion int, preview bool) (
|
||||
}
|
||||
sort.Ints(report.FolderUsesV3.FsWatcherDelays)
|
||||
|
||||
for _, cfg := range s.cfg.Devices() {
|
||||
if cfg.Untrusted {
|
||||
report.DeviceUsesV3.Untrusted++
|
||||
}
|
||||
}
|
||||
|
||||
guiCfg := s.cfg.GUI()
|
||||
// Anticipate multiple GUI configs in the future, hence store counts.
|
||||
if guiCfg.Enabled {
|
||||
|
||||
Reference in New Issue
Block a user