2022-03-03 06:21:35 +00:00
|
|
|
## nim-websock
|
2022-07-21 15:38:13 +00:00
|
|
|
## Copyright (c) 2021-2022 Status Research & Development GmbH
|
2022-03-03 06:21:35 +00:00
|
|
|
## Licensed under either of
|
|
|
|
## * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
|
|
|
## * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
|
|
|
## at your option.
|
|
|
|
## This file may not be copied, modified, or distributed except according to
|
|
|
|
## those terms.
|
|
|
|
|
|
|
|
import pkg/[
|
|
|
|
httputils,
|
2022-06-20 07:19:38 +00:00
|
|
|
chronos/unittest2/asynctests,
|
|
|
|
]
|
2022-03-03 06:21:35 +00:00
|
|
|
|
|
|
|
import ../websock/websock
|
|
|
|
|
|
|
|
import ./helpers
|
|
|
|
|
|
|
|
let address = initTAddress("127.0.0.1:8888")
|
|
|
|
|
|
|
|
type
|
|
|
|
TokenHook* = ref object of Hook
|
|
|
|
status: int
|
|
|
|
token: string
|
|
|
|
request: HttpRequest
|
|
|
|
|
|
|
|
proc clientAppendGoodToken(ctx: Hook, headers: var HttpTable):
|
2024-01-22 12:08:17 +00:00
|
|
|
Result[void, string] {.gcsafe, raises: [].} =
|
2022-03-03 06:21:35 +00:00
|
|
|
headers.add("auth-token", "good-token")
|
|
|
|
return ok()
|
|
|
|
|
|
|
|
proc clientAppendBadToken(ctx: Hook, headers: var HttpTable):
|
2024-01-22 12:08:17 +00:00
|
|
|
Result[void, string] {.gcsafe, raises: [].} =
|
2022-03-03 06:21:35 +00:00
|
|
|
headers.add("auth-token", "bad-token")
|
|
|
|
return ok()
|
|
|
|
|
|
|
|
proc clientVerify(ctx: Hook, headers: HttpTable):
|
2024-01-22 12:08:17 +00:00
|
|
|
Future[Result[void, string]] {.gcsafe, async: (raises: []).} =
|
2022-03-03 06:21:35 +00:00
|
|
|
var p = TokenHook(ctx)
|
|
|
|
p.token = headers.getString("auth-status")
|
|
|
|
return ok()
|
|
|
|
|
|
|
|
proc serverVerify(ctx: Hook, headers: HttpTable):
|
2024-01-22 12:08:17 +00:00
|
|
|
Future[Result[void, string]] {.gcsafe, async: (raises: []).} =
|
2022-03-03 06:21:35 +00:00
|
|
|
var p = TokenHook(ctx)
|
|
|
|
if headers.getString("auth-token") == "good-token":
|
|
|
|
p.status = 101
|
|
|
|
return ok()
|
|
|
|
|
|
|
|
proc serverAppend(ctx: Hook, headers: var HttpTable):
|
2024-01-22 12:08:17 +00:00
|
|
|
Result[void, string] {.gcsafe, raises: [].} =
|
2022-03-03 06:21:35 +00:00
|
|
|
var p = TokenHook(ctx)
|
|
|
|
if p.status == 101:
|
|
|
|
headers.add("auth-status", "accept")
|
|
|
|
else:
|
|
|
|
headers.add("auth-status", "reject")
|
|
|
|
p.status = 0
|
|
|
|
return ok()
|
|
|
|
|
|
|
|
proc goodClientHook(): Hook =
|
|
|
|
TokenHook(
|
|
|
|
append: clientAppendGoodToken,
|
|
|
|
verify: clientVerify
|
|
|
|
)
|
|
|
|
|
|
|
|
proc badClientHook(): Hook =
|
|
|
|
TokenHook(
|
|
|
|
append: clientAppendBadToken,
|
|
|
|
verify: clientVerify
|
|
|
|
)
|
|
|
|
|
|
|
|
proc serverHook(): Hook =
|
|
|
|
TokenHook(
|
|
|
|
append: serverAppend,
|
|
|
|
verify: serverVerify
|
|
|
|
)
|
|
|
|
|
|
|
|
proc serverVerifyWithCode(ctx: Hook, headers: HttpTable):
|
2024-01-22 12:08:17 +00:00
|
|
|
Future[Result[void, string]] {.gcsafe, async: (raises: []).} =
|
|
|
|
try:
|
|
|
|
var p = TokenHook(ctx)
|
|
|
|
if headers.getString("auth-token") == "good-token":
|
|
|
|
p.status = 101
|
|
|
|
return ok()
|
|
|
|
else:
|
|
|
|
await p.request.stream.writer.sendError(Http401)
|
|
|
|
return err("authentication error")
|
|
|
|
except CatchableError as exc:
|
|
|
|
return err(exc.msg)
|
2022-03-03 06:21:35 +00:00
|
|
|
|
|
|
|
proc serverHookWithCode(request: HttpRequest): Hook =
|
|
|
|
TokenHook(
|
|
|
|
append: serverAppend,
|
|
|
|
verify: serverVerifyWithCode,
|
|
|
|
request: request
|
|
|
|
)
|
|
|
|
|
|
|
|
suite "Test Hooks":
|
2022-06-20 07:19:38 +00:00
|
|
|
setup:
|
|
|
|
var
|
|
|
|
server: HttpServer
|
2024-01-22 12:08:17 +00:00
|
|
|
goodCP {.used.} = goodClientHook()
|
|
|
|
badCP {.used.} = badClientHook()
|
2022-03-03 06:21:35 +00:00
|
|
|
|
|
|
|
teardown:
|
2022-06-20 07:19:38 +00:00
|
|
|
if server != nil:
|
|
|
|
server.stop()
|
|
|
|
waitFor server.closeWait()
|
2022-03-03 06:21:35 +00:00
|
|
|
|
2022-06-20 07:19:38 +00:00
|
|
|
asyncTest "client with valid token":
|
2022-03-03 06:21:35 +00:00
|
|
|
proc handle(request: HttpRequest) {.async.} =
|
|
|
|
check request.uri.path == WSPath
|
|
|
|
let
|
|
|
|
server = WSServer.new()
|
2024-01-22 12:08:17 +00:00
|
|
|
discard await server.handleRequest(
|
2022-03-03 06:21:35 +00:00
|
|
|
request,
|
|
|
|
hooks = @[serverHook()]
|
|
|
|
)
|
|
|
|
|
|
|
|
server = createServer(
|
|
|
|
address = address,
|
|
|
|
handler = handle,
|
|
|
|
flags = {ReuseAddr})
|
|
|
|
|
|
|
|
let session = await WebSocket.connect(
|
|
|
|
host = initTAddress("127.0.0.1:8888"),
|
|
|
|
path = WSPath,
|
|
|
|
hooks = @[goodCP]
|
|
|
|
)
|
|
|
|
|
|
|
|
check TokenHook(goodCP).token == "accept"
|
|
|
|
await session.stream.closeWait()
|
|
|
|
|
2022-06-20 07:19:38 +00:00
|
|
|
asyncTest "client with bad token":
|
2022-03-03 06:21:35 +00:00
|
|
|
proc handle(request: HttpRequest) {.async.} =
|
|
|
|
check request.uri.path == WSPath
|
|
|
|
let
|
|
|
|
server = WSServer.new()
|
2024-01-22 12:08:17 +00:00
|
|
|
discard await server.handleRequest(
|
2022-03-03 06:21:35 +00:00
|
|
|
request,
|
|
|
|
hooks = @[serverHook()]
|
|
|
|
)
|
|
|
|
|
|
|
|
server = createServer(
|
|
|
|
address = address,
|
|
|
|
handler = handle,
|
|
|
|
flags = {ReuseAddr})
|
|
|
|
|
|
|
|
let session = await WebSocket.connect(
|
|
|
|
host = initTAddress("127.0.0.1:8888"),
|
|
|
|
path = WSPath,
|
|
|
|
hooks = @[badCP]
|
|
|
|
)
|
|
|
|
|
|
|
|
check TokenHook(badCP).token == "reject"
|
|
|
|
await session.stream.closeWait()
|
|
|
|
|
2022-06-20 07:19:38 +00:00
|
|
|
asyncTest "server hook with code get good client":
|
2022-03-03 06:21:35 +00:00
|
|
|
proc handle(request: HttpRequest) {.async.} =
|
|
|
|
check request.uri.path == WSPath
|
|
|
|
let
|
|
|
|
server = WSServer.new()
|
2024-01-22 12:08:17 +00:00
|
|
|
discard await server.handleRequest(
|
2022-03-03 06:21:35 +00:00
|
|
|
request,
|
|
|
|
hooks = @[serverHookWithCode(request)]
|
|
|
|
)
|
|
|
|
|
|
|
|
server = createServer(
|
|
|
|
address = address,
|
|
|
|
handler = handle,
|
|
|
|
flags = {ReuseAddr})
|
|
|
|
|
|
|
|
let session = await WebSocket.connect(
|
|
|
|
host = initTAddress("127.0.0.1:8888"),
|
|
|
|
path = WSPath,
|
|
|
|
hooks = @[goodCP]
|
|
|
|
)
|
|
|
|
|
|
|
|
check TokenHook(goodCP).token == "accept"
|
|
|
|
await session.stream.closeWait()
|
|
|
|
|
2022-06-20 07:19:38 +00:00
|
|
|
asyncTest "server hook with code get bad client":
|
2022-03-03 06:21:35 +00:00
|
|
|
proc handle(request: HttpRequest) {.async.} =
|
|
|
|
check request.uri.path == WSPath
|
|
|
|
let
|
|
|
|
server = WSServer.new()
|
2024-01-22 12:08:17 +00:00
|
|
|
discard await server.handleRequest(
|
2022-03-03 06:21:35 +00:00
|
|
|
request,
|
|
|
|
hooks = @[serverHookWithCode(request)]
|
|
|
|
)
|
|
|
|
|
|
|
|
server = createServer(
|
|
|
|
address = address,
|
|
|
|
handler = handle,
|
|
|
|
flags = {ReuseAddr})
|
|
|
|
|
|
|
|
expect WSFailedUpgradeError:
|
|
|
|
let session = await WebSocket.connect(
|
|
|
|
host = initTAddress("127.0.0.1:8888"),
|
|
|
|
path = WSPath,
|
|
|
|
hooks = @[badCP]
|
|
|
|
)
|
|
|
|
await session.stream.closeWait()
|