fix(rest): encode waku message payload in base64

This commit is contained in:
Lorenzo Delgado 2022-08-29 16:54:11 +02:00 committed by Lorenzo Delgado
parent 842cfb3476
commit 791ce6d222
7 changed files with 86 additions and 39 deletions

View File

@ -11,7 +11,7 @@ import
libp2p/protocols/pubsub/pubsub
import
../../waku/v2/node/wakunode2,
../../waku/v2/node/rest/[server, client, utils],
../../waku/v2/node/rest/[server, client, base64, utils],
../../waku/v2/node/rest/relay/[api_types, relay_api, topic_cache]
@ -164,8 +164,8 @@ suite "REST API - Relay":
response.contentType == $MIMETYPE_JSON
response.data.len == 3
response.data.all do (msg: RelayWakuMessage) -> bool:
msg.payload == "TEST-1" and
string(msg.contentTopic.get()) == "content-topic-x" and
msg.payload == Base64String.encode("TEST-1") and
msg.contentTopic.get().string == "content-topic-x" and
msg.version.get() == Natural(1) and
msg.timestamp.get() == int64(2022)
@ -211,7 +211,7 @@ suite "REST API - Relay":
discard await client.relayPostSubscriptionsV1(newTopics)
let response = await client.relayPostMessagesV1(defaultTopic, RelayWakuMessage(
payload: "TEST-PAYLOAD",
payload: Base64String.encode("TEST-PAYLOAD"),
contentTopic: some(ContentTopicString(defaultContentTopic)),
timestamp: some(int64(2022))
))

View File

@ -1,12 +1,13 @@
{.used.}
import std/typetraits
import chronicles,
unittest2,
import
stew/[results, byteutils],
chronicles,
unittest2,
json_serialization
import
../../waku/v2/node/rest/serdes,
../../waku/v2/node/rest/base64,
../../waku/v2/node/rest/relay/api_types
@ -15,25 +16,27 @@ suite "Relay API - serialization":
suite "RelayWakuMessage - decode":
test "optional fields are not provided":
# Given
let jsonBytes = toBytes("""{ "payload": "MESSAGE" }""")
let payload = Base64String.encode("MESSAGE")
let jsonBytes = toBytes("{\"payload\":\"" & $payload & "\"}")
# When
let res = decodeFromJsonBytes(RelayWakuMessage, jsonBytes, requireAllFields = true)
# Then
require(res.isOk)
require(res.isOk())
let value = res.get()
check:
value.payload == "MESSAGE"
value.contentTopic.isNone
value.version.isNone
value.timestamp.isNone
value.payload == payload
value.contentTopic.isNone()
value.version.isNone()
value.timestamp.isNone()
suite "RelayWakuMessage - encode":
test "optional fields are none":
# Given
let payload = Base64String.encode("MESSAGE")
let data = RelayWakuMessage(
payload: "MESSAGE",
payload: payload,
contentTopic: none(ContentTopicString),
version: none(Natural),
timestamp: none(int64)
@ -43,7 +46,7 @@ suite "Relay API - serialization":
let res = encodeIntoJsonBytes(data)
# Then
require(res.isOk)
require(res.isOk())
let value = res.get()
check:
value == toBytes("""{"payload":"MESSAGE"}""")
value == toBytes("{\"payload\":\"" & $payload & "\"}")

View File

@ -0,0 +1,27 @@
{.push raises: [Defect].}
import stew/[results, byteutils, base64]
type Base64String* = distinct string
proc encode*(t: type Base64String, value: string|seq[byte]): Base64String =
let val = block:
when value is string:
toBytes(value)
else:
value
Base64String(base64.encode(Base64, val))
proc decode*(t: Base64String): Result[seq[byte], cstring] =
try:
ok(base64.decode(Base64, string(t)))
except:
err("failed to decode base64 string")
proc `$`*(t: Base64String): string {.inline.}=
string(t)
proc `==`*(lhs: Base64String|string, rhs: Base64String|string): bool {.inline.}=
string(lhs) == string(rhs)

View File

@ -1,24 +1,25 @@
{.push raises: [ Defect ].}
{.push raises: [Defect].}
import
std/[sets, strformat],
stew/byteutils,
chronicles,
json_serialization,
json_serialization/std/options,
presto/[route, client, common]
import ".."/serdes
import ../../wakunode2
import
../../../protocol/waku_message,
../serdes,
../base64
#### Types
type
PubSubTopicString* = distinct string
ContentTopicString* = distinct string
PubSubTopicString* = distinct string
ContentTopicString* = distinct string
type RelayWakuMessage* = object
payload*: string
payload*: Base64String
contentTopic*: Option[ContentTopicString]
version*: Option[Natural]
timestamp*: Option[int64]
@ -37,23 +38,29 @@ type
proc toRelayWakuMessage*(msg: WakuMessage): RelayWakuMessage =
RelayWakuMessage(
payload: string.fromBytes(msg.payload),
payload: base64.encode(Base64String, msg.payload),
contentTopic: some(ContentTopicString(msg.contentTopic)),
version: some(Natural(msg.version)),
timestamp: some(msg.timestamp)
)
proc toWakuMessage*(msg: RelayWakuMessage, version = 0): WakuMessage =
proc toWakuMessage*(msg: RelayWakuMessage, version = 0): Result[WakuMessage, cstring] =
const defaultContentTopic = ContentTopicString("/waku/2/default-content/proto")
WakuMessage(
payload: msg.payload.toBytes(),
contentTopic: ContentTopic(msg.contentTopic.get(defaultContentTopic)),
version: uint32(msg.version.get(version)),
timestamp: msg.timestamp.get(0)
)
let
payload = ?msg.payload.decode()
contentTopic = ContentTopic(msg.contentTopic.get(defaultContentTopic))
version = uint32(msg.version.get(version))
timestamp = msg.timestamp.get(0)
ok(WakuMessage(payload: payload, contentTopic: contentTopic, version: version, timestamp: timestamp))
#### Serialization and deserialization
proc writeValue*(writer: var JsonWriter[RestJson], value: Base64String)
{.raises: [IOError, Defect].} =
writer.writeValue(string(value))
proc writeValue*(writer: var JsonWriter[RestJson], value: PubSubTopicString)
{.raises: [IOError, Defect].} =
writer.writeValue(string(value))
@ -74,6 +81,10 @@ proc writeValue*(writer: var JsonWriter[RestJson], value: RelayWakuMessage)
writer.writeField("timestamp", value.timestamp)
writer.endRecord()
proc readValue*(reader: var JsonReader[RestJson], value: var Base64String)
{.raises: [SerializationError, IOError, Defect].} =
value = Base64String(reader.readValue(string))
proc readValue*(reader: var JsonReader[RestJson], value: var PubSubTopicString)
{.raises: [SerializationError, IOError, Defect].} =
value = PubSubTopicString(reader.readValue(string))
@ -85,7 +96,7 @@ proc readValue*(reader: var JsonReader[RestJson], value: var ContentTopicString)
proc readValue*(reader: var JsonReader[RestJson], value: var RelayWakuMessage)
{.raises: [SerializationError, IOError, Defect].} =
var
payload = none(string)
payload = none(Base64String)
contentTopic = none(ContentTopicString)
version = none(Natural)
timestamp = none(int64)
@ -100,7 +111,7 @@ proc readValue*(reader: var JsonReader[RestJson], value: var RelayWakuMessage)
case fieldName
of "payload":
payload = some(reader.readValue(string))
payload = some(reader.readValue(Base64String))
of "contentTopic":
contentTopic = some(reader.readValue(ContentTopicString))
of "version":

View File

@ -7,9 +7,12 @@ import
json_serialization,
json_serialization/std/options,
presto/[route, client, common]
import ".."/[serdes, utils]
import ../../wakunode2
import "."/[api_types, topic_cache]
import
../../wakunode2,
../serdes,
../utils,
./api_types,
./topic_cache
logScope: topics = "rest_api_relay"
@ -130,9 +133,11 @@ proc installRelayPostMessagesV1Handler*(router: var RestRouter, node: WakuNode)
if reqResult.isErr():
return RestApiResponse.badRequest()
let message: RelayPostMessagesRequest = reqResult.get()
let resMessage = reqResult.value.toWakuMessage(version = 0)
if resMessage.isErr():
return RestApiResponse.badRequest()
if not (waitFor node.publish(pubSubTopic, message.toWakuMessage(version = 0)).withTimeout(futTimeout)):
if not (waitFor node.publish(pubSubTopic, resMessage.value).withTimeout(futTimeout)):
error "Failed to publish message to topic", topic=pubSubTopic
return RestApiResponse.internalServerError()

View File

@ -118,6 +118,7 @@ components:
properties:
payload:
type: string
format: byte
contentTopic:
$ref: '#/components/schemas/ContentTopic'
version:

View File

@ -1,7 +1,7 @@
{.push raises: [Defect].}
import std/typetraits
import
std/typetraits,
stew/results,
chronicles,
serialization,