github.com/artpar/rclone@v1.67.3/cmd/serve/proxy/proxy_test.go (about)

     1  package proxy
     2  
     3  import (
     4  	"context"
     5  	"crypto/rand"
     6  	"crypto/rsa"
     7  	"crypto/sha256"
     8  	"encoding/base64"
     9  	"log"
    10  	"strings"
    11  	"testing"
    12  
    13  	_ "github.com/artpar/rclone/backend/local"
    14  	"github.com/artpar/rclone/fs/config/configmap"
    15  	"github.com/artpar/rclone/fs/config/obscure"
    16  	"github.com/stretchr/testify/assert"
    17  	"github.com/stretchr/testify/require"
    18  	"golang.org/x/crypto/ssh"
    19  )
    20  
    21  func TestRun(t *testing.T) {
    22  	opt := DefaultOpt
    23  	cmd := "go run proxy_code.go"
    24  	opt.AuthProxy = cmd
    25  	p := New(context.Background(), &opt)
    26  
    27  	t.Run("Normal", func(t *testing.T) {
    28  		config, err := p.run(map[string]string{
    29  			"type": "ftp",
    30  			"user": "me",
    31  			"pass": "pass",
    32  			"host": "127.0.0.1",
    33  		})
    34  		require.NoError(t, err)
    35  		assert.Equal(t, configmap.Simple{
    36  			"type":  "ftp",
    37  			"user":  "me-test",
    38  			"pass":  "pass",
    39  			"host":  "127.0.0.1",
    40  			"_root": "",
    41  		}, config)
    42  	})
    43  
    44  	t.Run("Error", func(t *testing.T) {
    45  		config, err := p.run(map[string]string{
    46  			"error": "potato",
    47  		})
    48  		assert.Nil(t, config)
    49  		require.Error(t, err)
    50  		require.Contains(t, err.Error(), "potato")
    51  	})
    52  
    53  	t.Run("Obscure", func(t *testing.T) {
    54  		config, err := p.run(map[string]string{
    55  			"type":     "ftp",
    56  			"user":     "me",
    57  			"pass":     "pass",
    58  			"host":     "127.0.0.1",
    59  			"_obscure": "pass,user",
    60  		})
    61  		require.NoError(t, err)
    62  		config["user"] = obscure.MustReveal(config["user"])
    63  		config["pass"] = obscure.MustReveal(config["pass"])
    64  		assert.Equal(t, configmap.Simple{
    65  			"type":     "ftp",
    66  			"user":     "me-test",
    67  			"pass":     "pass",
    68  			"host":     "127.0.0.1",
    69  			"_obscure": "pass,user",
    70  			"_root":    "",
    71  		}, config)
    72  	})
    73  
    74  	const testUser = "testUser"
    75  	const testPass = "testPass"
    76  
    77  	t.Run("call w/Password", func(t *testing.T) {
    78  		// check cache empty
    79  		assert.Equal(t, 0, p.vfsCache.Entries())
    80  		defer p.vfsCache.Clear()
    81  
    82  		passwordBytes := []byte(testPass)
    83  		value, err := p.call(testUser, testPass, false)
    84  		require.NoError(t, err)
    85  		entry, ok := value.(cacheEntry)
    86  		require.True(t, ok)
    87  
    88  		// check hash is correct in entry
    89  		assert.Equal(t, entry.pwHash, sha256.Sum256(passwordBytes))
    90  		require.NotNil(t, entry.vfs)
    91  		f := entry.vfs.Fs()
    92  		require.NotNil(t, f)
    93  		assert.Equal(t, "proxy-"+testUser, f.Name())
    94  		assert.True(t, strings.HasPrefix(f.String(), "Local file system"))
    95  
    96  		// check it is in the cache
    97  		assert.Equal(t, 1, p.vfsCache.Entries())
    98  		cacheValue, ok := p.vfsCache.GetMaybe(testUser)
    99  		assert.True(t, ok)
   100  		assert.Equal(t, value, cacheValue)
   101  	})
   102  
   103  	t.Run("Call w/Password", func(t *testing.T) {
   104  		// check cache empty
   105  		assert.Equal(t, 0, p.vfsCache.Entries())
   106  		defer p.vfsCache.Clear()
   107  
   108  		vfs, vfsKey, err := p.Call(testUser, testPass, false)
   109  		require.NoError(t, err)
   110  		require.NotNil(t, vfs)
   111  		assert.Equal(t, "proxy-"+testUser, vfs.Fs().Name())
   112  		assert.Equal(t, testUser, vfsKey)
   113  
   114  		// check it is in the cache
   115  		assert.Equal(t, 1, p.vfsCache.Entries())
   116  		cacheValue, ok := p.vfsCache.GetMaybe(testUser)
   117  		assert.True(t, ok)
   118  		cacheEntry, ok := cacheValue.(cacheEntry)
   119  		assert.True(t, ok)
   120  		assert.Equal(t, vfs, cacheEntry.vfs)
   121  
   122  		// Test Get works while we have something in the cache
   123  		t.Run("Get", func(t *testing.T) {
   124  			assert.Equal(t, vfs, p.Get(testUser))
   125  			assert.Nil(t, p.Get("unknown"))
   126  		})
   127  
   128  		// now try again from the cache
   129  		vfs, vfsKey, err = p.Call(testUser, testPass, false)
   130  		require.NoError(t, err)
   131  		require.NotNil(t, vfs)
   132  		assert.Equal(t, "proxy-"+testUser, vfs.Fs().Name())
   133  		assert.Equal(t, testUser, vfsKey)
   134  
   135  		// check cache is at the same level
   136  		assert.Equal(t, 1, p.vfsCache.Entries())
   137  
   138  		// now try again from the cache but with wrong password
   139  		vfs, vfsKey, err = p.Call(testUser, testPass+"wrong", false)
   140  		require.Error(t, err)
   141  		require.Contains(t, err.Error(), "incorrect password")
   142  		require.Nil(t, vfs)
   143  		require.Equal(t, "", vfsKey)
   144  
   145  		// check cache is at the same level
   146  		assert.Equal(t, 1, p.vfsCache.Entries())
   147  
   148  	})
   149  
   150  	privateKey, privateKeyErr := rsa.GenerateKey(rand.Reader, 2048)
   151  	if privateKeyErr != nil {
   152  		log.Fatal("error generating test private key " + privateKeyErr.Error())
   153  	}
   154  	publicKey, publicKeyError := ssh.NewPublicKey(&privateKey.PublicKey)
   155  	if privateKeyErr != nil {
   156  		log.Fatal("error generating test public key " + publicKeyError.Error())
   157  	}
   158  
   159  	publicKeyString := base64.StdEncoding.EncodeToString(publicKey.Marshal())
   160  
   161  	t.Run("Call w/PublicKey", func(t *testing.T) {
   162  		// check cache empty
   163  		assert.Equal(t, 0, p.vfsCache.Entries())
   164  		defer p.vfsCache.Clear()
   165  
   166  		value, err := p.call(testUser, publicKeyString, true)
   167  		require.NoError(t, err)
   168  		entry, ok := value.(cacheEntry)
   169  		require.True(t, ok)
   170  
   171  		// check publicKey is correct in entry
   172  		require.NoError(t, err)
   173  		require.NotNil(t, entry.vfs)
   174  		f := entry.vfs.Fs()
   175  		require.NotNil(t, f)
   176  		assert.Equal(t, "proxy-"+testUser, f.Name())
   177  		assert.True(t, strings.HasPrefix(f.String(), "Local file system"))
   178  
   179  		// check it is in the cache
   180  		assert.Equal(t, 1, p.vfsCache.Entries())
   181  		cacheValue, ok := p.vfsCache.GetMaybe(testUser)
   182  		assert.True(t, ok)
   183  		assert.Equal(t, value, cacheValue)
   184  	})
   185  
   186  	t.Run("call w/PublicKey", func(t *testing.T) {
   187  		// check cache empty
   188  		assert.Equal(t, 0, p.vfsCache.Entries())
   189  		defer p.vfsCache.Clear()
   190  
   191  		vfs, vfsKey, err := p.Call(
   192  			testUser,
   193  			publicKeyString,
   194  			true,
   195  		)
   196  		require.NoError(t, err)
   197  		require.NotNil(t, vfs)
   198  		assert.Equal(t, "proxy-"+testUser, vfs.Fs().Name())
   199  		assert.Equal(t, testUser, vfsKey)
   200  
   201  		// check it is in the cache
   202  		assert.Equal(t, 1, p.vfsCache.Entries())
   203  		cacheValue, ok := p.vfsCache.GetMaybe(testUser)
   204  		assert.True(t, ok)
   205  		cacheEntry, ok := cacheValue.(cacheEntry)
   206  		assert.True(t, ok)
   207  		assert.Equal(t, vfs, cacheEntry.vfs)
   208  
   209  		// Test Get works while we have something in the cache
   210  		t.Run("Get", func(t *testing.T) {
   211  			assert.Equal(t, vfs, p.Get(testUser))
   212  			assert.Nil(t, p.Get("unknown"))
   213  		})
   214  
   215  		// now try again from the cache
   216  		vfs, vfsKey, err = p.Call(testUser, publicKeyString, true)
   217  		require.NoError(t, err)
   218  		require.NotNil(t, vfs)
   219  		assert.Equal(t, "proxy-"+testUser, vfs.Fs().Name())
   220  		assert.Equal(t, testUser, vfsKey)
   221  
   222  		// check cache is at the same level
   223  		assert.Equal(t, 1, p.vfsCache.Entries())
   224  
   225  		// now try again from the cache but with wrong public key
   226  		vfs, vfsKey, err = p.Call(testUser, publicKeyString+"wrong", true)
   227  		require.Error(t, err)
   228  		require.Contains(t, err.Error(), "incorrect public key")
   229  		require.Nil(t, vfs)
   230  		require.Equal(t, "", vfsKey)
   231  
   232  		// check cache is at the same level
   233  		assert.Equal(t, 1, p.vfsCache.Entries())
   234  	})
   235  }