mirror of
https://github.com/fiatjaf/nak.git
synced 2024-12-22 10:05:52 -05:00
amazing recursion with futures on EventSignatures handler.
This commit is contained in:
parent
3a97f7928b
commit
2f455ab225
|
@ -1,5 +1,4 @@
|
|||
enablePlugins(ScalaJSPlugin)
|
||||
// enablePlugins(ScalaJSBundlerPlugin)
|
||||
|
||||
name := "app"
|
||||
scalaVersion := "2.13.7"
|
||||
|
@ -9,3 +8,7 @@ scalaJSUseMainModuleInitializer := true
|
|||
libraryDependencies += "org.scala-js" %%% "scalajs-dom" % "2.1.0"
|
||||
libraryDependencies += "me.shadaj" %%% "slinky-core" % "0.7.0"
|
||||
libraryDependencies += "me.shadaj" %%% "slinky-web" % "0.7.0"
|
||||
libraryDependencies ++= Seq(
|
||||
"io.circe" %%% "circe-core",
|
||||
"io.circe" %%% "circe-parser"
|
||||
).map(_ % "0.14.1")
|
||||
|
|
|
@ -6,10 +6,10 @@ import slinky.core.FunctionalComponent
|
|||
import slinky.web.html._
|
||||
import slinky.core.facade.Hooks._
|
||||
|
||||
import app.handlers.{Handler, Nothing, KeyHandling}
|
||||
import app.handlers.{Handler, Nothing, KeyHandling, EventSignatures}
|
||||
|
||||
object Base {
|
||||
val handlers: List[Handler] = List(KeyHandling, Nothing)
|
||||
val handlers: List[Handler] = List(KeyHandling, EventSignatures, Nothing)
|
||||
|
||||
val component = FunctionalComponent[Unit] { props =>
|
||||
val (typedValue, setTypedValue) = useState("")
|
||||
|
|
|
@ -1,21 +1,200 @@
|
|||
package app.handlers
|
||||
|
||||
import scala.annotation.{nowarn, tailrec}
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.concurrent.Future
|
||||
import scala.scalajs.js
|
||||
import slinky.core.FunctionalComponent
|
||||
import slinky.web.html._
|
||||
import slinky.core.facade.Hooks._
|
||||
import slinky.core.facade.Fragment
|
||||
import io.circe._
|
||||
import io.circe.parser._
|
||||
import io.circe.{Json, HCursor}
|
||||
import io.circe.parser.{parse}
|
||||
|
||||
import app.modules.Nostr
|
||||
import app.handlers.{Handler}
|
||||
import app.components.{Item}
|
||||
|
||||
object EventSignatures extends Handler {
|
||||
override def handles(value: String): Boolean = false
|
||||
val keymatcher = "^[a-f0-9]{64}$".r
|
||||
|
||||
override val component = FunctionalComponent[String] { props =>
|
||||
Fragment(
|
||||
"nada"
|
||||
def badProperties(c: HCursor): Seq[String] = Seq(
|
||||
(
|
||||
c.get[Double]("kind").getOrElse[Double](-1) >= 0 match {
|
||||
case true => None;
|
||||
case false => Some("kind")
|
||||
}
|
||||
),
|
||||
(
|
||||
keymatcher.matches(
|
||||
c.get[String]("pubkey").getOrElse("").toLowerCase()
|
||||
) match {
|
||||
case true => None;
|
||||
case false => Some("pubkey")
|
||||
}
|
||||
),
|
||||
(
|
||||
c.get[String]("content").exists((_) => true) match {
|
||||
case true => None;
|
||||
case false => Some("content")
|
||||
}
|
||||
),
|
||||
(
|
||||
c
|
||||
.get[List[List[String]]]("tags")
|
||||
.exists((_) => true) match {
|
||||
case true => None;
|
||||
case false => Some("tags")
|
||||
}
|
||||
)
|
||||
)
|
||||
.filter(res => res.isDefined)
|
||||
.map(res => res.get)
|
||||
|
||||
override def handles(value: String): Boolean = parse(value) match {
|
||||
case Left(_) => false
|
||||
case Right(json) => {
|
||||
badProperties(json.hcursor).length < 4
|
||||
}
|
||||
}
|
||||
|
||||
type MaybeItem = Future[
|
||||
Either[slinky.core.TagMod[Nothing], slinky.core.TagMod[Nothing]]
|
||||
]
|
||||
|
||||
@nowarn("cat=other")
|
||||
def itemWrongProperties(evtj: String): MaybeItem = Future {
|
||||
val c = parse(evtj).toOption.get.hcursor
|
||||
val bad = badProperties(c)
|
||||
|
||||
if (bad.length > 0) {
|
||||
Left(
|
||||
Item.component(
|
||||
Item.props(
|
||||
"event missing or wrong properties",
|
||||
"",
|
||||
bad.mkString(", ")
|
||||
)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
Right(div())
|
||||
}
|
||||
}
|
||||
|
||||
@nowarn("cat=other")
|
||||
def itemSerializedEvent(evtj: String): MaybeItem = Future {
|
||||
val event: js.Dynamic = js.JSON.parse(evtj)
|
||||
|
||||
Right(
|
||||
Item.component(
|
||||
Item.props(
|
||||
"serialized event",
|
||||
"according to nip-01 signature algorithm",
|
||||
Nostr.serializeEvent(event)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@nowarn("cat=other")
|
||||
def itemEventId(evtj: String): MaybeItem = Future {
|
||||
val event: js.Dynamic = js.JSON.parse(evtj)
|
||||
|
||||
Right(
|
||||
Item.component(
|
||||
Item.props(
|
||||
"event id",
|
||||
"sha256 hash of serialized event",
|
||||
Nostr.getEventHash(event)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@nowarn("cat=other")
|
||||
def itemEventIdMatches(evtj: String): MaybeItem = Future {
|
||||
val c = parse(evtj).toOption.get.hcursor
|
||||
val event: js.Dynamic = js.JSON.parse(evtj)
|
||||
|
||||
def render(result: Boolean) = Item.component(
|
||||
Item.props(
|
||||
"does the implied event id match the given event id?",
|
||||
"if not, that means you're hashing the event uncorrectly",
|
||||
f"${result match {
|
||||
case true => "yes"; case false => "no"
|
||||
}}"
|
||||
)
|
||||
)
|
||||
|
||||
Nostr
|
||||
.getEventHash(event) == (c.get[String]("id")).toOption.get match {
|
||||
case true => Right(render(true))
|
||||
case false => Left(render(false))
|
||||
}
|
||||
}
|
||||
|
||||
@nowarn("cat=other")
|
||||
def itemSignatureValid(evtj: String): MaybeItem = Future {
|
||||
val event: js.Dynamic = js.JSON.parse(evtj)
|
||||
|
||||
def render(result: Boolean) = Item.component(
|
||||
Item.props(
|
||||
"is signature valid?",
|
||||
"",
|
||||
f"${result match {
|
||||
case true => "yes"; case false => "no"
|
||||
}}"
|
||||
)
|
||||
)
|
||||
|
||||
true match {
|
||||
case true => Right(render(true))
|
||||
case false => Left(render(false))
|
||||
}
|
||||
}
|
||||
|
||||
val protoElements = List[(String) => MaybeItem](
|
||||
itemWrongProperties,
|
||||
itemSerializedEvent,
|
||||
itemEventId,
|
||||
itemEventIdMatches,
|
||||
itemSignatureValid
|
||||
)
|
||||
|
||||
@nowarn("cat=other")
|
||||
override val component = FunctionalComponent[String] { props =>
|
||||
val (elements, setElements) =
|
||||
useState(Seq.empty[slinky.core.TagMod[Nothing]])
|
||||
|
||||
useEffect(
|
||||
() => {
|
||||
def runAndUnwrapUntilFirstLeft(
|
||||
remaining: List[String => Future[
|
||||
Either[slinky.core.TagMod[Nothing], slinky.core.TagMod[Nothing]]
|
||||
]],
|
||||
acc: List[slinky.core.TagMod[Nothing]]
|
||||
): Future[List[slinky.core.TagMod[Nothing]]] = remaining match {
|
||||
case fn :: tail => {
|
||||
fn(props) flatMap { res =>
|
||||
res match {
|
||||
case Left(el) => runAndUnwrapUntilFirstLeft(Nil, el :: acc)
|
||||
case Right(el) => runAndUnwrapUntilFirstLeft(tail, el :: acc)
|
||||
}
|
||||
}
|
||||
}
|
||||
case Nil => Future { acc.reverse }
|
||||
}
|
||||
|
||||
runAndUnwrapUntilFirstLeft(protoElements, List()) foreach { elements =>
|
||||
setElements(elements)
|
||||
}
|
||||
|
||||
() => {}
|
||||
},
|
||||
Seq(props)
|
||||
)
|
||||
|
||||
Fragment(elements: _*)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,4 +7,8 @@ import scala.scalajs.js
|
|||
@JSGlobal
|
||||
object Nostr extends js.Object {
|
||||
def getPublicKey(text: String): String = js.native
|
||||
def getEventHash(evt: js.Dynamic): String = js.native
|
||||
def serializeEvent(evt: js.Dynamic): String = js.native
|
||||
def verifySignature(evt: js.Dynamic): Boolean = js.native
|
||||
def signEvent(evt: js.Dynamic, privateKey: String): String = js.native
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user