mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-09 16:14:40 +00:00
refactor(clink): model event tags via PTag/ETag classes + builder DSL
Brings OfferEvent/DebitEvent/ManageEvent (21001-3) in line with the codebase
tag conventions, replacing raw inline tags:
- Build via eventTemplate(KIND, content) { pTag(...); eTag/add; alt(...) } and
signer.sign(template), instead of hand-rolled arrayOf("p"/"e", ...) + sign().
- Accessors use PTag.parseKey / ETag.parseId instead of matching "p"/"e" literals.
Behavior-preserving: PTag.assemble(x, null) yields the identical ["p", x] bytes
and tag order is unchanged, so signed events are byte-identical. All CLINK tests
pass (ClinkEventTest, ClinkClientServerTest, pointer/interop).
Note: these are NIP-44-encrypted request/response events, so create*() stays a
suspend factory that encrypts then signs the template — matching NIP-47; a pure
pre-signing template isn't possible without the signer.
This commit is contained in:
+22
-18
@@ -27,7 +27,11 @@ import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.OptimizedJsonMapper
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions
|
||||
import com.vitorpamplona.quartz.nip31Alts.AltTag
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.events.ETag
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.people.PTag
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.people.pTag
|
||||
import com.vitorpamplona.quartz.nip31Alts.alt
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
|
||||
/**
|
||||
@@ -48,9 +52,9 @@ class DebitEvent(
|
||||
) : Event(id, pubKey, createdAt, KIND, tags, content, sig) {
|
||||
override fun isContentEncoded() = true
|
||||
|
||||
fun recipientPubKey() = tags.firstOrNull { it.size > 1 && it[0] == "p" }?.get(1)
|
||||
fun recipientPubKey() = tags.firstNotNullOfOrNull(PTag::parseKey)
|
||||
|
||||
fun requestId() = tags.firstOrNull { it.size > 1 && it[0] == "e" }?.get(1)
|
||||
fun requestId() = tags.firstNotNullOfOrNull(ETag::parseId)
|
||||
|
||||
fun isResponse() = requestId() != null
|
||||
|
||||
@@ -80,14 +84,14 @@ class DebitEvent(
|
||||
signer: NostrSigner,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
): DebitEvent {
|
||||
val tags =
|
||||
arrayOf(
|
||||
arrayOf("p", servicePubKey),
|
||||
Clink.versionTag(),
|
||||
AltTag.assemble(ALT),
|
||||
)
|
||||
val encrypted = signer.nip44Encrypt(OptimizedJsonMapper.toJson(request), servicePubKey)
|
||||
return signer.sign(createdAt, KIND, tags, encrypted)
|
||||
return signer.sign(
|
||||
eventTemplate(KIND, encrypted, createdAt) {
|
||||
pTag(servicePubKey, null)
|
||||
add(Clink.versionTag())
|
||||
alt(ALT)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/** Builds a response event (service side) referencing the original [requestEvent]. */
|
||||
@@ -98,15 +102,15 @@ class DebitEvent(
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
): DebitEvent {
|
||||
val requestorPubKey = requestEvent.pubKey
|
||||
val tags =
|
||||
arrayOf(
|
||||
arrayOf("p", requestorPubKey),
|
||||
arrayOf("e", requestEvent.id),
|
||||
Clink.versionTag(),
|
||||
AltTag.assemble(ALT),
|
||||
)
|
||||
val encrypted = signer.nip44Encrypt(OptimizedJsonMapper.toJson(response), requestorPubKey)
|
||||
return signer.sign(createdAt, KIND, tags, encrypted)
|
||||
return signer.sign(
|
||||
eventTemplate(KIND, encrypted, createdAt) {
|
||||
pTag(requestorPubKey, null)
|
||||
add(ETag.assemble(requestEvent.id, null, null))
|
||||
add(Clink.versionTag())
|
||||
alt(ALT)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+22
-18
@@ -27,7 +27,11 @@ import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.OptimizedJsonMapper
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions
|
||||
import com.vitorpamplona.quartz.nip31Alts.AltTag
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.events.ETag
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.people.PTag
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.people.pTag
|
||||
import com.vitorpamplona.quartz.nip31Alts.alt
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
|
||||
/**
|
||||
@@ -48,9 +52,9 @@ class ManageEvent(
|
||||
) : Event(id, pubKey, createdAt, KIND, tags, content, sig) {
|
||||
override fun isContentEncoded() = true
|
||||
|
||||
fun recipientPubKey() = tags.firstOrNull { it.size > 1 && it[0] == "p" }?.get(1)
|
||||
fun recipientPubKey() = tags.firstNotNullOfOrNull(PTag::parseKey)
|
||||
|
||||
fun requestId() = tags.firstOrNull { it.size > 1 && it[0] == "e" }?.get(1)
|
||||
fun requestId() = tags.firstNotNullOfOrNull(ETag::parseId)
|
||||
|
||||
fun isResponse() = requestId() != null
|
||||
|
||||
@@ -80,14 +84,14 @@ class ManageEvent(
|
||||
signer: NostrSigner,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
): ManageEvent {
|
||||
val tags =
|
||||
arrayOf(
|
||||
arrayOf("p", serverPubKey),
|
||||
Clink.versionTag(),
|
||||
AltTag.assemble(ALT),
|
||||
)
|
||||
val encrypted = signer.nip44Encrypt(OptimizedJsonMapper.toJson(request), serverPubKey)
|
||||
return signer.sign(createdAt, KIND, tags, encrypted)
|
||||
return signer.sign(
|
||||
eventTemplate(KIND, encrypted, createdAt) {
|
||||
pTag(serverPubKey, null)
|
||||
add(Clink.versionTag())
|
||||
alt(ALT)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/** Builds a response event (server side) referencing the original [requestEvent]. */
|
||||
@@ -98,15 +102,15 @@ class ManageEvent(
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
): ManageEvent {
|
||||
val appPubKey = requestEvent.pubKey
|
||||
val tags =
|
||||
arrayOf(
|
||||
arrayOf("p", appPubKey),
|
||||
arrayOf("e", requestEvent.id),
|
||||
Clink.versionTag(),
|
||||
AltTag.assemble(ALT),
|
||||
)
|
||||
val encrypted = signer.nip44Encrypt(OptimizedJsonMapper.toJson(response), appPubKey)
|
||||
return signer.sign(createdAt, KIND, tags, encrypted)
|
||||
return signer.sign(
|
||||
eventTemplate(KIND, encrypted, createdAt) {
|
||||
pTag(appPubKey, null)
|
||||
add(ETag.assemble(requestEvent.id, null, null))
|
||||
add(Clink.versionTag())
|
||||
alt(ALT)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+22
-18
@@ -27,7 +27,11 @@ import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.OptimizedJsonMapper
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions
|
||||
import com.vitorpamplona.quartz.nip31Alts.AltTag
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.events.ETag
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.people.PTag
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.people.pTag
|
||||
import com.vitorpamplona.quartz.nip31Alts.alt
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
|
||||
/**
|
||||
@@ -49,10 +53,10 @@ class OfferEvent(
|
||||
override fun isContentEncoded() = true
|
||||
|
||||
/** The `p` tag — the counterparty this message is addressed to. */
|
||||
fun recipientPubKey() = tags.firstOrNull { it.size > 1 && it[0] == "p" }?.get(1)
|
||||
fun recipientPubKey() = tags.firstNotNullOfOrNull(PTag::parseKey)
|
||||
|
||||
/** The `e` tag — present only on responses, referencing the request event id. */
|
||||
fun requestId() = tags.firstOrNull { it.size > 1 && it[0] == "e" }?.get(1)
|
||||
fun requestId() = tags.firstNotNullOfOrNull(ETag::parseId)
|
||||
|
||||
fun isResponse() = requestId() != null
|
||||
|
||||
@@ -82,14 +86,14 @@ class OfferEvent(
|
||||
signer: NostrSigner,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
): OfferEvent {
|
||||
val tags =
|
||||
arrayOf(
|
||||
arrayOf("p", servicePubKey),
|
||||
Clink.versionTag(),
|
||||
AltTag.assemble(ALT),
|
||||
)
|
||||
val encrypted = signer.nip44Encrypt(OptimizedJsonMapper.toJson(request), servicePubKey)
|
||||
return signer.sign(createdAt, KIND, tags, encrypted)
|
||||
return signer.sign(
|
||||
eventTemplate(KIND, encrypted, createdAt) {
|
||||
pTag(servicePubKey, null)
|
||||
add(Clink.versionTag())
|
||||
alt(ALT)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/** Builds a response event (service side) referencing the original [requestEvent]. */
|
||||
@@ -100,15 +104,15 @@ class OfferEvent(
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
): OfferEvent {
|
||||
val payerPubKey = requestEvent.pubKey
|
||||
val tags =
|
||||
arrayOf(
|
||||
arrayOf("p", payerPubKey),
|
||||
arrayOf("e", requestEvent.id),
|
||||
Clink.versionTag(),
|
||||
AltTag.assemble(ALT),
|
||||
)
|
||||
val encrypted = signer.nip44Encrypt(OptimizedJsonMapper.toJson(response), payerPubKey)
|
||||
return signer.sign(createdAt, KIND, tags, encrypted)
|
||||
return signer.sign(
|
||||
eventTemplate(KIND, encrypted, createdAt) {
|
||||
pTag(payerPubKey, null)
|
||||
add(ETag.assemble(requestEvent.id, null, null))
|
||||
add(Clink.versionTag())
|
||||
alt(ALT)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user