You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardexpand all lines: README.md
+55-16
Original file line number
Diff line number
Diff line change
@@ -4,9 +4,11 @@
4
4
5
5
This repository contains the code for the validator monitoring system. The system is designed to listen signatures request from different networks validate them and store the results in a database.
6
6
7
+
It also contains a simple JWT generator that can be used to easily generate the JWT token necessary to access some API endpoints. More on this on the [API](#api) section.
8
+
7
9
In dappnode, the signature request and validation flow is as follows:
8
10
9
-
1. The staking brain sends the signature request of type `PROOF_OF_VALIDATION` to the web3signer (see https://github.com/Consensys/web3signer/pull/982). The request has the following format:
11
+
**1.** The staking brain sends the signature request of type `PROOF_OF_VALIDATION` to the web3signer (see <https://github.com/Consensys/web3signer/pull/982>). The request has the following format:
10
12
11
13
```json
12
14
{
@@ -16,17 +18,54 @@ In dappnode, the signature request and validation flow is as follows:
16
18
}
17
19
```
18
20
19
-
2. The web3signer answers with the `PROOF_OF_VALIDATION` signature. Its important to notice that the order of the items in the JSON matters.
21
+
**2.** The web3signer answers with the `PROOF_OF_VALIDATION` signature. Its important to notice that the order of the items in the JSON matters.
20
22
21
-
3. The staking brain sends back all the `PROOF_OF_VALIDATION` signatures to the the signatures monitoring system. The listener will validate the requests, the validators and the signatures and finally store the result into a mongo db.
23
+
**3.** The staking brain sends back all the `PROOF_OF_VALIDATION` signatures to the the signatures monitoring system. The listener will validate the requests, the validators and the signatures and finally store the result into a mongo db.
22
24
23
-
## API
25
+
## API
24
26
25
27
-`/signatures?network=<network>`:
26
28
-`POST`: TODO
27
29
-`GET`: TODO
28
30
29
-
## Validation
31
+
### Authentication
32
+
33
+
The `GET /signatures` endpoint is protected by a JWT token, which must be included in the HTTPS request. This token should be passed in the Authorization header using the Bearer schema. The expected format is:
34
+
35
+
```text
36
+
Bearer <JWT token>
37
+
```
38
+
39
+
#### JWT requirements
40
+
41
+
To access the `GET /signatures` endpoint, the JWT must meet the following criteria:
42
+
43
+
-**Key ID** (`kid`): The JWT must include a kid claim in the header. It will be used to identify which public key to use to verify the signature.
44
+
45
+
As a nice to have, the JWT can also include the following claims as part of the payload:
46
+
47
+
-**Expiration time** (`exp`): The expiration time of the token, in Unix time. If no `exp` is provided, the token will be valid indefinitely.
48
+
-**Subject** (`sub`): Additional information about the user or entity behind the token. (e.g. an email address)
49
+
50
+
#### Generating the JWT
51
+
52
+
To generate a JWT token, you can use the `jwt-generator` tool included in this repository. The tool requires an RSA private key in PEM format to sign the token.
53
+
A keypair in PEM format can be generated using OpenSSL:
Only JWT tokens with whitelisted "kid" and pubkey will be accepted. Please contact the dappnode team for more information on this.
67
+
68
+
## Validation
30
69
31
70
The process of validating the request and the signature follows the next steps:
32
71
@@ -35,30 +74,30 @@ The process of validating the request and the signature follows the next steps:
35
74
36
75
```go
37
76
typeSignatureRequeststruct {
38
-
Payloadstring`json:"payload"`
39
-
Pubkeystring`json:"pubkey"`
40
-
Signaturestring`json:"signature"`
41
-
TagTag`json:"tag"`
77
+
Payloadstring`json:"payload"`
78
+
Pubkeystring`json:"pubkey"`
79
+
Signaturestring`json:"signature"`
80
+
TagTag`json:"tag"`
42
81
}
43
82
```
44
83
45
84
The payload must be encoded in base64 and must have the following format:
46
85
47
86
```go
48
87
typeDecodedPayloadstruct {
49
-
Typestring`json:"type"`
50
-
Platformstring`json:"platform"`
51
-
Timestampstring`json:"timestamp"`
88
+
Typestring`json:"type"`
89
+
Platformstring`json:"platform"`
90
+
Timestampstring`json:"timestamp"`
52
91
}
53
92
```
54
93
55
-
3. The validators must be in status "active_on_going" according to a standard beacon node API, see https://ethereum.github.io/beacon-APIs/#/Beacon/postStateValidators:
94
+
3. The validators must be in status "active_on_going" according to a standard beacon node API, see <https://ethereum.github.io/beacon-APIs/#/Beacon/postStateValidators>:
56
95
3.1 The signatures from the validators that are not in this status will be discarded.
57
96
3.2 If in the moment of querying the beacon node to get the validator status the beacon node is down the signature will be accepted storing the validator status as "unknown" for later validation.
58
97
4. Only the signatures that have passed the previous steps will be validated. The validation of the signature will be done using the pubkey from the request.
59
98
5. Only valid signatures will be stored in the database.
60
99
61
-
## Crons
100
+
## Crons
62
101
63
102
There are 2 cron to ensure the system is working properly:
64
103
@@ -88,12 +127,12 @@ bson.M{
88
127
"timestamp": req.DecodedPayload.Timestamp,
89
128
},
90
129
},
91
-
}
130
+
}
92
131
```
93
132
94
133
**Mongo db UI**
95
134
96
-
There is a express mongo db UI that can be accessed at `http://localhost:8080`. If its running in dev mode and the compose dev was deployed on a dappnode environment then it can be access through http://ui.dappnode:8080
135
+
There is a express mongo db UI that can be accessed at `http://localhost:8080`. If its running in dev mode and the compose dev was deployed on a dappnode environment then it can be access through <http://ui.dappnode:8080>
"publicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq81M9pHCZEExzJFgWEXK\navIs0AexsLlP6CIGkbvfe/GX+kIjP28kkXYGCJlUuVhGYa8wU2mBYeXTbtvi9OR9\ndmKTOzsl3QzIKVd5BqXqbTmQxGp0S6ShujK6LHTOELxwYhFKulx2ls2DSyXhqOGx\nyh0Gm/3H7CiCgNHMJWUUiy5Xyp71vtimzDM+OniUVQE/ZjPg5WG+cM536Ms8XcK1\nNIN0z8ovgAibHqw8jEljxM89Sn9XD3mQo8kBTG+3dLsjUbHZDiJZogNgeXsOrM7m\nh3YtIwMvr5YEWUR7ON7ST5Wrwx14uF6YDE0yo6nb/cmmSSUJ/cdX36dNK3dGrYhB\nywIDAQAB\n-----END PUBLIC KEY-----",
privateKeyPath:=flag.String("private-key", "", "Path to the RSA private key file (mandatory)")
17
+
subject:=flag.String("sub", "", "Subject claim for the JWT (optional)")
18
+
expiration:=flag.String("exp", "", "Expiration duration for the JWT in hours (optional, e.g., '24h' for 24 hours). If no value is provided, the generated token will not expire.")
19
+
kid:=flag.String("kid", "", "Key ID (kid) for the JWT (mandatory)")
20
+
outputFilePath:=flag.String("output", "token.jwt", "Output file path for the JWT. Defaults to ./token.jwt")
21
+
22
+
flag.Parse()
23
+
24
+
// Check for mandatory parameters
25
+
if*kid==""||*privateKeyPath=="" {
26
+
logger.Fatal("Key ID (kid) and private key path must be provided")
27
+
}
28
+
29
+
// Read the private key file
30
+
privateKeyData, err:=os.ReadFile(*privateKeyPath)
31
+
iferr!=nil {
32
+
logger.Fatal(fmt.Sprintf("Failed to read private key file: %v", err))
0 commit comments