En este post voy a documentar cómo compilar el firmador de licencias para el plugin HTTP a ESC POS Bluetooth.
Primero:
sudo dnf install java-17-openjdk java-17-openjdk-devel
Luego:
curl -s https://get.sdkman.io | bash`
source "$HOME/.sdkman/bin/sdkman-init.sh"
sdk install kotlin
Compilando
Compilamos con:
kotlinc server2.kt -cp gson-2.11.0.jar -include-runtime -d server.jar
Y como se llama server2
la clase se llamará Server2Kt. Lo ejecutamos con:
java -cp "server.jar:gson-2.11.0.jar" Server2Kt
Si quisiéramos en segundo plano:
java -cp "server.jar:gson-2.11.0.jar" Server2Kt >> ~/log_kt.log 2>&1
Código fuente y dependencias
Tenemos entonces:
- gson-2.11.0.jar (descargable desde https://repo1.maven.org/maven2/com/google/code/gson/gson/2.11.0/gson-2.11.0.jar)
- servidor.kt
El código del servidor es el siguiente:
import com.google.gson.Gson
import com.google.gson.annotations.SerializedName
import com.sun.net.httpserver.HttpServer
import java.net.InetSocketAddress
import java.nio.charset.StandardCharsets
import java.security.KeyFactory
import java.security.PrivateKey
import java.security.Signature
import java.security.spec.PKCS8EncodedKeySpec
import java.util.Base64
const val PASSWORD = "123"
data class RequestData(
@SerializedName("claveApi") val claveApi: String,
@SerializedName("fechaInicio") val fechaInicio: String,
@SerializedName("fechaFin") val fechaFin: String,
@SerializedName("clavePrivada") val clavePrivada: String,
@SerializedName("contraseña") val contraseña: String
)
val gson = Gson()
fun firmarMensaje(mensaje: String, clavePrivada: PrivateKey): String {
val firma = Signature.getInstance("SHA256withRSA")
firma.initSign(clavePrivada)
firma.update(mensaje.toByteArray())
return Base64.getEncoder().encodeToString(firma.sign())
}
fun obtenerClavePrivada(clavePrivadaBase64: String): PrivateKey {
val claveBytes = Base64.getDecoder().decode(clavePrivadaBase64)
val spec = PKCS8EncodedKeySpec(claveBytes)
return KeyFactory.getInstance("RSA").generatePrivate(spec)
}
fun main() {
val server = HttpServer.create(InetSocketAddress(7777), 0)
server.createContext("/") { exchange ->
if (exchange.requestMethod.equals("POST", ignoreCase = true)) {
val body = exchange.requestBody.bufferedReader().readText()
val data = gson.fromJson(body, RequestData::class.java)
if (data.contraseña != PASSWORD) {
val resp = "Contraseña incorrecta"
exchange.sendResponseHeaders(403, resp.length.toLong())
exchange.responseBody.use { it.write(resp.toByteArray()) }
return@createContext
}
val mensaje = "${data.claveApi}__${data.fechaInicio}__${data.fechaFin}"
val firma = firmarMensaje(mensaje, obtenerClavePrivada(data.clavePrivada))
val resultado = "$mensaje###$firma"
val resultadoBase64 = Base64.getEncoder().encodeToString(resultado.toByteArray(StandardCharsets.UTF_8))
exchange.sendResponseHeaders(200, resultadoBase64.length.toLong())
exchange.responseBody.use { it.write(resultadoBase64.toByteArray()) }
} else {
exchange.sendResponseHeaders(405, -1)
}
}
server.executor = null
server.start()
println("Servidor iniciado en http://localhost:7777")
}
Compilamos:
kotlinc servidor.kt -cp gson-2.11.0.jar -include-runtime -d servidor_kotlin.jar
Eso nos dará como resultado el archivo servidor_kotlin.jar. Lo ejecutamos así:
java -cp "servidor_kotlin.jar:gson-2.11.0.jar" ServidorKt
También se puede en segundo plano:
java -cp "servidor_kotlin.jar:gson-2.11.0.jar" ServidorKt >> ~/firmadores/kotlin/log.log 2>&1 &
Las versiones son:
parzibyte@server[~/firmadores/kotlin]$ kotlinc -version
info: kotlinc-jvm 2.2.10 (JRE 17.0.16+8-LTS)
parzibyte@server[~/firmadores/kotlin]$ java --version
openjdk 17.0.16 2025-07-15 LTS
OpenJDK Runtime Environment (Red_Hat-17.0.16.0.8-1) (build 17.0.16+8-LTS)
OpenJDK 64-Bit Server VM (Red_Hat-17.0.16.0.8-1) (build 17.0.16+8-LTS, mixed mode, sharing)
parzibyte@server[~/firmadores/kotlin]$
Para usarlo le enviamos la clave privada limpia sin -----BEGIN PUBLIC KEY-----
, -----END PUBLIC KEY-----
ni saltos de línea
Si el post ha sido de tu agrado te invito a que me sigas para saber cuando haya escrito un nuevo post, haya
actualizado algún sistema o publicado un nuevo software.
Facebook
| X
| Instagram
| Telegram |
También estoy a tus órdenes para cualquier contratación en mi página de contacto