Skip to content

Commit

Permalink
fix: token prompts appearing over other prompts
Browse files Browse the repository at this point in the history
  • Loading branch information
russellbanks committed Jan 26, 2023
1 parent 52596ef commit a197424
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 34 deletions.
9 changes: 3 additions & 6 deletions src/main/kotlin/commands/ChangeToken.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,10 @@ class ChangeToken : CliktCommand(name = "token"), KoinComponent {
private val tokenStore: TokenStore by inject()

override fun run() = runBlocking {
if (tokenStore.storedToken == null) {
tokenStore.token.await()
if (tokenStore.token == null) {
tokenStore.promptForToken(currentContext.terminal)
} else {
val confirmed = confirm(
text = "Would you like to change the currently stored token?",
default = true
)
val confirmed = confirm(text = "Would you like to change the currently stored token?", default = true)
if (confirmed == true) {
tokenStore.promptForToken(currentContext.terminal).also { tokenStore.putToken(it) }
currentContext.terminal.success("Token changed successfully")
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/data/GitHubImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class GitHubImpl : KoinComponent {
val github: Deferred<GitHub> = CoroutineScope(Dispatchers.IO).async {
GitHubBuilder()
.withConnector(KtorGitHubConnector(get<Http>().client))
.withOAuthToken(get<TokenStore>().token.await())
.withOAuthToken(get<TokenStore>().token)
.build()
}
private val sharedManifestData: SharedManifestData by inject()
Expand Down
9 changes: 9 additions & 0 deletions src/main/kotlin/data/shared/PackageIdentifier.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,21 @@ import org.koin.core.component.inject
import schemas.Schema
import schemas.SchemasImpl
import schemas.data.InstallerSchema
import token.TokenStore
import java.io.IOException
import kotlin.system.exitProcess

object PackageIdentifier : KoinComponent {
private val sharedManifestData: SharedManifestData by inject()
private lateinit var installerSchema: InstallerSchema
private val tokenStore: TokenStore by inject()

suspend fun Terminal.packageIdentifierPrompt(packageIdentifierParameter: String? = null) {
val schemasImpl: SchemasImpl = get()
if (packageIdentifierParameter == null) {
if (tokenStore.token == null) {
tokenStore.promptForToken(this)
}
println(colors.brightGreen(identifierInfo))
info(example)
sharedManifestData.packageIdentifier = prompt(
Expand All @@ -45,6 +50,10 @@ object PackageIdentifier : KoinComponent {
?: ConversionResult.Valid(input.trim())
}
) ?: exitProcess(ExitCode.CtrlC.code)
if (!tokenStore.isTokenValid.await()) {
println()
tokenStore.invalidTokenPrompt(this)
}
sharedManifestData.latestVersion = getLatestVersion(sharedManifestData.packageIdentifier)
println()
} else {
Expand Down
45 changes: 18 additions & 27 deletions src/main/kotlin/token/TokenStore.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,51 +17,42 @@ import kotlin.system.exitProcess
class TokenStore {
private val credentialStore = StorageProvider.getTokenStorage()
?: throw UnsupportedOperationException("Could not find secure token storage for the current operating system")
var token: Deferred<String> = CoroutineScope(Dispatchers.IO).async { getToken(Terminal()) }
var storedToken = credentialStore[credentialKey]

private suspend fun getToken(terminal: Terminal): String {
return if (credentialStore[credentialKey] == null) {
promptForToken(terminal).also { putToken(it) }
} else {
val credentialToken = credentialStore[credentialKey]?.value ?: ""
val (tokenValid, ioException) = checkIfTokenValid(credentialToken)
if (tokenValid) {
credentialToken
} else {
terminal.warning(ioException ?: "Token is invalid. Please enter a new token.")
promptForToken(terminal).also { putToken(it) }
}
}
}
private var storedToken = credentialStore[credentialKey]
val token: String?
get() = storedToken?.value
val isTokenValid: Deferred<Boolean> = CoroutineScope(Dispatchers.IO).async { checkIfTokenValid(storedToken?.value) }

suspend fun putToken(tokenString: String) = coroutineScope {
credentialStore.add(credentialKey, Token(tokenString))
token = async { tokenString }
storedToken = Token(tokenString)
}

fun promptForToken(terminal: Terminal): String {
suspend fun promptForToken(terminal: Terminal): String {
return terminal.prompt(
prompt = terminal.colors.brightGreen("Please enter your GitHub personal access token"),
convert = {
val (tokenValid, ioException) = checkIfTokenValid(it)
if (tokenValid) {
if (checkIfTokenValid(it)) {
ConversionResult.Valid(it)
} else {
ConversionResult.Invalid(ioException?.message ?: "Invalid token. Please try again.")
ConversionResult.Invalid("Invalid token. Please try again.")
}
}
) ?: exitProcess(ExitCode.CtrlC.code)
)?.also { putToken(it) } ?: exitProcess(ExitCode.CtrlC.code)
}

private fun checkIfTokenValid(tokenString: String?): Pair<Boolean, IOException?> {
private fun checkIfTokenValid(tokenString: String?): Boolean {
return try {
GitHubBuilder().withOAuthToken(tokenString).build().isCredentialValid to null
} catch (ioException: IOException) {
false to ioException
GitHubBuilder().withOAuthToken(tokenString).build().isCredentialValid
} catch (_: IOException) {
false
}
}

suspend fun invalidTokenPrompt(terminal: Terminal) {
terminal.warning("Token is invalid. Please enter a new token.")
promptForToken(terminal).also { putToken(it) }
}

companion object {
private const val credentialKey = "komac/github-access-token"
}
Expand Down

0 comments on commit a197424

Please sign in to comment.