SecurityTest.kt (3309B)
1 /* 2 * This file is part of LibEuFin. 3 * Copyright (C) 2023-2024 Taler Systems S.A. 4 5 * LibEuFin is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU Affero General Public License as 7 * published by the Free Software Foundation; either version 3, or 8 * (at your option) any later version. 9 10 * LibEuFin is distributed in the hope that it will be useful, but 11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General 13 * Public License for more details. 14 15 * You should have received a copy of the GNU Affero General Public 16 * License along with LibEuFin; see the file COPYING. If not, see 17 * <http://www.gnu.org/licenses/> 18 */ 19 20 import io.ktor.client.request.* 21 import io.ktor.http.* 22 import io.ktor.http.content.* 23 import kotlinx.serialization.json.Json 24 import org.junit.Test 25 import tech.libeufin.common.* 26 import tech.libeufin.common.test.* 27 28 inline fun <reified B> HttpRequestBuilder.jsonDeflate(b: B) { 29 val json = Json.encodeToString(kotlinx.serialization.serializer<B>(), b) 30 contentType(ContentType.Application.Json) 31 headers[HttpHeaders.ContentEncoding] = "deflate" 32 setBody(json.toByteArray().inputStream().deflate().readBytes()) 33 } 34 35 inline fun <reified B> HttpRequestBuilder.jsonStreamDeflate(b: B) { 36 val json = Json.encodeToString(kotlinx.serialization.serializer<B>(), b) 37 headers[HttpHeaders.ContentEncoding] = "deflate" 38 setBody(OutputStreamContent({ 39 write(json.toByteArray().inputStream().deflate().readBytes()) 40 }, ContentType.Application.Json)) 41 } 42 43 inline fun <reified B> HttpRequestBuilder.jsonStream(b: B) { 44 val json = Json.encodeToString(kotlinx.serialization.serializer<B>(), b) 45 setBody(OutputStreamContent({ 46 write(json.toByteArray()) 47 }, ContentType.Application.Json)) 48 } 49 50 class SecurityTest { 51 @Test 52 fun bodySizeLimit() = bankSetup { 53 val valid_req = obj { 54 "payto_uri" to "$exchangePayto?message=payout" 55 "amount" to "KUDOS:0.3" 56 } 57 val too_big = obj(valid_req) { 58 "payto_uri" to "$exchangePayto?message=payout${"A".repeat(MAX_BODY_LENGTH+1)}" 59 } 60 61 client.postA("/accounts/merchant/transactions") { 62 json(valid_req) 63 }.assertOk() 64 65 // Check body too big 66 client.postA("/accounts/merchant/transactions") { 67 json(too_big) 68 }.assertPayloadTooLarge() 69 70 // Check body too big even after compression 71 client.postA("/accounts/merchant/transactions") { 72 jsonDeflate(too_big) 73 }.assertPayloadTooLarge() 74 75 // Check streaming body too big 76 client.postA("/accounts/merchant/transactions") { 77 jsonStream(too_big) 78 }.assertPayloadTooLarge() 79 80 // Check streaming body too big even after compression 81 client.postA("/accounts/merchant/transactions") { 82 jsonStreamDeflate(too_big) 83 }.assertPayloadTooLarge() 84 85 // Check unknown encoding 86 client.postA("/accounts/merchant/transactions") { 87 headers[HttpHeaders.ContentEncoding] = "unknown" 88 json(valid_req) 89 }.assertStatus(HttpStatusCode.UnsupportedMediaType, TalerErrorCode.GENERIC_COMPRESSION_INVALID) 90 } 91 } 92 93 94