diff --git a/config.go b/config.go new file mode 100644 index 0000000..7734886 --- /dev/null +++ b/config.go @@ -0,0 +1,83 @@ +package main + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + + "github.com/9seconds/mtg/v2/mtglib" + "github.com/pelletier/go-toml" +) + +type config struct { + Debug bool `json:"debug"` + Secret mtglib.Secret `json:"secret"` +} + +type configRaw struct { + Debug bool `toml:"debug" json:"debug"` + Secret string `toml:"secret" json:"secret"` + BindTo string `toml:"bind-to" json:"bind-to"` + TCPBuffer string `toml:"tcp-buffer" json:"tcp-buffer"` + PreferIP string `toml:"prefer-ip" json:"prefer-ip"` + CloakPort uint `toml:"cloak-port" json:"cloak-port"` + Probes struct { + Time struct { + Enabled bool `toml:"enabled" json:"enabled"` + AllowSkewness string `toml:"allow-skewness" json:"allow-skewness"` + } `toml:"time" json:"time"` + AntiReplay struct { + Enabled bool `toml:"enabled" json:"enabled"` + MaxSize string `toml:"max-size" json:"max-size"` + TTL string `toml:"ttl" json:"ttl"` + } `toml:"anti-replay" json:"anti-replay"` + } `toml:"probes" json:"probes"` + Network struct { + PublicIP struct { + IPv4 string `toml:"ipv4" json:"ipv4"` + IPv6 string `toml:"ipv6" json:"ipv6"` + } `toml:"public-ip" json:"public-ip"` + DOHHostname string `toml:"doh-hostname" json:"doh-hostname"` + Proxies []string `toml:"proxies" json:"proxies"` + } `toml:"network" json:"network"` + Stats struct { + StatsD struct { + Enabled bool `toml:"enabled" json:"enabled"` + Address string `toml:"address" json:"address"` + MetricPrefix string `toml:"metric-prefix" json:"metric-prefix"` + } `toml:"statsd" json:"statsd"` + Prometheus struct { + Enabled bool `toml:"enabled" json:"enabled"` + BindTo string `toml:"bind-to" json:"bind-to"` + HTTPPath string `toml:"http-path" json:"http-path"` + MetricPrefix string `toml:"metric-prefix" json:"metric-prefix"` + } `toml:"prometheus" json:"prometheus"` + } `toml:"stats" json:"stats"` +} + +func parseConfig(reader io.Reader) (*config, error) { + rawConf := &configRaw{} + + if err := toml.NewDecoder(reader).Decode(rawConf); err != nil { + return nil, fmt.Errorf("cannot parse toml config: %w", err) + } + + jsonBuf := &bytes.Buffer{} + jsonEncoder := json.NewEncoder(jsonBuf) + + jsonEncoder.SetEscapeHTML(false) + jsonEncoder.SetIndent("", "") + + if err := jsonEncoder.Encode(rawConf); err != nil { + return nil, fmt.Errorf("cannot dump into interim format: %w", err) + } + + conf := &config{} + + if err := json.NewDecoder(jsonBuf).Decode(conf); err != nil { + return nil, fmt.Errorf("cannot parse final config: %w", err) + } + + return conf, nil +} diff --git a/main.go b/main.go index 5f8b319..61e5db8 100644 --- a/main.go +++ b/main.go @@ -2,12 +2,9 @@ package main import ( "fmt" - "io/ioutil" "math/rand" "os" "time" - - "github.com/9seconds/mtg/v2/mtglib/network" ) var version = "dev" // has to be set by ldflags @@ -17,15 +14,5 @@ func main() { f, _ := os.Open("example.config.toml") - fmt.Println(parseRawConfig(f)) - - bd, _ := network.NewDefaultDialer(0, 0) - d, _ := network.NewNetwork(bd, "9.9.9.9", 0) - - r, err := d.HTTP.Get("https://ifconfig.co") - - fmt.Println(err) - body, _ := ioutil.ReadAll(r.Body) - - fmt.Println(string(body)) + fmt.Println(parseConfig(f)) } diff --git a/mtglib/init.go b/mtglib/init.go new file mode 100644 index 0000000..1fa135a --- /dev/null +++ b/mtglib/init.go @@ -0,0 +1,7 @@ +package mtglib + +import "errors" + +var ( + ErrSecretEmpty = errors.New("secret is empty") +) diff --git a/mtglib/secret.go b/mtglib/secret.go index 4981707..8fe6a90 100644 --- a/mtglib/secret.go +++ b/mtglib/secret.go @@ -8,7 +8,7 @@ import ( "strings" ) -const SecretKeyLength = 32 +const SecretKeyLength = 16 type Secret struct { Key []byte @@ -30,11 +30,19 @@ func (s *Secret) UnmarshalText(data []byte) error { return ErrSecretEmpty } - decoded, err := base64.RawStdEncoding.DecodeString(text) - if err != nil && strings.HasPrefix(text, "ee") { + var ( + decoded []byte + err error + ) + + if strings.HasPrefix(text, "ee") { decoded, err = hex.DecodeString(strings.TrimPrefix(text, "ee")) } + if err != nil || len(decoded) <= SecretKeyLength { + decoded, err = base64.RawURLEncoding.DecodeString(text) + } + if err != nil { return fmt.Errorf("incorrect secret format: %w", err) } @@ -50,7 +58,10 @@ func (s *Secret) UnmarshalText(data []byte) error { } func (s Secret) Base64() string { - return base64.StdEncoding.EncodeToString(append(s.Key[:], s.Host...)) + data := append([]byte{238}, s.Key...) // 238 = hex ee + data = append(data, s.Host...) + + return base64.RawURLEncoding.EncodeToString(data) } func (s Secret) String() string { @@ -58,7 +69,7 @@ func (s Secret) String() string { } func (s Secret) EE() string { - return "ee" + hex.EncodeToString(append(s.Key[:], s.Host...)) + return "ee" + hex.EncodeToString(append(s.Key, s.Host...)) } func GenerateSecret(hostname string) Secret { diff --git a/raw_config.go b/raw_config.go deleted file mode 100644 index 7e1b3d8..0000000 --- a/raw_config.go +++ /dev/null @@ -1,63 +0,0 @@ -package main - -import ( - "fmt" - "io" - - "github.com/pelletier/go-toml" -) - -type rawConfig struct { - Debug bool `toml:"debug"` - Secret string `toml:"secret"` - BindTo string `toml:"bind-to"` - TCPBuffer string `toml:"tcp-buffer"` - PreferIP string `toml:"prefer-ip"` - CloakPort uint `toml:"cloak-port"` - Probes struct { - Time struct { - Enabled bool `toml:"enabled"` - AllowSkewness string `toml:"allow-skewness"` - } `toml:"time"` - AntiReplay struct { - Enabled bool `toml:"enabled"` - MaxSize string `toml:"max-size"` - TTL string `toml:"ttl"` - } `toml:"anti-replay"` - } `toml:"probes"` - Network struct { - PublicIP struct { - IPv4 string `toml:"ipv4"` - IPv6 string `toml:"ipv6"` - } `toml:"public-ip"` - Dialers struct { - Telegram string `toml:"telegram"` - Default string `toml:"default"` - } `toml:"dialers"` - DOHHostname string `toml:"doh-hostname"` - Proxies []string `toml:"proxies"` - } `toml:"network"` - Stats struct { - StatsD struct { - Enabled bool `toml:"enabled"` - Address string `toml:"address"` - MetricPrefix string `toml:"metric-prefix"` - } `toml:"statsd"` - Prometheus struct { - Enabled bool `toml:"enabled"` - BindTo string `toml:"bind-to"` - HttpPath string `toml:"http-path"` - MetricPrefix string `toml:"metric-prefix"` - } `toml:"prometheus"` - } `toml:"stats"` -} - -func parseRawConfig(reader io.Reader) (*rawConfig, error) { - conf := &rawConfig{} - - if err := toml.NewDecoder(reader).Decode(conf); err != nil { - return nil, fmt.Errorf("cannot parse config: %w", err) - } - - return conf, nil -}