2024-06-28 10:34:57 +00:00
|
|
|
{.push raises: [].}
|
2023-04-04 08:58:45 +00:00
|
|
|
|
|
|
|
import
|
|
|
|
chronicles,
|
|
|
|
chronos,
|
2023-05-02 14:20:38 +00:00
|
|
|
metrics,
|
2023-04-04 08:58:45 +00:00
|
|
|
stew/byteutils,
|
2023-05-05 08:12:49 +00:00
|
|
|
stew/endians2,
|
2023-04-04 08:58:45 +00:00
|
|
|
libp2p/protocols/pubsub/gossipsub,
|
|
|
|
libp2p/protocols/pubsub/errors,
|
|
|
|
nimcrypto/sha2,
|
|
|
|
secp256k1
|
|
|
|
|
2024-03-15 23:08:47 +00:00
|
|
|
const MessageWindowInSec = 5 * 60 # +- 5 minutes
|
2023-05-05 08:12:49 +00:00
|
|
|
|
2024-03-15 23:08:47 +00:00
|
|
|
import ./external_config, ../waku_relay/protocol, ../waku_core
|
2023-05-02 14:20:38 +00:00
|
|
|
|
2024-03-15 23:08:47 +00:00
|
|
|
declarePublicCounter waku_msg_validator_signed_outcome,
|
|
|
|
"number of messages for each validation outcome", ["result"]
|
2023-04-04 08:58:45 +00:00
|
|
|
|
2023-05-04 13:38:52 +00:00
|
|
|
# Application level message hash
|
2023-04-04 08:58:45 +00:00
|
|
|
proc msgHash*(pubSubTopic: string, msg: WakuMessage): array[32, byte] =
|
|
|
|
var ctx: sha256
|
|
|
|
ctx.init()
|
2024-03-15 23:08:47 +00:00
|
|
|
defer:
|
|
|
|
ctx.clear()
|
2023-04-04 08:58:45 +00:00
|
|
|
|
|
|
|
ctx.update(pubsubTopic.toBytes())
|
|
|
|
ctx.update(msg.payload)
|
|
|
|
ctx.update(msg.contentTopic.toBytes())
|
2023-05-05 08:12:49 +00:00
|
|
|
ctx.update(msg.timestamp.uint64.toBytes(Endianness.littleEndian))
|
2024-05-06 08:20:21 +00:00
|
|
|
# ctx.update(msg.meta) meta is not included in the message hash, as the signature goes in the meta field
|
2024-03-15 23:08:47 +00:00
|
|
|
ctx.update(
|
|
|
|
if msg.ephemeral:
|
|
|
|
@[1.byte]
|
|
|
|
else:
|
|
|
|
@[0.byte]
|
|
|
|
)
|
2023-04-04 08:58:45 +00:00
|
|
|
|
|
|
|
return ctx.finish()
|
|
|
|
|
2023-05-05 08:12:49 +00:00
|
|
|
proc withinTimeWindow*(msg: WakuMessage): bool =
|
|
|
|
# Returns true if the message timestamp is:
|
|
|
|
# abs(now - msg.timestamp) < MessageWindowInSec
|
|
|
|
let ts = msg.timestamp
|
|
|
|
let now = getNowInNanosecondTime()
|
|
|
|
let window = getNanosecondTime(MessageWindowInSec)
|
|
|
|
|
|
|
|
if abs(now - ts) < window:
|
|
|
|
return true
|
|
|
|
return false
|
|
|
|
|
2024-08-19 10:56:22 +00:00
|
|
|
proc addSignedShardsValidator*(
|
|
|
|
w: WakuRelay, protectedShards: seq[ProtectedShard], clusterId: uint16
|
|
|
|
) =
|
|
|
|
debug "adding validator to signed shards", protectedShards, clusterId
|
2023-04-04 08:58:45 +00:00
|
|
|
|
2024-03-15 23:08:47 +00:00
|
|
|
proc validator(
|
|
|
|
topic: string, msg: WakuMessage
|
|
|
|
): Future[errors.ValidationResult] {.async.} =
|
2023-05-02 14:20:38 +00:00
|
|
|
var outcome = errors.ValidationResult.Reject
|
|
|
|
|
2024-08-19 10:56:22 +00:00
|
|
|
for protectedShard in protectedShards:
|
|
|
|
let topicString =
|
|
|
|
$RelayShard(clusterId: clusterId, shardId: uint16(protectedShard.shard))
|
|
|
|
if (topicString == topic):
|
2024-02-01 17:16:10 +00:00
|
|
|
if msg.timestamp != 0:
|
|
|
|
if msg.withinTimeWindow():
|
|
|
|
let msgHash = SkMessage(topic.msgHash(msg))
|
|
|
|
let recoveredSignature = SkSignature.fromRaw(msg.meta)
|
|
|
|
if recoveredSignature.isOk():
|
2024-08-19 10:56:22 +00:00
|
|
|
if recoveredSignature.get.verify(msgHash, protectedShard.key):
|
2024-02-01 17:16:10 +00:00
|
|
|
outcome = errors.ValidationResult.Accept
|
2023-05-02 14:20:38 +00:00
|
|
|
|
2024-02-01 17:16:10 +00:00
|
|
|
if outcome != errors.ValidationResult.Accept:
|
2024-03-15 23:08:47 +00:00
|
|
|
debug "signed topic validation failed",
|
2024-08-19 10:56:22 +00:00
|
|
|
topic = topic, publicShardKey = protectedShard.key
|
2024-02-01 17:16:10 +00:00
|
|
|
waku_msg_validator_signed_outcome.inc(labelValues = [$outcome])
|
|
|
|
return outcome
|
2023-04-04 08:58:45 +00:00
|
|
|
|
2024-02-01 17:16:10 +00:00
|
|
|
return errors.ValidationResult.Accept
|
|
|
|
|
2024-08-19 10:56:22 +00:00
|
|
|
w.addValidator(validator, "signed shard validation failed")
|