mirror of
https://github.com/unclebob/more-speech.git
synced 2024-09-30 10:30:56 +00:00
Check signatures of incoming events. Move hex/num/bytes utilities from ecc to util.
This commit is contained in:
parent
c94bafd84a
commit
bdd2f32b37
@ -1,65 +1,10 @@
|
||||
(ns more-speech.nostr.ellliptic-signature-spec
|
||||
(ns more-speech.nostr.elliptic-signature-spec
|
||||
(:require [speclj.core :refer :all]
|
||||
[more-speech.nostr.elliptic-signature :refer :all])
|
||||
[more-speech.nostr.elliptic-signature :refer :all]
|
||||
[more-speech.nostr.util :refer :all])
|
||||
)
|
||||
|
||||
(describe "verification"
|
||||
(it "decodes chars"
|
||||
(should= 16rab (Integer/parseInt "ab" 16)))
|
||||
|
||||
(it "does hex-decode"
|
||||
(should= "deadbeef" (bytes->hex-string (hex-string->bytes "deadbeef")))
|
||||
(should= "aff9a9f017f32b2e8b60754a4102db9d9cf9ff2b967804b50e070780aa45c9a8"
|
||||
(bytes->hex-string (hex-string->bytes "aff9a9f017f32b2e8b60754a4102db9d9cf9ff2b967804b50e070780aa45c9a8")))
|
||||
)
|
||||
|
||||
(it "converts byte arrays to strings"
|
||||
(should= "abcdef" (bytes->hex-string (hex-string->bytes "abcdef"))))
|
||||
|
||||
(it "xors bytes"
|
||||
(should= "b2ce" (bytes->hex-string (xor-bytes (hex-string->bytes "af01")
|
||||
(hex-string->bytes "1dcf"))))
|
||||
(should= "000000000000"
|
||||
(bytes->hex-string
|
||||
(xor-bytes (hex-string->bytes "deadbeeffeed")
|
||||
(hex-string->bytes "deadbeeffeed"))))
|
||||
(should= "ffffffffffff"
|
||||
(bytes->hex-string
|
||||
(xor-bytes (hex-string->bytes "aaaacccc3333")
|
||||
(hex-string->bytes "55553333cccc"))))
|
||||
)
|
||||
|
||||
(it "should convert numbers to bytes"
|
||||
(should= "1fcde563"
|
||||
(bytes->hex-string
|
||||
(num->bytes 4
|
||||
(bytes->num
|
||||
(hex-string->bytes "1fcde563")))))
|
||||
|
||||
(should= "ffcde563"
|
||||
(bytes->hex-string
|
||||
(num->bytes 4
|
||||
(bytes->num
|
||||
(hex-string->bytes "ffcde563")))))
|
||||
)
|
||||
|
||||
;(it "signs"
|
||||
; (let [private-key-1 (sha-256 (.getBytes "my private key 1" StandardCharsets/UTF_8))
|
||||
; private-key-2 (sha-256 (.getBytes "my private key 2" StandardCharsets/UTF_8))
|
||||
; public-key-1 (pub-key private-key-1)
|
||||
; public-key-2 (pub-key private-key-2)
|
||||
; message-1 (sha-256 (.getBytes "my message 1" StandardCharsets/UTF_8))
|
||||
; message-2 (sha-256 (.getBytes "my message 2" StandardCharsets/UTF_8))
|
||||
; sig-1 (sign private-key-1 message-1)
|
||||
; sig-2 (sign private-key-2 message-2)
|
||||
; ]
|
||||
; (should= true (verify public-key-1 message-1 sig-1))
|
||||
; (should= true (verify public-key-2 message-2 sig-2))
|
||||
; (should-not (verify public-key-1 message-1 sig-2))
|
||||
; (should-not (verify public-key-2 message-2 sig-1))
|
||||
; (should-not (verify public-key-1 message-2 sig-1))
|
||||
; (should-not (verify public-key-2 message-1 sig-2))))
|
||||
|
||||
(it "verifies Aaron Dixon's example."
|
||||
(should= true
|
||||
(do-verify
|
@ -1,7 +1,8 @@
|
||||
(ns more-speech.nostr.events_spec
|
||||
(:require [speclj.core :refer :all]
|
||||
[more-speech.nostr.events :refer :all]
|
||||
[more-speech.nostr.elliptic-signature :as ecc]))
|
||||
[more-speech.nostr.elliptic-signature :refer :all]
|
||||
[more-speech.nostr.util :refer :all]))
|
||||
|
||||
(defrecord event-handler-dummy []
|
||||
event-handler
|
||||
@ -89,83 +90,83 @@
|
||||
|
||||
(describe "Composing outgoing events"
|
||||
(it "composes an original message."
|
||||
(let [private-key (ecc/num->bytes 64 314159)
|
||||
event-state {:keys {:private-key (ecc/bytes->hex-string private-key)}}
|
||||
public-key (ecc/get-pub-key private-key)
|
||||
(let [private-key (num->bytes 64 314159)
|
||||
event-state {:keys {:private-key (bytes->hex-string private-key)}}
|
||||
public-key (get-pub-key private-key)
|
||||
text "message text"
|
||||
event (compose-text-event event-state text)
|
||||
{:keys [pubkey created_at kind tags content id sig]} (second event)
|
||||
now (quot (System/currentTimeMillis) 1000)]
|
||||
(should= "EVENT" (first event))
|
||||
(should= (ecc/bytes->hex-string public-key) pubkey)
|
||||
(should= (bytes->hex-string public-key) pubkey)
|
||||
(should (<= 0 (- now created_at) 1)) ;within one second.
|
||||
(should= 1 kind)
|
||||
(should= [] tags)
|
||||
(should= text content)
|
||||
(should (ecc/do-verify (ecc/hex-string->bytes id)
|
||||
(should (do-verify (hex-string->bytes id)
|
||||
public-key
|
||||
(ecc/hex-string->bytes sig)))))
|
||||
(hex-string->bytes sig)))))
|
||||
|
||||
(it "composes a reply to a root article."
|
||||
(let [private-key (ecc/num->bytes 64 42)
|
||||
(let [private-key (num->bytes 64 42)
|
||||
root-id 7734
|
||||
root-id-hex (hexify root-id)
|
||||
root-author 99
|
||||
event-state {:keys {:private-key (ecc/bytes->hex-string private-key)}
|
||||
event-state {:keys {:private-key (bytes->hex-string private-key)}
|
||||
:text-event-map {root-id {:pubkey root-author
|
||||
:tags []}}}
|
||||
public-key (ecc/get-pub-key private-key)
|
||||
public-key (get-pub-key private-key)
|
||||
text "message text"
|
||||
event (compose-text-event event-state text root-id)
|
||||
{:keys [pubkey created_at kind tags content id sig]} (second event)
|
||||
now (quot (System/currentTimeMillis) 1000)]
|
||||
(should= "EVENT" (first event))
|
||||
(should= (ecc/bytes->hex-string public-key) pubkey)
|
||||
(should= (bytes->hex-string public-key) pubkey)
|
||||
(should (<= 0 (- now created_at) 1)) ;within one second.
|
||||
(should= 1 kind)
|
||||
(should= [[:e root-id-hex] [:p (hexify root-author)]] tags)
|
||||
(should= text content)
|
||||
(should (ecc/do-verify (ecc/hex-string->bytes id)
|
||||
(should (do-verify (hex-string->bytes id)
|
||||
public-key
|
||||
(ecc/hex-string->bytes sig)))))
|
||||
(hex-string->bytes sig)))))
|
||||
|
||||
(it "composes a reply to a non-root article."
|
||||
(let [private-key (ecc/num->bytes 64 42)
|
||||
(let [private-key (num->bytes 64 42)
|
||||
root-child-id 7734
|
||||
root-child-id-hex (hexify root-child-id)
|
||||
root-child-author 88
|
||||
root-id 1952
|
||||
root-id-hex (hexify root-id)
|
||||
root-author 99
|
||||
event-state {:keys {:private-key (ecc/bytes->hex-string private-key)}
|
||||
event-state {:keys {:private-key (bytes->hex-string private-key)}
|
||||
:text-event-map {root-child-id {:pubkey root-child-author
|
||||
:tags [[:e root-id-hex]
|
||||
[:p (hexify root-author)]]}
|
||||
root-id {:pubkey root-author
|
||||
:tags []}}}
|
||||
public-key (ecc/get-pub-key private-key)
|
||||
public-key (get-pub-key private-key)
|
||||
text "message text"
|
||||
event (compose-text-event event-state text root-child-id)
|
||||
{:keys [pubkey created_at kind tags content id sig]} (second event)
|
||||
now (quot (System/currentTimeMillis) 1000)]
|
||||
(should= "EVENT" (first event))
|
||||
(should= (ecc/bytes->hex-string public-key) pubkey)
|
||||
(should= (bytes->hex-string public-key) pubkey)
|
||||
(should (<= 0 (- now created_at) 1)) ;within one second.
|
||||
(should= 1 kind)
|
||||
(should= [[:e root-id-hex] [:e root-child-id-hex]
|
||||
[:p (hexify root-child-author)] [:p (hexify root-author)]] tags)
|
||||
(should= text content)
|
||||
(should (ecc/do-verify (ecc/hex-string->bytes id)
|
||||
(should (do-verify (hex-string->bytes id)
|
||||
public-key
|
||||
(ecc/hex-string->bytes sig)))))
|
||||
(hex-string->bytes sig)))))
|
||||
|
||||
(it "author is removed from replies"
|
||||
(let [private-key (ecc/num->bytes 64 42)
|
||||
author (ecc/bytes->num (ecc/get-pub-key private-key))
|
||||
(let [private-key (num->bytes 64 42)
|
||||
author (bytes->num (get-pub-key private-key))
|
||||
root-id 7734
|
||||
root-id-hex (hexify root-id)
|
||||
root-author 99
|
||||
event-state {:keys {:private-key (ecc/bytes->hex-string private-key)}
|
||||
event-state {:keys {:private-key (bytes->hex-string private-key)}
|
||||
:text-event-map {root-id {:pubkey root-author
|
||||
:tags [[:p (hexify author)]]}}}
|
||||
event (compose-text-event event-state "" root-id)
|
||||
@ -174,22 +175,22 @@
|
||||
(should= [[:e root-id-hex] [:p (hexify root-author)]] tags)))
|
||||
|
||||
(it "composes a message with a slash."
|
||||
(let [private-key (ecc/num->bytes 64 42)
|
||||
event-state {:keys {:private-key (ecc/bytes->hex-string private-key)}}
|
||||
public-key (ecc/get-pub-key private-key)
|
||||
(let [private-key (num->bytes 64 42)
|
||||
event-state {:keys {:private-key (bytes->hex-string private-key)}}
|
||||
public-key (get-pub-key private-key)
|
||||
text "message/text"
|
||||
event (compose-text-event event-state text)
|
||||
{:keys [pubkey created_at kind tags content id sig]} (second event)
|
||||
now (quot (System/currentTimeMillis) 1000)]
|
||||
(should= "EVENT" (first event))
|
||||
(should= (ecc/bytes->hex-string public-key) pubkey)
|
||||
(should= (bytes->hex-string public-key) pubkey)
|
||||
(should (<= 0 (- now created_at) 1)) ;within one second.
|
||||
(should= 1 kind)
|
||||
(should= [] tags)
|
||||
(should= text content)
|
||||
(should (ecc/do-verify (ecc/hex-string->bytes id)
|
||||
(should (do-verify (hex-string->bytes id)
|
||||
public-key
|
||||
(ecc/hex-string->bytes sig)))))
|
||||
(hex-string->bytes sig)))))
|
||||
)
|
||||
|
||||
(describe "get references"
|
||||
|
@ -3,6 +3,9 @@
|
||||
[more-speech.nostr.util :refer :all]))
|
||||
|
||||
(describe "Hex string and bytes conversions"
|
||||
(it "decodes chars"
|
||||
(should= 16rab (Integer/parseInt "ab" 16)))
|
||||
|
||||
(it "does hex-decode"
|
||||
(should= "deadbeef" (bytes->hex-string (hex-string->bytes "deadbeef")))
|
||||
(should= "aff9a9f017f32b2e8b60754a4102db9d9cf9ff2b967804b50e070780aa45c9a8"
|
||||
@ -12,6 +15,19 @@
|
||||
(it "converts byte arrays to strings"
|
||||
(should= "abcdef" (bytes->hex-string (hex-string->bytes "abcdef"))))
|
||||
|
||||
(it "xors bytes"
|
||||
(should= "b2ce" (bytes->hex-string (xor-bytes (hex-string->bytes "af01")
|
||||
(hex-string->bytes "1dcf"))))
|
||||
(should= "000000000000"
|
||||
(bytes->hex-string
|
||||
(xor-bytes (hex-string->bytes "deadbeeffeed")
|
||||
(hex-string->bytes "deadbeeffeed"))))
|
||||
(should= "ffffffffffff"
|
||||
(bytes->hex-string
|
||||
(xor-bytes (hex-string->bytes "aaaacccc3333")
|
||||
(hex-string->bytes "55553333cccc"))))
|
||||
)
|
||||
|
||||
(it "should convert numbers to bytes"
|
||||
(should= "1fcde563"
|
||||
(bytes->hex-string
|
||||
|
@ -1,9 +1,8 @@
|
||||
;;Stories
|
||||
;; - validate incoming messages.
|
||||
;; - Add author/date, etc. to replies.
|
||||
;; - Start checking sdefs in update.
|
||||
;; - Clean up java schnorr library.
|
||||
;; - Threading does not work quite right. Do some diagnosis.
|
||||
;; - Threading needs some rethinking.
|
||||
;; - Mark read and highlight properly.
|
||||
;; - Save names and headers. Request after latest save.
|
||||
;; - Consider subject/topic in the tags
|
||||
|
@ -1,71 +1,5 @@
|
||||
(ns more-speech.nostr.elliptic-signature
|
||||
(:import (java.security MessageDigest)
|
||||
(schnorr Schnorr)))
|
||||
|
||||
(defn sha-256
|
||||
"Returns the sha256 hash of the message.
|
||||
Both the message and the hash are byte-arrays."
|
||||
^bytes [^bytes message]
|
||||
(let [digest (MessageDigest/getInstance "SHA-256")]
|
||||
(.digest digest message)))
|
||||
|
||||
(defn num->bytes
|
||||
"Returns the byte-array representation of n.
|
||||
The array will have the specified length."
|
||||
[length n]
|
||||
(let [a (.toByteArray (biginteger n))
|
||||
l (count a)
|
||||
zeros (repeat (- length l) (byte 0))]
|
||||
(if (> l length)
|
||||
(byte-array (drop (- l length) (seq a)))
|
||||
(byte-array (concat zeros a)))))
|
||||
|
||||
(defn bytes->num
|
||||
"Returns a BigInteger from a byte-array."
|
||||
^BigInteger [^bytes bytes]
|
||||
(BigInteger. 1 bytes))
|
||||
|
||||
(defn bytes->hex-string
|
||||
"Returns a string containing the hexadecimal
|
||||
representation of the byte-array. This is the
|
||||
inverse of hex-string->bytes."
|
||||
[byte-array]
|
||||
(let [byte-seq (for [i (range (alength byte-array))] (aget byte-array i))
|
||||
byte-strings (map #(apply str (take-last 2 (format "%02x" %))) byte-seq)]
|
||||
(apply str (apply concat byte-strings))))
|
||||
|
||||
(defn num32->hex-string [n]
|
||||
(->> n (num->bytes 32) bytes->hex-string))
|
||||
|
||||
(defn ^bytes hex-string->bytes
|
||||
"returns a byte-array containing the bytes described
|
||||
by the hex-string. This is the inverse of bytes->hex-string."
|
||||
[hex-string]
|
||||
(let [byte-strings (map #(apply str %) (partition 2 hex-string))
|
||||
byte-vector (map #(Integer/parseInt % 16) byte-strings)]
|
||||
(byte-array byte-vector)))
|
||||
|
||||
(defn hex-string->num
|
||||
"returns BigInteger from a hex string"
|
||||
[hex-string]
|
||||
(-> hex-string hex-string->bytes bytes->num))
|
||||
|
||||
(defn bytes= [^bytes b1 ^bytes b2]
|
||||
(assert (= (alength b1) (alength b2)) "bytes= args not same size.")
|
||||
(loop [index 0]
|
||||
(if (= index (alength b1))
|
||||
true
|
||||
(if (= (aget b1 index) (aget b2 index))
|
||||
(recur (inc index))
|
||||
false)))
|
||||
)
|
||||
|
||||
(defn xor-bytes [^bytes a ^bytes b]
|
||||
(assert (= (alength a) (alength b)) "byte-wise-xor: arguments not same size.")
|
||||
(let [result (byte-array (alength a))]
|
||||
(doseq [i (range (alength a))]
|
||||
(aset result i (byte (bit-xor (aget a i) (aget b i)))))
|
||||
result))
|
||||
(:import (schnorr Schnorr)))
|
||||
|
||||
(defn do-sign [message private-key aux-rand]
|
||||
(Schnorr/sign message private-key aux-rand))
|
||||
|
@ -3,7 +3,8 @@
|
||||
[clojure.data.json :as json]
|
||||
[more-speech.nostr.util :refer [hex-string->num]]
|
||||
[more-speech.nostr.elliptic-signature :as ecc]
|
||||
[clojure.core.async :as async])
|
||||
[clojure.core.async :as async]
|
||||
[more-speech.nostr.util :as util])
|
||||
(:import (java.nio.charset StandardCharsets)))
|
||||
|
||||
(s/def ::id number?)
|
||||
@ -22,7 +23,7 @@
|
||||
::tags
|
||||
::references]))
|
||||
(defn hexify [n]
|
||||
(ecc/num32->hex-string n))
|
||||
(util/num32->hex-string n))
|
||||
|
||||
(defprotocol event-handler
|
||||
(handle-text-event [handler event])
|
||||
@ -44,7 +45,14 @@
|
||||
(defn process-event [{:keys [nicknames] :as event-state} event]
|
||||
(let [_name-of (fn [pubkey] (get nicknames pubkey pubkey))
|
||||
[_name _subscription-id inner-event :as _decoded-msg] event
|
||||
{:strs [_id _pubkey _created_at kind _tags _content _sig]} inner-event]
|
||||
{:strs [id pubkey _created_at kind _tags _content sig]} inner-event
|
||||
valid? (ecc/do-verify (util/hex-string->bytes id)
|
||||
(util/hex-string->bytes pubkey)
|
||||
(util/hex-string->bytes sig))]
|
||||
(if (not valid?)
|
||||
(do
|
||||
(prn 'signature-verification-failed event)
|
||||
event-state)
|
||||
(condp = kind
|
||||
0 (process-name-event event-state inner-event)
|
||||
3 (do
|
||||
@ -57,7 +65,7 @@
|
||||
;(printf "%s: %s %s %s\n" kind (f/format-time created_at) (name-of pubkey) content)
|
||||
event-state)
|
||||
(do (prn "unknown event: " event)
|
||||
event-state))))
|
||||
event-state)))))
|
||||
|
||||
(defn process-name-event [event-state {:strs [_id pubkey _created_at _kind _tags content _sig] :as event}]
|
||||
(try
|
||||
@ -141,7 +149,7 @@
|
||||
"returns byte array of id given the clojure form of the body"
|
||||
[{:keys [pubkey created_at kind tags content]}]
|
||||
(let [id-event (to-json [0 pubkey created_at kind tags content])
|
||||
id (ecc/sha-256 (.getBytes id-event StandardCharsets/UTF_8))]
|
||||
id (util/sha-256 (.getBytes id-event StandardCharsets/UTF_8))]
|
||||
id)
|
||||
)
|
||||
|
||||
@ -155,23 +163,23 @@
|
||||
|
||||
([event-state text reply-to-or-nil]
|
||||
(let [private-key (get-in event-state [:keys :private-key])
|
||||
private-key (ecc/hex-string->bytes private-key)
|
||||
private-key (util/hex-string->bytes private-key)
|
||||
pubkey (ecc/get-pub-key private-key)
|
||||
root (get-reply-root event-state reply-to-or-nil)
|
||||
tags (concat (make-event-reference-tags reply-to-or-nil root)
|
||||
(make-people-reference-tags event-state pubkey reply-to-or-nil))
|
||||
content text
|
||||
now (quot (System/currentTimeMillis) 1000)
|
||||
body {:pubkey (ecc/bytes->hex-string pubkey)
|
||||
body {:pubkey (util/bytes->hex-string pubkey)
|
||||
:created_at now
|
||||
:kind 1
|
||||
:tags tags
|
||||
:content content}
|
||||
id (make-id body)
|
||||
aux-rand (ecc/num->bytes 32 (biginteger (System/currentTimeMillis)))
|
||||
aux-rand (util/num->bytes 32 (biginteger (System/currentTimeMillis)))
|
||||
signature (ecc/do-sign id private-key aux-rand)
|
||||
event (assoc body :id (ecc/bytes->hex-string id)
|
||||
:sig (ecc/bytes->hex-string signature))
|
||||
event (assoc body :id (util/bytes->hex-string id)
|
||||
:sig (util/bytes->hex-string signature))
|
||||
]
|
||||
["EVENT" event])))
|
||||
|
||||
|
@ -90,7 +90,7 @@
|
||||
(defn get-events [event-agent]
|
||||
(let [conn (connect-to-relay (get relays 0) event-agent)
|
||||
id "more-speech"
|
||||
date (make-date "04/1/2022")
|
||||
date (make-date "04/20/2022")
|
||||
send-chan (:send-chan @event-agent)
|
||||
]
|
||||
(prn date (format-time date))
|
||||
|
@ -1,4 +1,5 @@
|
||||
(ns more-speech.nostr.util)
|
||||
(ns more-speech.nostr.util
|
||||
(:import (java.security MessageDigest)))
|
||||
|
||||
(defn num->bytes
|
||||
"Returns the byte-array representation of n.
|
||||
@ -35,12 +36,36 @@
|
||||
)
|
||||
|
||||
(defn hex-string->num
|
||||
"Converts a hex string to a BigInteger"
|
||||
^BigInteger [hex-string]
|
||||
(bytes->num (hex-string->bytes hex-string))
|
||||
"returns BigInteger from a hex string"
|
||||
[hex-string]
|
||||
(-> hex-string hex-string->bytes bytes->num))
|
||||
|
||||
(defn num32->hex-string [n]
|
||||
"converts a number to a 32 byte hex-string"
|
||||
(->> n (num->bytes 32) bytes->hex-string))
|
||||
|
||||
(defn bytes=
|
||||
"compares two byte arrays for equality."
|
||||
[^bytes b1 ^bytes b2]
|
||||
(assert (= (alength b1) (alength b2)) "bytes= args not same size.")
|
||||
(loop [index 0]
|
||||
(if (= index (alength b1))
|
||||
true
|
||||
(if (= (aget b1 index) (aget b2 index))
|
||||
(recur (inc index))
|
||||
false)))
|
||||
)
|
||||
|
||||
(defn num->hex-string
|
||||
"converts a BigInteger to a hex-string"
|
||||
[^BigInteger num]
|
||||
(bytes->hex-string (num->bytes 32 num)))
|
||||
(defn sha-256
|
||||
"Returns the sha256 hash of the message.
|
||||
Both the message and the hash are byte-arrays."
|
||||
^bytes [^bytes message]
|
||||
(let [digest (MessageDigest/getInstance "SHA-256")]
|
||||
(.digest digest message)))
|
||||
|
||||
(defn xor-bytes [^bytes a ^bytes b]
|
||||
(assert (= (alength a) (alength b)) "byte-wise-xor: arguments not same size.")
|
||||
(let [result (byte-array (alength a))]
|
||||
(doseq [i (range (alength a))]
|
||||
(aset result i (byte (bit-xor (aget a i) (aget b i)))))
|
||||
result))
|
||||
|
@ -42,7 +42,7 @@
|
||||
(defn format-user-id [nicknames user-id]
|
||||
(if (nil? user-id)
|
||||
""
|
||||
(abbreviate (get nicknames user-id (util/num->hex-string user-id)) 20)))
|
||||
(abbreviate (get nicknames user-id (util/num32->hex-string user-id)) 20)))
|
||||
|
||||
(defn format-header [nicknames {:keys [pubkey created-at content] :as event}]
|
||||
(if (nil? event)
|
||||
|
@ -1,8 +1,8 @@
|
||||
(ns more-speech.ui.swing.article-tree
|
||||
(:require [more-speech.nostr.events :as events]
|
||||
[more-speech.ui.formatters :as formatters]
|
||||
[more-speech.nostr.elliptic-signature :as ecc]
|
||||
[more-speech.ui.config :as config])
|
||||
[more-speech.ui.config :as config]
|
||||
[more-speech.nostr.util :as util])
|
||||
(:use [seesaw core font tree])
|
||||
(:import (javax.swing.tree DefaultMutableTreeNode DefaultTreeModel TreePath)))
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
(if (some? referent)
|
||||
(let [replied-event (get text-map referent)]
|
||||
(text! reply-to (format-user (:pubkey replied-event)))
|
||||
(text! citing (formatters/abbreviate (ecc/num32->hex-string referent) 32)))
|
||||
(text! citing (formatters/abbreviate (util/num32->hex-string referent) 32)))
|
||||
(do (text! reply-to "")
|
||||
(text! citing "")))
|
||||
)))
|
||||
|
Loading…
Reference in New Issue
Block a user