Skip to content

Commit 65eb9bf

Browse files
committed
Initial commit: Log Managing System with Kotlin client and Go API
1 parent ba417ac commit 65eb9bf

8 files changed

Lines changed: 1110 additions & 348 deletions

File tree

LogManagingApi/logmanagingapi.go

Lines changed: 250 additions & 89 deletions
Large diffs are not rendered by default.
Lines changed: 68 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,83 @@
11
plugins {
2-
id("java-library")
3-
id("org.jetbrains.kotlin.jvm")
2+
kotlin("jvm") version "1.9.21"
3+
kotlin("plugin.serialization") version "1.9.21"
4+
`maven-publish`
45
}
56

7+
group = "org.aria.danesh"
8+
version = "1.0.0"
9+
610
java {
7-
sourceCompatibility = JavaVersion.VERSION_17 // Or a higher version if needed
8-
targetCompatibility = JavaVersion.VERSION_17
11+
toolchain {
12+
languageVersion.set(JavaLanguageVersion.of(17))
13+
}
914
}
15+
1016
repositories {
1117
mavenCentral()
1218
}
1319

1420
dependencies {
15-
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") // Or jdk7 if needed
16-
implementation("org.json:json:20231013") // Add JSON dependency
17-
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3") // Coroutines core
18-
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.3") // Coroutines jdk8
19-
}
21+
// Kotlin
22+
implementation("org.jetbrains.kotlin:kotlin-stdlib:1.9.21")
23+
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
24+
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
2025

21-
tasks.test {
22-
useJUnitPlatform()
26+
// HTTP Client
27+
implementation("com.squareup.okhttp3:okhttp:4.12.0")
28+
29+
// Logging
30+
implementation("org.slf4j:slf4j-api:2.0.9")
31+
implementation("ch.qos.logback:logback-classic:1.4.14")
32+
33+
// Testing
34+
testImplementation("org.jetbrains.kotlin:kotlin-test:1.9.21")
35+
testImplementation("org.jetbrains.kotlin:kotlin-test-junit5:1.9.21")
36+
testImplementation("io.mockk:mockk:1.13.8")
2337
}
24-
kotlin {
25-
jvmToolchain(17)
38+
39+
tasks {
40+
compileKotlin {
41+
kotlinOptions {
42+
jvmTarget = "17"
43+
freeCompilerArgs = listOf("-opt-in=kotlin.RequiresOptIn")
44+
}
45+
}
46+
47+
compileJava {
48+
targetCompatibility = "17"
49+
}
50+
51+
test {
52+
useJUnitPlatform()
53+
}
54+
55+
jar {
56+
manifest {
57+
attributes(
58+
mapOf(
59+
"Implementation-Title" to project.name,
60+
"Implementation-Version" to project.version
61+
)
62+
)
63+
}
64+
}
2665
}
27-
tasks.build {
28-
exec {
29-
commandLine ("${rootDir}\\build.bat", "windows", "amd64", "LogManagingApi-windows-64.exe")
66+
67+
publishing {
68+
publications {
69+
create<MavenPublication>("maven") {
70+
from(components["java"])
71+
}
72+
}
73+
repositories {
74+
maven {
75+
name = "GitHubPackages"
76+
url = uri("https://maven.pkg.github.com/yourusername/LogManagingSystem")
77+
credentials {
78+
username = System.getenv("GITHUB_USERNAME")
79+
password = System.getenv("GITHUB_TOKEN")
80+
}
81+
}
3082
}
31-
// exec {
32-
// commandLine ("${rootDir}\\build.bat", "windows", "386", "LogManagingApi-windows-32.exe")
33-
// }
34-
// exec {
35-
// commandLine ("${rootDir}\\build.bat", "linux", "amd64", "LogManagingApi_linux_amd64")
36-
// }
37-
// exec {
38-
// commandLine ("${rootDir}\\build.bat", "linux", "386", "LogManagingApi_linux_386")
39-
// }
40-
// exec {
41-
// commandLine ("${rootDir}\\build.bat", "linux", "arm64", "LogManagingApi_linux_arm64")
42-
// }
43-
// exec {
44-
// commandLine ("${rootDir}\\build.bat", "linux", "arm", "LogManagingApi_linux_arm")
45-
// }
46-
// exec {
47-
// commandLine ("${rootDir}\\build.bat", "darwin", "amd64", "LogManagingApi_darwin_amd64")
48-
// }
49-
// exec {
50-
// commandLine("${rootDir}\\build.bat", "darwin", "arm64", "LogManagingApi_darwin_arm64")
51-
// }
5283
}

LogManagingKotlinLib/src/main/java/com/aria/danesh/logmanagingkotlinlib/LogManagingKotlinLib.kt renamed to LogManagingKotlinLib/src/main/kotlin/com/aria/danesh/logmanagingkotlinlib/LogManagingKotlinLib.kt

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,19 @@ import java.util.Base64
1212
import javax.crypto.Cipher
1313
import javax.crypto.spec.IvParameterSpec
1414
import javax.crypto.spec.SecretKeySpec
15-
import org.json.JSONObject
15+
import kotlinx.serialization.*
16+
import kotlinx.serialization.json.*
17+
18+
@Serializable
19+
data class LogData(
20+
val imel: String,
21+
val error: String
22+
)
23+
24+
@Serializable
25+
data class EncryptedRequest(
26+
val encrypted_data: String
27+
)
1628

1729
// LogManagingKotlinLib class for handling encrypted log sending.
1830
class LogManagingKotlinLib(
@@ -21,23 +33,24 @@ class LogManagingKotlinLib(
2133
private val password: String, // Password for basic authentication.
2234
private val encryptionKey: String // Encryption key.
2335
) {
36+
private val json = Json {
37+
ignoreUnknownKeys = true
38+
encodeDefaults = true
39+
}
2440

2541
// Sends an encrypted log message to the API.
2642
suspend fun sendEncryptedLog(imel: String, errorMessage: String): Result<String> = withContext(Dispatchers.IO) {
2743
try {
28-
// Create a JSON object with IMEL and error message.
29-
val jsonData = JSONObject().apply {
30-
put("imel", imel)
31-
put("error", errorMessage)
32-
}
44+
// Create a data object with IMEL and error message.
45+
val logData = LogData(imel, errorMessage)
46+
val jsonData = json.encodeToString(logData)
3347

3448
// Encrypt the JSON data.
35-
val encryptedData = encrypt(jsonData.toString(), encryptionKey)
49+
val encryptedData = encrypt(jsonData, encryptionKey)
3650

37-
// Create a JSON object with the encrypted data.
38-
val postData = JSONObject().apply {
39-
put("encrypted_data", encryptedData)
40-
}.toString()
51+
// Create the encrypted request object.
52+
val encryptedRequest = EncryptedRequest(encryptedData)
53+
val postData = json.encodeToString(encryptedRequest)
4154

4255
// Encode credentials for basic authentication.
4356
val credentials = "$username:$password"
@@ -62,18 +75,17 @@ class LogManagingKotlinLib(
6275
// Read the response from the input stream.
6376
BufferedReader(InputStreamReader(connection.inputStream)).use { reader ->
6477
val response = reader.readText()
65-
return@withContext Result.success(response) // Return success with the response.
78+
Result.success(response) // Return success with the response.
6679
}
6780
} else {
6881
// Handle error response.
6982
BufferedReader(InputStreamReader(connection.errorStream)).use { reader ->
7083
val errorResponse = reader.readText()
71-
return@withContext Result.failure(IOException("HTTP error: $responseCode, $errorResponse")) // Return failure with error details.
84+
Result.failure(IOException("HTTP error: $responseCode, $errorResponse")) // Return failure with error details.
7285
}
7386
}
74-
return@withContext Result.failure(IOException("Unexpected end of request")) // Return failure if no response is received.
7587
} catch (e: Exception) {
76-
return@withContext Result.failure(e) // Return failure for any exception.
88+
Result.failure(e) // Return failure for any exception.
7789
}
7890
}
7991

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
package org.aria.danesh.logmanagingkotlinlib
2+
3+
import org.slf4j.LoggerFactory
4+
import java.security.SecureRandom
5+
import javax.crypto.Cipher
6+
import javax.crypto.spec.IvParameterSpec
7+
import javax.crypto.spec.SecretKeySpec
8+
import java.util.Base64
9+
import java.security.MessageDigest
10+
11+
/**
12+
* Utility class for handling encryption operations.
13+
*/
14+
object EncryptionUtils {
15+
private val logger = LoggerFactory.getLogger(EncryptionUtils::class.java)
16+
private const val ALGORITHM = "AES/CFB/NoPadding"
17+
private const val KEY_ALGORITHM = "AES"
18+
private const val SALT_LENGTH = 16
19+
private const val IV_LENGTH = 16
20+
21+
/**
22+
* Encrypts the given data using AES-CFB encryption with a derived key.
23+
* @param data The data to encrypt
24+
* @param key The encryption key
25+
* @return Base64 encoded encrypted data
26+
*/
27+
fun encrypt(data: String, key: String): String {
28+
try {
29+
// Generate random salt
30+
val salt = generateRandomBytes(SALT_LENGTH)
31+
32+
// Generate random IV
33+
val iv = generateRandomBytes(IV_LENGTH)
34+
35+
// Derive key from password and salt
36+
val derivedKey = deriveKey(key, salt)
37+
38+
// Create cipher instance
39+
val cipher = Cipher.getInstance(ALGORITHM)
40+
val keySpec = SecretKeySpec(derivedKey, KEY_ALGORITHM)
41+
val ivSpec = IvParameterSpec(iv)
42+
43+
// Initialize cipher for encryption
44+
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec)
45+
46+
// Encrypt the data
47+
val encryptedData = cipher.doFinal(data.toByteArray())
48+
49+
// Combine salt, IV, and encrypted data
50+
val combined = ByteArray(salt.size + iv.size + encryptedData.size)
51+
System.arraycopy(salt, 0, combined, 0, salt.size)
52+
System.arraycopy(iv, 0, combined, salt.size, iv.size)
53+
System.arraycopy(encryptedData, 0, combined, salt.size + iv.size, encryptedData.size)
54+
55+
// Encode as Base64
56+
return Base64.getEncoder().encodeToString(combined)
57+
} catch (e: Exception) {
58+
logger.error("Encryption failed", e)
59+
throw LogManagingException("Encryption failed: ${e.message}", e)
60+
}
61+
}
62+
63+
/**
64+
* Decrypts the given encrypted data using AES-CFB decryption with a derived key.
65+
* @param encryptedData The Base64 encoded encrypted data
66+
* @param key The encryption key
67+
* @return Decrypted data
68+
*/
69+
fun decrypt(encryptedData: String, key: String): String {
70+
try {
71+
// Decode Base64
72+
val combined = Base64.getDecoder().decode(encryptedData)
73+
74+
// Extract salt, IV, and encrypted data
75+
val salt = combined.copyOfRange(0, SALT_LENGTH)
76+
val iv = combined.copyOfRange(SALT_LENGTH, SALT_LENGTH + IV_LENGTH)
77+
val data = combined.copyOfRange(SALT_LENGTH + IV_LENGTH, combined.size)
78+
79+
// Derive key from password and salt
80+
val derivedKey = deriveKey(key, salt)
81+
82+
// Create cipher instance
83+
val cipher = Cipher.getInstance(ALGORITHM)
84+
val keySpec = SecretKeySpec(derivedKey, KEY_ALGORITHM)
85+
val ivSpec = IvParameterSpec(iv)
86+
87+
// Initialize cipher for decryption
88+
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec)
89+
90+
// Decrypt the data
91+
val decryptedData = cipher.doFinal(data)
92+
93+
return String(decryptedData)
94+
} catch (e: Exception) {
95+
logger.error("Decryption failed", e)
96+
throw LogManagingException("Decryption failed: ${e.message}", e)
97+
}
98+
}
99+
100+
/**
101+
* Generates random bytes using SecureRandom.
102+
* @param length The length of the random bytes to generate
103+
* @return Array of random bytes
104+
*/
105+
private fun generateRandomBytes(length: Int): ByteArray {
106+
val bytes = ByteArray(length)
107+
SecureRandom().nextBytes(bytes)
108+
return bytes
109+
}
110+
111+
/**
112+
* Derives a key from the password and salt using SHA-256.
113+
* @param password The password
114+
* @param salt The salt
115+
* @return Derived key
116+
*/
117+
private fun deriveKey(password: String, salt: ByteArray): ByteArray {
118+
val md = MessageDigest.getInstance("SHA-256")
119+
val combined = password.toByteArray() + salt
120+
return md.digest(combined)
121+
}
122+
}

0 commit comments

Comments
 (0)