Skip to content

Commit

Permalink
Merge pull request #101 from bshtv/maven-repositories-with-auth-support
Browse files Browse the repository at this point in the history
Maven repositories with auth support
  • Loading branch information
ligee authored Mar 21, 2022
2 parents d28c768 + 4c76da2 commit 8982e2a
Show file tree
Hide file tree
Showing 5 changed files with 289 additions and 3 deletions.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,17 @@ mvn -Dkotlin.version=1.4.10 -DskipTests package
To start the shell, run `bin/ki.sh` on Linux and macOS. On Windows, use `bin\ki.bat` instead.

To exit the shell, type `:q` or `:quit`.

## Adding maven repositories that require auth

The following options are supported:

```bash
:repository https://myrepo.org username=user password=pwd
:repository https://myrepo.org username:user password:pwd

:repository https:myrepo.org ./path/to/file
# properties file should contain
# username=john
# password=johnpwd
```
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,20 @@ import org.jetbrains.kotlinx.ki.shell.Command
import org.jetbrains.kotlinx.ki.shell.Plugin
import org.jetbrains.kotlinx.ki.shell.Shell
import org.jetbrains.kotlinx.ki.shell.configuration.ReplConfiguration
import java.io.File
import java.util.Properties
import kotlin.script.experimental.api.*
import kotlin.script.experimental.dependencies.*
import kotlin.script.experimental.dependencies.maven.MavenDependenciesResolver
import kotlin.script.experimental.jvm.JvmDependency

data class RepoCredentials(val username: String, val password: String)

private const val CREDENTIALS_USERNAME_PROPERTY = "username"
private const val CREDENTIALS_PASSWORD_PROPERTY = "password"
private const val MANDATORY_REPO_COMMAND_ARGS = 2
private const val OPTIONAL_REPO_COMMAND_ARGS = 2

class DependenciesPlugin : Plugin {

inner class DependsOnCommand(conf: ReplConfiguration): BaseCommand() {
Expand All @@ -34,10 +43,79 @@ class DependenciesPlugin : Plugin {

override val params = "<repository coordinates>"

private val emptyRepoCredentials = RepoCredentials("", "")

override fun execute(line: String): Command.Result {
val p = line.indexOf(' ')
val repo = line.substring(p + 1).trim()
return Command.Result.RunSnippets(listOf("@file:Repository(\"$repo\")"))
val args = line.split(' ')

return Command.Result.RunSnippets(buildSnippet(args))
}

private fun buildSnippet(args: List<String>): List<String> {
val repo = if (args.size > 1) args[1].trim() else ""

if (args.size <= MANDATORY_REPO_COMMAND_ARGS) {
return listOf("@file:Repository(\"$repo\")")
}

val (username, password) = getCredentials(
args.drop(MANDATORY_REPO_COMMAND_ARGS).take(OPTIONAL_REPO_COMMAND_ARGS)
)

return listOf("@file:Repository(\"$repo\", options = [\"username=$username\", \"password=$password\"])")
}

private fun getCredentials(args: List<String>): RepoCredentials {
return when (args.size) {
2 -> buildCredentialsFromUsernameAndPassword(args)
1 -> buildCredentialsFromFile(args)
else -> emptyRepoCredentials
}
}

private fun buildCredentialsFromUsernameAndPassword(args: List<String>): RepoCredentials {
val props = Properties()

return args.joinToString("\n").reader().use { reader ->
props.load(reader)

RepoCredentials(
props.getProperty(CREDENTIALS_USERNAME_PROPERTY, ""),
props.getProperty(CREDENTIALS_PASSWORD_PROPERTY, "")
)
}
}

private fun buildCredentialsFromFile(args: List<String>): RepoCredentials {
val path = args[0]
val credFile = File(path)

return when {
!credFile.exists() -> {
println("File $path not found.")
emptyRepoCredentials
}
!credFile.canRead() -> {
println("Cannot open $path.")
emptyRepoCredentials
}
else -> {
try {
credFile.reader().use { reader ->
val props = Properties()
props.load(reader)

RepoCredentials(
props.getProperty(CREDENTIALS_USERNAME_PROPERTY, ""),
props.getProperty(CREDENTIALS_PASSWORD_PROPERTY, "")
)
}
} catch (e: Exception) {
println(e.message)
emptyRepoCredentials
}
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
package org.jetbrains.kotlinx.ki.shell.plugins

import junit.framework.TestCase
import org.jetbrains.kotlinx.ki.shell.Command
import org.jetbrains.kotlinx.ki.shell.configuration.ReplConfigurationBase
import org.junit.Test

class DependenciesPluginTest : TestCase() {

private val repoCommand = DependenciesPlugin().RepositoryCommand(object : ReplConfigurationBase() {})

private fun extractSnippetFromCommand(command: Command.Result.RunSnippets): String {
return command.snippetsToRun.toList()[0]
}

@Test
fun testWhenRepoUrlNotPassed() {
val command = repoCommand.execute(":repository ") as Command.Result.RunSnippets

assertEquals("@file:Repository(\"\")", extractSnippetFromCommand(command))
}

@Test
fun testWhenRepoUrlPassed() {
val command = repoCommand.execute(":repository https://packages.team/path/to/maven")
as Command.Result.RunSnippets

assertEquals(
"@file:Repository(\"https://packages.team/path/to/maven\")",
extractSnippetFromCommand(command)
)
}

@Test
fun testUsernameAndPasswordEqualSeparator() {
val command = repoCommand.execute(":repository https://packages.team/path/to/maven username=user password=pass")
as Command.Result.RunSnippets

assertEquals(
"@file:Repository(\"https://packages.team/path/to/maven\", options = [\"username=user\", \"password=pass\"])",
extractSnippetFromCommand(command)
)
}

@Test
fun testUsernameOnlyEqualSeparator() {
val command = repoCommand.execute(":repository https://packages.team/path/to/maven username=user barepassword")
as Command.Result.RunSnippets

assertEquals(
"@file:Repository(\"https://packages.team/path/to/maven\", options = [\"username=user\", \"password=\"])",
extractSnippetFromCommand(command)
)
}

@Test
fun testPasswordOnlyEqualSeparator() {
val command = repoCommand.execute(":repository https://packages.team/path/to/maven bareusername password=pass")
as Command.Result.RunSnippets

assertEquals(
"@file:Repository(\"https://packages.team/path/to/maven\", options = [\"username=\", \"password=pass\"])",
extractSnippetFromCommand(command)
)
}

@Test
fun testUsernameWithEqualEqualSeparator() {
val command = repoCommand.execute(":repository https://packages.team/path/to/maven username=my=user password=pass")
as Command.Result.RunSnippets

assertEquals(
"@file:Repository(\"https://packages.team/path/to/maven\", options = [\"username=my=user\", \"password=pass\"])",
extractSnippetFromCommand(command)
)
}

@Test
fun testPasswordWithEqualEqualSeparator() {
val command = repoCommand.execute(":repository https://packages.team/path/to/maven username=user password=my=pass")
as Command.Result.RunSnippets

assertEquals(
"@file:Repository(\"https://packages.team/path/to/maven\", options = [\"username=user\", \"password=my=pass\"])",
extractSnippetFromCommand(command)
)
}

@Test
fun testUsernameAndPasswordSemicolonSeparator() {
val command = repoCommand.execute(":repository https://packages.team/path/to/maven username:user password:pass")
as Command.Result.RunSnippets

assertEquals(
"@file:Repository(\"https://packages.team/path/to/maven\", options = [\"username=user\", \"password=pass\"])",
extractSnippetFromCommand(command)
)
}

@Test
fun testUsernameOnlySemicolonSeparator() {
val command = repoCommand.execute(":repository https://packages.team/path/to/maven username:user barepassword")
as Command.Result.RunSnippets

assertEquals(
"@file:Repository(\"https://packages.team/path/to/maven\", options = [\"username=user\", \"password=\"])",
extractSnippetFromCommand(command)
)
}

@Test
fun testPasswordOnlySemicolonSeparator() {
val command = repoCommand.execute(":repository https://packages.team/path/to/maven bareusername password:pass")
as Command.Result.RunSnippets

assertEquals(
"@file:Repository(\"https://packages.team/path/to/maven\", options = [\"username=\", \"password=pass\"])",
extractSnippetFromCommand(command)
)
}

@Test
fun testUsernameWithSemicolonSemicolonSeparator() {
val command = repoCommand.execute(":repository https://packages.team/path/to/maven username:my:user password:pass")
as Command.Result.RunSnippets

assertEquals(
"@file:Repository(\"https://packages.team/path/to/maven\", options = [\"username=my:user\", \"password=pass\"])",
extractSnippetFromCommand(command)
)
}

@Test
fun testPasswordWithSemicolonSemicolonSeparator() {
val command = repoCommand.execute(":repository https://packages.team/path/to/maven username:user password:my:pass")
as Command.Result.RunSnippets

assertEquals(
"@file:Repository(\"https://packages.team/path/to/maven\", options = [\"username=user\", \"password=my:pass\"])",
extractSnippetFromCommand(command)
)
}

@Test
fun testFilenamePassed() {
val filePath = "./src/test/resources/valid.credentials"
val command = repoCommand.execute(":repository https://packages.team/path/to/maven $filePath")
as Command.Result.RunSnippets

assertEquals(
"@file:Repository(\"https://packages.team/path/to/maven\", options = [\"username=fileusername\", \"password=file password\"])",
extractSnippetFromCommand(command)
)
}

@Test
fun testNotFoundFilename() {
val filePath = "blabla"
val command = repoCommand.execute(":repository https://packages.team/path/to/maven $filePath")
as Command.Result.RunSnippets

assertEquals(
"@file:Repository(\"https://packages.team/path/to/maven\", options = [\"username=\", \"password=\"])",
extractSnippetFromCommand(command)
)
}

@Test
fun testMissingCredentialsFile() {
val filePath = "./src/test/resources/missing.credentials"
val command = repoCommand.execute(":repository https://packages.team/path/to/maven $filePath")
as Command.Result.RunSnippets

assertEquals(
"@file:Repository(\"https://packages.team/path/to/maven\", options = [\"username=\", \"password=\"])",
extractSnippetFromCommand(command)
)
}

@Test
fun testCredentialsFileIsDirectory() {
val filePath = "./src/test/resources"
val command = repoCommand.execute(":repository https://packages.team/path/to/maven $filePath")
as Command.Result.RunSnippets

assertEquals(
"@file:Repository(\"https://packages.team/path/to/maven\", options = [\"username=\", \"password=\"])",
extractSnippetFromCommand(command)
)
}
}
1 change: 1 addition & 0 deletions ki-shell/src/test/resources/missing.credentials
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
blabla
2 changes: 2 additions & 0 deletions ki-shell/src/test/resources/valid.credentials
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
username=fileusername
password=file password

0 comments on commit 8982e2a

Please sign in to comment.