mirror of
https://github.com/fiatjaf/nak.git
synced 2024-11-22 16:19:07 -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(ScalaJSPlugin)
|
||||||
// enablePlugins(ScalaJSBundlerPlugin)
|
|
||||||
|
|
||||||
name := "app"
|
name := "app"
|
||||||
scalaVersion := "2.13.7"
|
scalaVersion := "2.13.7"
|
||||||
|
@ -9,3 +8,7 @@ scalaJSUseMainModuleInitializer := true
|
||||||
libraryDependencies += "org.scala-js" %%% "scalajs-dom" % "2.1.0"
|
libraryDependencies += "org.scala-js" %%% "scalajs-dom" % "2.1.0"
|
||||||
libraryDependencies += "me.shadaj" %%% "slinky-core" % "0.7.0"
|
libraryDependencies += "me.shadaj" %%% "slinky-core" % "0.7.0"
|
||||||
libraryDependencies += "me.shadaj" %%% "slinky-web" % "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.web.html._
|
||||||
import slinky.core.facade.Hooks._
|
import slinky.core.facade.Hooks._
|
||||||
|
|
||||||
import app.handlers.{Handler, Nothing, KeyHandling}
|
import app.handlers.{Handler, Nothing, KeyHandling, EventSignatures}
|
||||||
|
|
||||||
object Base {
|
object Base {
|
||||||
val handlers: List[Handler] = List(KeyHandling, Nothing)
|
val handlers: List[Handler] = List(KeyHandling, EventSignatures, Nothing)
|
||||||
|
|
||||||
val component = FunctionalComponent[Unit] { props =>
|
val component = FunctionalComponent[Unit] { props =>
|
||||||
val (typedValue, setTypedValue) = useState("")
|
val (typedValue, setTypedValue) = useState("")
|
||||||
|
|
|
@ -1,21 +1,200 @@
|
||||||
package app.handlers
|
package app.handlers
|
||||||
|
|
||||||
|
import scala.annotation.{nowarn, tailrec}
|
||||||
|
import scala.concurrent.ExecutionContext.Implicits.global
|
||||||
|
import scala.concurrent.Future
|
||||||
import scala.scalajs.js
|
import scala.scalajs.js
|
||||||
import slinky.core.FunctionalComponent
|
import slinky.core.FunctionalComponent
|
||||||
import slinky.web.html._
|
import slinky.web.html._
|
||||||
import slinky.core.facade.Hooks._
|
import slinky.core.facade.Hooks._
|
||||||
import slinky.core.facade.Fragment
|
import slinky.core.facade.Fragment
|
||||||
import io.circe._
|
import io.circe.{Json, HCursor}
|
||||||
import io.circe.parser._
|
import io.circe.parser.{parse}
|
||||||
|
|
||||||
|
import app.modules.Nostr
|
||||||
import app.handlers.{Handler}
|
import app.handlers.{Handler}
|
||||||
|
import app.components.{Item}
|
||||||
|
|
||||||
object EventSignatures extends Handler {
|
object EventSignatures extends Handler {
|
||||||
override def handles(value: String): Boolean = false
|
val keymatcher = "^[a-f0-9]{64}$".r
|
||||||
|
|
||||||
override val component = FunctionalComponent[String] { props =>
|
def badProperties(c: HCursor): Seq[String] = Seq(
|
||||||
Fragment(
|
(
|
||||||
"nada"
|
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
|
@JSGlobal
|
||||||
object Nostr extends js.Object {
|
object Nostr extends js.Object {
|
||||||
def getPublicKey(text: String): String = js.native
|
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