Skip to content

Commit 79c5e79

Browse files
author
Todd Blose
committed
Merge remote-tracking branch 'origin/issue3106' into socks-proxy
2 parents d16c6b9 + bfbadbd commit 79c5e79

File tree

14 files changed

+753
-4824
lines changed

14 files changed

+753
-4824
lines changed

src/github.com/getlantern/flashlight/client/client.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ type Client struct {
5555
l net.Listener
5656
}
5757

58+
// PackagedSettings provided access to configuration embedded in the package.
59+
type PackagedSettings struct {
60+
StartupUrl string
61+
ChainedServers map[string]*ChainedServerInfo
62+
}
63+
5864
// ListenAndServe makes the client listen for HTTP connections. onListeningFn
5965
// is a callback that gets invoked as soon as the server is accepting TCP
6066
// connections.

src/github.com/getlantern/flashlight/packaged/packaged.go renamed to src/github.com/getlantern/flashlight/client/packaged.go

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
// Package packaged provided access to configuration embedded directly in Lantern installation
1+
// Package packaged provided access to ration embedded directly in Lantern installation
22
// packages. On OSX, that means data embedded in the Lantern.app app bundle in
33
// Lantern.app/Contents/Resources/.lantern.yaml, while on Windows that means data embedded
44
// in AppData/Roaming/Lantern/.lantern.yaml. This allows customization embedded in the
55
// installer outside of the auto-updated binary that should only be used under special
66
// circumstances.
7-
package packaged
7+
package client
88

99
import (
1010
"errors"
@@ -15,27 +15,20 @@ import (
1515
"strings"
1616

1717
"github.com/getlantern/appdir"
18-
"github.com/getlantern/golog"
1918
"github.com/getlantern/yaml"
2019
)
2120

2221
var (
23-
log = golog.LoggerFor("flashlight.packaged")
2422
name = ".packaged-lantern.yaml"
2523

26-
// This is the local copy of our embedded configuration file. This is necessary
27-
// to ensure we remember the embedded configuration across auto-updated
24+
// This is the local copy of our embedded ration file. This is necessary
25+
// to ensure we remember the embedded ration across auto-updated
2826
// binaries. We write to the local file system instead of to the package
2927
// itself (app bundle on OSX, install directory on Windows) because
3028
// we're not always sure we can write to that directory.
3129
local = appdir.General("Lantern") + "/" + name
3230
)
3331

34-
// PackagedSettings provided access to configuration embedded in the package.
35-
type PackagedSettings struct {
36-
StartupUrl string
37-
}
38-
3932
// ReadSettings reads packaged settings from pre-determined paths
4033
// on the various OSes.
4134
func ReadSettings() (string, *PackagedSettings, error) {

src/github.com/getlantern/flashlight/packaged/packaged_test.go renamed to src/github.com/getlantern/flashlight/client/packaged_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package packaged
1+
package client
22

33
import (
44
"io/ioutil"

src/github.com/getlantern/flashlight/config/config.go

Lines changed: 91 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"path/filepath"
1111
"regexp"
1212
"sort"
13+
"strings"
1314
"sync/atomic"
1415
"time"
1516

@@ -18,6 +19,7 @@ import (
1819
"github.com/getlantern/appdir"
1920
"github.com/getlantern/fronted"
2021
"github.com/getlantern/golog"
22+
"github.com/getlantern/jibber_jabber"
2123
"github.com/getlantern/launcher"
2224
"github.com/getlantern/proxiedsites"
2325
"github.com/getlantern/yaml"
@@ -41,7 +43,7 @@ var (
4143
m *yamlconf.Manager
4244
lastCloudConfigETag = map[string]string{}
4345
httpClient atomic.Value
44-
r = regexp.MustCompile("\\d+")
46+
r = regexp.MustCompile("\\d+\\.\\d+")
4547
)
4648

4749
type Config struct {
@@ -98,35 +100,51 @@ func majorVersion(version string) string {
98100
// copyNewest is a one-time function for using older config files in the 2.x series.
99101
// from 2.0.2 forward, Lantern will consider all major versions to be compatible and
100102
// will name them accordingly, as in "lantern-2.yaml".
101-
func copyNewest(file string) {
103+
func copyNewest(file string, existsFunc func(file string) (string, bool)) string {
102104
// If we already have a config file with the latest name, use that one.
103105
// Otherwise, copy the most recent config file available.
104-
cur, exists := configExists(file)
105-
106+
cur, exists := existsFunc(file)
106107
if exists {
107-
return
108+
log.Debugf("Using existing config")
109+
return cur
108110
}
109111
files := []string{"lantern-2.0.1.yaml", "lantern-2.0.0+stable.yaml", "lantern-2.0.0+manoto.yaml", "lantern-2.0.0-beta8.yaml"}
110112

111113
for _, file := range files {
112-
if path, exists := configExists(file); exists {
114+
if path, exists := existsFunc(file); exists {
113115
if err := os.Rename(path, cur); err != nil {
114116
log.Errorf("Could not rename file from %v to %v: %v", path, cur, err)
115117
} else {
116-
return
118+
log.Debugf("Copied old config at %v to %v", path, cur)
119+
return path
117120
}
118121
}
119122
}
123+
return cur
120124
}
121125

122126
// Init initializes the configuration system.
123-
func Init(version string) (*Config, error) {
127+
func Init(version string) (*Config, error, string) {
128+
path, settings, err := client.ReadSettings()
129+
if err != nil {
130+
// Let packaged itself log errors as necessary.
131+
// This could happen if we're auto-updated from an older version that didn't
132+
// have packaged settings, for example.
133+
log.Debugf("Could not read yaml from %v: %v", path, err)
134+
135+
}
124136
file := "lantern-" + majorVersion(version) + ".yaml"
125-
copyNewest(file)
137+
//copyNewest(file, configExists)
126138
configPath, err := InConfigDir(file)
127139
if err != nil {
128140
log.Errorf("Could not get config path? %v", err)
129-
return nil, err
141+
return nil, err, ""
142+
}
143+
144+
// If there's no configuration at the designated configuration path, download it
145+
// using the embedded servers.
146+
if _, err := os.Stat(configPath); os.IsNotExist(err) {
147+
fetchInitialConfig(configPath, settings)
130148
}
131149
m = &yamlconf.Manager{
132150
FilePath: configPath,
@@ -152,7 +170,7 @@ func Init(version string) (*Config, error) {
152170
}
153171

154172
var bytes []byte
155-
if bytes, err = cfg.fetchCloudConfig(); err == nil {
173+
if bytes, err = cfg.fetchCloudConfig(httpClient.Load().(*http.Client)); err == nil {
156174
// bytes will be nil if the config is unchanged (not modified)
157175
if bytes != nil {
158176
mutate = func(ycfg yamlconf.Config) error {
@@ -173,10 +191,14 @@ func Init(version string) (*Config, error) {
173191
cfg = initial.(*Config)
174192
err = updateGlobals(cfg)
175193
if err != nil {
176-
return nil, err
194+
return nil, err, ""
177195
}
178196
}
179-
return cfg, err
197+
if settings != nil {
198+
return cfg, err, settings.StartupUrl
199+
} else {
200+
return cfg, err, ""
201+
}
180202
}
181203

182204
// Run runs the configuration system.
@@ -216,7 +238,7 @@ func InConfigDir(filename string) (string, error) {
216238
cdir = appdir.General("Lantern")
217239
}
218240

219-
log.Debugf("Placing configuration in %v", cdir)
241+
log.Debugf("Using config dir %v", cdir)
220242
if _, err := os.Stat(cdir); err != nil {
221243
if os.IsNotExist(err) {
222244
// Create config dir
@@ -309,6 +331,28 @@ func (cfg *Config) ApplyDefaults() {
309331
}
310332
}
311333

334+
func defaultRoundRobin() string {
335+
localeTerritory, err := jibber_jabber.DetectTerritory()
336+
if err != nil {
337+
localeTerritory = "us"
338+
}
339+
log.Debugf("Locale territory: %v", localeTerritory)
340+
return defaultRoundRobinForTerritory(localeTerritory)
341+
}
342+
343+
// defaultDataCenter customizes the default data center depending on the user's locale.
344+
func defaultRoundRobinForTerritory(localeTerritory string) string {
345+
lt := strings.ToLower(localeTerritory)
346+
datacenter := ""
347+
if lt == "cn" {
348+
datacenter = "jp"
349+
} else {
350+
datacenter = "nl"
351+
}
352+
log.Debugf("datacenter: %v", datacenter)
353+
return datacenter + ".fallbacks.getiantem.org"
354+
}
355+
312356
func (cfg *Config) applyClientDefaults() {
313357
// Make sure we always have at least one masquerade set
314358
if cfg.Client.MasqueradeSets == nil {
@@ -325,7 +369,7 @@ func (cfg *Config) applyClientDefaults() {
325369
if len(cfg.Client.FrontedServers) == 0 && len(cfg.Client.ChainedServers) == 0 {
326370
cfg.Client.FrontedServers = []*client.FrontedServerInfo{
327371
&client.FrontedServerInfo{
328-
Host: "jp.fallbacks.getiantem.org",
372+
Host: defaultRoundRobin(),
329373
Port: 443,
330374
PoolSize: 0,
331375
MasqueradeSet: cloudflare,
@@ -387,7 +431,37 @@ func (cfg Config) cloudPollSleepTime() time.Duration {
387431
return time.Duration((CloudConfigPollInterval.Nanoseconds() / 2) + rand.Int63n(CloudConfigPollInterval.Nanoseconds()))
388432
}
389433

390-
func (cfg Config) fetchCloudConfig() ([]byte, error) {
434+
func (cfg Config) fetchInitialConfig(path string, ps *client.PackagedSettings) error {
435+
var err error
436+
for _, s := range ps.ChainedServers {
437+
log.Debugf("Fetching config using chained server: %v", s.Addr)
438+
dialer, er := s.Dialer()
439+
if er != nil {
440+
log.Errorf("Unable to configure chained server. Received error: %v", er)
441+
continue
442+
}
443+
http := &http.Client{
444+
Transport: &http.Transport{
445+
DisableKeepAlives: true,
446+
Dial: dialer.Dial,
447+
},
448+
}
449+
var data []byte
450+
data, err = cfg.fetchCloudConfig(http)
451+
if err == nil {
452+
if er := ioutil.WriteFile(path, data, 0644); er != nil {
453+
log.Errorf("Could not create file at %v, %v", path, er)
454+
err = er
455+
} else {
456+
log.Debugf("Wrote file at: %s", path)
457+
return nil
458+
}
459+
}
460+
}
461+
return err
462+
}
463+
464+
func (cfg Config) fetchCloudConfig(client *http.Client) ([]byte, error) {
391465
url := cfg.CloudConfig
392466
log.Debugf("Checking for cloud configuration at: %s", url)
393467
req, err := http.NewRequest("GET", url, nil)
@@ -407,7 +481,7 @@ func (cfg Config) fetchCloudConfig() ([]byte, error) {
407481
// successive requests
408482
req.Close = true
409483

410-
resp, err := httpClient.Load().(*http.Client).Do(req)
484+
resp, err := client.Do(req)
411485
if err != nil {
412486
return nil, fmt.Errorf("Unable to fetch cloud config at %s: %s", url, err)
413487
}
Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,77 @@
11
package config
22

33
import (
4+
"io/ioutil"
5+
"strings"
46
"testing"
57

8+
"github.com/getlantern/flashlight/client"
9+
"github.com/getlantern/yaml"
610
"github.com/stretchr/testify/assert"
711
)
812

13+
func TestInitialConfig(t *testing.T) {
14+
path, _ := ioutil.TempFile("", "config")
15+
16+
yamlPath := "test-packaged.yaml"
17+
data, err := ioutil.ReadFile(yamlPath)
18+
if err != nil {
19+
// This will happen whenever there's no packaged settings, which is often
20+
log.Debugf("Error reading file %v", err)
21+
}
22+
23+
trimmed := strings.TrimSpace(string(data))
24+
25+
log.Debugf("Read bytes: %v", trimmed)
26+
var s client.PackagedSettings
27+
err = yaml.Unmarshal([]byte(trimmed), &s)
28+
29+
if err != nil {
30+
log.Errorf("Could not read yaml: %v", err)
31+
}
32+
err = fetchInitialConfig(path.Name(), &s)
33+
assert.Nil(t, err, "Should not get an error fetching config")
34+
}
35+
36+
/*
37+
func TestCopyOldConfig(t *testing.T) {
38+
existsFunc := func(file string) (string, bool) {
39+
return "fullpath", true
40+
}
41+
42+
path := copyNewest("lantern-2.yaml", existsFunc)
43+
assert.Equal(t, "fullpath", path, "unexpected path used")
44+
45+
// Test with temp files to make sure the actual copy of an old file to a
46+
// new one works.
47+
tf, _ := ioutil.TempFile("", "2.0.1")
48+
tf2, _ := ioutil.TempFile("", "2.0.2")
49+
50+
log.Debugf("Created temp file: %v", tf.Name())
51+
52+
existsFunc = func(file string) (string, bool) {
53+
if file == "lantern-2.0.1.yaml" {
54+
return tf.Name(), true
55+
}
56+
return tf2.Name(), false
57+
}
58+
59+
path = copyNewest("lantern-2.yaml", existsFunc)
60+
assert.Equal(t, tf.Name(), path, "unexpected path used")
61+
}
62+
963
func TestMajorVersion(t *testing.T) {
10-
ver := majorVersion("22.0.2")
64+
ver := "222.00.1"
65+
maj := majorVersion(ver)
66+
assert.Equal(t, "222.00", maj, "Unexpected major version")
67+
}
1168
12-
assert.Equal(t, "22", ver, "Could not read version")
69+
func TestDataCenter(t *testing.T) {
70+
dc := defaultRoundRobinForTerritory("IR")
71+
assert.Equal(t, "nl.fallbacks.getiantem.org", dc, "Unexpected data center")
72+
dc = defaultRoundRobinForTerritory("cn")
73+
assert.Equal(t, "jp.fallbacks.getiantem.org", dc, "Unexpected data center")
74+
dc = defaultRoundRobin()
75+
assert.Equal(t, "nl.fallbacks.getiantem.org", dc, "Unexpected data center")
1376
}
77+
*/

0 commit comments

Comments
 (0)