Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/message verification and tooling #202

Merged
merged 3 commits into from
Feb 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ inThisBuild(
// NO NEED ATM "-Ykind-projector"
) ++
// Because DeriveJson(Decoder/Encoder).gen[DidFail] exceeded maximal number of successive inlines (default is 32)
Seq("-Xmax-inlines", "38")
Seq("-Xmax-inlines", "42")

// ### commonSettings ###
// Compile / doc / sources := Nil,
Expand Down
16 changes: 11 additions & 5 deletions demo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,22 @@ docker build --tag scala_did_demo ./demo/
docker tag scala_did_demo registry.fly.io/scala-did-demo
# flyctl auth docker
docker push registry.fly.io/scala-did-demo
# 2024/02/05 +- 119.3MB
# 2023/11/15 +- 124.1MB
# 2023/10/28 +- 118.1MB
# 2023/10/20 +- 117.3MB
# 2023/09/24 +- 115.1MB
# +- 52MB
flyctl image update -a scala-did-demo
flyctl deploy ./demo/ -i registry.fly.io/scala-did-demo
```

## History of deployments

Size of the last docker layer:
- 2024/02/18 +- 121.2MB
- 2024/02/13 +- 120.8MB
- 2024/02/05 +- 119.3MB
- 2023/11/15 +- 124.1MB
- 2023/10/28 +- 118.1MB
- 2023/10/20 +- 117.3MB
- 2023/09/24 +- 115.1MB

## Others

Sort by file size
Expand Down
11 changes: 5 additions & 6 deletions demo/jvm/src/main/scala/fmgp/did/demo/AppServer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ import fmgp.did.comm.protocol._
import fmgp.did.method.peer.DidPeerResolver
import fmgp.did.method.hardcode.HardcodeResolver
import fmgp.did.uniresolver.Uniresolver
import fmgp.util._
import fmgp.did.framework.Operator
import fmgp.util._

// import zio.http.endpoint.RoutesMiddleware

Expand Down Expand Up @@ -50,7 +50,8 @@ object AppServer extends ZIOAppDefault {
// http://localhost:8080/oob?_oob=eyJ0eXBlIjoiaHR0cHM6Ly9kaWRjb21tLm9yZy9vdXQtb2YtYmFuZC8yLjAvaW52aXRhdGlvbiIsImlkIjoiNTk5ZjM2MzgtYjU2My00OTM3LTk0ODctZGZlNTUwOTlkOTAwIiwiZnJvbSI6ImRpZDpleGFtcGxlOnZlcmlmaWVyIiwiYm9keSI6eyJnb2FsX2NvZGUiOiJzdHJlYW1saW5lZC12cCIsImFjY2VwdCI6WyJkaWRjb21tL3YyIl19fQ
).toHttpApp @@ (Middleware.requestLogging(loggedRequestHeaders = Set(Header.Host, Header.Origin)) ++ Middleware.debug)

def appOther = Routes(
def appOther = appOtherRoutes.logErrorAndRespond.toHttpApp
def appOtherRoutes: Routes[Resolver, Throwable] = Routes( // TODO outes[Resolver, DidException]
Method.GET / "oob" -> handler { (req: Request) =>
for {
_ <- ZIO.log("oob")
Expand All @@ -65,11 +66,9 @@ object AppServer extends ZIOAppDefault {
Method.POST / "ops" -> handler { (req: Request) =>
req.body.asString
.tap(e => ZIO.log("ops"))
.tap(e => ZIO.logTrace(s"ops: $e"))
.flatMap(e => OperationsServerRPC.ops(e))
.flatMap(e => OperationsServerRPC.ops(e).tapErrorCause(cause => ZIO.logErrorCause(cause)))
.map(e => Response.text(e))
},

// ### MAKE KEYS ###
Method.POST / "makeKey" -> handler { (req: Request) =>
req.body.asString
Expand Down Expand Up @@ -100,7 +99,7 @@ object AppServer extends ZIOAppDefault {
case Left(error) => ZIO.succeed(Response.text(error.error).copy(status = Status.BadRequest)).debug
case Right(value) => ZIO.succeed(Response.text("DID:" + value)).debug
},
).sandbox.toHttpApp
)

def appWebsite = Routes(
// Method.GET / trailing -> handler { // html.Html.fromDomElement()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ object OperationsServerRPC {
case SignOpInput(agent, msg) =>
operations
.sign(msg)
.provideEnvironment(ZEnvironment(agent))
.provideEnvironment(ZEnvironment(agent, resolver))
.mapBoth(ex => SignOpOutput(Left(ex)), e => SignOpOutput(Right(e)))
.merge
case VerifyOpInput(msg) =>
Expand Down
12 changes: 12 additions & 0 deletions demo/jvm/src/main/scala/fmgp/util/RoutesExtra.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package fmgp.util

import zio._
import zio.http._

extension [Env, Err](r: Routes[Env, Err])
def logErrorAndRespond(using trace: Trace): Routes[Env, Nothing] =
Routes.fromIterable(
r.routes
.map(e => e.transform(x => x.tapErrorCauseZIO(c => ZIO.logErrorCause(c))))
.map(_.handleErrorCause(Response.fromCause(_)))
)
20 changes: 11 additions & 9 deletions did-imp/js/src/main/scala/fmgp/crypto/UtilsJS.scala
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,15 @@ object UtilsJS {
}

// TODO make private
def toKeyLike: IO[UnknownError.type, (KeyLike, String)] = {
val aux = key.toJWK
ZIO
.fromPromiseJS(importJWK(aux))
.map(k => (k.asInstanceOf[KeyLike], aux.alg.get))
.orElseFail(UnknownError)
def toKeyLike: IO[CryptoFailed, (KeyLike, String, String)] = {
key.kid match
case None => ZIO.fail(FailToExtractKid(s"Fail to extract kid from ${key.toJson}"))
case Some(kid) =>
val aux = key.toJWK
ZIO
.fromPromiseJS(importJWK(aux))
.map(k => (k.asInstanceOf[KeyLike], aux.alg.get, kid))
.orElseFail(UnknownError)
}

def verify(jwm: SignedMessage): IO[CryptoFailed, Boolean] =
Expand All @@ -113,15 +116,14 @@ object UtilsJS {
extension (key: PrivateKey) {
def sign(payload: Array[Byte]): IO[CryptoFailed, SignedMessage] = {
val data = js.typedarray.Uint8Array.from(payload.toSeq.map(_.toShort).toJSIterable)

key.toKeyLike
.flatMap { (thisKey, alg) =>
.flatMap { (thisKey, alg, kid) =>
ZIO
.fromPromiseJS(
GeneralSign(data) // We can also use CompactSign
.tap(
_.addSignature(thisKey.asInstanceOf[KeyLike])
.setProtectedHeader(CompactJWSHeaderParameters(alg))
.setProtectedHeader(CompactJWSHeaderParameters(alg).set("kid", kid))
)
.sign()
)
Expand Down
5 changes: 3 additions & 2 deletions did-imp/js/src/test/scala/fmgp/crypto/JWMSuiteJS.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,16 @@ import scala.util.Failure
import scala.util.Success
import scala.util.Try

/** didImpJS/testOnly fmgp.crypto.JWMSuiteJS */
class JWMSuiteJS extends ZSuite {

import scala.scalajs.js

testZ("sign and verify an example") {
val key: ECPrivateKey = JWKExamples.senderKeySecp256k1.fromJson[ECPrivateKey].toOption.get
sign(key, DIDCommExamples.plaintextMessageObj).flatMap { jwsObject =>
verify(key.toPublicKey, jwsObject).map(e => assert(e))
<&> verify(key.toPublicKey, SignedMessageExamples.exampleSignatureES256K_obj).map(e => assert(e))
verify(key.toPublicKey, jwsObject).map(e => assert(e)) <&>
verify(key.toPublicKey, SignedMessageExamples.exampleSignatureES256K_obj).map(e => assert(e))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,22 @@ object PlatformSpecificOperations {

def sign(key: PrivateKey, payload: Array[Byte]): IO[CurveError, SignedMessage] =
key match {
case okp: OKPPrivateKey if okp.crv == Curve.Ed25519 =>
ZIO.succeed(okp.toJWK.signWithEd25519(payload, key.jwaAlgorithmtoSign))
case okp: OKPPrivateKey =>
ZIO.fail(UnsupportedCurve(obtained = okp.crv, supported = Set(Curve.Ed25519)))
case okp @ OKPPrivateKey(kty, Curve.Ed25519, d, x, kid) =>
ZIO.succeed(okpKeySignWithEd25519(okpKey2JWK(okp), payload, key.jwaAlgorithmtoSign))
case okp @ OKPPrivateKey(kty, crv, d, x, kid) =>
ZIO.fail(UnsupportedCurve(obtained = crv, supported = Set(Curve.Ed25519)))
case ec: ECPrivateKey =>
ZIO.succeed(ec.toJWK.sign(payload, key.jwaAlgorithmtoSign))
ZIO.succeed(ecKeySign(ec.toJWK, payload, key.jwaAlgorithmtoSign))
}

def verify(key: PublicKey, jwm: SignedMessage): UIO[Boolean] =
ZIO.succeed(key.match {
case okp: OKPPublicKey => okp.toJWK.verify(jwm, key.jwaAlgorithmtoSign)
case ec: ECPublicKey => ec.toJWK.verify(jwm, key.jwaAlgorithmtoSign)
})
def verify(key: PublicKey, jwm: SignedMessage): IO[CurveError, Boolean] =
key.match {
case okp @ OKPPublicKey(kty, Curve.Ed25519, x, kid) =>
ZIO.succeed(okpKeyVerifyWithEd25519(okpKey2JWK(okp), jwm, key.jwaAlgorithmtoSign))
case okp @ OKPPublicKey(kty, crv, x, kid) =>
ZIO.fail(UnsupportedCurve(obtained = crv, supported = Set(Curve.Ed25519)))
case ec: ECPublicKey =>
ZIO.succeed(ecKeyVerify(ec.toJWK, jwm, key.jwaAlgorithmtoSign))
}

}
Loading
Loading