Skip to content

Commit

Permalink
chore: Implemented CORS handling for nwaku REST server (#2470)
Browse files Browse the repository at this point in the history
* Add allowOrigin configuration for wakunode and WakuRestServer
Update nim-presto to the latest master that contains middleware support
Rework Rest Server in waku to utilize chronos' and presto's new middleware design and added proper CORS handling.
Added cors tests and fixes

Co-authored-by: Ivan FB <128452529+Ivansete-status@users.noreply.github.com>
  • Loading branch information
NagyZoltanPeter and Ivansete-status committed Feb 29, 2024
1 parent 3f4f6d7 commit d832f92
Show file tree
Hide file tree
Showing 16 changed files with 623 additions and 97 deletions.
63 changes: 42 additions & 21 deletions apps/wakunode2/app.nim
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ type
node: WakuNode

rpcServer: Option[RpcHttpServer]
restServer: Option[RestServerRef]
restServer: Option[WakuRestServerRef]
metricsServer: Option[MetricsHttpServerRef]

AppResult*[T] = Result[T, string]
Expand Down Expand Up @@ -667,34 +667,55 @@ proc startApp*(app: var App): AppResult[void] =

## Monitoring and external interfaces

proc startRestServer(app: App, address: IpAddress, port: Port, conf: WakuNodeConf): AppResult[RestServerRef] =
proc startRestServer(app: App,
address: IpAddress,
port: Port,
conf: WakuNodeConf):
AppResult[WakuRestServerRef] =

# Used to register api endpoints that are not currently installed as keys,
# values are holding error messages to be returned to the client
var notInstalledTab: Table[string, string] = initTable[string, string]()

proc requestErrorHandler(error: RestRequestError,
request: HttpRequestRef):
Future[HttpResponseRef] {.async.} =
case error
of RestRequestError.Invalid:
return await request.respond(Http400, "Invalid request", HttpTable.init())
of RestRequestError.NotFound:
let rootPath = request.rawPath.split("/")[1]
if notInstalledTab.hasKey(rootPath):
return await request.respond(Http404, notInstalledTab[rootPath], HttpTable.init())
else:
return await request.respond(Http400, "Bad request initiated. Invalid path or method used.", HttpTable.init())
of RestRequestError.InvalidContentBody:
return await request.respond(Http400, "Invalid content body", HttpTable.init())
of RestRequestError.InvalidContentType:
return await request.respond(Http400, "Invalid content type", HttpTable.init())
of RestRequestError.Unexpected:
return defaultResponse()
let requestErrorHandler : RestRequestErrorHandler = proc (error: RestRequestError,
request: HttpRequestRef):
Future[HttpResponseRef]
{.async: (raises: [CancelledError]).} =
try:
case error
of RestRequestError.Invalid:
return await request.respond(Http400, "Invalid request", HttpTable.init())
of RestRequestError.NotFound:
let paths = request.rawPath.split("/")
let rootPath = if len(paths) > 1:
paths[1]
else:
""
notInstalledTab.withValue(rootPath, errMsg):
return await request.respond(Http404, errMsg[], HttpTable.init())
do:
return await request.respond(Http400, "Bad request initiated. Invalid path or method used.", HttpTable.init())
of RestRequestError.InvalidContentBody:
return await request.respond(Http400, "Invalid content body", HttpTable.init())
of RestRequestError.InvalidContentType:
return await request.respond(Http400, "Invalid content type", HttpTable.init())
of RestRequestError.Unexpected:
return defaultResponse()
except HttpWriteError:
error "Failed to write response to client", error = getCurrentExceptionMsg()
discard

return defaultResponse()

let server = ? newRestHttpServer(address, port, requestErrorHandler = requestErrorHandler)
let allowedOrigin = if len(conf.restAllowOrigin) > 0 :
some(conf.restAllowOrigin.join(","))
else:
none(string)

let server = ? newRestHttpServer(address, port,
allowedOrigin = allowedOrigin,
requestErrorHandler = requestErrorHandler)

## Admin REST API
if conf.restAdmin:
installAdminApiHandlers(server.router, app.node)
Expand Down
8 changes: 8 additions & 0 deletions apps/wakunode2/external_config.nim
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,14 @@ type
defaultValue: false
name: "rest-private" }: bool

restAllowOrigin* {.
desc: "Allow cross-origin requests from the specified origin." &
"Argument may be repeated." &
"Wildcards: * or ? allowed." &
"Ex.: \"localhost:*\" or \"127.0.0.1:8080\"",
defaultValue: newSeq[string]()
name: "rest-allow-origin" }: seq[string]

## Metrics config

metricsServer* {.
Expand Down
3 changes: 2 additions & 1 deletion tests/all_tests_waku.nim
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ import
./wakunode_rest/test_rest_filter,
./wakunode_rest/test_rest_legacy_filter,
./wakunode_rest/test_rest_lightpush,
./wakunode_rest/test_rest_admin
./wakunode_rest/test_rest_admin,
./wakunode_rest/test_rest_cors

import
./waku_rln_relay/test_waku_rln_relay,
Expand Down
3 changes: 2 additions & 1 deletion tests/wakunode_rest/test_all.nim
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ import
./test_rest_relay,
./test_rest_serdes,
./test_rest_store,
./test_rest_admin
./test_rest_admin,
./test_rest_cors
4 changes: 2 additions & 2 deletions tests/wakunode_rest/test_rest_admin.nim
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ suite "Waku v2 Rest API - Admin":
var peerInfo1 {.threadvar.}: RemotePeerInfo
var peerInfo2 {.threadvar.}: RemotePeerInfo
var peerInfo3 {.threadvar.}: RemotePeerInfo
var restServer {.threadvar.}: RestServerRef
var restServer {.threadvar.}: WakuRestServerRef
var client{.threadvar.}: RestClientRef

asyncSetup:
Expand All @@ -46,7 +46,7 @@ suite "Waku v2 Rest API - Admin":

let restPort = Port(58011)
let restAddress = parseIpAddress("127.0.0.1")
restServer = RestServerRef.init(restAddress, restPort).tryGet()
restServer = WakuRestServerRef.init(restAddress, restPort).tryGet()

installAdminApiHandlers(restServer.router, node1)

Expand Down

0 comments on commit d832f92

Please sign in to comment.