@@ -2,6 +2,7 @@ package cloud.skadi
22
33import cloud.skadi.gist.shared.*
44import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
5+ import io.ktor.client.engine.*
56import io.ktor.http.*
67import io.ktor.server.testing.*
78import org.jsoup.Jsoup
@@ -138,6 +139,7 @@ class ApplicationTest {
138139 }
139140 }
140141 }
142+
141143 @Test
142144 fun `can create private gist after login` () {
143145 withTestDb { dbName ->
@@ -157,7 +159,7 @@ class ApplicationTest {
157159 cookiesSession {
158160 login()
159161 val gistUrl = testGist()
160- handleRequest(HttpMethod .Get ," /logout" ).apply {
162+ handleRequest(HttpMethod .Get , " /logout" ).apply {
161163 assertEquals(HttpStatusCode .Found , response.status())
162164 }
163165 handleRequest(HttpMethod .Get , gistUrl.encodedPath).apply {
@@ -167,24 +169,27 @@ class ApplicationTest {
167169 }
168170 }
169171 }
172+
170173 @Test
171174 fun `cannot access private gist as a different user` () {
172175 withTestDb { dbName ->
173176 withTestApplication({ testModuleSetup(dbName) }) {
174177 cookiesSession {
175178 login()
176179 val gistUrl = testGist()
177- handleRequest(HttpMethod .Get ," /logout" ).apply {
180+ handleRequest(HttpMethod .Get , " /logout" ).apply {
178181 assertEquals(HttpStatusCode .Found , response.status())
179182 }
180183 login(
" testuser2" ,
" [email protected] " )
181184 handleRequest(HttpMethod .Get , gistUrl.encodedPath).apply {
185+ response.content
182186 assertEquals(HttpStatusCode .NotFound , response.status())
183187 }
184188 }
185189 }
186190 }
187191 }
192+
188193 @Test
189194 fun `gist with empty root is rejected` () {
190195 withTestDb { dbName ->
@@ -205,18 +210,124 @@ class ApplicationTest {
205210 }
206211
207212 @Test
208- fun `cannot edit gist gist without login` () {
213+ fun `cannot edit gist without login` () {
209214 withTestDb { dbName ->
210215 withTestApplication({ testModuleSetup(dbName) }) {
211216 cookiesSession {
212217 login()
213218 val gistUrl = testGist()
214- handleRequest(HttpMethod .Get ," /logout" ).apply {
219+ logout()
220+ handleRequest(HttpMethod .Get , gistUrl.encodedPath + " /edit" ).apply {
215221 assertEquals(HttpStatusCode .Found , response.status())
222+ assert (response.headers[HttpHeaders .Location ]!! .startsWith(" /login/github" ))
223+ }
224+ }
225+ }
226+ }
227+ }
228+
229+ @Test
230+ fun `can edit my gist` () {
231+ withTestDb { dbName ->
232+ withTestApplication({ testModuleSetup(dbName) }) {
233+ cookiesSession {
234+ login()
235+ val gistUrl = testGist()
236+ handleRequest(HttpMethod .Get , gistUrl.encodedPath + " /edit" ).apply {
237+ assertEquals(HttpStatusCode .OK , response.status())
216238 }
239+ }
240+ }
241+ }
242+ }
243+
244+ @Test
245+ fun `cannot edit gist without different users gist` () {
246+ withTestDb { dbName ->
247+ withTestApplication({ testModuleSetup(dbName) }) {
248+ cookiesSession {
249+ login()
250+ val gistUrl = testGist()
251+ logout()
252+ login(
" user2" ,
" [email protected] " )
217253 handleRequest(HttpMethod .Get , gistUrl.encodedPath + " /edit" ).apply {
254+ assertEquals(HttpStatusCode .NotFound , response.status())
255+ }
256+ }
257+ }
258+ }
259+ }
260+
261+ @Test
262+ fun `can delete my gist` () {
263+ withTestDb { dbName ->
264+ withTestApplication({ testModuleSetup(dbName) }) {
265+ cookiesSession {
266+ login()
267+ val gistUrl = testGist()
268+ val csrfToken = handleRequest(HttpMethod .Get , gistUrl.encodedPath + " /delete" ).run {
269+ val document = Jsoup .parse(response.content)
270+ val csrf =
271+ document.selectFirst(" body > div.container > form > input[type=\" hidden\" ]:nth-child(2)" )
272+ csrf?.attr(" value" )!!
273+ }
274+ handleRequest(HttpMethod .Post , gistUrl.encodedPath + " /delete" ) {
275+ addHeader(HttpHeaders .ContentType , ContentType .Application .FormUrlEncoded .toString())
276+ setBody(listOf (" CSRFToken" to csrfToken).formUrlEncode())
277+ }.apply {
218278 assertEquals(HttpStatusCode .Found , response.status())
219- assert (response.headers[HttpHeaders .Location ]!! .startsWith(" /login/github" ))
279+ }
280+ }
281+ }
282+ }
283+ }
284+
285+ @Test
286+ fun `cannot delete when not logged in` () {
287+ withTestDb { dbName ->
288+ withTestApplication({ testModuleSetup(dbName) }) {
289+ cookiesSession {
290+ login()
291+ val gistUrl = testGist()
292+ val csrfToken = handleRequest(HttpMethod .Get , gistUrl.encodedPath + " /delete" ).run {
293+ val document = Jsoup .parse(response.content)
294+ val csrf =
295+ document.selectFirst(" body > div.container > form > input[type=\" hidden\" ]:nth-child(2)" )
296+ csrf?.attr(" value" )!!
297+ }
298+ logout()
299+ handleRequest(HttpMethod .Post , gistUrl.encodedPath + " /delete" ) {
300+ addHeader(HttpHeaders .ContentType , ContentType .Application .FormUrlEncoded .toString())
301+ setBody(listOf (" CSRFToken" to csrfToken).formUrlEncode())
302+ }.apply {
303+ assertEquals(HttpStatusCode .Found , response.status())
304+ assert (response.headers[HttpHeaders .Location ]!! .startsWith(" /login" ))
305+ }
306+ }
307+ }
308+ }
309+ }
310+
311+ @Test
312+ fun `cannot delete as different user` () {
313+ withTestDb { dbName ->
314+ withTestApplication({ testModuleSetup(dbName) }) {
315+ cookiesSession {
316+ login()
317+ val gistUrl = testGist()
318+ val csrfToken = handleRequest(HttpMethod .Get , gistUrl.encodedPath + " /delete" ).run {
319+ val document = Jsoup .parse(response.content)
320+ val csrf =
321+ document.selectFirst(" body > div.container > form > input[type=\" hidden\" ]:nth-child(2)" )
322+ csrf?.attr(" value" )!!
323+ }
324+ logout()
325+ login(
" user2" ,
" [email protected] " )
326+ handleRequest(HttpMethod .Post , gistUrl.encodedPath + " /delete" ) {
327+ addHeader(HttpHeaders .ContentType , ContentType .Application .FormUrlEncoded .toString())
328+ setBody(listOf (" CSRFToken" to csrfToken).formUrlEncode())
329+ }.apply {
330+ assertEquals(HttpStatusCode .NotFound , response.status())
220331 }
221332 }
222333 }
0 commit comments