diff --git a/JWTEmitter/src/org/tbasket/jwt/JwtGenerator.scala b/JWTEmitter/src/org/tbasket/jwt/JwtGenerator.scala index f7ad17a..88af336 100644 --- a/JWTEmitter/src/org/tbasket/jwt/JwtGenerator.scala +++ b/JWTEmitter/src/org/tbasket/jwt/JwtGenerator.scala @@ -1,6 +1,7 @@ package org.tbasket.jwt import pdi.jwt.* +import pdi.jwt.algorithms.JwtAsymmetricAlgorithm import zio.* import zio.http.{Request, Response} import zio.json.* @@ -8,28 +9,28 @@ import zio.json.ast.Json import java.lang.System.currentTimeMillis import java.nio.file.* -import java.security.Key +import java.security.{Key, PrivateKey} import java.security.interfaces.RSAPrivateKey import java.security.spec.PKCS8EncodedKeySpec import java.util.concurrent.TimeUnit import java.util.{Date, UUID} import javax.crypto.SecretKey -import scala.concurrent.duration +import java.time.Duration -object JwtGenerator: - - private val ExpirationDate = Duration(15, TimeUnit.DAYS).toMillis - private val Key = Files.readString(Path.of("id_rsa")) +class JwtGenerator(tokenLifespan: Duration, key: PrivateKey, algorithm: JwtAsymmetricAlgorithm): private def claims(content: String) = JwtClaim( - expiration = Some(currentTimeMillis() + ExpirationDate), + expiration = Some(currentTimeMillis() + tokenLifespan.toMillis), issuedAt = Some(currentTimeMillis()), jwtId = Some(UUID.randomUUID().toString), content = content ) + def generateTokenResponse(request: Request): Task[Response] = for claims <- request.body.asString.map(claims) - jwt <- ZIO.attempt(JwtZIOJson.encode(claims, Key, JwtAlgorithm.RS256)) + jwt <- ZIO.attempt(JwtZIOJson.encode(claims, key, algorithm)).catchAll(e => { + ZIO.attempt(e.printStackTrace()).as("error") + }) yield Response.json(jwt) diff --git a/JWTEmitter/src/org/tbasket/jwt/Main.scala b/JWTEmitter/src/org/tbasket/jwt/Main.scala index 67d98ee..48a2739 100644 --- a/JWTEmitter/src/org/tbasket/jwt/Main.scala +++ b/JWTEmitter/src/org/tbasket/jwt/Main.scala @@ -1,12 +1,18 @@ package org.tbasket.jwt +import pdi.jwt.JwtAlgorithm +import pdi.jwt.algorithms.JwtUnknownAlgorithm import zio.* -import zio.stream.* import zio.http.* import zio.http.ServerConfig.LeakDetectionLevel import zio.http.model.{Method, Status} +import zio.stream.* -import java.nio.file.Files +import java.nio.file.{Files, Path} +import java.security.{KeyFactory, PrivateKey} +import java.security.spec.{KeySpec, PKCS8EncodedKeySpec, RSAPrivateKeySpec, X509EncodedKeySpec} +import java.time.Duration +import scala.util.chaining.scalaUtilChainingOps object Main extends ZIOAppDefault: @@ -18,11 +24,9 @@ object Main extends ZIOAppDefault: case Some(oorPort) => ZIO.dieMessage(s"'$oorPort' is out of range.'") case None => ZIO.dieMessage("given argument is not a valid integer") - private val app = Http.collectZIO[Request][Any, Throwable, Response] { + private val app = Http.collectZIO[Request] { case r @ Method.GET -> _ / "jwt" => - ZIO.attempt(JwtGenerator) - .flatMap(_.generateTokenResponse(r)) - .catchAll(e => ZIO.die(e)) + ZIO.serviceWithZIO[JwtGenerator](_.generateTokenResponse(r)) case _ => ZIO.succeed(Response(status = Status.NotFound)) } @@ -32,11 +36,15 @@ object Main extends ZIOAppDefault: .port(port) .leakDetection(LeakDetectionLevel.PARANOID) + val pbytes = Files.readAllBytes(Path.of("/home/maxime/tmp/key.pcqks")) + val key: PrivateKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(pbytes)) + + val generator = new JwtGenerator(Duration.ofDays(15), key, JwtAlgorithm.RS256) val configLayer = ServerConfig.live(config) (Server.install( app ) *> Console.printLine(s"JWT AppToken open on port $port") *> ZIO.never) - .provide(configLayer, Server.live) + .provide(configLayer, Server.live, ZLayer.succeed(generator)) val run = ZIO.serviceWithZIO[ZIOAppArgs](args => port(args.getArgs))