New stricter beacon-node URL parsing

This commit is contained in:
cheatfate 2023-05-09 23:09:09 +03:00 committed by Zahary Karadjov
parent 8b7ec932cb
commit a36cacda44
No known key found for this signature in database
GPG Key ID: C1F42EAFF38D570F
4 changed files with 191 additions and 34 deletions

View File

@ -570,6 +570,11 @@ OK: 24/24 Fail: 0/24 Skip: 0/24
+ BeaconBlockType OK + BeaconBlockType OK
``` ```
OK: 1/1 Fail: 0/1 Skip: 0/1 OK: 1/1 Fail: 0/1 Skip: 0/1
## Validator Client test suite
```diff
+ normalizeUri() test vectors OK
```
OK: 1/1 Fail: 0/1 Skip: 0/1
## Validator change pool testing suite ## Validator change pool testing suite
```diff ```diff
+ addValidatorChangeMessage/getAttesterSlashingMessage OK + addValidatorChangeMessage/getAttesterSlashingMessage OK
@ -680,4 +685,4 @@ OK: 2/2 Fail: 0/2 Skip: 0/2
OK: 9/9 Fail: 0/9 Skip: 0/9 OK: 9/9 Fail: 0/9 Skip: 0/9
---TOTAL--- ---TOTAL---
OK: 389/394 Fail: 0/394 Skip: 5/394 OK: 390/395 Fail: 0/395 Skip: 5/395

View File

@ -501,44 +501,44 @@ proc parseRoles*(data: string): Result[set[BeaconNodeRole], cstring] =
return err("Invalid beacon node role string found") return err("Invalid beacon node role string found")
ok(res) ok(res)
proc normalizeUri*(remoteUri: Uri): Uri = proc normalizeUri*(r: Uri): Result[Uri, cstring] =
var r = remoteUri const
if (len(r.scheme) == 0) and (len(r.username) == 0) and MissingPortNumber = cstring("Missing port number")
(len(r.password) == 0) and (len(r.hostname) == 0) and MissingHostname = cstring("Missing hostname")
(len(r.port) == 0) and (len(r.path) > 0): UnknownScheme = cstring("Unknown scheme value")
# When `scheme` is not specified and `port` is not specified - whole
# hostname is stored in `path`.`query` and `anchor` could still be present. if ($r).toLowerAscii().startsWith("http://") or
# test.com ($r).toLowerAscii().startsWith("https://"):
# test.com?q=query # When a scheme is provided, only a hostname is required
# test.com?q=query#anchor=anchor if len(r.hostname) == 0: return err(MissingHostname)
parseUri("http://" & $remoteUri & ":" & $defaultEth2RestPort) return ok(r)
elif (len(r.scheme) > 0) and (len(r.username) == 0) and
(len(r.password) == 0) and (len(r.hostname) == 0) and # Check for unknown scheme
(len(r.port) == 0) and (len(r.path) > 0): if ($r).contains("://"):
# When `scheme` is not specified but `port` is specified - whole return err(UnknownScheme)
# hostname is stored in `scheme` and `port` is in `path`.
# 192.168.0.1:5052 # Add the default scheme (http)
# test.com:5052 let normalized =
# test.com:5052?q=query if ($r).startsWith("//"):
# test.com:5052?q=query#anchor=anchor parseUri("http:" & $r)
parseUri("http://" & $remoteUri)
elif (len(r.scheme) > 0) and (len(r.hostname) > 0):
# When `scheme` is specified, but `port` is not we use default.
# http://192.168.0.1
# http://test.com
# http://test.com?q=query
# http://test.com?q=query#anchor=anchor
if len(r.port) == 0: r.port = $defaultEth2RestPort
r
else: else:
remoteUri parseUri("http://" & $r)
if len(normalized.hostname) == 0:
return err(MissingHostname)
if len(normalized.port) == 0:
return err(MissingPortNumber)
ok(normalized)
proc init*(t: typedesc[BeaconNodeServerRef], remote: Uri, proc init*(t: typedesc[BeaconNodeServerRef], remote: Uri,
index: int): Result[BeaconNodeServerRef, string] = index: int): Result[BeaconNodeServerRef, string] =
doAssert(index >= 0) doAssert(index >= 0)
let let
flags = {RestClientFlag.CommaSeparatedArray} flags = {RestClientFlag.CommaSeparatedArray}
remoteUri = normalizeUri(remote) remoteUri = normalizeUri(remote).valueOr:
return err("Invalid URL: " & $error)
client = client =
block: block:
let res = RestClientRef.new($remoteUri, flags = flags) let res = RestClientRef.new($remoteUri, flags = flags)

View File

@ -49,7 +49,8 @@ import # Unit test
./test_signing_node, ./test_signing_node,
./consensus_spec/all_tests as consensus_all_tests, ./consensus_spec/all_tests as consensus_all_tests,
./slashing_protection/test_fixtures, ./slashing_protection/test_fixtures,
./slashing_protection/test_slashing_protection_db ./slashing_protection/test_slashing_protection_db,
./test_validator_client
when not defined(i386): when not defined(i386):
# Avoids "Out of memory" CI failures # Avoids "Out of memory" CI failures

View File

@ -0,0 +1,151 @@
# beacon_chain
# Copyright (c) 2018-2023 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
{.push raises: [].}
{.used.}
import std/strutils
import unittest2
import ../beacon_chain/validator_client/common
const
HostNames = [
"[2001:db8::1]",
"127.0.0.1",
"hostname.com",
"localhost",
"username:password@[2001:db8::1]",
"username:password@127.0.0.1",
"username:password@hostname.com",
"username:password@localhost",
]
GoodTestVectors = [
("http://$1",
"ok(http://$1)"),
("http://$1?q=query",
"ok(http://$1?q=query)"),
("http://$1?q=query#anchor",
"ok(http://$1?q=query#anchor)"),
("http://$1/subpath/",
"ok(http://$1/subpath/)"),
("http://$1/subpath/q=query",
"ok(http://$1/subpath/q=query)"),
("http://$1/subpath/q=query#anchor",
"ok(http://$1/subpath/q=query#anchor)"),
("http://$1/subpath",
"ok(http://$1/subpath)"),
("http://$1/subpath?q=query",
"ok(http://$1/subpath?q=query)"),
("http://$1/subpath?q=query#anchor",
"ok(http://$1/subpath?q=query#anchor)"),
("https://$1",
"ok(https://$1)"),
("https://$1?q=query",
"ok(https://$1?q=query)"),
("https://$1?q=query#anchor",
"ok(https://$1?q=query#anchor)"),
("https://$1/subpath/",
"ok(https://$1/subpath/)"),
("https://$1/subpath/q=query",
"ok(https://$1/subpath/q=query)"),
("https://$1/subpath/q=query#anchor",
"ok(https://$1/subpath/q=query#anchor)"),
("https://$1/subpath",
"ok(https://$1/subpath)"),
("https://$1/subpath?q=query",
"ok(https://$1/subpath?q=query)"),
("https://$1/subpath?q=query#anchor",
"ok(https://$1/subpath?q=query#anchor)"),
("$1:5052",
"ok(http://$1:5052)"),
("$1:5052?q=query",
"ok(http://$1:5052?q=query)"),
("$1:5052?q=query#anchor",
"ok(http://$1:5052?q=query#anchor)"),
("$1:5052/subpath/",
"ok(http://$1:5052/subpath/)"),
("$1:5052/subpath/q=query",
"ok(http://$1:5052/subpath/q=query)"),
("$1:5052/subpath/q=query#anchor",
"ok(http://$1:5052/subpath/q=query#anchor)"),
("$1:5052/subpath",
"ok(http://$1:5052/subpath)"),
("$1:5052/subpath?q=query",
"ok(http://$1:5052/subpath?q=query)"),
("$1:5052/subpath?q=query#anchor",
"ok(http://$1:5052/subpath?q=query#anchor)"),
("bnode://$1:5052",
"err(Unknown scheme value)"),
("bnode://$1:5052?q=query",
"err(Unknown scheme value)"),
("bnode://$1:5052?q=query#anchor",
"err(Unknown scheme value)"),
("bnode://$1:5052/subpath/",
"err(Unknown scheme value)"),
("bnode://$1:5052/subpath/q=query",
"err(Unknown scheme value)"),
("bnode://$1:5052/subpath/q=query#anchor",
"err(Unknown scheme value)"),
("bnode://$1:5052/subpath",
"err(Unknown scheme value)"),
("bnode://$1:5052/subpath?q=query",
"err(Unknown scheme value)"),
("bnode://$1:5052/subpath?q=query#anchor",
"err(Unknown scheme value)"),
("//$1:5052",
"ok(http://$1:5052)"),
("//$1:5052?q=query",
"ok(http://$1:5052?q=query)"),
("//$1:5052?q=query#anchor",
"ok(http://$1:5052?q=query#anchor)"),
("//$1:5052/subpath/",
"ok(http://$1:5052/subpath/)"),
("//$1:5052/subpath/q=query",
"ok(http://$1:5052/subpath/q=query)"),
("//$1:5052/subpath/q=query#anchor",
"ok(http://$1:5052/subpath/q=query#anchor)"),
("//$1:5052/subpath",
"ok(http://$1:5052/subpath)"),
("//$1:5052/subpath?q=query",
"ok(http://$1:5052/subpath?q=query)"),
("//$1:5052/subpath?q=query#anchor",
"ok(http://$1:5052/subpath?q=query#anchor)"),
("//$1", "err(Missing port number)"),
("//$1?q=query", "err(Missing port number)"),
("//$1?q=query#anchor", "err(Missing port number)"),
("//$1/subpath/", "err(Missing port number)"),
("//$1/subpath/q=query", "err(Missing port number)"),
("//$1/subpath/q=query#anchor", "err(Missing port number)"),
("//$1/subpath", "err(Missing port number)"),
("//$1/subpath?q=query", "err(Missing port number)"),
("//$1/subpath?q=query#anchor", "err(Missing port number)"),
("$1", "err(Missing port number)"),
("$1?q=query", "err(Missing port number)"),
("$1?q=query#anchor", "err(Missing port number)"),
("$1/subpath/", "err(Missing port number)"),
("$1/subpath/q=query", "err(Missing port number)"),
("$1/subpath/q=query#anchor", "err(Missing port number)"),
("$1/subpath", "err(Missing port number)"),
("$1/subpath?q=query", "err(Missing port number)"),
("$1/subpath?q=query#anchor", "err(Missing port number)"),
("", "err(Missing hostname)")
]
suite "Validator Client test suite":
test "normalizeUri() test vectors":
for hostname in HostNames:
for vector in GoodTestVectors:
let expect = vector[1] % (hostname)
check $normalizeUri(parseUri(vector[0] % (hostname))) == expect