diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dc9797a..37030e3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,7 +50,7 @@ jobs: - name: Upload to Sonatype if: github.event_name == 'push' && github.ref == 'refs/heads/main' && matrix.java == '17' run: | - ./gradlew publishToMavenCentral --no-configuration-cache -PmavenCentralUsername=${ORG_GRADLE_PROJECT_mavenCentralUsername} -PmavenCentralPassword=${ORG_GRADLE_PROJECT_mavenCentralPassword} + ./gradlew publishToMavenCentral --no-configuration-cache -PmavenCentralUsername="${ORG_GRADLE_PROJECT_mavenCentralUsername}" -PmavenCentralPassword="${ORG_GRADLE_PROJECT_mavenCentralPassword}" env: ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.MAVEN_GPG_KEYID }} @@ -58,11 +58,9 @@ jobs: ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.SONATYPE_USERNAME }} ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.SONATYPE_PASSWORD }} - - name: Upload coverage to Qlty - if: matrix.java == '25' - uses: qltysh/qlty-action/coverage@a19242102d17e497f437d7466aa01b528537e899 # v2.2.0 - with: - token: ${{ secrets.QLTY_COVERAGE_TOKEN }} - format: jacoco - add-prefix: sshlib/src/main/kotlin/ - files: ${{ github.workspace }}/build/reports/kover/report.xml + - name: Run SonarCloud analysis + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + if: "${{ matrix.java == '25' && env.SONAR_TOKEN != '' }}" + run: ./gradlew :sshlib:sonar -Dsonar.projectVersion=${{ github.sha }} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index edf2982..d3ac2b4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -21,6 +21,7 @@ publish = "0.36.0" release = "3.1.0" kover = "0.9.8" cyclonedx = "3.2.4" +sonarqube = "7.3.0.8198" [libraries] kaitai-runtime = { module = "io.kaitai:kaitai-struct-runtime", version.ref = "kaitai" } @@ -52,3 +53,4 @@ publish = { id = "com.vanniktech.maven.publish", version.ref = "publish" } release = { id = "net.researchgate.release", version.ref = "release" } kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" } cyclonedx = { id = "org.cyclonedx.bom", version.ref = "cyclonedx" } +sonarqube = { id = "org.sonarqube", version.ref = "sonarqube" } diff --git a/protocol/build.gradle.kts b/protocol/build.gradle.kts index 6adeb6a..cf75aec 100644 --- a/protocol/build.gradle.kts +++ b/protocol/build.gradle.kts @@ -44,9 +44,12 @@ abstract class KaitaiTask : JavaExec() { File(outputDirPath.get()).mkdirs() args = listOf( "--read-write", - "--target", "java", - "--outdir", outputDirPath.get(), - "--java-package", javaPackage.get() + "--target", + "java", + "--outdir", + outputDirPath.get(), + "--java-package", + javaPackage.get(), ) + ksyFiles.files.map { it.absolutePath } super.exec() } @@ -83,7 +86,7 @@ java { } } -val gitHubUrl = "https://github.com/kruton/ssh-proto" +val gitHubUrl = "https://github.com/connectbot/cbssh" dokka { moduleName.set("ConnectBot SSH Protocol Messages") @@ -125,8 +128,8 @@ mavenPublishing { pom { name.set("protocol") - description.set("ConnectBot's SSH protocol messages in Kaitai Struct.") - inceptionYear.set("2025") + description.set("Protocol messages for ConnectBot SSH client library") + inceptionYear.set("2019") url.set(gitHubUrl) licenses { license { diff --git a/sshlib/build.gradle.kts b/sshlib/build.gradle.kts index d540601..3405f48 100644 --- a/sshlib/build.gradle.kts +++ b/sshlib/build.gradle.kts @@ -24,6 +24,7 @@ plugins { alias(libs.plugins.metalava) alias(libs.plugins.kover) alias(libs.plugins.cyclonedx) + alias(libs.plugins.sonarqube) `java-library` } @@ -80,7 +81,7 @@ kotlin { } } -val gitHubUrl = "https://github.com/kruton/ssh-proto" +val gitHubUrl = "https://github.com/connectbot/cbssh" dokka { moduleName.set("ConnectBot SSH Library") @@ -122,8 +123,8 @@ mavenPublishing { pom { name.set("sshlib") - description.set("ConnectBot's SSH library written with Kotlin suspend functions.") - inceptionYear.set("2025") + description.set("ConnectBot SSH Client Library") + inceptionYear.set("2019") url.set(gitHubUrl) licenses { license { @@ -146,3 +147,12 @@ mavenPublishing { } } } + +sonar { + properties { + property("sonar.projectKey", "connectbot_cbssh") + property("sonar.organization", "connectbot") + property("sonar.host.url", "https://sonarcloud.io") + property("sonar.coverage.jacoco.xmlReportPaths", "build/reports/kover/report.xml") + } +} diff --git a/sshlib/src/main/kotlin/org/connectbot/sshlib/crypto/ChaCha20ParamFactory.kt b/sshlib/src/main/kotlin/org/connectbot/sshlib/crypto/ChaCha20ParamFactory.kt index e523b3b..3abbc63 100644 --- a/sshlib/src/main/kotlin/org/connectbot/sshlib/crypto/ChaCha20ParamFactory.kt +++ b/sshlib/src/main/kotlin/org/connectbot/sshlib/crypto/ChaCha20ParamFactory.kt @@ -1,6 +1,6 @@ /* * ConnectBot SSH Library - * Copyright 2025 Kenny Root + * Copyright 2025-2026 Kenny Root * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,7 +40,7 @@ internal object ChaCha20ParamFactory { val testParams = ctor.newInstance(testNonce, 0) as AlgorithmParameterSpec val testKeySpec = SecretKeySpec(testKey, "ChaCha20") - val testCipher = Cipher.getInstance("ChaCha20") + val testCipher = Cipher.getInstance("ChaCha20/None/NoPadding") testCipher.init(Cipher.DECRYPT_MODE, testKeySpec, testParams) useSpec = true diff --git a/sshlib/src/main/kotlin/org/connectbot/sshlib/crypto/ChaCha20Poly1305Cipher.kt b/sshlib/src/main/kotlin/org/connectbot/sshlib/crypto/ChaCha20Poly1305Cipher.kt index 0a613b6..d0d20fe 100644 --- a/sshlib/src/main/kotlin/org/connectbot/sshlib/crypto/ChaCha20Poly1305Cipher.kt +++ b/sshlib/src/main/kotlin/org/connectbot/sshlib/crypto/ChaCha20Poly1305Cipher.kt @@ -1,6 +1,6 @@ /* * ConnectBot SSH Library - * Copyright 2025 Kenny Root + * Copyright 2025-2026 Kenny Root * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,6 +35,8 @@ internal class ChaCha20Poly1305Cipher(private val key: ByteArray) : PacketAead { const val KEY_SIZE = 64 const val TAG_SIZE = 16 const val BLOCK_SIZE = 8 + const val KEYSPEC_ALGO = "ChaCha20" + const val CIPHER_ALGO = "ChaCha20/None/NoPadding" } override val tagLength: Int = TAG_SIZE @@ -58,12 +60,12 @@ internal class ChaCha20Poly1305Cipher(private val key: ByteArray) : PacketAead { init { require(key.size == KEY_SIZE) { "ChaCha20-Poly1305 requires 64 bytes of key material" } - mainKeySpec = SecretKeySpec(key, 0, 32, "ChaCha20") - headerKeySpec = SecretKeySpec(key, 32, 32, "ChaCha20") + mainKeySpec = SecretKeySpec(key, 0, 32, KEYSPEC_ALGO) + headerKeySpec = SecretKeySpec(key, 32, 32, KEYSPEC_ALGO) - headerCipher = Cipher.getInstance("ChaCha20") - polyKeyCipher = Cipher.getInstance("ChaCha20") - payloadCipher = Cipher.getInstance("ChaCha20") + headerCipher = Cipher.getInstance(CIPHER_ALGO) + polyKeyCipher = Cipher.getInstance(CIPHER_ALGO) + payloadCipher = Cipher.getInstance(CIPHER_ALGO) } private fun updateNonce(seqNum: Long) {