Skip to content

Commit

Permalink
webapp: support to verify sign message
Browse files Browse the repository at this point in the history
Support to verify sign message in the Decrypt Tool
Minor UI improvements
Work for #197
  • Loading branch information
FabioPinheiro committed Feb 19, 2024
1 parent 6a61080 commit e230f37
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 50 deletions.
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: 11 additions & 0 deletions did/shared/src/main/scala/fmgp/did/Agent.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,15 @@ import fmgp.crypto._
trait Agent { // Rename to Identity
def id: DID
def keyStore: KeyStore

// def didDocument: DIDDocument
// // Extra Methods
// def getPrivateKeysTypeAuthentication: Set[PrivateKey] = {
// val allKeysTypeAuthentication = didDocument.allKeysTypeAuthentication
// keyStore.keys.filter(k =>
// k.kid match
// case None => false // no kid ...
// case Some(kid) => allKeysTypeAuthentication.map(_.id).contains(kid)
// )
// }
}
1 change: 1 addition & 0 deletions did/shared/src/main/scala/fmgp/did/comm/OpaqueTypes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ opaque type Payload = Base64
object Payload:
def fromBase64url(data: String): Payload = Base64.fromBase64url(data)
extension (data: Payload)
/** decode the base64url to a string */
def content: String = data.decodeToString
def base64url: String = data.urlBase64
given decoder: JsonDecoder[Payload] = Base64.decoder
Expand Down
2 changes: 1 addition & 1 deletion webapp/src/main/scala/fmgp/webapp/BasicMessageTool.scala
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ object BasicMessageTool {
case Right(json) =>
Seq(
button(
"Copy to Encrypt Tool",
"Copy to Encrypt/Sign Tool",
onClick --> { _ => EncryptTool.dataTextVar.set(json) },
MyRouter.navigateTo(MyRouter.EncryptPage)
)
Expand Down
119 changes: 82 additions & 37 deletions webapp/src/main/scala/fmgp/webapp/DecryptTool.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,37 @@ import fmgp.crypto.error._

import fmgp.did.AgentProvider
import fmgp.Utils

object DecryptTool {
val dataVar: Var[String] = Var(initial = "")
val encryptedMessageVar: Signal[Either[String, EncryptedMessage]] =
dataVar.signal.map(_.fromJson[EncryptedMessage])
val messageVar: Signal[Either[String, SignedOrEncryptedMessage]] =
dataVar.signal.map(_.fromJson[SignedOrEncryptedMessage](SignedOrEncryptedMessage.decoder))
val decryptDataVar: Var[Option[Array[Byte]]] = Var(initial = None)
val decryptMessageVar: Var[Option[Either[DidFail, Message]]] = Var(initial = None)

def job(owner: Owner) =
Signal
.combine(
Global.agentVar,
encryptedMessageVar
messageVar
)
.map {
case (_, Right(sMsg: SignedMessage)) =>
val program = OperationsClientRPC
.verify2PlaintextMessage(sMsg)
.flatMap { plaintext =>
ZIO.succeed(decryptDataVar.set(Some(sMsg.payload.content.getBytes))) *> // side effect!
ZIO.succeed(decryptMessageVar.set(Some(Right(plaintext)))) *> // side effect!
ZIO.succeed(Global.messageRecive(sMsg, plaintext)) // side effect!
}
Utils.runProgram(program.provideSomeLayer(Global.resolverLayer))
case (None, _) =>
decryptDataVar.set(None) // side effect!
decryptMessageVar.set(None) // side effect!
case (Some(agent), Left(error)) =>
decryptDataVar.set(None) // side effect!
decryptMessageVar.set(Some(Left(FailToParse("Fail to parse Encrypted Message: " + error)))) // side effect!
case (Some(agent), Right(msg)) =>
decryptMessageVar.set(Some(Left(FailToParse("Fail to parse Message: " + error)))) // side effect!
case (Some(agent), Right(msg: EncryptedMessage)) =>
val program =
OperationsClientRPC
.decryptRaw(msg)
Expand Down Expand Up @@ -71,64 +81,99 @@ object DecryptTool {
job(ctx.owner)
()
},
code("DecryptTool Page"),
code("Decrypt/Verify Tool"),
p(
overflowWrap.:=("anywhere"),
"Agent: ",
" ",
code(child.text <-- Global.agentVar.signal.map(_.map(_.id.string).getOrElse("NO AGENT IS SELECTED!")))
code(
child.text <-- Global.agentVar.signal
.map(_.map(_.id.string).getOrElse("NO AGENT IS SELECTED! (It can still verify sign message)"))
)
),
p("Encrypted Message Data:"),
p("Message Data:"),
textArea(
rows := 20,
cols := 80,
autoFocus(true),
placeholder("<EncryptedMessage>"),
placeholder("<SignedMessage or EncryptedMessage>"),
value <-- dataVar,
inContext { thisNode => onInput.map(_ => thisNode.ref.value) --> dataVar }
),
p("Encrypted Message Protected Header (parsed):"),
p("Message Protected Header (parsed):"),
div(
children <-- encryptedMessageVar.map { mMsg =>
children <-- messageVar.map { mMsg =>
mMsg.toSeq
.flatMap {
_.`protected`.obj match
case header @ AnonProtectedHeader(epk, apv, typ, enc, alg) =>
Seq(
p("Anoncrypt:"),
pre(code(header.toJsonPretty)),
)
case header @ AuthProtectedHeader(epk, apv, skid, apu, typ, enc, alg) =>
Seq(
p(
"Authcrypt from: ",
code(
a(skid.did.string, MyRouter.navigateTo(MyRouter.ResolverPage(skid.did.string))),
"#",
skid.fragment
case sMsg: SignedMessage =>
sMsg.signatures.flatMap { e =>
e.`protected`.obj.kid match
case None => Seq(pre(code("'kid' is missing from Protected Header!"))) // TODO REMOVE case
case Some(vmr) =>
Seq(
pre(
code(
a(vmr.did.string, MyRouter.navigateTo(MyRouter.ResolverPage(vmr.did.string))),
"#",
vmr.fragment,
";"
)
),
pre(code(e.`protected`.obj.toJson)),
)
),
pre(code(header.toJsonPretty))
)
}
case eMsg: EncryptedMessage =>
eMsg.`protected`.obj match
case header @ AnonProtectedHeader(epk, apv, typ, enc, alg) =>
Seq(
p("Anoncrypt:"),
pre(code(header.toJsonPretty)),
)
case header @ AuthProtectedHeader(epk, apv, skid, apu, typ, enc, alg) =>
Seq(
p(
"Authcrypt from: ",
code(
a(skid.did.string, MyRouter.navigateTo(MyRouter.ResolverPage(skid.did.string))),
"#",
skid.fragment
)
),
pre(code(header.toJsonPretty))
)
}
},
),
p("Recipients kid:"),
ul(
children <-- encryptedMessageVar.map { mMsg =>
mMsg.toSeq
.flatMap(_.recipients.toSeq.map(_.header.kid))
.map(kid =>
li(code(a(kid.did.string, MyRouter.navigateTo(MyRouter.ResolverPage(kid.did.string))), "#", kid.fragment))
)
},
children <-- messageVar.map(_.toSeq).map {
case sMsg: SignedMessage =>
sMsg.payloadAsPlaintextMessage match
case Left(error) => Seq(li(code(error.toText)))
case Right(pMsg) =>
pMsg.to.toSeq.flatten.map { to =>
li(code(a(to.value, MyRouter.navigateTo(MyRouter.ResolverPage(to.value)))))
}
case eMsg: EncryptedMessage =>
eMsg.recipients.toSeq
.map(_.header.kid)
.map(kid =>
li(
code(
a(kid.did.string, MyRouter.navigateTo(MyRouter.ResolverPage(kid.did.string))),
"#",
kid.fragment
)
)
)
}
),
p("Raw Data (as UTF8) after decrypting:"),
p("Raw Data (as UTF8) after decrypting/verifying:"),
pre(code(child.text <-- decryptDataVar.signal.map {
case None => "<none>"
case Some(bytes) => String(bytes)
})),
p("Message after decrypting:"),
p("Message after decrypting/verifying:"),
pre(code(child.text <-- decryptMessageVar.signal.map {
case None => "<none>"
case Some(Left(didFail)) => didFail.toString
Expand Down
4 changes: 2 additions & 2 deletions webapp/src/main/scala/fmgp/webapp/EncryptTool.scala
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ object EncryptTool {
callCommand(ctx.owner) // side effect
()
},
code("DecryptTool Page"),
code("Encrypt/Sign Tool"),
p(
overflowWrap.:=("anywhere"),
"Agent: ",
Expand Down Expand Up @@ -562,7 +562,7 @@ object EncryptTool {
"Got a message",
button("Copy to clipboard", onClick --> { _ => Global.copyToClipboard((reply: Message).toJson) }),
button(
"Copy to Decryot Tool",
"Copy to Decryot/Verify Tool",
onClick --> { _ => DecryptTool.dataVar.set((reply: Message).toJsonPretty) },
MyRouter.navigateTo(MyRouter.DecryptPage)
)
Expand Down
4 changes: 2 additions & 2 deletions webapp/src/main/scala/fmgp/webapp/Home.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ object Home {
showPage(MyRouter.QRcodePage, "DIDComm over QRcode"),
showPage(MyRouter.NFCScannerPage, "DIDComm over NFC"),
showPage(MyRouter.ResolverPage(App.didExample), "DID Resolver Tool"),
showPage(MyRouter.EncryptPage, "Encrypt Tool"),
showPage(MyRouter.DecryptPage, "Decrypt Tool"),
showPage(MyRouter.EncryptPage, "Encrypt/Sign Tool"),
showPage(MyRouter.DecryptPage, "Decrypt/Verify Tool"),
// p(
// "Navigate to ",
// b("Message DB"),
Expand Down
4 changes: 2 additions & 2 deletions webapp/src/main/scala/fmgp/webapp/MyRouter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ object MyRouter {
// case object AgentDBPage extends Page("MessageDB", "folder_open")
case object AgentMessageStoragePage extends Page("AgentMessageStorage", "forum")
case class ResolverPage(did: String) extends Page("Resolver", "dns")
case object EncryptPage extends Page("Encrypt", "enhanced_encryption")
case object DecryptPage extends Page("Decrypt", "email")
case object EncryptPage extends Page("Encrypt/Sign", "enhanced_encryption")
case object DecryptPage extends Page("Decrypt/Verify", "email")
case object BasicMessagePage extends Page("BasicMessage", "message")
case object TrustPingPage extends Page("TrustPing", "network_ping")
case object TapIntoStreamPage extends Page("TapIntoStream", "chat")
Expand Down
2 changes: 1 addition & 1 deletion webapp/src/main/scala/fmgp/webapp/TrustPingTool.scala
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ object TrustPingTool {
case Left(error) => new CommentNode("")
case Right(json) =>
button(
"Copy to Encrypt Tool",
"Copy to Encrypt/Sign Tool",
disabled <-- mTrustPingVar.signal.map(_.isLeft),
onClick --> { _ => EncryptTool.dataTextVar.set(json) },
MyRouter.navigateTo(MyRouter.EncryptPage)
Expand Down

0 comments on commit e230f37

Please sign in to comment.