Skip to content

Commit

Permalink
refactor to read domain from config
Browse files Browse the repository at this point in the history
  • Loading branch information
jayvaznewm committed Jun 25, 2023
1 parent 5ecce17 commit 3f84c16
Show file tree
Hide file tree
Showing 8 changed files with 44 additions and 23 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.newm.server.aws.cloudfront

import io.ktor.http.Cookie
import io.newm.server.features.song.model.AudioStreamData
import io.newm.server.security.PrivateKeyReader
import software.amazon.awssdk.services.cloudfront.CloudFrontUtilities
Expand All @@ -11,6 +12,7 @@ data class CloudfrontAudioStreamArguments(
var url: String,
var keyPairId: String,
var privateKey: String,
var cookieDomain: String,
var expirationDate: Instant = Instant.now().plus(1, ChronoUnit.DAYS)
)

Expand All @@ -19,9 +21,9 @@ class CloudfrontAudioStreamData(
) : AudioStreamData {
override val url: String
get() = this.args.url
override val cookies: Map<String, String> by lazy { createSignedCookies() }
override val cookies: List<Cookie> by lazy { createSignedCookies() }

private fun createSignedCookies(): Map<String, String> {
private fun createSignedCookies(): List<Cookie> {
val streamUrl = this.url

// resource is the "dirname" of the URL with the filename removed,
Expand All @@ -44,13 +46,21 @@ class CloudfrontAudioStreamData(
val (keyPairIdHeaderName, keyPairIdHeaderValue) = signedCookies.keyPairIdHeaderValue().split("=")
val (policyHeaderName, policyHeaderValue) = signedCookies.policyHeaderValue().split("=")

return mapOf(
signatureHeaderName to signatureHeaderValue,
keyPairIdHeaderName to keyPairIdHeaderValue,
policyHeaderName to policyHeaderValue
return listOf(
cookie(name = signatureHeaderName, value = signatureHeaderValue),
cookie(name = keyPairIdHeaderName, value = keyPairIdHeaderValue),
cookie(name = policyHeaderName, value = policyHeaderValue),
)
}

private fun cookie(name: String, value: String): Cookie = Cookie(
name = name,
value = value,
path = "/",
domain = args.cookieDomain,
extensions = mapOf("SameSite" to "Strict")
)
}

fun cloudfrontAudioStreamData(init: CloudfrontAudioStreamArguments.() -> Unit): CloudfrontAudioStreamData =
CloudfrontAudioStreamData(CloudfrontAudioStreamArguments("", "", "").apply(init))
CloudfrontAudioStreamData(CloudfrontAudioStreamArguments("", "", "", "").apply(init))
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,7 @@ fun Routing.createSongRoutes() {
val streamData = songRepository.generateAudioStreamData(
songId = songId,
)
streamData.cookies.forEach { cookie ->
response.cookies.append(
name = cookie.key,
value = cookie.value,
domain = "newm.io",
path = "/",
extensions = mapOf("SameSite" to "Strict")
)
}
streamData.cookies.forEach { response.cookies.append(it) }
respond(
AudioStreamResponse(streamData)
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.newm.server.features.song.model

import io.ktor.http.Cookie
import kotlinx.serialization.Serializable

@Serializable
Expand All @@ -11,5 +12,5 @@ data class AudioStreamResponse(

interface AudioStreamData {
val url: String
val cookies: Map<String, String>
val cookies: List<Cookie>
}
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ internal class SongRepositoryImpl(
val mediaHostUrl = URL(environment.getConfigString("aws.cloudFront.audioStream.hostUrl"))
val kpid = environment.getSecureConfigString("aws.cloudFront.audioStream.keyPairId")
val pk = environment.getSecureConfigString("aws.cloudFront.audioStream.privateKey")
val cookieDom = environment.getConfigString("ktor.deployment.cookieDomain")

// fix up the url so that the url does not point to old cloudfront distros
val streamUrl = URLBuilder().apply {
Expand All @@ -235,6 +236,7 @@ internal class SongRepositoryImpl(
url = streamUrl.toString()
keyPairId = kpid
privateKey = pk
cookieDomain = cookieDom
}
}

Expand Down
2 changes: 2 additions & 0 deletions newm-server/src/main/resources/application.conf
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ ktor {
connectionGroupSize = 13
workerGroupSize = 13
callGroupSize = 24
cookieDomain = "newm.io"
cookieDomain = ${?COOKIE_DOMAIN}
}
application {
modules = [io.newm.server.ApplicationKt.module]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ class CloudfrontAudioStreamDataTest : BaseApplicationTests() {
this.privateKey = pk
}

assertThat(streamData.cookies).containsKey("CloudFront-Key-Pair-Id")
assertThat(streamData.cookies["CloudFront-Key-Pair-Id"]).isEqualTo(keyPairId)
assertThat(streamData.cookies).containsKey("CloudFront-Policy")
val policy = streamData.cookies["CloudFront-Policy"]
assertThat(streamData.cookies.filter { it.name == "CloudFront-Key-Pair-Id" }).isNotEmpty()
assertThat(streamData.cookies.filter { it.name == "CloudFront-Signature" }).isNotEmpty()
assertThat(streamData.cookies.filter { it.name == "CloudFront-Policy" }).isNotEmpty()
val policy = streamData.cookies.filter { it.name == "CloudFront-Policy" }.first().value
// policy is a slightly customized base64 encoded string, so just checking that it exists for now
assertThat(policy).isNotNull()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import java.io.EOFException
import java.io.File
import java.time.LocalDate
import java.time.LocalDateTime
import java.util.UUID
import java.util.*

class SongRoutesTests : BaseApplicationTests() {

Expand Down Expand Up @@ -797,6 +797,13 @@ class SongRoutesTests : BaseApplicationTests() {
val environment: ApplicationEnvironment by inject()
val updatedHost = environment.getConfigString("aws.cloudFront.audioStream.hostUrl")
assertThat(resp.url).startsWith(updatedHost)

// assert that cookies are created
val cookies = response.setCookie()
assertThat(cookies).isNotEmpty()
assertThat(cookies.filter { it.name == "CloudFront-Key-Pair-Id" }).isNotEmpty()
assertThat(cookies.filter { it.name == "CloudFront-Signature" }).isNotEmpty()
assertThat(cookies.filter { it.name == "CloudFront-Policy" }).isNotEmpty()
}

// TODO: complete implementation of testGenerateMintingPaymentTransaction() bellow
Expand Down Expand Up @@ -830,7 +837,12 @@ class SongRoutesTests : BaseApplicationTests() {
*/
}

fun addSongToDatabase(offset: Int = 0, ownerId: UUID? = null, phrase: String? = null, init: (SongEntity.() -> Unit)? = null): Song {
fun addSongToDatabase(
offset: Int = 0,
ownerId: UUID? = null,
phrase: String? = null,
init: (SongEntity.() -> Unit)? = null
): Song {
val ownerEntityId = ownerId?.let {
EntityID(it, UserTable)
} ?: transaction {
Expand Down
2 changes: 2 additions & 0 deletions newm-server/src/test/resources/test-application.conf
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ ktor {
connectionGroupSize = 13
workerGroupSize = 13
callGroupSize = 24
cookieDomain = "newm.io"
cookieDomain = ${?COOKIE_DOMAIN}
}
application {
modules = [io.newm.server.TestApplicationKt.testModule]
Expand Down

0 comments on commit 3f84c16

Please sign in to comment.