Add tests for obfuscated2 clientside

This commit is contained in:
9seconds
2021-03-22 11:34:32 +03:00
parent 4d2d21e101
commit 69203f3e23
21 changed files with 320 additions and 22 deletions
-2
View File
@@ -30,8 +30,6 @@ jobs:
strategy:
matrix:
go_version:
- ~1.14
- ~1.15
- ^1.16
steps:
- name: Checkout
+2 -3
View File
@@ -5,7 +5,6 @@ import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"net/url"
@@ -123,11 +122,11 @@ func (c *Access) getIP(protocol string) net.IP {
}
defer func() {
io.Copy(ioutil.Discard, resp.Body) // nolint: errcheck
io.Copy(io.Discard, resp.Body) // nolint: errcheck
resp.Body.Close()
}()
data, err := ioutil.ReadAll(resp.Body)
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil
}
+2 -2
View File
@@ -2,9 +2,9 @@ package cli
import (
"fmt"
"io/ioutil"
"net"
"net/url"
"os"
"github.com/9seconds/mtg/v2/config"
"github.com/9seconds/mtg/v2/mtglib"
@@ -19,7 +19,7 @@ type base struct {
}
func (b *base) ReadConfig(version string) error {
content, err := ioutil.ReadFile(b.ConfigPath)
content, err := os.ReadFile(b.ConfigPath)
if err != nil {
return fmt.Errorf("cannot read config file: %w", err)
}
+2 -2
View File
@@ -1,7 +1,7 @@
package config_test
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
@@ -14,7 +14,7 @@ type ConfigTestSuite struct {
}
func (suite *ConfigTestSuite) ReadConfig(filename string) []byte {
data, err := ioutil.ReadFile(filepath.Join("testdata", filename))
data, err := os.ReadFile(filepath.Join("testdata", filename))
suite.NoError(err)
return data
+1 -2
View File
@@ -5,7 +5,6 @@ import (
"context"
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"net/url"
@@ -216,7 +215,7 @@ func (f *Firehol) updateRemoteURL(ctx context.Context, url string,
}(ctx, resp.Body)
defer func(rc io.ReadCloser) {
io.Copy(ioutil.Discard, rc) // nolint: errcheck
io.Copy(io.Discard, rc) // nolint: errcheck
rc.Close()
}(resp.Body)
@@ -8,7 +8,7 @@ import (
"io"
)
func ClientHandshake(secret []byte, reader io.Reader) (int16, cipher.Stream, cipher.Stream, error) {
func ClientHandshake(secret []byte, reader io.Reader) (int, cipher.Stream, cipher.Stream, error) {
handshake := clientHandhakeFrame{}
if _, err := io.ReadFull(reader, handshake.data[:]); err != nil {
@@ -0,0 +1,85 @@
package obfuscated2_test
import (
"bytes"
"testing"
"github.com/9seconds/mtg/v2/mtglib/internal/obfuscated2"
"github.com/9seconds/mtg/v2/testlib"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/suite"
)
type ClientHandshakeTestSuite struct {
suite.Suite
SnapshotTestSuite
}
func (suite *ClientHandshakeTestSuite) SetupSuite() {
suite.NoError(suite.IngestSnapshots("client_snapshots", "snapshot-ok-"))
}
func (suite *ClientHandshakeTestSuite) TestCannotRead() {
buf := bytes.NewBuffer([]byte{1, 2, 3})
_, _, _, err := obfuscated2.ClientHandshake([]byte{1, 2, 3}, buf) // nolint: dogsled
suite.Error(err)
}
func (suite *ClientHandshakeTestSuite) TestOk() {
for nameV, snapshotV := range suite.snapshots {
snapshot := snapshotV
suite.T().Run(nameV, func(t *testing.T) {
buf := bytes.NewBuffer(snapshot.Frame.data)
dc, encryptor, decryptor, err := obfuscated2.ClientHandshake(
snapshot.Secret.data, buf)
assert.NoError(t, err)
assert.EqualValues(t, snapshot.DC, dc)
writeData := make([]byte, len(snapshot.Encrypted.Text.data))
readData := make([]byte, len(snapshot.Decrypted.Text.data))
connMock := &testlib.NetConnMock{}
connMock.On("Read", mock.Anything).
Once().
Return(len(snapshot.Decrypted.Text.data), nil).
Run(func(args mock.Arguments) {
arr := args.Get(0).([]byte)
copy(arr, snapshot.Decrypted.Cipher.data)
})
connMock.On("Write", mock.Anything).
Once().
Return(len(snapshot.Encrypted.Text.data), nil).
Run(func(args mock.Arguments) {
arr := args.Get(0).([]byte)
copy(writeData, arr)
})
conn := &obfuscated2.Conn{
Conn: connMock,
Encryptor: encryptor,
Decryptor: decryptor,
}
n, err := conn.Read(readData)
assert.Equal(t, len(readData), n)
assert.NoError(t, err)
assert.Equal(t, snapshot.Decrypted.Text.data, readData)
n, err = conn.Write(snapshot.Encrypted.Text.data)
assert.Equal(t, len(writeData), n)
assert.NoError(t, err)
assert.Equal(t, snapshot.Encrypted.Cipher.data, writeData)
connMock.AssertExpectations(t)
})
}
}
func TestClientHandshake(t *testing.T) {
t.Parallel()
suite.Run(t, &ClientHandshakeTestSuite{})
}
+10 -2
View File
@@ -35,10 +35,18 @@ type handshakeFrame struct {
data [handshakeFrameLen]byte
}
func (h *handshakeFrame) dc() int16 {
func (h *handshakeFrame) dc() int {
data := h.data[handshakeFrameOffsetDC:handshakeFrameOffsetEnd]
idx := int16(binary.LittleEndian.Uint16(data))
return int16(binary.LittleEndian.Uint16(data))
switch {
case idx > 0:
return int(idx) - 1
case idx < 0:
return -int(idx + 1)
default:
return 0
}
}
func (h *handshakeFrame) key() []byte {
+83
View File
@@ -0,0 +1,83 @@
package obfuscated2_test
import (
"encoding/base64"
"encoding/json"
"fmt"
"os"
"path/filepath"
"strings"
)
type snapshotBytes struct {
data []byte
}
func (s snapshotBytes) MarshalText() ([]byte, error) {
if len(s.data) == 0 {
return nil, nil
}
return []byte(base64.RawStdEncoding.EncodeToString(s.data)), nil
}
func (s *snapshotBytes) UnmarshalText(data []byte) error {
val, err := base64.RawStdEncoding.DecodeString(string(data))
if err != nil {
return fmt.Errorf("cannot unmarshal %v: %w", len(val), err)
}
s.data = val
return nil
}
type Obfuscated2Snapshot struct {
Secret snapshotBytes `json:"secret"`
Frame snapshotBytes `json:"frame"`
DC int16 `json:"dc"`
Encrypted struct {
Text snapshotBytes `json:"text"`
Cipher snapshotBytes `json:"cipher"`
} `json:"encrypted"`
Decrypted struct {
Text snapshotBytes `json:"text"`
Cipher snapshotBytes `json:"cipher"`
} `json:"decrypted"`
}
type SnapshotTestSuite struct {
snapshots map[string]*Obfuscated2Snapshot
}
func (suite *SnapshotTestSuite) IngestSnapshots(dirname, namePrefix string) error {
suite.snapshots = map[string]*Obfuscated2Snapshot{}
files, err := os.ReadDir(filepath.Join("testdata", dirname))
if err != nil {
return fmt.Errorf("cannot ingest snapshots: %w", err)
}
for _, v := range files {
if !strings.HasPrefix(v.Name(), namePrefix) {
continue
}
filename := filepath.Join("testdata", dirname, v.Name())
contents, err := os.ReadFile(filename)
if err != nil {
return fmt.Errorf("cannot read %s: %w", filename, err)
}
value := &Obfuscated2Snapshot{}
if err := json.Unmarshal(contents, value); err != nil {
return fmt.Errorf("cannot unmarshal %s: %w", filename, err)
}
suite.snapshots[v.Name()] = value
}
return nil
}
@@ -0,0 +1,13 @@
{
"secret": "NnoYmu4Y+jHBkAVO/UqOlQ",
"frame": "gDcXwaMY4RwlR+nJw+ILDr123UJHHjjE/U5pF4m/Y04AmH7lEpEL6UYRnIYDbDlOHSDxc1ToziPvNlJJh8RMow",
"dc": 1,
"encrypted": {
"text": "AQIDBAUGBwgJCg",
"cipher": "wZV3TR39l9nRoQ"
},
"decrypted": {
"text": "4wZj6mUUew",
"cipher": "YWJjZGVmZw"
}
}
@@ -0,0 +1,13 @@
{
"secret": "NnoYmu4Y+jHBkAVO/UqOlQ",
"frame": "M2WyxeiwIQB+ZOFxNzSNHtu9OdESkfxv3JkKFimCxUoYA3BD/Ql9nXB/OIonCKLUKCcS0VzZ2P6/+5oQ9GI8YA",
"dc": 1,
"encrypted": {
"text": "AQIDBAUGBwgJCg",
"cipher": "tzAwrCz00odERg"
},
"decrypted": {
"text": "QkIvwGQDgA",
"cipher": "YWJjZGVmZw"
}
}
@@ -0,0 +1,13 @@
{
"secret": "NnoYmu4Y+jHBkAVO/UqOlQ",
"frame": "ZEZY1K3SZZgHX2MgMeYMMVoIPYR6eP+bgKxjI7IHl6sPLhfH2jRitS7/VA6Kz8E2L+uLqVom7x4zO+D5Q5iARA",
"dc": 1,
"encrypted": {
"text": "AQIDBAUGBwgJCg",
"cipher": "WptF2u4ZSDMZxQ"
},
"decrypted": {
"text": "DT+Ob9yGWA",
"cipher": "YWJjZGVmZw"
}
}
@@ -0,0 +1,13 @@
{
"secret": "NnoYmu4Y+jHBkAVO/UqOlQ",
"frame": "/rbO1fCVLR7o28nrc9inrdDU+4Z4uOqbC2kMnNnzItv0fJmn4hcUXK6YBJQZVI01i7rFlgiCtTgrHtyfQp9p9w",
"dc": 1,
"encrypted": {
"text": "AQIDBAUGBwgJCg",
"cipher": "jKZzALBemf72Cw"
},
"decrypted": {
"text": "fMOlRiN20A",
"cipher": "YWJjZGVmZw"
}
}
@@ -0,0 +1,13 @@
{
"secret": "NnoYmu4Y+jHBkAVO/UqOlQ",
"frame": "SfqaPWt1F8WTfrTkTl06s7F1nUcBR6AUp5uniCcYpVCJvgYpOO3TQHUZbLaFbI5qYRjJBQDe9OpXDJjR/5z4lg",
"dc": 1,
"encrypted": {
"text": "AQIDBAUGBwgJCg",
"cipher": "0DtHeQPN2bv7Qw"
},
"decrypted": {
"text": "BWPiYKe4bA",
"cipher": "YWJjZGVmZw"
}
}
@@ -0,0 +1,13 @@
{
"secret": "NnoYmu4Y+jHBkAVO/UqOlQ",
"frame": "MF6BfhvxyI61vFHZN/ecrDF1sZux/JdgVjKX1Yzy7SmBhYu+8bS25ta8iFsj/4y2moBpeNFp7rqekCE3FRb29A",
"dc": 1,
"encrypted": {
"text": "AQIDBAUGBwgJCg",
"cipher": "MujITanGx9xf9g"
},
"decrypted": {
"text": "0xVTx0JKug",
"cipher": "YWJjZGVmZw"
}
}
@@ -0,0 +1,13 @@
{
"secret": "NnoYmu4Y+jHBkAVO/UqOlQ",
"frame": "YY3y0amcDqggxeNbnyyacKl++b3Q7X0XL9coxctXxJOYZQ/uXIaWFm1KD3s0VIKQ6C7NqJ8hnnJOcpp2Bdau6A",
"dc": 1,
"encrypted": {
"text": "AQIDBAUGBwgJCg",
"cipher": "mni7eHb24tufLQ"
},
"decrypted": {
"text": "Aqi/2cgHXA",
"cipher": "YWJjZGVmZw"
}
}
@@ -0,0 +1,13 @@
{
"secret": "NnoYmu4Y+jHBkAVO/UqOlQ",
"frame": "k0f9Sv7V7svvxmHlIP4Ajg0sTGb0NXHfJDk1h6VgAnV0my1F+NU8KPG35kqXC9IDQZK/6fOABb7npO8/TCHEzQ",
"dc": 1,
"encrypted": {
"text": "AQIDBAUGBwgJCg",
"cipher": "efUzYxRvqEYPlw"
},
"decrypted": {
"text": "FFPwzZkL2A",
"cipher": "YWJjZGVmZw"
}
}
@@ -0,0 +1,13 @@
{
"secret": "NnoYmu4Y+jHBkAVO/UqOlQ",
"frame": "NiK5AnDAJw+fsytYBnxOmcDl6jx3uQECznBS4WIaHXGWP0tcioPikE1mVtkp33aXT7bCfFlst+b0PvcldGSARw",
"dc": 1,
"encrypted": {
"text": "AQIDBAUGBwgJCg",
"cipher": "56aF+oauHVDbPQ"
},
"decrypted": {
"text": "KycK+00LvQ",
"cipher": "YWJjZGVmZw"
}
}
@@ -0,0 +1,13 @@
{
"secret": "NnoYmu4Y+jHBkAVO/UqOlQ",
"frame": "nYvAavvf0TywZ4hkfGEgf6ZmnIUsDWjRKzLktqF65D+3ha/LqViPdpvsexguXBd5HClDaY6YNXjb1TbjWWfYGQ",
"dc": 1,
"encrypted": {
"text": "AQIDBAUGBwgJCg",
"cipher": "t4GyXOdaa/phBw"
},
"decrypted": {
"text": "lWNj5kAaug",
"cipher": "YWJjZGVmZw"
}
}
+2 -6
View File
@@ -100,12 +100,8 @@ func (p *Proxy) doObfuscated2Handshake(ctx *streamContext) error {
return fmt.Errorf("cannot process client handshake: %w", err)
}
if dc < 0 {
dc = -dc
}
ctx.dc = int(dc)
ctx.logger = ctx.logger.BindInt("dc", ctx.dc)
ctx.dc = dc
ctx.logger = ctx.logger.BindInt("dc", dc)
ctx.clientConn = &obfuscated2.Conn{
Conn: ctx.clientConn,
Encryptor: encryptor,
+2 -2
View File
@@ -2,7 +2,7 @@ package stats_test
import (
"fmt"
"io/ioutil"
"io"
"net"
"net/http"
"testing"
@@ -32,7 +32,7 @@ func (suite *PrometheusTestSuite) Get() (string, error) {
defer resp.Body.Close()
data, err := ioutil.ReadAll(resp.Body)
data, err := io.ReadAll(resp.Body)
if err != nil {
return "", err // nolint: wrapcheck
}