Skip to content

Commit

Permalink
Merge branch 'main' into junyi-outline-cli
Browse files Browse the repository at this point in the history
  • Loading branch information
jyyi1 committed Oct 17, 2023
2 parents 4cfacb7 + a19d8ee commit e361b2b
Show file tree
Hide file tree
Showing 28 changed files with 450 additions and 79 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.vscode

# MacOS files
.DS_Store
.idea
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Choose from one of the following methods to integrate the Outline SDK into your

The Outline Client uses a **generated mobile library** on Android, iOS and macOS (based on Cordova) and a **side service** on Windows and Linux (based on Electron).

Below we provide more details on each integration approach.
Below we provide more details on each integration approach. For more details about setting up and using Outline SDK features, see the [Discussions tab](https://github.com/Jigsaw-Code/outline-sdk/discussions).

### Generated Mobile Library

Expand Down
4 changes: 2 additions & 2 deletions network/lwip2transport/device.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ var inst *lwIPDevice = nil
// [lwIP library] to perform the translation.
//
// LwIP device must be a singleton object due to limitations in [lwIP library]. If you try to call ConfigureDevice more
// than once, we will Close the previous device and reconfigures it.
// than once, we will Close the previous device and reconfigure it.
//
// To use a LwIP device:
// 1. Call [ConfigureDevice] with two handlers for TCP and UDP traffic.
Expand All @@ -62,7 +62,7 @@ var inst *lwIPDevice = nil
// 3. Read IP packets from the device to get the TCP/UDP responses.
//
// A LwIP device is NOT thread-safe. However it is safe to use Write, Read/WriteTo and Close in different goroutines.
// But keep in mind that only one goroutine can call Write at a time; and only one goroutine can use either Read or
// Keep in mind that only one goroutine can call Write at a time, and only one goroutine can use either Read or
// WriteTo at a time.
//
// [lwIP library]: https://savannah.nongnu.org/projects/lwip/
Expand Down
2 changes: 1 addition & 1 deletion transport/shadowsocks/cipher.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ func simpleEVPBytesToKey(data []byte, keyLen int) ([]byte, error) {
return derived[:keyLen], nil
}

// NewEncryptionKey creates a Cipher given a cipher name and a secret.
// NewEncryptionKey creates a Cipher with a cipher name and a secret.
// The cipher name must be the IETF name (as per https://www.iana.org/assignments/aead-parameters/aead-parameters.xhtml)
// or the Shadowsocks alias from https://shadowsocks.org/guide/aead.html.
func NewEncryptionKey(cipherName string, secretText string) (*EncryptionKey, error) {
Expand Down
2 changes: 1 addition & 1 deletion transport/shadowsocks/packet.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
"io"
)

// ErrShortPacket indicates the destination packet given to Unpack is too short.
// ErrShortPacket indicates that the destination packet given to Unpack is too short.
var ErrShortPacket = errors.New("short packet")

// Assumes all ciphers have NonceSize() <= 12.
Expand Down
2 changes: 1 addition & 1 deletion transport/shadowsocks/salt.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func (g prefixSaltGenerator) GetSalt(salt []byte) error {
return err
}

// NewPrefixSaltGenerator returns a SaltGenerator whose output consists of
// NewPrefixSaltGenerator returns a SaltGenerator with output including
// the provided prefix, followed by random bytes. This is useful to change
// how shadowsocks traffic is classified by middleboxes.
//
Expand Down
7 changes: 4 additions & 3 deletions transport/shadowsocks/stream_dialer.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,12 @@ type StreamDialer struct {
key *EncryptionKey

// SaltGenerator is used by Shadowsocks to generate the connection salts.
// `SaltGenerator` may be `nil`, which defaults to [shadowsocks.RandomSaltGenerator].
// `SaltGenerator` can be `nil`, which defaults to [shadowsocks.RandomSaltGenerator].
SaltGenerator SaltGenerator

// ClientDataWait specifies the amount of time to wait for client data before sending
// the Shadowsocks connection request to the proxy server. It's 10 milliseconds by default.
// the Shadowsocks connection request to the proxy server. This value is 10 milliseconds
// by default.
//
// StreamDialer has an optimization to send the initial client payload along with
// the Shadowsocks connection request. This saves one packet during connection, and also
Expand All @@ -62,7 +63,7 @@ type StreamDialer struct {

var _ transport.StreamDialer = (*StreamDialer)(nil)

// Dial implements StreamDialer.Dial via a Shadowsocks server.
// Dial implements StreamDialer.Dial using a Shadowsocks server.
//
// The Shadowsocks StreamDialer returns a connection after the connection to the proxy is established,
// but before the connection to the target is established. That means we cannot signal "connection refused"
Expand Down
2 changes: 1 addition & 1 deletion transport/socks5/socks5.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (
"strconv"
)

// ReplyCode is byte unsigned number that represents a SOCKS error as indicated in the REP field of the server response.
// ReplyCode is a byte-unsigned number that represents a SOCKS error as indicated in the REP field of the server response.
type ReplyCode byte

// SOCKS reply codes, as enumerated in https://datatracker.ietf.org/doc/html/rfc1928#section-6.
Expand Down
2 changes: 1 addition & 1 deletion transport/socks5/stream_dialer.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func (c *streamDialer) Dial(ctx context.Context, remoteAddr string) (transport.S

// For protocol details, see https://datatracker.ietf.org/doc/html/rfc1928#section-3

// Buffer large enough for method and connect requests with a domain name address
// Buffer large enough for method and connect requests with a domain name address.
header := [3 + 4 + 256 + 2]byte{}

// Method request:
Expand Down
4 changes: 2 additions & 2 deletions transport/split/writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ type SplitWriter struct {
var _ io.Writer = (*SplitWriter)(nil)
var _ io.ReaderFrom = (*SplitWriter)(nil)

// NewWriter creates a [io.Writer] that ensures the byte sequence is split at prefixBytes,
// meaning a write will end right after byte index prefixBytes - 1, before a write starting at byte index prefixBytes.
// NewWriter creates a [io.Writer] that ensures the byte sequence is split at prefixBytes.
// A write will end right after byte index prefixBytes - 1, before a write starting at byte index prefixBytes.
// For example, if you have a write of [0123456789] and prefixBytes = 3, you will get writes [012] and [3456789].
func NewWriter(writer io.Writer, prefixBytes int64) *SplitWriter {
return &SplitWriter{writer, prefixBytes}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ This app illustrates how to use different transports to fetch a URL in Go.
Direct fetch:

```sh
$ go run ./x/examples/outline-fetch/main.go https://ipinfo.io
$ go run github.com/Jigsaw-Code/outline-sdk/x/examples/fetch@latest https://ipinfo.io
{
...
"city": "Amsterdam",
Expand All @@ -18,7 +18,7 @@ $ go run ./x/examples/outline-fetch/main.go https://ipinfo.io
Using a Shadowsocks server:

```sh
$ go run ./x/examples/outline-fetch/main.go -transport ss://[redacted]@[redacted]:80 https://ipinfo.io
$ go run github.com/Jigsaw-Code/outline-sdk/x/examples/fetch@latest -transport ss://[redacted]@[redacted]:80 https://ipinfo.io
{
...
"region": "New Jersey",
Expand All @@ -31,7 +31,7 @@ $ go run ./x/examples/outline-fetch/main.go -transport ss://[redacted]@[redacted
Using a SOCKS5 server:

```sh
$ go run ./x/examples/outline-fetch/main.go -transport socks5://[redacted]:5703 https://ipinfo.io
$ go run github.com/Jigsaw-Code/outline-sdk/x/examples/fetch@latest -transport socks5://[redacted]:5703 https://ipinfo.io
{
...
"city": "Berlin",
Expand All @@ -41,10 +41,10 @@ $ go run ./x/examples/outline-fetch/main.go -transport socks5://[redacted]:5703
}
```

<!-- Using packet splitting:
Using packet splitting:

```sh
$ go run ./x/examples/outline-fetch/main.go -transport split://3 https://ipinfo.io
$ go run github.com/Jigsaw-Code/outline-sdk/x/examples/fetch@latest -transport split:3 https://ipinfo.io
{
...
"city": "Amsterdam",
Expand All @@ -55,5 +55,6 @@ $ go run ./x/examples/outline-fetch/main.go -transport split://3 https://ipinfo
```

You should see this on Wireshark:
<img width="652" alt="image" src="https://github.com/Jigsaw-Code/outline-sdk/assets/113565/9c19667d-d0fb-4d33-b0a6-275674481dce"> -->

<img width="652" alt="image" src="https://github.com/Jigsaw-Code/outline-sdk/assets/113565/9c19667d-d0fb-4d33-b0a6-275674481dce">

26 changes: 25 additions & 1 deletion x/examples/outline-fetch/main.go → x/examples/fetch/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,36 @@ import (
"net"
"net/http"
"os"
"path"
"strings"

"github.com/Jigsaw-Code/outline-sdk/x/config"
)

var debugLog log.Logger = *log.New(io.Discard, "", 0)

func init() {
flag.Usage = func() {
fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [flags...] <url>\n", path.Base(os.Args[0]))
flag.PrintDefaults()
}
}

func main() {
verboseFlag := flag.Bool("v", false, "Enable debug output")
transportFlag := flag.String("transport", "", "Transport config")

flag.Parse()

if *verboseFlag {
debugLog = *log.New(os.Stderr, "[DEBUG] ", log.LstdFlags|log.Lmicroseconds|log.Lshortfile)
}

url := flag.Arg(0)
if url == "" {
log.Fatal("Need to pass the URL to fetch in the command-line")
log.Print("Need to pass the URL to fetch in the command-line")
flag.Usage()
os.Exit(1)
}

dialer, err := config.NewStreamDialer(*transportFlag)
Expand All @@ -55,6 +73,12 @@ func main() {
}
defer resp.Body.Close()

if *verboseFlag {
for k, v := range resp.Header {
debugLog.Printf("%v: %v", k, v)
}
}

_, err = io.Copy(os.Stdout, resp.Body)
if err != nil {
log.Fatalf("Read of page body failed: %v", err)
Expand Down
2 changes: 1 addition & 1 deletion x/examples/outline-connectivity-app/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,13 +121,13 @@ If at any point you run into issues during development, try `yarn reset`.

### Needed Improvements

1. **\[P1\]** android-specific CSS
1. **\[P1\]** read browser language on load, centralize language list, and only localize once
1. **\[P1\]** documentation on how to generate mobile app build credentials
1. **\[P1\]** add individual test result errors to the test result output UI
1. **\[P2\]** use x/config to parse the access key and showcase the different transports (see: https://github.com/Jigsaw-Code/outline-sdk/blob/main/x/examples/outline-connectivity/main.go)
1. **\[P2\]** generalize request handler via generics/reflection
1. **\[P2\]** create a logo for the app
1. **\[P2\]** android-specific toggle CSS
1. **\[P2\]** make backend request calls non-blocking
1. **\[P2\]** introducing some kind of tracing into the test

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class MobileBackendPlugin: Plugin() {
val rawInputMessage = Json.encodeToString(
FrontendRequest(
call.getString("resourceName")!!,
call.getString("parameters")!!
call.getString("parameters") ?: "{}"
)
)

Expand Down
17 changes: 9 additions & 8 deletions x/examples/outline-connectivity-app/app_mobile/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,18 @@ import { registerPlugin } from "@capacitor/core";
// Capacitor requires passing in a root object to each native call,
// that is then accessed via APIs like `call.getString("objectKey")`.
const MobileBackend = registerPlugin<{
Request(request: { resourceName: string; parameters: string}): Promise<{ error: string; body: string}>;
Request(request: { resourceName: string; parameters: string }): Promise<{ error: string; body: string }>;
}>("MobileBackend");

async function requestBackend<T, K>(resourceName: string, parameters: T): Promise<K> {
const response = await MobileBackend.Request({
resourceName, parameters: JSON.stringify(parameters)
const response = await MobileBackend.Request({
resourceName, parameters: JSON.stringify(parameters)
});

if (response.error) {
throw new Error(response.error);
}

return JSON.parse(response.body);
}

Expand All @@ -46,11 +46,12 @@ SharedFrontend.registerAllElements();
@customElement("app-main")
export class AppMain extends LitElement {
render() {
return html`<connectivity-test-page .onSubmit=${
(parameters: ConnectivityTestRequest) =>
return html`<connectivity-test-page
.loadPlatform=${() => requestBackend<void, SharedFrontend.PlatformMetadata>("Platform", void 0)}
.onSubmit=${(parameters: ConnectivityTestRequest) =>
requestBackend<ConnectivityTestRequest, ConnectivityTestResponse>(
"ConnectivityTest", parameters
"ConnectivityTest", parameters
)
} />`;
} />`;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public class MobileBackendPlugin: CAPPlugin {
let rawRequest = try encoder.encode(
FrontendRequest(
resourceName: call.getString("resourceName")!,
parameters: call.getString("parameters")!
parameters: call.getString("parameters") ?? "{}"
)
)

Expand Down
8 changes: 4 additions & 4 deletions x/examples/outline-connectivity-app/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ require (
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.1 // indirect
github.com/wailsapp/mimetype v1.4.1 // indirect
golang.org/x/crypto v0.12.0 // indirect
golang.org/x/crypto v0.14.0 // indirect
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/net v0.14.0 // indirect
golang.org/x/sys v0.11.0 // indirect
golang.org/x/text v0.12.0 // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.org/x/tools v0.12.1-0.20230818130535-1517d1a3ba60 // indirect
)
16 changes: 8 additions & 8 deletions x/examples/outline-connectivity-app/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ github.com/wailsapp/wails/v2 v2.5.1 h1:mfG+2kWqQXYOwdgI43HEILjOZDXbk5woPYI3jP2b+
github.com/wailsapp/wails/v2 v2.5.1/go.mod h1:jbOZbcr/zm79PxXxAjP8UoVlDd9wLW3uDs+isIthDfs=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM=
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
golang.org/x/mobile v0.0.0-20230905140555-fbe1c053b6a9 h1:LaLfQUz4L1tfuOlrtEouZLZ0qHDwKn87E1NKoiudP/o=
Expand All @@ -71,8 +71,8 @@ golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand All @@ -84,14 +84,14 @@ golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.12.1-0.20230818130535-1517d1a3ba60 h1:o4bs4seAAlSiZQAZbO6/RP5XBCZCooQS3Pgc0AUjWts=
golang.org/x/tools v0.12.1-0.20230818130535-1517d1a3ba60/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func HandleRequest(rawRequest []byte) []byte {

result, resultError = ConnectivityTest(parameters)
} else if request.ResourceName == "Platform" {
result = Platform(parameters)
result = Platform()
} else {
response.Error = "HandleRequest: method name not found"
}
Expand Down
2 changes: 1 addition & 1 deletion x/examples/outline-connectivity-app/shared_backend/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ type PlatformMetadata struct {
}

func Platform() PlatformMetadata {
return []PlatformMetadata{ OS: runtime.GOOS }
return PlatformMetadata{OS: runtime.GOOS}
}

func makeErrorRecord(err error) *ConnectivityTestError {
Expand Down
Loading

0 comments on commit e361b2b

Please sign in to comment.