Skip to content

Commit

Permalink
merge latest
Browse files Browse the repository at this point in the history
  • Loading branch information
atavism committed Dec 19, 2024
2 parents 6d44caa + 7195208 commit 674fb36
Show file tree
Hide file tree
Showing 12 changed files with 786 additions and 115 deletions.
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,17 @@ All these dependencies must be in your PATH. Some of this is Android specific, s
* `flutter pub get`
* `flutter run --flavor prod` or if you are using android studio use desktop configuration

#### As a Command-Line Application

A command-line implementation of Lantern is defined in the `cli` directory.

* `go build -o lantern-cli ./cli`
* `./lantern-cli <arguments>` (run with `-h` or `--help` to see available arguments)

You will likely want to specify the `-addr` argument (e.g. `-addr localhost:8080`) to define where the local proxy should be available.

If you want to point at a specific remote proxy, consult `hit_proxy.bash` for an example on how to set up a config directory with specific proxy config.

### Running on emulators

You can easily run emulators directly from the command line with the following:
Expand Down
82 changes: 82 additions & 0 deletions cli/cli.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Command cli provides a command-line implementation of the Lantern client. Run this command with
// -h or --help to see all available arguments.
package main

import (
"context"
"os"
"os/signal"
"sync"
"syscall"
"time"

"github.com/getlantern/golog"
"github.com/getlantern/lantern-client/desktop/app"

"github.com/pterm/pterm"
)

var (
log = golog.LoggerFor("lantern")
)

type cliClient struct {
app *app.App
mu sync.Mutex
}

func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, os.Interrupt, syscall.SIGTERM)
go func() {
<-signalChan
pterm.Warning.Println("Received shutdown signal.")
cancel()
}()

client := &cliClient{}
client.start(ctx)
defer client.stop()

<-ctx.Done()
}

func (client *cliClient) start(ctx context.Context) {
client.mu.Lock()
defer client.mu.Unlock()
if client.app != nil {
pterm.Warning.Println("Lantern is already running")
return
}

// create new instance of Lantern app
app, err := app.NewApp()
if err != nil {
pterm.Error.Printf("Unable to initialize app: %v", err)
return
}
client.app = app

// Run Lantern in the background
go app.Run(ctx)
}

func (client *cliClient) stop() {
client.mu.Lock()
defer client.mu.Unlock()
if client.app == nil {
// Lantern is not running, no cleanup needed
return
}

pterm.Info.Println("Stopping Lantern...")
client.app.Exit(nil)
client.app = nil

// small delay to give Lantern time to cleanup
time.Sleep(1 * time.Second)
pterm.Success.Println("Lantern stopped successfully.")
}
158 changes: 77 additions & 81 deletions desktop/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,17 +93,17 @@ type App struct {
}

// NewApp creates a new desktop app that initializes the app and acts as a moderator between all desktop components.
func NewApp() *App {
func NewApp() (*App, error) {
// initialize app config and flags based on environment variables
flags, err := initializeAppConfig()
if err != nil {
log.Fatalf("failed to initialize app config: %w", err)
return nil, fmt.Errorf("failed to initialize app config: %w", err)
}
return NewAppWithFlags(flags, flags.ConfigDir)
}

// NewAppWithFlags creates a new instance of App initialized with the given flags and configDir
func NewAppWithFlags(flags flashlight.Flags, configDir string) *App {
func NewAppWithFlags(flags flashlight.Flags, configDir string) (*App, error) {
if configDir == "" {
log.Debug("Config directory is empty, using default location")
configDir = appdir.General(common.DefaultAppName)
Expand Down Expand Up @@ -141,10 +141,10 @@ func NewAppWithFlags(flags flashlight.Flags, configDir string) *App {
app.translations.Set(os.DirFS("locale/translation"))

if e := app.configService.StartService(app.ws); e != nil {
app.Exit(fmt.Errorf("unable to register config service: %q", e))
return nil, fmt.Errorf("unable to register config service: %q", e)
}

return app
return app, nil
}

// Run starts the app.
Expand All @@ -156,88 +156,84 @@ func (app *App) Run(ctx context.Context) {
}
}()

// Run below in separate goroutine as config.Init() can potentially block when Lantern runs
// for the first time. User can still quit Lantern through systray menu when it happens.
go func() {
log.Debug(app.Flags)
userConfig := func() common.UserConfig {
return settings.UserConfig(app.Settings())
}
proClient := proclient.NewClient(fmt.Sprintf("https://%s", common.ProAPIHost), userConfig)
authClient := auth.NewClient(fmt.Sprintf("https://%s", common.DFBaseUrl), userConfig)
log.Debug(app.Flags)
userConfig := func() common.UserConfig {
return settings.UserConfig(app.Settings())
}
proClient := proclient.NewClient(fmt.Sprintf("https://%s", common.ProAPIHost), userConfig)
authClient := auth.NewClient(fmt.Sprintf("https://%s", common.DFBaseUrl), userConfig)

app.mu.Lock()
app.proClient = proClient
app.authClient = authClient
app.mu.Unlock()
app.mu.Lock()
app.proClient = proClient
app.authClient = authClient
app.mu.Unlock()

settings := app.Settings()
settings := app.Settings()

if app.Flags.ProxyAll {
// If proxyall flag was supplied, force proxying of all
settings.SetProxyAll(true)
}
if app.Flags.ProxyAll {
// If proxyall flag was supplied, force proxying of all
settings.SetProxyAll(true)
}

listenAddr := app.Flags.Addr
if listenAddr == "" {
listenAddr = settings.GetAddr()
}
if listenAddr == "" {
listenAddr = defaultHTTPProxyAddress
}
listenAddr := app.Flags.Addr
if listenAddr == "" {
listenAddr = settings.GetAddr()
}
if listenAddr == "" {
listenAddr = defaultHTTPProxyAddress
}

socksAddr := app.Flags.SocksAddr
if socksAddr == "" {
socksAddr = settings.GetSOCKSAddr()
}
if socksAddr == "" {
socksAddr = defaultSOCKSProxyAddress
}
socksAddr := app.Flags.SocksAddr
if socksAddr == "" {
socksAddr = settings.GetSOCKSAddr()
}
if socksAddr == "" {
socksAddr = defaultSOCKSProxyAddress
}

if app.Flags.Timeout > 0 {
go func() {
time.AfterFunc(app.Flags.Timeout, func() {
app.Exit(errors.New("No succeeding proxy got after running for %v, global config fetched: %v, proxies fetched: %v",
app.Flags.Timeout, app.fetchedGlobalConfig.Load(), app.fetchedProxiesConfig.Load()))
})
}()
}
var err error
app.flashlight, err = flashlight.New(
common.DefaultAppName,
common.ApplicationVersion,
common.RevisionDate,
app.configDir,
app.Flags.VPN,
func() bool { return settings.GetDisconnected() }, // check whether we're disconnected
settings.GetProxyAll,
func() bool { return false }, // on desktop, we do not allow private hosts
settings.IsAutoReport,
app.Flags.AsMap(),
settings,
app.statsTracker,
app.IsPro,
settings.GetLanguage,
func(addr string) (string, error) { return addr, nil }, // no dnsgrab reverse lookups on desktop
// Dummy analytics function
func(category, action, label string) {},
flashlight.WithOnConfig(app.onConfigUpdate),
flashlight.WithOnProxies(app.onProxiesUpdate),
flashlight.WithOnSucceedingProxy(app.onSucceedingProxy),
)
if err != nil {
app.Exit(err)
return
}
app.beforeStart(ctx, listenAddr)

app.flashlight.Run(
listenAddr,
socksAddr,
app.afterStart,
func(err error) { _ = app.Exit(err) },
)
}()
if app.Flags.Timeout > 0 {
go func() {
time.AfterFunc(app.Flags.Timeout, func() {
app.Exit(errors.New("No succeeding proxy got after running for %v, global config fetched: %v, proxies fetched: %v",
app.Flags.Timeout, app.fetchedGlobalConfig.Load(), app.fetchedProxiesConfig.Load()))
})
}()
}
var err error
app.flashlight, err = flashlight.New(
common.DefaultAppName,
common.ApplicationVersion,
common.RevisionDate,
app.configDir,
app.Flags.VPN,
func() bool { return settings.GetDisconnected() }, // check whether we're disconnected
settings.GetProxyAll,
func() bool { return false }, // on desktop, we do not allow private hosts
settings.IsAutoReport,
app.Flags.AsMap(),
settings,
app.statsTracker,
app.IsPro,
settings.GetLanguage,
func(addr string) (string, error) { return addr, nil }, // no dnsgrab reverse lookups on desktop
// Dummy analytics function
func(category, action, label string) {},
flashlight.WithOnConfig(app.onConfigUpdate),
flashlight.WithOnProxies(app.onProxiesUpdate),
flashlight.WithOnSucceedingProxy(app.onSucceedingProxy),
)
if err != nil {
app.Exit(err)
return
}
app.beforeStart(ctx, listenAddr)

app.flashlight.Run(
listenAddr,
socksAddr,
app.afterStart,
func(err error) { _ = app.Exit(err) },
)
}

// IsFeatureEnabled checks whether or not the given feature is enabled by flashlight
Expand Down
3 changes: 2 additions & 1 deletion desktop/app/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,8 @@ func startApp(t *testing.T, helper *integrationtest.Helper) (*App, error) {
Timeout: time.Duration(0),
}
ss := settings.EmptySettings()
a := NewAppWithFlags(flags, helper.ConfigDir)
a, err := NewAppWithFlags(flags, helper.ConfigDir)
require.NoError(t, err)
id := ss.GetUserID()
if id == 0 {
ss.SetUserIDAndToken(1, "token")
Expand Down
8 changes: 6 additions & 2 deletions desktop/lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,11 @@ func start() *C.char {
}
golog.SetPrepender(logging.Timestamped)

a = app.NewApp()
a.Run(context.Background())
a, err = app.NewApp()
if err != nil {
log.Fatal(err)
}
go a.Run(context.Background())

return C.CString("")
}
Expand Down Expand Up @@ -418,6 +421,7 @@ func reportIssue(email, issueType, description *C.char) *C.char {
osVersion,
"",
nil,
"",
)
if err != nil {
return sendError(err)
Expand Down
33 changes: 24 additions & 9 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ require (
github.com/getlantern/eventual v1.0.0
github.com/getlantern/eventual/v2 v2.0.2
github.com/getlantern/filepersist v0.0.0-20210901195658-ed29a1cb0b7c
github.com/getlantern/flashlight/v7 v7.6.165
github.com/getlantern/flashlight/v7 v7.6.173
github.com/getlantern/fronted v0.0.0-20241218113928-4db253857875
github.com/getlantern/geolookup v0.0.0-20230327091034-aebe73c6eef4
github.com/getlantern/golog v0.0.0-20230503153817-8e72de7e0a65
github.com/getlantern/hidden v0.0.0-20220104173330-f221c5a24770
github.com/getlantern/i18n v0.0.0-20181205222232-2afc4f49bb1c
Expand Down Expand Up @@ -68,22 +70,35 @@ require (
github.com/joho/godotenv v1.5.1
github.com/leekchan/accounting v1.0.0
github.com/moul/http2curl v1.0.0
github.com/pterm/pterm v0.12.80
github.com/shopspring/decimal v1.4.0
github.com/stretchr/testify v1.9.0
golang.org/x/crypto v0.31.0
github.com/stretchr/testify v1.10.0
golang.org/x/crypto v0.29.0
golang.org/x/mobile v0.0.0-20241016134751-7ff83004ec2c
golang.org/x/net v0.30.0
golang.org/x/sys v0.28.0
golang.org/x/sys v0.27.0
google.golang.org/protobuf v1.35.2
nhooyr.io/websocket v1.8.17
)

require (
atomicgo.dev/cursor v0.2.0 // indirect
atomicgo.dev/keyboard v0.2.9 // indirect
atomicgo.dev/schedule v0.1.0 // indirect
github.com/alitto/pond/v2 v2.1.5 // indirect
github.com/cloudflare/circl v1.3.7 // indirect
github.com/coder/websocket v1.8.12 // indirect
github.com/getlantern/fronted v0.0.0-20241212194832-a55b6db2616e // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/containerd/console v1.0.3 // indirect
github.com/getlantern/lantern-water v0.0.0-20241218135103-60224336cf1d // indirect
github.com/getlantern/sing-vmess v0.0.0-20241209111030-0f2c02b4eb9a // indirect
github.com/gofrs/uuid/v5 v5.3.0 // indirect
github.com/gookit/color v1.5.4 // indirect
github.com/lithammer/fuzzysearch v1.1.8 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/rivo/uniseg v0.4.4 // indirect
github.com/sagernet/sing v0.6.0-alpha.18 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
golang.org/x/term v0.26.0 // indirect
)

require (
Expand Down Expand Up @@ -327,13 +342,13 @@ require (
go.opentelemetry.io/otel/trace v1.24.0 // indirect
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/mock v0.4.0 // indirect
go.uber.org/mock v0.5.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 // indirect
golang.org/x/mod v0.21.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/sync v0.9.0 // indirect
golang.org/x/text v0.20.0 // indirect
golang.org/x/time v0.6.0 // indirect
golang.org/x/tools v0.26.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240808171019-573a1156607a // indirect
Expand Down
Loading

0 comments on commit 674fb36

Please sign in to comment.