Skip to content

Commit

Permalink
Fix refresh token validation issue
Browse files Browse the repository at this point in the history
  • Loading branch information
Andreas Volkmann committed Dec 7, 2020
1 parent 60b18b9 commit c967720
Show file tree
Hide file tree
Showing 12 changed files with 60 additions and 69 deletions.
25 changes: 14 additions & 11 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
plugins {
id 'org.jetbrains.kotlin.jvm' version '1.3.72'
id "com.github.ben-manes.versions" version "0.28.0"
id 'org.springframework.boot' version '2.2.6.RELEASE'
id 'org.jetbrains.kotlin.jvm' version '1.4.20'
id "com.github.ben-manes.versions" version "0.36.0"
id 'org.springframework.boot' version '2.4.0'
}

ext {
ktor_version = '1.3.1'
ktor_version = '1.4.1'
spotify_api_vesrion = '4.3.0'
jrawVersion = '1.1.0'
junit_version = '5.6.1'
junit_version = '5.7.0'
}

group 'me.avo'
Expand Down Expand Up @@ -36,12 +36,12 @@ dependencies {
compile group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.3'
compile 'org.kodein.di:kodein-di-generic-jvm:6.5.5'
compile 'com.github.salomonbrys.kotson:kotson:2.5.0'
compile 'org.yaml:snakeyaml:1.26'
compile 'org.yaml:snakeyaml:1.27'
compile 'com.apurebase:arkenv:3.1.0'
compile 'org.apache.commons:commons-text:1.8'
compile 'org.apache.commons:commons-text:1.9'

testImplementation "io.strikt:strikt-core:0.26.0"
testImplementation "io.mockk:mockk:1.10.0"
testImplementation "io.strikt:strikt-core:0.28.1"
testImplementation "io.mockk:mockk:1.10.3"
testCompile group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: junit_version
testRuntime "org.junit.jupiter:junit-jupiter-engine:$junit_version"
}
Expand All @@ -58,8 +58,11 @@ test {
}

compileKotlin {
kotlinOptions.jvmTarget = "11"
kotlinOptions.jvmTarget = "13"
kotlinOptions.useIR = true

}
compileTestKotlin {
kotlinOptions.jvmTarget = "11"
kotlinOptions.jvmTarget = "13"
kotlinOptions.useIR = true
}
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
11 changes: 7 additions & 4 deletions src/main/kotlin/me/avo/spottit/config/Arguments.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package me.avo.spottit.config

import com.apurebase.arkenv.Arkenv
import com.apurebase.arkenv.argument
import me.avo.spottit.exception.InvalidRefreshTokenException
import java.io.File

object Arguments : Arkenv("Spottit") {
Expand All @@ -12,7 +13,6 @@ object Arguments : Arkenv("Spottit") {

val useLists: List<String> by argument {
description = "When defined will only update lists with the provided comma-separated ids"
mapping = { it.split(',') }
defaultValue = ::emptyList
}

Expand All @@ -33,18 +33,21 @@ object Arguments : Arkenv("Spottit") {
mapping = ::File
}

val refreshToken: String by argument {
defaultValue = { refreshTokenFile.readText().trim() }
private val refreshTokenArg: String? by argument {
defaultValue = refreshTokenFile.readText()::trim
}

val editDistance: Int by argument()

val spotifyClientId: String by argument()

val spotifyClientSecret: String by argument()
val redirectUri: String by argument()

val redditClientId: String by argument()

val redditClientSecret: String by argument()
val deviceName: String by argument()
val redditMaxPage: Int by argument()

fun getRefreshToken(): String = refreshTokenArg ?: throw InvalidRefreshTokenException()
}
2 changes: 1 addition & 1 deletion src/main/kotlin/me/avo/spottit/config/Dependency.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ val prodKodein = Kodein {
)
}

bind() from singleton { Server(instance(), instance()) }
bind() from singleton { Server(instance()) }

bind() from singleton {
ManualAuthService(instance(), instance())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package me.avo.spottit.exception

class InvalidRefreshTokenException : IllegalArgumentException(
"An invalid refresh token has been provided."
)
34 changes: 16 additions & 18 deletions src/main/kotlin/me/avo/spottit/server/Server.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,35 @@

package me.avo.spottit.server

import com.wrapper.spotify.model_objects.credentials.AuthorizationCodeCredentials
import freemarker.cache.ClassTemplateLoader
import freemarker.template.Configuration
import io.ktor.application.Application
import io.ktor.application.call
import io.ktor.application.install
import io.ktor.features.CallLogging
import io.ktor.features.StatusPages
import io.ktor.freemarker.FreeMarker
import io.ktor.http.HttpStatusCode
import io.ktor.application.*
import io.ktor.features.*
import io.ktor.freemarker.*
import io.ktor.http.*
import io.ktor.http.HttpStatusCode.Companion.InternalServerError
import io.ktor.response.respond
import io.ktor.routing.Routing
import io.ktor.routing.get
import io.ktor.server.cio.CIO
import io.ktor.server.engine.ApplicationEngine
import io.ktor.server.engine.embeddedServer
import io.ktor.response.*
import io.ktor.routing.*
import io.ktor.server.cio.*
import io.ktor.server.engine.*
import me.avo.spottit.Spottit
import me.avo.spottit.config.Arguments
import me.avo.spottit.service.AuthorizationService
import me.avo.spottit.service.spotify.SpotifyAuthService
import org.slf4j.event.Level

class Server(
private val spotifyAuthService: SpotifyAuthService,
private val authService: AuthorizationService
private val spotifyAuthService: SpotifyAuthService
) {

fun prepareServer(): ApplicationEngine = embeddedServer(
factory = CIO, port = Arguments.port, module = module()
)

private fun writeCredentials(credentials: AuthorizationCodeCredentials) {
Arguments.refreshTokenFile.writeText(credentials.refreshToken)
}

private fun module(): Application.() -> Unit = {
install(Routing) {
get("spotify/auth/{...}") {
Expand All @@ -44,13 +42,13 @@ class Server(
else -> {
val credentials = spotifyAuthService.grantAccess(code)
call.respond(Templates.auth(credentials.accessToken, credentials.refreshToken))
authService.writeCredentials(credentials)
writeCredentials(credentials)
}
}
}
}
install(CallLogging) { level = Level.INFO }
install(FreeMarker) { setupFreemarker() }
install(FreeMarker, Configuration::setupFreemarker)
install(StatusPages) {
exception<Throwable> {
val status = when (it) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
package me.avo.spottit.service

import com.wrapper.spotify.model_objects.credentials.AuthorizationCodeCredentials
import me.avo.spottit.model.Configuration

interface AuthorizationService {

fun authorize(configuration: Configuration)

fun writeCredentials(credentials: AuthorizationCodeCredentials)

fun getRequiredScopes(configuration: Configuration): Iterable<String>
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package me.avo.spottit.service.spotify

import com.wrapper.spotify.model_objects.credentials.AuthorizationCodeCredentials
import me.avo.spottit.config.Arguments
import me.avo.spottit.model.Configuration
import me.avo.spottit.model.Playlist
import me.avo.spottit.server.Server
Expand All @@ -28,10 +26,6 @@ class ManualAuthService(
}
}

override fun writeCredentials(credentials: AuthorizationCodeCredentials) {
Arguments.refreshTokenFile.writeText(credentials.refreshToken)
}

override fun getRequiredScopes(configuration: Configuration): Iterable<String> {
val private = if (configuration.playlists.any(Playlist::isPrivate)) "playlist-modify-private" else null
val public = if (configuration.playlists.any { it.isPrivate.not() }) "playlist-modify-public" else null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import com.wrapper.spotify.SpotifyHttpManager
import com.wrapper.spotify.model_objects.credentials.AuthorizationCodeCredentials
import me.avo.spottit.config.Arguments
import me.avo.spottit.util.RetrySupport
import org.kodein.di.generic.instance
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.net.URI
Expand All @@ -28,7 +27,7 @@ class SpotifyAuthServiceImpl(
val auth = SpotifyApi.Builder()
.setClientId(clientId)
.setClientSecret(clientSecret)
.setRefreshToken(Arguments.refreshToken)
.setRefreshToken(getRefreshToken())
.build()
.authorizationCodeRefresh()
.execute()
Expand All @@ -43,7 +42,7 @@ class SpotifyAuthServiceImpl(
private fun updateCredentials(auth: AuthorizationCodeCredentials) {
accessToken = auth.accessToken
expiresInSeconds = auth.expiresIn
refreshToken = auth.refreshToken ?: Arguments.refreshToken
refreshToken = auth.refreshToken ?: getRefreshToken()
isInitialized = true
}

Expand All @@ -63,7 +62,9 @@ class SpotifyAuthServiceImpl(
.setClientId(clientId)
.setClientSecret(clientSecret)
.setRedirectUri(SpotifyHttpManager.makeUri(redirectUri))
.build()!!
.build()

private fun getRefreshToken(): String = Arguments.getRefreshToken()

override val logger: Logger = LoggerFactory.getLogger(this::class.java)
}
10 changes: 7 additions & 3 deletions src/test/kotlin/me/avo/spottit/config/ArgumentsTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,20 @@ import strikt.assertions.isFalse
import strikt.assertions.isTrue

internal class ArgumentsTest {
private val configPath = "config.yml"

@Test fun `parse args correctly`() {
val configPath = "config.yml"
val args = Arguments.parse(arrayOf("-c", configPath, "-ma", "-r"))
expectThat(args) {
get { this.configPath }.isEqualTo(configPath)
get { this.configPath } isEqualTo configPath
get { manualAuth }.isTrue()
get { doRefresh }.isTrue()
get { help }.isFalse()
get { editDistance }.isEqualTo(15)
get { editDistance } isEqualTo 15
}
}

@Test fun `manual auth should not require refresh token`() {
Arguments.parse(arrayOf("-c", configPath, "-ma", "--refreshTokenFile", "does_not_exist"))
}
}
14 changes: 0 additions & 14 deletions src/test/kotlin/me/avo/spottit/util/TokenUtilTest.kt

This file was deleted.

8 changes: 4 additions & 4 deletions src/test/resources/test_config.yml
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
playlists:
- id: 6cQk28LM0k3ogiCNEH0d9e # reddit test
maxSize: 10
maxSize: 6
subreddit: indieheads
sort: TOP
timePeriod: MONTH
minUpvotes: 5
minUpvotes: 4
isStrictMix: true
tagFilter:
includeExact:
- FRESH

- id: 492vM7yqKZxqV32jb5UWHf # private spottit
maxSize: 20
maxSize: 4
subreddit: hardstyle
sort: TOP
timePeriod: MONTH
isStrictMix: true
isPrivate: true

- id: 5oCt1rrIqdJhvTzBN6LN2a # private spottit #2
maxSize: 10
maxSize: 5
subreddit: electronicmusic
sort: TOP
timePeriod: ALL
Expand Down

0 comments on commit c967720

Please sign in to comment.