github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/model/remote/remote_test.go (about) 1 package remote 2 3 import ( 4 "bytes" 5 "net/http" 6 "net/http/httptest" 7 "net/url" 8 "testing" 9 10 "github.com/cozy/cozy-stack/pkg/config/config" 11 "github.com/cozy/cozy-stack/pkg/consts" 12 "github.com/cozy/cozy-stack/pkg/couchdb" 13 "github.com/cozy/cozy-stack/pkg/prefixer" 14 "github.com/stretchr/testify/assert" 15 "github.com/stretchr/testify/require" 16 ) 17 18 const doctype = "org.example.request" 19 20 func TestParseRawRequest(t *testing.T) { 21 config.UseTestFile(t) 22 23 raw := `GET` 24 _, err := ParseRawRequest(doctype, raw) 25 assert.Equal(t, ErrInvalidRequest, err) 26 27 raw = `PUT https://example.org/` 28 _, err = ParseRawRequest(doctype, raw) 29 assert.Equal(t, ErrInvalidRequest, err) 30 31 raw = `GET ftp://example.org/` 32 _, err = ParseRawRequest(doctype, raw) 33 assert.Equal(t, ErrInvalidRequest, err) 34 35 raw = `GET /etc/hosts` 36 _, err = ParseRawRequest(doctype, raw) 37 assert.Equal(t, ErrInvalidRequest, err) 38 39 raw = `GET https://example.org/ 40 Foo` 41 _, err = ParseRawRequest(doctype, raw) 42 assert.Equal(t, ErrInvalidRequest, err) 43 44 // Allow a trailing \n after headers on GET 45 raw = `GET https://www.wikidata.org/wiki/Special:EntityData/{{entity}}.json 46 Content-Type: application/json 47 ` 48 _, err = ParseRawRequest(doctype, raw) 49 assert.NoError(t, err) 50 51 raw = `GET https://www.wikidata.org/wiki/Special:EntityData/{{entity}}.json` 52 r1, err := ParseRawRequest(doctype, raw) 53 assert.NoError(t, err) 54 assert.Equal(t, "GET", r1.Verb) 55 assert.Equal(t, "https", r1.URL.Scheme) 56 assert.Equal(t, "www.wikidata.org", r1.URL.Host) 57 assert.Equal(t, "/wiki/Special:EntityData/{{entity}}.json", r1.URL.Path) 58 assert.Equal(t, "", r1.URL.RawQuery) 59 60 raw = `POST https://www.wikidata.org/w/api.php?action=wbsearchentities&search={{q}}&language=en&format=json 61 Accept-Language: fr-FR,en 62 Content-Type: application/json 63 64 one={{one}} 65 two={{two}}` 66 r2, err := ParseRawRequest(doctype, raw) 67 assert.NoError(t, err) 68 assert.Equal(t, "POST", r2.Verb) 69 assert.Equal(t, "https", r2.URL.Scheme) 70 assert.Equal(t, "www.wikidata.org", r2.URL.Host) 71 assert.Equal(t, "/w/api.php", r2.URL.Path) 72 assert.Equal(t, "action=wbsearchentities&search={{q}}&language=en&format=json", r2.URL.RawQuery) 73 assert.Equal(t, "fr-FR,en", r2.Headers["Accept-Language"]) 74 assert.Equal(t, "application/json", r2.Headers["Content-Type"]) 75 assert.Equal(t, `one={{one}} 76 two={{two}}`, r2.Body) 77 } 78 79 func TestExtractVariablesGET(t *testing.T) { 80 config.UseTestFile(t) 81 82 u, err := url.Parse("https://example.org/foo?one=un&two=deux") 83 assert.NoError(t, err) 84 in := &http.Request{URL: u} 85 vars, err := extractVariables("GET", in) 86 assert.NoError(t, err) 87 assert.Equal(t, "un", vars["one"]) 88 assert.Equal(t, "deux", vars["two"]) 89 } 90 91 func TestExtractVariablesPOST(t *testing.T) { 92 config.UseTestFile(t) 93 94 body := bytes.NewReader([]byte(`{"one": "un", "two": "deux"}`)) 95 in := httptest.NewRequest("POST", "https://example.com/bar", body) 96 vars, err := extractVariables("POST", in) 97 assert.NoError(t, err) 98 assert.Equal(t, "un", vars["one"]) 99 assert.Equal(t, "deux", vars["two"]) 100 101 body = bytes.NewReader([]byte(`one=un&two=deux`)) 102 in = httptest.NewRequest("POST", "https://example.com/bar", body) 103 _, err = extractVariables("POST", in) 104 assert.Error(t, err) 105 } 106 107 func TestInjectVariables(t *testing.T) { 108 config.UseTestFile(t) 109 110 raw := `POST https://example.org/foo/{{bar}}?q={{q}} 111 Content-Type: {{contentType}} 112 Accept-Language: {{lang}},en 113 114 { "one": "{{ json one }}", "two": "{{ json two }}" } 115 <p>{{html content}}</p>` 116 r, err := ParseRawRequest(doctype, raw) 117 require.NoError(t, err) 118 119 vars := map[string]string{ 120 "contentType": "application/json", 121 "bar": "baz&/", 122 "q": "Q42&?", 123 "lang": "fr-FR\n", 124 "one": "un\"\n", 125 "two": "deux", 126 "content": "hey ! <<>>", 127 } 128 129 err = injectVariables(r, vars) 130 assert.NoError(t, err) 131 assert.Equal(t, "POST", r.Verb) 132 assert.Equal(t, "https", r.URL.Scheme) 133 assert.Equal(t, "example.org", r.URL.Host) 134 assert.Equal(t, "/foo/baz&%2F", r.URL.Path) 135 assert.Equal(t, "q=Q42%26%3F", r.URL.RawQuery) 136 assert.Equal(t, "fr-FR\\n,en", r.Headers["Accept-Language"]) 137 assert.Equal(t, "application/json", r.Headers["Content-Type"]) 138 assert.Equal(t, `{ "one": "un\"\n", "two": "deux" } 139 <p>hey ! <<>></p>`, r.Body) 140 141 r, err = ParseRawRequest(doctype, `POST https://example.org/{{missing}}`) 142 assert.NoError(t, err) 143 err = injectVariables(r, vars) 144 assert.Equal(t, ErrMissingVar, err) 145 } 146 147 func TestInjectSecret(t *testing.T) { 148 if testing.Short() { 149 t.Skip("a couchdb is required for this test: test skipped due to the use of --short flag") 150 } 151 152 config.UseTestFile(t) 153 154 doctype := "cc.cozycloud.foobar" 155 doc := couchdb.JSONDoc{ 156 Type: consts.RemoteSecrets, 157 M: map[string]interface{}{ 158 "_id": doctype, 159 "token": "123456789", 160 }, 161 } 162 err := couchdb.CreateNamedDocWithDB(prefixer.SecretsPrefixer, &doc) 163 assert.NoError(t, err) 164 defer func() { 165 _ = couchdb.DeleteDoc(prefixer.SecretsPrefixer, &doc) 166 }() 167 168 raw := `POST https://example.org/foo/ 169 Authorization: Bearer {{secret_token}} 170 171 { "bar": "baz" } 172 ` 173 r, err := ParseRawRequest(doctype, raw) 174 assert.NoError(t, err) 175 err = injectVariables(r, map[string]string{}) 176 assert.NoError(t, err) 177 assert.Equal(t, "Bearer 123456789", r.Headers["Authorization"]) 178 }