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:

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