|
|
@ -10,20 +10,47 @@ import zio.stream.*
|
|
|
|
|
|
|
|
|
|
|
|
import java.nio.file.{Files, Path}
|
|
|
|
import java.nio.file.{Files, Path}
|
|
|
|
import java.security.{KeyFactory, PrivateKey}
|
|
|
|
import java.security.{KeyFactory, PrivateKey}
|
|
|
|
import java.security.spec.{KeySpec, PKCS8EncodedKeySpec, RSAPrivateKeySpec, X509EncodedKeySpec}
|
|
|
|
import java.security.spec.{
|
|
|
|
|
|
|
|
KeySpec,
|
|
|
|
|
|
|
|
PKCS8EncodedKeySpec,
|
|
|
|
|
|
|
|
RSAPrivateKeySpec,
|
|
|
|
|
|
|
|
X509EncodedKeySpec
|
|
|
|
|
|
|
|
}
|
|
|
|
import java.time.Duration
|
|
|
|
import java.time.Duration
|
|
|
|
import scala.util.chaining.scalaUtilChainingOps
|
|
|
|
import scala.util.chaining.scalaUtilChainingOps
|
|
|
|
|
|
|
|
|
|
|
|
object Main extends ZIOAppDefault:
|
|
|
|
object Main extends ZIOAppDefault:
|
|
|
|
|
|
|
|
|
|
|
|
private def port(args: Chunk[String]): Task[Int] =
|
|
|
|
private val KeyFactory = java.security.KeyFactory.getInstance("RSA")
|
|
|
|
args.headOption match
|
|
|
|
|
|
|
|
|
|
|
|
private def parsePort(port: Option[String]): Task[Int] =
|
|
|
|
|
|
|
|
port match
|
|
|
|
case None => ZIO.dieMessage("Must provide the port argument")
|
|
|
|
case None => ZIO.dieMessage("Must provide the port argument")
|
|
|
|
case Some(head) => head.toIntOption match
|
|
|
|
case Some(port) => port.toIntOption match
|
|
|
|
case Some(port) if port > 0 && port < 65536 => ZIO.succeed(port)
|
|
|
|
case Some(port) if port > 0 && port < 65536 => ZIO.succeed(port)
|
|
|
|
case Some(oorPort) => ZIO.dieMessage(s"'$oorPort' is out of range.'")
|
|
|
|
case Some(oorPort) => ZIO.dieMessage(s"'$oorPort' is out of range.'")
|
|
|
|
case None => ZIO.dieMessage("given argument is not a valid integer")
|
|
|
|
case None => ZIO.dieMessage("given argument is not a valid integer")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private def loadKey(keyFile: Option[String]): Task[PrivateKey] =
|
|
|
|
|
|
|
|
keyFile match
|
|
|
|
|
|
|
|
case None => ZIO.dieMessage("Key RSA File not given")
|
|
|
|
|
|
|
|
case Some(file) =>
|
|
|
|
|
|
|
|
ZIO
|
|
|
|
|
|
|
|
.attempt(Path.of(file))
|
|
|
|
|
|
|
|
.mapAttempt(Files.readAllBytes)
|
|
|
|
|
|
|
|
.mapAttempt(new PKCS8EncodedKeySpec(_))
|
|
|
|
|
|
|
|
.mapAttempt(KeyFactory.generatePrivate)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private def parseArgs(args: Chunk[String]): Task[(Int, PrivateKey)] =
|
|
|
|
|
|
|
|
def groups = args.toList.grouped(2)
|
|
|
|
|
|
|
|
val keyFile = groups.collectFirst {
|
|
|
|
|
|
|
|
case ("-k" | "--key") :: value :: Nil => value
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
val port = groups.collectFirst {
|
|
|
|
|
|
|
|
case ("-p" | "--port") :: value :: Nil => value
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
parsePort(port) <&> loadKey(keyFile)
|
|
|
|
|
|
|
|
|
|
|
|
private val app = Http.collectZIO[Request] {
|
|
|
|
private val app = Http.collectZIO[Request] {
|
|
|
|
case r @ Method.GET -> _ / "jwt" =>
|
|
|
|
case r @ Method.GET -> _ / "jwt" =>
|
|
|
|
ZIO.serviceWithZIO[JwtGenerator](_.generateTokenResponse(r))
|
|
|
|
ZIO.serviceWithZIO[JwtGenerator](_.generateTokenResponse(r))
|
|
|
@ -31,15 +58,13 @@ object Main extends ZIOAppDefault:
|
|
|
|
ZIO.succeed(Response(status = Status.NotFound))
|
|
|
|
ZIO.succeed(Response(status = Status.NotFound))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private def startServer(port: Int) =
|
|
|
|
private def startServer(port: Int, key: PrivateKey) =
|
|
|
|
val config = ServerConfig.default
|
|
|
|
val config = ServerConfig.default
|
|
|
|
.port(port)
|
|
|
|
.port(port)
|
|
|
|
.leakDetection(LeakDetectionLevel.PARANOID)
|
|
|
|
.leakDetection(LeakDetectionLevel.PARANOID)
|
|
|
|
|
|
|
|
|
|
|
|
val pbytes = Files.readAllBytes(Path.of("/home/maxime/tmp/key.pcqks"))
|
|
|
|
val generator =
|
|
|
|
val key: PrivateKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(pbytes))
|
|
|
|
new JwtGenerator(Duration.ofDays(15), key, JwtAlgorithm.RS256)
|
|
|
|
|
|
|
|
|
|
|
|
val generator = new JwtGenerator(Duration.ofDays(15), key, JwtAlgorithm.RS256)
|
|
|
|
|
|
|
|
val configLayer = ServerConfig.live(config)
|
|
|
|
val configLayer = ServerConfig.live(config)
|
|
|
|
(Server.install(
|
|
|
|
(Server.install(
|
|
|
|
app
|
|
|
|
app
|
|
|
@ -47,5 +72,5 @@ object Main extends ZIOAppDefault:
|
|
|
|
.provide(configLayer, Server.live, ZLayer.succeed(generator))
|
|
|
|
.provide(configLayer, Server.live, ZLayer.succeed(generator))
|
|
|
|
|
|
|
|
|
|
|
|
val run =
|
|
|
|
val run =
|
|
|
|
ZIO.serviceWithZIO[ZIOAppArgs](args => port(args.getArgs))
|
|
|
|
ZIO.serviceWithZIO[ZIOAppArgs](args => parseArgs(args.getArgs))
|
|
|
|
.flatMap(startServer)
|
|
|
|
.flatMap(startServer)
|
|
|
|