Compare commits

..

283 Commits

Author SHA1 Message Date
d30a45618c Update Rust crate serde to v1.0.214
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-29 01:34:48 +00:00
d5fc440b10 Update Rust crate reqwest to v0.12.9
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-10-29 00:29:38 +00:00
fc727422ab Update Rust crate tokio to v1.41.0
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-23 01:34:00 +00:00
21de91b318 Update Rust crate serde to v1.0.213
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-10-23 00:10:42 +00:00
0da7e74c09 Update Rust crate bytes to v1.8.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-10-22 00:21:15 +00:00
7742ea17da Update Rust crate futures to v0.3.31
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-10-06 00:28:20 +00:00
150a5cd012 Update Rust crate rustls-pemfile to v2.2.0
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-01 01:15:36 +00:00
bf78fc3abf Update Rust crate reqwest to v0.12.8
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-10-01 00:31:44 +00:00
f09cd78c57 Update Rust crate bytes to v1.7.2
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-09-19 00:34:05 +00:00
d73a2268a1 Update Rust crate tokio to v1.40.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-09-13 00:34:14 +00:00
b6bd55afa7 Update Rust crate serde to v1.0.210
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-12 01:40:13 +00:00
40039dee9f Update Rust crate clap to v4.5.17
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-09-12 00:34:29 +00:00
3422c2af89 cargo update
All checks were successful
continuous-integration/drone/push Build is passing
2024-08-23 09:57:06 +02:00
285fa1b984 Merge pull request 'Update Rust crate rustls-pemfile to v2.1.3' (#169) from renovate/rustls-pemfile-2.x-lockfile into master
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: #169
2024-08-23 07:55:49 +00:00
0bf05d056d Merge pull request 'Update Rust crate tokio to v1.39.2' (#167) from renovate/tokio-1.x-lockfile into master
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: #167
2024-08-23 07:55:34 +00:00
113bf913e2 Merge pull request 'Update Rust crate bytes to v1.7.0' (#168) from renovate/bytes-1.x-lockfile into master
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: #168
2024-08-23 07:55:17 +00:00
718acfa696 Merge pull request 'Update Rust crate actix-web-actors to v4.3.1' (#170) from renovate/actix-web-actors-4.x-lockfile into master
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: #170
2024-08-23 07:54:59 +00:00
add3dcefae Merge pull request 'Update Rust crate serde to v1.0.205' (#171) from renovate/serde-1.x-lockfile into master
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: #171
2024-08-23 07:16:24 +00:00
80eb736787 Merge pull request 'Update Rust crate clap to v4.5.11' (#165) from renovate/clap-4.x-lockfile into master
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: #165
2024-08-23 07:15:08 +00:00
d88afaa459 Update Rust crate serde to v1.0.205
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
2024-08-09 00:12:09 +00:00
0ea59a0fb0 Update Rust crate actix-web-actors to v4.3.1
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
2024-08-08 00:10:22 +00:00
268f8fcd64 Update Rust crate rustls-pemfile to v2.1.3
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
2024-08-04 00:10:17 +00:00
3c3a84d9ea Update Rust crate bytes to v1.7.0
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
2024-08-01 00:10:39 +00:00
d73f54ce0f Update Rust crate tokio to v1.39.2
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
2024-07-28 00:10:46 +00:00
023bf935eb Update Rust crate env_logger to v0.11.5
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-07-26 00:12:08 +00:00
6c24739c44 Update Rust crate clap to v4.5.11
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-07-26 00:12:05 +00:00
6e89eb03f5 Update Rust crate tokio to v1.39.1
All checks were successful
continuous-integration/drone/push Build is passing
2024-07-25 00:57:33 +00:00
c4a46a0609 Update Rust crate env_logger to v0.11.4
All checks were successful
continuous-integration/drone/push Build is passing
2024-07-24 01:17:11 +00:00
16f4e815a5 Update Rust crate clap to v4.5.10
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-07-24 00:10:36 +00:00
9d81fc4fff Update Rust crate tokio to v1.38.1
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-07-17 00:10:33 +00:00
e83c8389b3 Update Rust crate bytes to v1.6.1
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-07-14 00:09:38 +00:00
6d96850c84 Update Rust crate clap to v4.5.9
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-07-10 00:10:17 +00:00
32322ec8c9 Update Rust crate serde to v1.0.204
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-07-07 00:23:28 +00:00
4a19b8eb6b Merge pull request 'Update Rust crate log to v0.4.22' (#157) from renovate/log-0.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #157
2024-06-29 08:41:22 +00:00
70981b4f8b Update Rust crate log to v0.4.22
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-06-29 00:18:11 +00:00
808f3b1acc Update Rust crate clap to v4.5.8
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-06-29 00:18:07 +00:00
cba0bf53e0 Update Rust crate actix-web to v4.8.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-06-21 00:16:30 +00:00
61f98e2e70 Merge pull request 'Update Rust crate reqwest to v0.12.5' (#154) from renovate/reqwest-0.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #154
2024-06-18 16:24:51 +00:00
f0dd97dcac Update Rust crate reqwest to v0.12.5
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-06-18 00:17:14 +00:00
44851be0c0 Merge pull request 'Update Rust crate clap to v4.5.7' (#153) from renovate/clap-4.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #153
2024-06-14 17:51:37 +00:00
fdded8b5ce Update Rust crate clap to v4.5.7
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-06-11 00:14:15 +00:00
df6e2fdae2 Update Rust crate actix to v0.13.5
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-06-10 00:13:22 +00:00
627fbbf399 Update Rust crate actix-web to v4.7.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-06-09 00:14:28 +00:00
cb332240e0 Update Rust crate clap to v4.5.6
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-06-07 00:14:08 +00:00
3a387f7839 Update Rust crate tokio to v1.38.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-05-31 00:22:01 +00:00
2a9c5d388f Update Rust crate serde to v1.0.203
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-05-26 00:26:49 +00:00
1e573e18f6 Update Rust crate actix-web to v4.6.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-05-20 00:27:08 +00:00
316f3223c7 Update Rust crate actix-tls to v3.4.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-05-19 00:26:21 +00:00
45a860fea4 Update Rust crate serde to v1.0.202
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-05-16 00:22:20 +00:00
d39f3229b5 Update Rust crate rustls-pemfile to v2.1.2
All checks were successful
continuous-integration/drone/push Build is passing
2024-05-10 00:58:44 +00:00
1e5dc5a712 Update Rust crate serde to v1.0.201
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-05-10 00:32:29 +00:00
952c3f22c9 Update Rust crate serde to 1.0.200
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-05-02 00:05:46 +00:00
229c9bbdd9 Update Rust crate serde to 1.0.199
Some checks failed
continuous-integration/drone/pr Build is failing
continuous-integration/drone/push Build is passing
2024-04-28 00:06:55 +00:00
d613f7a1ef Update Rust crate actix-web to 4.5.1
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-04-27 00:18:52 +00:00
3aa7beb012 Update Rust crate reqwest to 0.12.4
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-04-20 00:12:22 +00:00
570e40d790 Merge pull request 'Update Rust crate serde to 1.0.198' (#138) from renovate/serde-1.x into master
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: #138
2024-04-17 05:59:49 +00:00
19a0ae0e7f Update Rust crate serde to 1.0.198
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-04-17 00:13:14 +00:00
e683505314 Update Rust crate pem to 3.0.4
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-04-09 00:14:42 +00:00
e0ad9ad050 Update Rust crate reqwest to 0.12.3
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-04-06 00:14:19 +00:00
2145b8cd2d Merge pull request 'Update Rust crate clap to 4.5.4' (#133) from renovate/clap-4.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #133
2024-04-05 05:59:02 +00:00
ab765f0da9 Merge pull request 'Update Rust crate tokio to 1.37.0' (#135) from renovate/tokio-1.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #135
2024-04-05 05:58:48 +00:00
dbc84463d6 Update Rust crate tokio to 1.37.0
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-03-29 00:22:48 +00:00
a415c328b1 Update Rust crate actix-tls to 3.3.0
All checks were successful
continuous-integration/drone/push Build is passing
2024-03-26 01:08:16 +00:00
ce3bfac99b Update Rust crate reqwest to 0.12.2
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-03-26 00:28:30 +00:00
386c5f545b Update Rust crate clap to 4.5.4
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-03-26 00:28:24 +00:00
2334bac822 Merge pull request 'Update Rust crate reqwest to 0.12.1' (#132) from renovate/reqwest-0.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #132
2024-03-25 09:37:54 +00:00
445dd8ede5 Update Rust crate reqwest to 0.12.1
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-03-23 00:28:50 +00:00
2db7e9596a Update Rust crate bytes to 1.6.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-03-23 00:28:45 +00:00
afe09b6cd0 Merge pull request 'Update Rust crate clap to 4.5.3' (#129) from renovate/clap-4.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #129
2024-03-22 14:42:54 +00:00
d0543a193f Merge pull request 'Update Rust crate reqwest to 0.11.27' (#130) from renovate/reqwest-0.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #130
2024-03-22 10:28:18 +00:00
e5f9291cd7 Update Rust crate reqwest to 0.11.27
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-03-20 00:07:10 +00:00
4e6f314e64 Update Rust crate clap to 4.5.3
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-03-16 00:09:30 +00:00
5d38025bb5 Merge pull request 'Update Rust crate reqwest to 0.11.26' (#128) from renovate/reqwest-0.x into master
Reviewed-on: #128
2024-03-15 13:35:18 +00:00
1552c5c678 Update Rust crate reqwest to 0.11.26
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-03-13 00:06:37 +00:00
f5dd68c255 Update Rust crate reqwest to 0.11.25
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-03-09 00:13:52 +00:00
ff5bfabe8a Update Rust crate x509-parser to 0.16.0
All checks were successful
continuous-integration/drone/push Build is passing
2024-03-07 00:25:03 +00:00
6d03789e08 Update Rust crate clap to 4.5.2
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-03-07 00:19:17 +00:00
e37cb74d0f Update Rust crate env_logger to 0.11.3
All checks were successful
continuous-integration/drone/push Build is passing
2024-03-06 00:26:50 +00:00
4ab86531fa Update Rust crate clap to 4.5.1
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-03-06 00:19:29 +00:00
1187b1d853 Update Rust crate serde to 1.0.197
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-03-05 00:15:01 +00:00
78cc13f25f Merge pull request 'Update Rust crate log to 0.4.21' (#120) from renovate/log-0.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #120
2024-03-04 09:09:55 +00:00
1ebd4822c4 Update Rust crate log to 0.4.21
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-02-29 00:14:05 +00:00
71522517fa Update Rust crate actix to 0.13.3
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-02-08 00:14:55 +00:00
54774488c6 Merge pull request 'Update Rust crate reqwest to 0.11.24' (#114) from renovate/reqwest-0.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #114
2024-02-05 17:58:18 +00:00
b0eeb004a9 Merge pull request 'Update Rust crate actix to 0.13.2' (#115) from renovate/actix-0.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #115
2024-02-05 17:56:07 +00:00
228ff22dc1 Update Rust crate actix-web-actors to 4.3.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-02-05 00:33:43 +00:00
2276e4eca0 Update Rust crate tokio to 1.36.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-02-03 00:33:42 +00:00
824744aade Update Rust crate actix to 0.13.2
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-02-02 00:35:35 +00:00
23e28b0480 Update Rust crate reqwest to 0.11.24
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-02-01 00:33:40 +00:00
b3a1be7c18 Update Rust crate env_logger to 0.10.2
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-01-19 00:33:24 +00:00
8bc3518a2d Fix cargo clippy issue
All checks were successful
continuous-integration/drone/push Build is passing
2024-01-17 19:53:13 +01:00
e534deefae Managed to update rustls to version 0.21 2024-01-17 19:52:28 +01:00
5609708848 Updated rustls_pemfile
All checks were successful
continuous-integration/drone/push Build is passing
2024-01-17 19:36:29 +01:00
9e396262ff Updated straightforward dependencies
All checks were successful
continuous-integration/drone/push Build is passing
2024-01-17 19:25:35 +01:00
4ee0d8c49d Merge pull request 'Update Rust crate serde to 1.0.195' (#107) from renovate/serde-1.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #107
2024-01-17 18:21:15 +00:00
ce5a4562a7 Merge pull request 'Update Rust crate clap to 4.4.14' (#108) from renovate/clap-4.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #108
2024-01-17 18:21:04 +00:00
c873c29339 Update Rust crate clap to 4.4.14
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-01-09 00:11:02 +00:00
c561441a4c Update Rust crate serde to 1.0.195
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-01-07 00:11:45 +00:00
a31868fb27 Update Rust crate clap to 4.4.13
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-01-05 00:11:21 +00:00
8a5cc2952f Allow Renovate to perform major updates
All checks were successful
continuous-integration/drone/push Build is passing
2024-01-03 10:04:48 +00:00
5d15ba4515 Update Rust crate serde to 1.0.194
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-01-03 00:21:46 +00:00
6d56f50512 Update Rust crate clap to 4.4.12
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-12-29 00:22:14 +00:00
41bef1bdcd Update Rust crate futures to 0.3.30
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-12-25 00:20:47 +00:00
88a11b143a Merge pull request 'Update Rust crate serde to 1.0.193' (#88) from renovate/serde-1.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #88
2023-12-23 13:36:09 +00:00
8622488028 Merge pull request 'Update Rust crate bytes to 1.5.0' (#94) from renovate/bytes-1.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #94
2023-12-23 13:36:01 +00:00
9500df553a Update Rust crate pem to 3.0.3
All checks were successful
continuous-integration/drone/push Build is passing
2023-12-15 00:16:12 +00:00
804c3e433b Update Rust crate env_logger to 0.10.1
All checks were successful
continuous-integration/drone/push Build is passing
2023-12-14 00:50:39 +00:00
9ba0125cfa Update Rust crate bytes to 1.5.0
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-12-14 00:18:20 +00:00
8ebe46d2e4 Update Rust crate serde to 1.0.193
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-12-14 00:18:03 +00:00
27d62d6552 Update Rust crate clap to 4.4.11
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-12-14 00:17:33 +00:00
62fd095171 Merge pull request 'Update Rust crate futures to 0.3.29' (#98) from renovate/futures-0.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #98
2023-12-13 08:46:24 +00:00
7c5e82d9de Merge pull request 'Update Rust crate actix to 0.13.1' (#92) from renovate/actix-0.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #92
2023-12-13 08:46:08 +00:00
a73a87b636 Merge pull request 'Update Rust crate rustls-pemfile to 1.0.4' (#99) from renovate/rustls-pemfile-1.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #99
2023-12-13 08:45:47 +00:00
edfce0a15e Merge pull request 'Update Rust crate clap to 4.4.0' (#89) from renovate/clap-4.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #89
2023-12-13 08:45:32 +00:00
41e6e43da9 Merge pull request 'Update Rust crate mktemp to 0.5.1' (#95) from renovate/mktemp-0.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #95
2023-12-13 08:45:15 +00:00
301ee29e95 Update Rust crate rustls-pemfile to 1.0.4
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-11-10 00:38:16 +00:00
50c88074f8 Update Rust crate futures to 0.3.29
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-10-27 00:32:09 +00:00
965c235169 Update Rust crate webpki to 0.22.4
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-10-10 00:08:40 +00:00
863a835e9a Update Rust crate webpki to 0.22.2
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-10-01 00:07:31 +00:00
6310d8a55f Update Rust crate mktemp to 0.5.1
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-09-09 00:31:04 +00:00
b6b196f2fb Update Rust crate webpki to 0.22.1
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-08-31 00:31:56 +00:00
f1d31d0496 Update Rust crate actix to 0.13.1
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-08-31 00:31:46 +00:00
db1f3fccad Update Rust crate actix-tls to 3.1.1
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-08-30 00:30:52 +00:00
16803df507 Update Rust crate actix-tls to 3.1.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-08-27 00:37:03 +00:00
781e5860af Update Rust crate clap to 4.4.0
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-08-26 00:35:59 +00:00
e0c29e8aa8 Update Rust crate pem to 3.0.2
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-08-25 00:42:21 +00:00
80e5c3abc3 Update Rust crate serde to 1.0.185
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-08-22 00:41:48 +00:00
5b6b525b1e Update Rust crate clap to 4.3.23
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-08-19 00:30:45 +00:00
17282b82df Update Rust crate log to 0.4.20
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-08-13 00:34:51 +00:00
07124b452b Update Rust crate clap to 4.3.21
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-08-09 00:30:19 +00:00
fa057bd233 Update Rust crate serde to 1.0.183
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-08-08 00:30:49 +00:00
0df1567020 Update Rust crate serde to 1.0.182
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-08-07 00:29:51 +00:00
9ac7c74379 Merge pull request 'Update Rust crate pem to v3' (#74) from renovate/pem-3.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #74
2023-08-05 08:26:23 +00:00
07622a7cec Update Rust crate pem to v3
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-08-05 00:25:28 +00:00
85a728319c Update Rust crate x509-parser to 0.15.1
All checks were successful
continuous-integration/drone/push Build is passing
2023-08-04 01:15:24 +00:00
985457da43 Update Rust crate serde to 1.0.181
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-08-04 00:36:34 +00:00
917b035b6f Update Rust crate serde to 1.0.180
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-08-01 00:20:27 +00:00
ddd4fed0ca Update Rust crate serde to 1.0.178
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-07-29 00:30:57 +00:00
cc99e5052b Update Rust crate serde to 1.0.177
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-07-28 00:31:01 +00:00
d89fef263e Update Rust crate serde to 1.0.176
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-07-27 00:31:20 +00:00
7774c946cf Update Rust crate serde to 1.0.175
Some checks failed
renovate/artifacts Artifact file update failure
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-07-25 00:37:43 +00:00
404cd681e8 Update Rust crate urlencoding to 2.1.3
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-07-22 08:05:11 +00:00
6db636638c Update Rust crate serde to 1.0.174
All checks were successful
continuous-integration/drone/push Build is passing
2023-07-22 01:32:38 +00:00
9d8caeeac5 Update Rust crate clap to 4.3.19
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-07-22 00:40:37 +00:00
590bc33aa7 Update Rust crate serde to 1.0.173
All checks were successful
continuous-integration/drone/push Build is passing
2023-07-20 01:03:27 +00:00
33aa208cdb Update Rust crate clap to 4.3.17
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-07-20 00:18:47 +00:00
ed4c7b066f Update Rust crate clap to 4.3.16
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-07-19 00:17:53 +00:00
83bea2a428 Update Rust crate clap to 4.3.14
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-07-18 00:18:20 +00:00
5d1e2510f5 Update Rust crate clap to 4.3.12
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-07-15 00:16:31 +00:00
5779410575 Update Rust crate serde to 1.0.171
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-07-11 00:17:34 +00:00
7ce658ab92 Update Rust crate clap to 4.3.11
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-07-08 00:17:19 +00:00
1d0c3a719c Enable auto-merge of Renovate PR
All checks were successful
continuous-integration/drone/push Build is passing
2023-07-07 15:49:36 +00:00
b3060aef43 Merge pull request 'Update Rust crate rustls-pemfile to 1.0.3' (#60) from renovate/rustls-pemfile-1.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #60
2023-07-04 16:41:14 +00:00
6439c36b8c Merge pull request 'Update Rust crate clap to 4.3.10' (#59) from renovate/clap-4.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #59
2023-07-04 16:41:06 +00:00
600f441c14 Merge pull request 'Update Rust crate serde to 1.0.166' (#61) from renovate/serde-1.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #61
2023-07-04 16:40:54 +00:00
75400eec47 Update Rust crate serde to 1.0.166
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-07-04 00:11:44 +00:00
b96e045ecf Update Rust crate clap to 4.3.10
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-07-01 00:11:03 +00:00
35a7aee89f Update Rust crate rustls-pemfile to 1.0.3
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-06-29 00:10:40 +00:00
2d368dfdd5 Merge pull request 'Update Rust crate clap to 4.3.5' (#58) from renovate/clap-4.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #58
2023-06-21 16:18:35 +00:00
4c7ab677de Update Rust crate clap to 4.3.5
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-06-21 00:18:22 +00:00
6998400962 Merge pull request 'Update Rust crate clap to 4.3.4' (#56) from renovate/clap-4.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #56
2023-06-15 13:30:38 +00:00
ca64c20397 Update Rust crate clap to 4.3.4
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-06-15 00:27:58 +00:00
a44820ba0c Merge pull request 'Update Rust crate log to 0.4.19' (#55) from renovate/log-0.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #55
2023-06-14 06:40:50 +00:00
5654bc25f9 Update Rust crate log to 0.4.19
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-06-12 00:27:03 +00:00
835164d431 Merge pull request 'Update Rust crate serde to 1.0.164' (#53) from renovate/serde-1.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #53
2023-06-09 09:20:32 +00:00
af6974d769 Update Rust crate serde to 1.0.164
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-06-09 00:27:54 +00:00
08f27b61bb Merge pull request 'Update Rust crate clap to 4.3.2' (#52) from renovate/clap-4.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #52
2023-06-06 06:34:40 +00:00
87c5ec87b3 Update Rust crate clap to 4.3.2
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-06-06 00:27:40 +00:00
85f5828446 Merge pull request 'Update Rust crate log to 0.4.18' (#51) from renovate/log-0.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #51
2023-05-30 08:38:17 +00:00
ab14d9f6cf Update Rust crate log to 0.4.18
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-05-29 00:35:50 +00:00
35b10ea4a9 Merge pull request 'Update Rust crate serde to 1.0.163' (#48) from renovate/serde-1.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #48
2023-05-23 11:37:11 +00:00
6847e080d2 Merge pull request 'Update Rust crate clap to 4.3.0' (#49) from renovate/clap-4.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #49
2023-05-23 11:36:57 +00:00
4fa1ea491a Update Rust crate clap to 4.3.0
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-05-23 09:52:34 +00:00
f87f259af5 Update Rust crate serde to 1.0.163
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-05-23 09:52:31 +00:00
4bd92e7ee2 Update RustTLS to version 0.20.7 (#47)
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #47
2023-05-19 11:10:59 +00:00
b3cc6f01a2 Merge pull request 'Update Rust crate serde to 1.0.162' (#46) from renovate/serde-1.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #46
2023-05-11 11:47:33 +00:00
830003e527 Merge pull request 'Update Rust crate clap to 4.2.7' (#45) from renovate/clap-4.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #45
2023-05-11 11:47:24 +00:00
968a485b44 Update Rust crate serde to 1.0.162
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-05-11 00:12:09 +00:00
41d3d7f69e Update Rust crate clap to 4.2.7
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-05-11 00:11:58 +00:00
e65c0d7eb9 Merge pull request 'Update Rust crate clap to 4.2.5' (#44) from renovate/clap-4.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #44
2023-05-01 08:29:07 +00:00
5df45fd295 Update Rust crate clap to 4.2.5
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-04-28 00:25:51 +00:00
c3084982b3 Merge pull request 'Update Rust crate serde to 1.0.160' (#42) from renovate/serde-1.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #42
2023-04-24 09:24:55 +00:00
858f01e1b9 Merge pull request 'Update Rust crate clap to 4.2.3' (#43) from renovate/clap-4.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #43
2023-04-24 09:24:44 +00:00
4766f8b796 Update Rust crate clap to 4.2.4
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-04-20 00:26:49 +00:00
9c7157d591 Update Rust crate serde to 1.0.160
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-04-12 00:29:46 +00:00
e7d5bac8db Update a few dependencies (#40)
All checks were successful
continuous-integration/drone/push Build is passing
Unable to update rustls for now (`actix-web` depends on a too old version of `rustls`)

Reviewed-on: #40
2023-04-11 12:37:48 +00:00
a3052e08e7 Merge pull request 'Update Rust crate serde to 1.0.159' (#38) from renovate/serde-1.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #38
2023-04-11 11:51:38 +00:00
61774e13b2 Update Rust crate serde to 1.0.159
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-04-01 00:10:21 +00:00
9e848225e2 Merge pull request 'Update Rust crate clap to 4.1.6' (#35) from renovate/clap-4.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #35
2023-03-11 12:45:18 +00:00
266c906abf Merge pull request 'Update Rust crate serde to 1.0.154' (#36) from renovate/serde-1.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #36
2023-03-11 12:45:08 +00:00
40f1d720fe Update Rust crate serde to 1.0.154
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-03-10 00:25:10 +00:00
ecc77ccb99 Update Rust crate clap to 4.1.8
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-03-10 00:25:08 +00:00
764f04da38 Merge pull request 'Update Rust crate bytes to 1.4.0' (#34) from renovate/bytes-1.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #34
2023-02-10 17:14:19 +00:00
865b854409 Update Rust crate bytes to 1.4.0
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-02-04 00:17:45 +00:00
d65a7d232c cargo update
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-02 10:28:06 +01:00
76469dd6fc Update to code to Rust 1.67
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-02 10:27:37 +01:00
c839a52f4c Merge pull request 'Update Rust crate actix-web-actors to 4.2.0' (#31) from renovate/actix-web-actors-4.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #31
2023-01-24 09:06:15 +00:00
c98bacb070 Update Rust crate actix-web-actors to 4.2.0
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-01-24 00:15:45 +00:00
02fe48cb0d Merge pull request 'Update Rust crate pem to 1.1.1' (#27) from renovate/pem-1.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #27
2023-01-23 13:58:58 +00:00
a9ca0584ed Merge pull request 'Update Rust crate clap to 4.1.1' (#29) from renovate/clap-4.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #29
2023-01-23 13:58:16 +00:00
82f2358f32 Merge pull request 'Update Rust crate rustls-pemfile to 1.0.2' (#30) from renovate/rustls-pemfile-1.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #30
2023-01-23 13:58:07 +00:00
4e1302cf3f Update Rust crate clap to 4.1.1
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-01-19 09:18:57 +00:00
ea177f6eb8 Update Rust crate rustls-pemfile to 1.0.2
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-01-19 09:18:52 +00:00
15d640127a Update Rust crate pem to 1.1.1
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-01-19 09:18:34 +00:00
fefe684fdd Merge pull request 'Update Rust crate hyper-rustls to 0.23.2' (#23) from renovate/hyper-rustls-0.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #23
2023-01-02 09:11:12 +00:00
efa26e3d01 Merge pull request 'Update Rust crate serde to 1.0.151' (#24) from renovate/serde-1.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #24
2023-01-02 09:10:59 +00:00
1ba7c9602b Merge pull request 'Update Rust crate tokio-tungstenite to 0.18.0' (#25) from renovate/tokio-tungstenite-0.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #25
2023-01-02 09:10:47 +00:00
1ef7d3a52c Merge pull request 'Update Rust crate clap to 4.0.32' (#26) from renovate/clap-4.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #26
2023-01-02 09:10:36 +00:00
0bb37ddfb2 Update Rust crate serde to 1.0.152
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-12-29 00:22:33 +00:00
cdb0afc601 Update Rust crate clap to 4.0.32
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-12-24 00:26:18 +00:00
0cfe671320 Update Rust crate hyper-rustls to 0.23.2
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-12-13 00:24:08 +00:00
d15455e5ce Merge pull request 'Update Rust crate clap to 4.0.29' (#22) from renovate/clap-4.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #22
2022-12-08 11:26:48 +00:00
6c75064a1c Update Rust crate clap to 4.0.29
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-11-30 00:35:12 +00:00
3e2720099e Merge pull request 'Update Rust crate serde to 1.0.148' (#20) from renovate/serde-1.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #20
2022-11-29 07:58:16 +00:00
45bf153682 Merge pull request 'Update Rust crate env_logger to 0.10.0' (#21) from renovate/env_logger-0.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #21
2022-11-29 07:58:09 +00:00
9920c63b8b Update Rust crate tokio-tungstenite to 0.18.0
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-11-29 00:37:56 +00:00
369639510a Update Rust crate env_logger to 0.10.0
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-11-29 00:37:53 +00:00
0e1076cfb6 Update Rust crate serde to 1.0.148
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-11-29 00:37:49 +00:00
79cb4ff469 Merge pull request 'Update Rust crate env_logger to 0.9.3' (#15) from renovate/env_logger-0.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #15
2022-11-24 11:25:08 +00:00
3c2ea933c4 Merge pull request 'Update Rust crate mktemp to 0.5.0' (#16) from renovate/mktemp-0.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #16
2022-11-24 11:25:01 +00:00
0205a40600 Merge pull request 'Update Rust crate clap to 4.0.25' (#17) from renovate/clap-4.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #17
2022-11-24 11:24:53 +00:00
0c7c6c4df2 Merge pull request 'Update Rust crate hyper-rustls to 0.23.1' (#18) from renovate/hyper-rustls-0.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #18
2022-11-24 11:24:44 +00:00
9fa409df26 Update Rust crate hyper-rustls to 0.23.1
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-11-16 00:15:56 +00:00
2f4af66a19 Update Rust crate clap to 4.0.25
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-11-16 00:15:53 +00:00
4b61f79be8 Merge pull request 'Update Rust crate clap to 4.0.18' (#11) from renovate/clap-4.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #11
2022-11-12 14:50:13 +00:00
96bb688a32 Merge pull request 'Update Rust crate rustls to 0.20.7' (#12) from renovate/rustls-0.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #12
2022-11-12 14:50:06 +00:00
6d6c8e4bfa Merge pull request 'Update Rust crate futures to 0.3.25' (#13) from renovate/futures-0.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #13
2022-11-12 14:49:59 +00:00
27f6834ab5 Merge pull request 'Update Rust crate serde to 1.0.147' (#14) from renovate/serde-1.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #14
2022-11-12 14:49:50 +00:00
5e3a36dbcc Update Rust crate mktemp to 0.5.0
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-11-10 00:25:48 +00:00
4468a75326 Update Rust crate env_logger to 0.9.3
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-11-10 00:25:36 +00:00
05474fd50e Update Rust crate clap to 4.0.22
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-11-10 00:25:32 +00:00
0572161b00 Update Rust crate serde to 1.0.147
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-11-04 00:40:15 +00:00
68f6d85ffe Update Rust crate rustls to 0.20.7
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-11-04 00:40:08 +00:00
9ac66b702f Update Rust crate futures to 0.3.25
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-11-04 00:40:03 +00:00
aa7bea05f5 Merge pull request 'Update Rust crate clap to 4.0.11' (#10) from renovate/clap-4.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #10
2022-10-10 15:52:44 +00:00
5625a0d738 Update Rust crate clap to 4.0.11
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-10-10 00:33:25 +00:00
50c8ac03b2 Merge pull request 'Update Rust crate serde to 1.0.145' (#8) from renovate/serde-1.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #8
2022-10-08 12:55:26 +00:00
f0fec7564c Merge pull request 'Update Rust crate clap to v4' (#9) from renovate/clap-4.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #9
2022-10-08 12:55:17 +00:00
9e383fc7cf Update Rust crate clap to v4
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-10-08 00:35:55 +00:00
8f688b54e3 Update Rust crate serde to 1.0.145
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-10-01 00:11:46 +00:00
47dde332d2 Merge pull request 'Update Rust crate clap to 3.2.22' (#6) from renovate/clap-3.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #6
2022-09-21 06:42:46 +00:00
a30122b533 Merge pull request 'Update Rust crate env_logger to 0.9.1' (#7) from renovate/env_logger-0.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #7
2022-09-21 06:42:34 +00:00
011f70c119 Update Rust crate env_logger to 0.9.1
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-09-20 00:36:44 +00:00
2b1b2484af Update Rust crate clap to 3.2.22
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-09-20 00:36:38 +00:00
8efccaaa45 Merge pull request 'Update Rust crate urlencoding to 2.1.2' (#4) from renovate/urlencoding-2.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #4
2022-09-12 07:34:55 +00:00
1574dd7196 Merge branch 'master' into renovate/urlencoding-2.x
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-09-12 07:34:46 +00:00
3f5f92eaa6 Merge pull request 'Update Rust crate clap to 3.2.20' (#5) from renovate/clap-3.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #5
2022-09-12 07:34:39 +00:00
58b21bf59d Update Rust crate urlencoding to 2.1.2
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-09-09 17:51:53 +00:00
585735769f Update Rust crate clap to 3.2.20
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-09-09 17:51:49 +00:00
d5f1f2c925 cargo clippy
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2022-09-02 15:58:16 +02:00
4ce1988e4c Forbid cargo clippy warnings
Some checks failed
continuous-integration/drone/push Build is failing
2022-09-02 15:55:42 +02:00
edb88bb8c8 Merge pull request 'Configure renovate' (#3) from renovate/configure into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #3
2022-09-02 13:46:02 +00:00
dcb00ccc6e Merge branch 'master' into renovate/configure
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is passing
2022-09-02 13:45:50 +00:00
eaddcc699b Fix README
All checks were successful
continuous-integration/drone/push Build is passing
2022-09-02 15:45:09 +02:00
72f9e00b80 Add Drone badge
All checks were successful
continuous-integration/drone/push Build is passing
2022-09-02 15:44:43 +02:00
55da596587 Configure Drone CI 2022-09-02 15:42:20 +02:00
1321cf79c6 Improve messages logging 2022-09-02 15:40:00 +02:00
391d0facd2 Merge pull request 'Add end2end tests' (#2) from e2e-tests into master
Reviewed-on: #2
2022-09-02 13:15:58 +00:00
59aadeacd4 Add more configuration tests 2022-09-02 15:01:34 +02:00
a5e48cf9d0 Add TLS invalid cases checks 2022-09-02 14:14:05 +02:00
4f89bc06a0 Add new test for TLS mutual authentication 2022-09-02 10:57:53 +02:00
019ae92605 Add new test for client configuration 2022-09-02 10:42:22 +02:00
6f8055f1c7 Remove useless tests configuration 2022-09-02 10:21:13 +02:00
54214a3308 Add new test for invalid TLS configuration 2022-09-02 10:18:20 +02:00
40c1bfc938 Add new test based on token auth with TLS 2022-09-02 09:43:07 +02:00
886843d087 Add new test based on token auth 2022-09-02 08:59:07 +02:00
62fa71ea6e Check the case with invalid token 2022-09-01 17:05:13 +02:00
43a6d2c3a2 Start to write e2e tests 2022-09-01 15:03:20 +02:00
caa62b8e49 Merge pull request 'Merge the two binaries (client and server) into a single one' (#1) from merge-binaries into master
Reviewed-on: #1
2022-09-01 08:16:46 +00:00
7c64003b13 Update README 2022-09-01 10:16:02 +02:00
b24e8ba68b Merged all workspace projects into a single binary project 2022-09-01 10:11:24 +02:00
3be4c5a68e Remove useless OpenSSL dependency 2022-09-01 09:16:21 +02:00
27b50d2333 Refactor project to make it easier to test 2022-09-01 09:08:45 +02:00
ce1237a13b Add renovate.json 2022-09-01 00:26:39 +00:00
c173ed3c5c Update README 2022-08-31 15:42:58 +02:00
1ce19ff56a Add support for CRL on server side 2022-08-31 15:37:51 +02:00
c063cdcef6 Remove redundant code 2022-08-31 15:00:41 +02:00
3cbbd72a14 cargo fmt 2022-08-31 14:36:07 +02:00
cd0f6fea94 Client can authenticate using TLS certificate 2022-08-31 14:35:52 +02:00
27b52dfcb7 Add client TLS auth on server side 2022-08-31 12:24:54 +02:00
1b95b10553 Optimize root certificate management on client side 2022-08-31 11:21:23 +02:00
723ed5e390 Can specify custom server root certificate for client 2022-08-31 10:59:07 +02:00
3b2866fa6a Add embedded TLS server 2022-08-31 09:29:22 +02:00
71 changed files with 4713 additions and 929 deletions

13
.drone.yml Normal file
View File

@ -0,0 +1,13 @@
---
kind: pipeline
type: docker
name: default
steps:
- name: cargo_check
image: rust
commands:
- rustup component add clippy
- cargo clippy -- -D warnings
- cargo test

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
target
.idea
pki

1878
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,32 @@
[workspace]
[package]
name = "tcp_over_http"
version = "0.1.0"
edition = "2021"
description = "TCP-over-HTTP solution"
members = [
"base",
"tcp_relay_server",
"tcp_relay_client"
]
[dependencies]
clap = { version = "4.5.4", features = ["derive", "env"] }
log = "0.4.21"
env_logger = "0.11.3"
actix = "0.13.3"
actix-web = { version = "4.5.1", features = ["rustls-0_21"] }
actix-web-actors = "4.3.0"
actix-tls = "3.3.0"
serde = { version = "1.0.200", features = ["derive"] }
tokio = { version = "1.37.0", features = ["full"] }
futures = "0.3.30"
webpki = "0.22.4"
x509-parser = "0.16.0"
pem = "3.0.4"
reqwest = { version = "0.12.4", features = ["json", "rustls-tls"], default-features = false }
tokio-tungstenite = { version = "0.20.0", features = ["__rustls-tls", "rustls-tls-native-roots"] }
urlencoding = "2.1.3"
hyper-rustls = { version = "0.23.2", features = ["rustls-native-certs"] }
bytes = "1.6.0"
rustls-pemfile = "2.0.0"
rustls = { version = "0.21.0", features = ["dangerous_configuration"] }
rustls-native-certs = "0.6.3"
[dev-dependencies]
rand = "0.8.5"
mktemp = "0.5.1"

View File

@ -1,4 +1,6 @@
# TCP over HTTP
[![Build Status](https://drone.communiquons.org/api/badges/pierre/tcp-over-http/status.svg)](https://drone.communiquons.org/pierre/tcp-over-http)
This project aims to provide an easy-to-setup TCP forwarding solution:
```
@ -6,17 +8,28 @@ This project aims to provide an easy-to-setup TCP forwarding solution:
| | | Client | | Server | | |
| Client | -- TCP xx -- | | -- HTTP 80 / 443 -- | | -- TCP xx -- | Server |
| | | Relay | | Relay | | |
|--------|   |--------| |--------| |--------|
|--------| |--------| |--------| |--------|
```
This project can be used especially to bypass firewalls that blocks traffics
from ports others than the 80 / 443 duo.
from ports others than the HTTP / HTTPS ports. The TCP traffic is encapsulated inside an
HTTP WebSocket between the client and the server relays.
This repository contains two binaries:
## Authentication
The client can authenticate against the server relays through two different means:
* `tpc_relay_server`: The server relay
* `tcp_relay_client`: The client relay
* Using a token (the server relay can have several tokens at the same time)
* Using a client TLS certificate. In this case, the server relay must act as a HTTPS server, and you must provide the
server the required certificates / key files in PEM format. It is also possible to provide the server a CRL file.
The clients relay authenticates itself to the server using a token.
## Binary
This repository contains a single binary which can be used as a server or a client, depending of command line arguments:
* Server mode: Act as a server relay. In case of token authentication (NOT TLS authentication), it can be put behind a reverse proxy.
* Client mode: Act as a client relay. It basically does three things:
* Fetch the list of forwared ports configuration from the server
* Listen to these port locally
* When a connection occurs on one of these ports, it forward the data exchanged by the socket to and from the server.
A single server - client relay pair can relay multiple ports simultaneously from the same machine.

View File

@ -1,7 +0,0 @@
[package]
name = "base"
version = "0.1.0"
edition = "2021"
[dependencies]
serde = { version = "1.0.144", features = ["derive"] }

9
renovate.json Normal file
View File

@ -0,0 +1,9 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"packageRules": [
{
"matchUpdateTypes": ["major", "minor", "patch"],
"automerge": true
}
]
}

86
src/base/cert_utils.rs Normal file
View File

@ -0,0 +1,86 @@
use std::error::Error;
use std::io::{Cursor, ErrorKind};
use rustls::{Certificate, PrivateKey};
use rustls_pemfile::Item;
/// Parse PEM certificates bytes into a [`rustls::Certificate`] structure
///
/// An error is returned if not any certificate could be found
pub fn parse_pem_certificates(certs: &[u8]) -> Result<Vec<Certificate>, Box<dyn Error>> {
let certs = rustls_pemfile::certs(&mut Cursor::new(certs))
.map(|c| c.map(|c| Certificate(c.to_vec())))
.collect::<Result<Vec<_>, _>>()?;
if certs.is_empty() {
Err(std::io::Error::new(
ErrorKind::InvalidData,
"Could not find any certificate!",
))?;
unreachable!();
}
Ok(certs)
}
/// Parse PEM private key bytes into a [`rustls::PrivateKey`] structure
pub fn parse_pem_private_key(privkey: &[u8]) -> Result<PrivateKey, Box<dyn Error>> {
let key = match rustls_pemfile::read_one(&mut Cursor::new(privkey))? {
None => {
Err(std::io::Error::new(
ErrorKind::Other,
"Failed to extract private key!",
))?;
unreachable!()
}
Some(Item::Pkcs8Key(key)) => key.secret_pkcs8_der().to_vec(),
Some(Item::Pkcs1Key(key)) => key.secret_pkcs1_der().to_vec(),
_ => {
Err(std::io::Error::new(
ErrorKind::Other,
"Unsupported private key type!",
))?;
unreachable!();
}
};
Ok(PrivateKey(key))
}
#[cfg(test)]
mod test {
use crate::base::cert_utils::{parse_pem_certificates, parse_pem_private_key};
const SAMPLE_CERT: &[u8] = include_bytes!("samples/TCPTunnelTest.crt");
const SAMPLE_KEY: &[u8] = include_bytes!("samples/TCPTunnelTest.key");
#[test]
fn parse_valid_cert() {
parse_pem_certificates(SAMPLE_CERT).unwrap();
}
#[test]
fn parse_invalid_cert_1() {
parse_pem_certificates("Random content".as_bytes()).unwrap_err();
}
#[test]
fn parse_invalid_cert_2() {
parse_pem_certificates(SAMPLE_KEY).unwrap_err();
}
#[test]
fn parse_valid_key() {
parse_pem_private_key(SAMPLE_KEY).unwrap();
}
#[test]
fn parse_invalid_key_1() {
parse_pem_private_key("Random content".as_bytes()).unwrap_err();
}
#[test]
fn parse_invalid_key_2() {
parse_pem_private_key(SAMPLE_CERT).unwrap_err();
}
}

12
src/base/err_utils.rs Normal file
View File

@ -0,0 +1,12 @@
use std::fmt::Display;
use std::io::ErrorKind;
/// Encapsulate errors in [`std::io::Error`] with a message
pub fn encpasulate_error<E: Display, F: ToString>(e: E, msg: F) -> std::io::Error {
std::io::Error::new(ErrorKind::Other, format!("{}:\n* {}", msg.to_string(), e))
}
/// Create a new [`std::io::Error`]
pub fn new_err(msg: &str) -> std::io::Error {
std::io::Error::new(ErrorKind::Other, msg.to_string())
}

5
src/base/mod.rs Normal file
View File

@ -0,0 +1,5 @@
pub mod cert_utils;
pub mod err_utils;
mod structs;
pub use structs::{RelayedPort, RemoteConfig};

View File

@ -0,0 +1,29 @@
-----BEGIN CERTIFICATE-----
MIIE8DCCAtigAwIBAgIBATANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDEw1UQ1BU
dW5uZWxUZXN0MB4XDTIyMDkwMTA2MzMyMFoXDTI0MDMwMTA2MzMxOFowGDEWMBQG
A1UEAxMNVENQVHVubmVsVGVzdDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
ggIBALqh3EXg3TYq5TwZPjOX35bM7kol+fLlwjLaXCTx/lTXU0hTFsIa0kFCiPsT
Vhm5nwhDLxnAARagc74gUHfhr6meMbsje2NzylmCpW1As1s1xo2n8oNi2YsqIA9A
HWQWsihf7fPlyZOgBIwUQBsLd6ujpwbvaEhwBArS+peVYuB3zDbuNBJ2lqdvD5fa
8aCyoPyseaJcaMMJ3R2W/8OYrUsJECKgg26A8zxF55RdvjJcBONG0kRlNsrxS6uO
9dnQ8kyvUReluPgTEfZm/M54dCi9VvKVRKA/5md/+SQWwQhPyIig3+XXeYQNoUN6
YXvlWw704VBg/hDBqrY42LjpS/FyMGsp4cHVCMXBLwRNHWPfik6w3rNTpFp7h4Mm
effxX2V/xuBr3IciVcsmeD4Xmfp0o6g3o5VPK4KIR5/b+aKe7uL8/9hTTLSqWpm8
+k0boE796/gb8egyELwBrPsrdGQIiIP2Ac6m53iTtEtceIOmMB+t7mUPkQHsiLoC
LeRm2dbPWEKz2mO8fOVjVYT9nxY92l/AveuksTui5GZ2z4ZVp1m6pAxVjVf+L/Sg
MMkEfcIUW6Xb8Ba+KYRCc/5U8Xkz26F80dhjGdeledTpBhkyKqsxcKpLqFsuYj3W
b5FfLBlQe/Yargqd8HhvgMydi+lHG14FAflhp8emnOGOzaPbAgMBAAGjRTBDMA4G
A1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBTQ9A38
JD46Si69hfW4me3CJZNK0DANBgkqhkiG9w0BAQsFAAOCAgEAIpNieyvlaO0E5oUz
1o7QJ+YtwwhPriOifrXAV+NaJj0n7Y1Fq4ztIhBPGtqwhPqgDUEn0G/mIr0BjA1w
/zQGJx1U8g9wNP8SERKVtD4Gx4S1ruLzTqK1V4xyV6bRhqmfi+YHNKviFNAEDDfz
rhiH1ULuoVfww8mH3FpL2oGhR+x900WkG98xtJ43ik/EIQu2kN+r5x9GPYC+NTC2
xScVG3OGbJLE7fHDJBPSa5vOCk4DkBXKyOjYwnfd8Saz2E1u6w7eH3dgzCqiw66K
lcksjKD4+F1t4Jhy1p/K3qzZsZQ/NpHH9v++LATtwvUN2bzPLiZ/LhV5QH/kg9Qf
49OBRMKjUJ6MgQ7/JOwtaHyu8jBuJWUNEE47hpHGUrIxmLUi2AWlxxQZdPic+Rxf
LKWoNlGx5OrzcIuIc3lb11zinRdaawOjVV0yCKWIlSkb77Flp8WJIlZ6ZHLtqwsU
8D9zN4EXefc9dXYMLyWvRHmHOTr8430PebYc/G5BA+XjOgpFQ3vu8trIA/3Dbuyc
ggz1abiDnBmp+I66AYV+Ker81maM6CQU+03WKHbHZyJWr74SKuILY1knys/fXJvT
UZRMhmaQqxc1QcWVOkWLv0RcAhEjwIX0+36NUC1W35JfrRpHtmqIiJH9kjcjr94w
5sjM2EUFmMC5z0zjF9cSYKSHLSI=
-----END CERTIFICATE-----

View File

@ -0,0 +1,51 @@
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----

6
src/lib.rs Normal file
View File

@ -0,0 +1,6 @@
mod base;
pub mod tcp_relay_client;
pub mod tcp_relay_server;
#[cfg(test)]
mod test;

49
src/main.rs Normal file
View File

@ -0,0 +1,49 @@
use clap::{Parser, Subcommand};
use tcp_over_http::tcp_relay_client::client_config::ClientConfig;
use tcp_over_http::tcp_relay_server::server_config::ServerConfig;
#[derive(Parser, Debug)]
#[clap(
author,
version,
about,
long_about = "Encapsulate TCP sockets inside HTTP WebSockets\nSource code: https://gitea.communiquons.org/pierre/tcp-over-http"
)]
struct CliArgs {
#[clap(subcommand)]
command: SubCommands,
}
#[derive(Subcommand, Debug)]
enum SubCommands {
/// Run as server
Server(ServerConfig),
/// Run as client
Client(ClientConfig),
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
let args: CliArgs = CliArgs::parse();
// Dispatch the request to the appropriate part of the program
match args.command {
SubCommands::Server(c) => tcp_over_http::tcp_relay_server::run_app(c).await,
SubCommands::Client(c) => tcp_over_http::tcp_relay_client::run_app(c).await,
}
}
#[cfg(test)]
mod test {
use crate::CliArgs;
#[test]
fn verify_cli() {
use clap::CommandFactory;
CliArgs::command().debug_assert()
}
}

View File

@ -0,0 +1,110 @@
use crate::base::err_utils::encpasulate_error;
use bytes::BufMut;
use clap::Parser;
/// TCP relay client
#[derive(Parser, Debug, Clone, Default)]
#[clap(author, version, about, long_about = None)]
pub struct ClientConfig {
/// Access token
#[clap(short, long)]
pub token: Option<String>,
/// Relay server
#[clap(short, long, default_value = "http://127.0.0.1:8000")]
pub relay_url: String,
/// Listen address
#[clap(short, long, default_value = "127.0.0.1")]
pub listen_address: String,
/// Alternative root certificate to use for server authentication
#[clap(short = 'c', long)]
pub root_certificate: Option<String>,
/// TLS certificate for TLS authentication.
#[clap(long)]
pub tls_cert: Option<String>,
/// TLS key for TLS authentication.
#[clap(long)]
pub tls_key: Option<String>,
#[clap(skip)]
pub _keys_cache: KeysCache,
}
#[derive(Parser, Debug, Clone, Default)]
pub struct KeysCache {
#[clap(skip)]
_root_certificate_cache: Option<Vec<u8>>,
#[clap(skip)]
_tls_cert_cache: Option<Vec<u8>>,
#[clap(skip)]
_tls_key_cache: Option<Vec<u8>>,
}
impl ClientConfig {
/// Load certificates and put them in cache
pub fn load_certificates(&mut self) -> std::io::Result<()> {
self._keys_cache = KeysCache {
_root_certificate_cache: load_pem_file(&self.root_certificate, "root certificate")?,
_tls_cert_cache: load_pem_file(&self.tls_cert, "client certificate")?,
_tls_key_cache: load_pem_file(&self.tls_key, "client key")?,
};
Ok(())
}
/// Get client token, returning a dummy token if none was specified
pub fn get_auth_token(&self) -> &str {
self.token.as_deref().unwrap_or("none")
}
/// Get root certificate content
pub fn get_root_certificate(&self) -> Option<Vec<u8>> {
self._keys_cache._root_certificate_cache.clone()
}
/// Get client certificate & key pair, if available
pub fn get_client_keypair(&self) -> Option<(&Vec<u8>, &Vec<u8>)> {
if let (Some(cert), Some(key)) = (
&self._keys_cache._tls_cert_cache,
&self._keys_cache._tls_key_cache,
) {
Some((cert, key))
} else {
None
}
}
/// Get client certificate & key pair, in a single memory buffer
pub fn get_merged_client_keypair(&self) -> Option<Vec<u8>> {
self.get_client_keypair().map(|(c, k)| {
let mut out = k.to_vec();
out.put_slice("\n".as_bytes());
out.put_slice(c);
out
})
}
}
fn load_pem_file(path: &Option<String>, name: &str) -> std::io::Result<Option<Vec<u8>>> {
Ok(match path {
None => None,
Some(p) => Some(
std::fs::read(p)
.map_err(|e| encpasulate_error(e, format!("Failed to load {name}!")))?,
),
})
}
#[cfg(test)]
mod test {
use crate::tcp_relay_client::client_config::ClientConfig;
#[test]
fn verify_cli() {
use clap::CommandFactory;
ClientConfig::command().debug_assert()
}
}

107
src/tcp_relay_client/mod.rs Normal file
View File

@ -0,0 +1,107 @@
extern crate core;
use std::error::Error;
use std::io::ErrorKind;
use std::sync::Arc;
use futures::future::join_all;
use reqwest::{Certificate, Identity};
use crate::base::err_utils::{encpasulate_error, new_err};
use crate::base::RemoteConfig;
use crate::tcp_relay_client::client_config::ClientConfig;
use crate::tcp_relay_client::relay_client::relay_client;
pub mod client_config;
mod relay_client;
/// Get remote server config i.e. get the list of forwarded ports
async fn get_server_config(conf: &ClientConfig) -> Result<RemoteConfig, Box<dyn Error>> {
let url = format!("{}/config", conf.relay_url);
log::info!("Retrieving configuration on {}", url);
let mut client = reqwest::Client::builder();
// Specify root certificate, if any was specified in the command line
if let Some(cert) = conf.get_root_certificate() {
client = client.add_root_certificate(Certificate::from_pem(&cert)?);
}
// Specify client certificate, if any
if let Some(kp) = conf.get_merged_client_keypair() {
let identity = Identity::from_pem(&kp)
.map_err(|e| encpasulate_error(e, "Failed to load certificates for reqwest!"))?;
client = client.identity(identity).use_rustls_tls();
}
let client = client.build().expect("Failed to build reqwest client");
let req = client
.get(url)
.header("Authorization", format!("Bearer {}", conf.get_auth_token()))
.send()
.await?;
if req.status().as_u16() != 200 {
Err(std::io::Error::new(
ErrorKind::Other,
format!(
"Could not retrieve configuration! (got status {})",
req.status()
),
))?;
}
Ok(req.json::<RemoteConfig>().await?)
}
/// Core logic of the application
pub async fn run_app(mut args: ClientConfig) -> std::io::Result<()> {
args.load_certificates()?;
let args = Arc::new(args);
// Check arguments coherence
if args.tls_cert.is_some() != args.tls_key.is_some() {
return Err(new_err(
"If you specify one of TLS certificate / key, you must then specify the other!",
));
}
if args.get_client_keypair().is_some() {
log::info!("Using client-side authentication");
}
// Get server relay configuration (fetch the list of port to forward)
let remote_conf = match get_server_config(&args).await {
Ok(c) => c,
Err(e) => {
Err(std::io::Error::new(
ErrorKind::Other,
format!("Failed to fetch relay configuration from server! {e}"),
))?;
unreachable!();
}
};
// Start to listen port
let mut handles = vec![];
for port in remote_conf {
let listen_address = format!("{}:{}", args.listen_address, port.port);
let h = tokio::spawn(relay_client(
format!(
"{}/ws?id={}&token={}",
args.relay_url,
port.id,
urlencoding::encode(args.get_auth_token())
)
.replace("http", "ws"),
listen_address,
args.clone(),
));
handles.push(h);
}
join_all(handles).await;
Ok(())
}

View File

@ -0,0 +1,155 @@
use std::sync::Arc;
use futures::{SinkExt, StreamExt};
use rustls::RootCertStore;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::{TcpListener, TcpStream};
use tokio_tungstenite::tungstenite::Message;
use crate::base::cert_utils;
use crate::tcp_relay_client::client_config::ClientConfig;
pub async fn relay_client(ws_url: String, listen_address: String, config: Arc<ClientConfig>) {
log::info!("Start to listen on {}", listen_address);
let listener = match TcpListener::bind(&listen_address).await {
Ok(l) => l,
Err(e) => {
log::error!("Failed to start to listen on {}! {}", listen_address, e);
std::process::exit(3);
}
};
loop {
let (socket, _) = listener
.accept()
.await
.expect("Failed to accept new connection!");
tokio::spawn(relay_connection(ws_url.clone(), socket, config.clone()));
}
}
/// Relay connection
///
/// WS read => TCP write
/// TCP read => WS write
async fn relay_connection(ws_url: String, socket: TcpStream, conf: Arc<ClientConfig>) {
log::debug!("Connecting to {}...", ws_url);
let ws_stream = if ws_url.starts_with("wss") {
let config = rustls::ClientConfig::builder().with_safe_defaults();
let config = match conf.get_root_certificate() {
None => {
// Perform a connection over TLS
let mut roots = RootCertStore::empty();
for cert in rustls_native_certs::load_native_certs()
.expect("Failed to load native certificates")
{
roots.add(&rustls::Certificate(cert.0)).unwrap();
}
config.with_root_certificates(roots)
}
Some(cert) => {
log::debug!("Using custom root certificates");
let mut store = RootCertStore::empty();
cert_utils::parse_pem_certificates(&cert)
.unwrap()
.iter()
.for_each(|c| store.add(c).expect("Failed to add certificate to chain!"));
config.with_root_certificates(store)
}
};
let config = match conf.get_client_keypair() {
None => config.with_no_client_auth(),
Some((certs, key)) => {
let certs = cert_utils::parse_pem_certificates(certs)
.expect("Failed to parse client certificate!");
let key = cert_utils::parse_pem_private_key(key)
.expect("Failed to parse client auth private key!");
config
.with_client_auth_cert(certs, key)
.expect("Failed to set client certificate!")
}
};
let connector = tokio_tungstenite::Connector::Rustls(Arc::new(config));
let (ws_stream, _) =
tokio_tungstenite::connect_async_tls_with_config(ws_url, None, false, Some(connector))
.await
.expect("Failed to connect to server relay!");
ws_stream
} else {
let (ws_stream, _) = tokio_tungstenite::connect_async(ws_url)
.await
.expect("Failed to connect to server relay!");
ws_stream
};
let (mut tcp_read, mut tcp_write) = socket.into_split();
let (mut ws_write, mut ws_read) = ws_stream.split();
// TCP read -> WS write
let future = async move {
let mut buff: [u8; 5000] = [0; 5000];
loop {
match tcp_read.read(&mut buff).await {
Ok(s) => {
if let Err(e) = ws_write.send(Message::Binary(Vec::from(&buff[0..s]))).await {
log::error!(
"Failed to write to WS connection! {:?} Exiting TCP read -> WS write loop...",e);
break;
}
if s == 0 {
log::info!("Got empty read TCP buffer. Stopping...");
break;
}
}
Err(e) => {
log::error!(
"Failed to read from TCP connection! {:?} Exitin TCP read -> WS write loop...",
e
);
break;
}
}
}
};
tokio::spawn(future);
// WS read -> TCP write
while let Some(m) = ws_read.next().await {
match m {
Err(e) => {
log::error!(
"Failed to read from WebSocket. Breaking read loop... {:?}",
e
);
break;
}
Ok(Message::Binary(b)) => {
if let Err(e) = tcp_write.write_all(&b).await {
log::error!(
"Failed to forward message to websocket. Closing reading end... {:?}",
e
);
break;
};
}
Ok(Message::Close(_r)) => {
log::info!("Server asked to close this WebSocket connection");
break;
}
Ok(m) => log::info!("{:?}", m),
}
}
}

130
src/tcp_relay_server/mod.rs Normal file
View File

@ -0,0 +1,130 @@
use std::sync::Arc;
use actix_web::web::Data;
use actix_web::{middleware, web, App, HttpRequest, HttpResponse, HttpServer, Responder};
use crate::base::err_utils::{encpasulate_error, new_err};
use crate::base::{cert_utils, RelayedPort};
use crate::tcp_relay_server::relay_ws::relay_ws;
use crate::tcp_relay_server::server_config::ServerConfig;
use crate::tcp_relay_server::tls_cert_client_verifier::CustomCertClientVerifier;
mod relay_ws;
pub mod server_config;
mod tls_cert_client_verifier;
pub async fn hello_route() -> &'static str {
"Hello world!"
}
pub async fn config_route(req: HttpRequest, data: Data<Arc<ServerConfig>>) -> impl Responder {
if data.has_token_auth() {
let token = req
.headers()
.get("Authorization")
.map(|t| t.to_str().unwrap_or_default())
.unwrap_or_default()
.strip_prefix("Bearer ")
.unwrap_or_default();
if !data.tokens.iter().any(|t| t.eq(token)) {
return HttpResponse::Unauthorized().json("Missing / invalid token");
}
}
HttpResponse::Ok().json(
data.ports
.iter()
.enumerate()
.map(|(id, port)| RelayedPort {
id,
port: port + data.increment_ports,
})
.collect::<Vec<_>>(),
)
}
pub async fn run_app(mut config: ServerConfig) -> std::io::Result<()> {
// Check if no port are to be forwarded
if config.ports.is_empty() {
return Err(new_err("No port to forward!"));
}
// Read tokens from file, if any
if let Some(file) = &config.tokens_file {
std::fs::read_to_string(file)
.map_err(|e| encpasulate_error(e, "Failed to read tokens file!"))?
.split('\n')
.filter(|l| !l.is_empty())
.for_each(|t| config.tokens.push(t.to_string()));
}
if !config.has_auth() {
return Err(new_err("No authentication method specified!"));
}
if config.tls_cert.is_some() != config.tls_key.is_some() {
return Err(new_err("Incomplete server TLS configuration!"));
}
if config.has_tls_client_auth() && !config.has_tls_config() {
return Err(new_err(
"Cannot provide client auth without TLS configuration!",
));
}
let args = Arc::new(config);
// Load TLS configuration, if any
let tls_config = if let (Some(cert), Some(key)) = (&args.tls_cert, &args.tls_key) {
// Load TLS certificate & private key
let cert_file = std::fs::read(cert)
.map_err(|e| encpasulate_error(e, "Failed to read certificate file"))?;
let key_file = std::fs::read(key)
.map_err(|e| encpasulate_error(e, "Failed to read server private key"))?;
// Get certificates chain
let cert_chain = cert_utils::parse_pem_certificates(&cert_file)
.map_err(|e| encpasulate_error(e, "Failed to extract certificates"))?;
// Get private key
let key = cert_utils::parse_pem_private_key(&key_file)
.map_err(|e| encpasulate_error(e, "Failed to extract private key!"))?;
let config = rustls::ServerConfig::builder().with_safe_defaults();
let config = match args.has_tls_client_auth() {
true => config
.with_client_cert_verifier(Arc::new(CustomCertClientVerifier::new(args.clone())?)),
false => config.with_no_client_auth(),
};
let config = config
.with_single_cert(cert_chain, key)
.expect("Failed to load TLS certificate!");
Some(config)
} else {
None
};
log::info!("Starting relay on http://{}", args.listen_address);
let args_clone = args.clone();
let server = HttpServer::new(move || {
App::new()
.wrap(middleware::Logger::default())
.app_data(Data::new(args_clone.clone()))
.route("/", web::get().to(hello_route))
.route("/config", web::get().to(config_route))
.route("/ws", web::get().to(relay_ws))
});
if let Some(tls_conf) = tls_config {
server.bind_rustls_021(&args.listen_address, tls_conf)?
} else {
server.bind(&args.listen_address)?
}
.run()
.await
}

View File

@ -2,14 +2,14 @@ use std::sync::Arc;
use std::time::{Duration, Instant};
use actix::{Actor, ActorContext, AsyncContext, Handler, Message, StreamHandler};
use actix_web::{Error, HttpRequest, HttpResponse, web};
use actix_web::{web, Error, HttpRequest, HttpResponse};
use actix_web_actors::ws;
use actix_web_actors::ws::{CloseCode, CloseReason};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::tcp::{OwnedReadHalf, OwnedWriteHalf};
use tokio::net::TcpStream;
use crate::args::Args;
use crate::tcp_relay_server::server_config::ServerConfig;
/// How often heartbeat pings are sent
const HEARTBEAT_INTERVAL: Duration = Duration::from_secs(5);
@ -32,7 +32,6 @@ struct RelayWS {
// Client must respond to ping at a specific interval, otherwise we drop connection
hb: Instant,
// TODO : handle socket close
}
@ -94,7 +93,6 @@ impl Actor for RelayWS {
}
log::info!("Exited read loop");
// TODO : notify context
};
tokio::spawn(future);
@ -110,7 +108,7 @@ impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for RelayWS {
Ok(ws::Message::Text(text)) => ctx.text(text),
Ok(ws::Message::Close(_reason)) => ctx.stop(),
Ok(ws::Message::Binary(data)) => {
if let Err(e) = futures::executor::block_on(self.tcp_write.write_all(&data.to_vec())) {
if let Err(e) = futures::executor::block_on(self.tcp_write.write_all(&data)) {
log::error!("Failed to forward some data, closing connection! {:?}", e);
ctx.stop();
}
@ -148,19 +146,33 @@ impl Handler<TCPReadEndClosed> for RelayWS {
#[derive(serde::Deserialize)]
pub struct WebSocketQuery {
id: usize,
token: String,
token: Option<String>,
}
pub async fn relay_ws(req: HttpRequest, stream: web::Payload,
pub async fn relay_ws(
req: HttpRequest,
stream: web::Payload,
query: web::Query<WebSocketQuery>,
conf: web::Data<Arc<Args>>) -> Result<HttpResponse, Error> {
if !conf.tokens.contains(&query.token) {
log::error!("Rejected WS request from {:?} due to invalid token!", req.peer_addr());
conf: web::Data<Arc<ServerConfig>>,
) -> Result<HttpResponse, Error> {
if conf.has_token_auth()
&& !conf
.tokens
.iter()
.any(|t| t == query.token.as_deref().unwrap_or_default())
{
log::error!(
"Rejected WS request from {:?} due to invalid token!",
req.peer_addr()
);
return Ok(HttpResponse::Unauthorized().json("Invalid / missing token!"));
}
if conf.ports.len() <= query.id {
log::error!("Rejected WS request from {:?} due to invalid port number!", req.peer_addr());
log::error!(
"Rejected WS request from {:?} due to invalid port number!",
req.peer_addr()
);
return Ok(HttpResponse::BadRequest().json("Invalid port number!"));
}
@ -169,14 +181,29 @@ pub async fn relay_ws(req: HttpRequest, stream: web::Payload,
let (tcp_read, tcp_write) = match TcpStream::connect(&upstream_addr).await {
Ok(s) => s.into_split(),
Err(e) => {
log::error!("Failed to establish connection with upstream server! {:?}", e);
return Ok(HttpResponse::InternalServerError()
.json("Failed to establish connection!"));
log::error!(
"Failed to establish connection with upstream server! {:?}",
e
);
return Ok(HttpResponse::InternalServerError().json("Failed to establish connection!"));
}
};
let relay = RelayWS { tcp_read: Some(tcp_read), tcp_write, hb: Instant::now() };
let relay = RelayWS {
tcp_read: Some(tcp_read),
tcp_write,
hb: Instant::now(),
};
let resp = ws::start(relay, &req, stream);
log::info!("Opening new WS connection for {:?} to {}", req.peer_addr(), upstream_addr);
log::info!(
"Opening new WS connection:\
* for {:?}\
* to {}\
* token {:?}",
req.peer_addr(),
upstream_addr,
query.token
);
resp
}

View File

@ -0,0 +1,84 @@
use clap::Parser;
/// TCP relay server mode
#[derive(Parser, Debug, Clone)]
#[clap(
author,
version,
about,
long_about = "TCP-over-HTTP server. This program can be configured behind a reverse-proxy (without TLS authentication)."
)]
pub struct ServerConfig {
/// Access tokens
#[clap(short, long)]
pub tokens: Vec<String>,
/// Access tokens stored in a file, one token per line
#[clap(long)]
pub tokens_file: Option<String>,
/// Forwarded ports
#[clap(short, long)]
pub ports: Vec<u16>,
/// Upstream server
#[clap(short, long, default_value = "127.0.0.1")]
pub upstream_server: String,
/// HTTP server listen address
#[clap(short, long, default_value = "0.0.0.0:8000")]
pub listen_address: String,
/// Increment ports on client. Useful for debugging and running both client and server
/// on the same machine
#[clap(short, long, default_value_t = 0)]
pub increment_ports: u16,
/// TLS certificate. Specify also private key to use HTTPS/TLS instead of HTTP
#[clap(long)]
pub tls_cert: Option<String>,
/// TLS private key. Specify also certificate to use HTTPS/TLS instead of HTTP
#[clap(long)]
pub tls_key: Option<String>,
/// Restrict TLS client authentication to certificates signed directly or indirectly by the
/// provided root certificates
///
/// This option automatically enable TLS client authentication
#[clap(long)]
pub tls_client_auth_root_cert: Option<String>,
/// TLS client authentication revocation list (CRL file)
#[clap(long)]
pub tls_revocation_list: Option<String>,
}
impl ServerConfig {
pub fn has_token_auth(&self) -> bool {
!self.tokens.is_empty()
}
pub fn has_tls_config(&self) -> bool {
self.tls_cert.is_some() && self.tls_key.is_some()
}
pub fn has_tls_client_auth(&self) -> bool {
self.tls_client_auth_root_cert.is_some()
}
pub fn has_auth(&self) -> bool {
self.has_token_auth() || self.has_tls_client_auth()
}
}
#[cfg(test)]
mod test {
use crate::tcp_relay_server::server_config::ServerConfig;
#[test]
fn verify_cli() {
use clap::CommandFactory;
ServerConfig::command().debug_assert()
}
}

View File

@ -0,0 +1,128 @@
use std::sync::Arc;
use std::time::SystemTime;
use rustls::server::{AllowAnyAuthenticatedClient, ClientCertVerified, ClientCertVerifier};
use rustls::{AlertDescription, Certificate, DistinguishedName, Error, RootCertStore};
use x509_parser::prelude::{CertificateRevocationList, FromDer, X509Certificate};
use crate::base::cert_utils::parse_pem_certificates;
use crate::base::err_utils::{encpasulate_error, new_err};
use crate::tcp_relay_server::server_config::ServerConfig;
pub struct CustomCertClientVerifier {
upstream_cert_verifier: Box<Arc<dyn ClientCertVerifier>>,
crl: Option<Vec<u8>>,
}
impl CustomCertClientVerifier {
pub fn new(conf: Arc<ServerConfig>) -> std::io::Result<Self> {
// Build root certifications list
let cert_path = conf
.tls_client_auth_root_cert
.as_deref()
.expect("No root certificates for client authentication provided!");
let cert_file = std::fs::read(cert_path).map_err(|e| {
encpasulate_error(
e,
"Failed to read root certificates for client authentication!",
)
})?;
let root_certs = parse_pem_certificates(&cert_file).map_err(|e| {
encpasulate_error(
e,
"Failed to read root certificates for server authentication!",
)
})?;
if root_certs.is_empty() {
return Err(new_err("No certificates found for client authentication!"));
}
let mut store = RootCertStore::empty();
for cert in root_certs {
store
.add(&cert)
.expect("Failed to add certificate to root store");
}
// Parse CRL file (if any)
let crl = if let Some(crl_file) = &conf.tls_revocation_list {
let crl_file = std::fs::read(crl_file)
.map_err(|e| encpasulate_error(e, "Failed to open / read CRL file!"))?;
let parsed_crl = pem::parse(crl_file)
.map_err(|e| encpasulate_error(e, "Failed to decode CRL file!"))?;
Some(parsed_crl.into_contents())
} else {
None
};
Ok(Self {
upstream_cert_verifier: Box::new(Arc::new(AllowAnyAuthenticatedClient::new(store))),
crl,
})
}
}
impl ClientCertVerifier for CustomCertClientVerifier {
fn offer_client_auth(&self) -> bool {
true
}
fn client_auth_mandatory(&self) -> bool {
true
}
fn client_auth_root_subjects(&self) -> &[DistinguishedName] {
&[]
}
fn verify_client_cert(
&self,
end_entity: &Certificate,
intermediates: &[Certificate],
now: SystemTime,
) -> Result<ClientCertVerified, Error> {
let (_rem, cert) =
X509Certificate::from_der(&end_entity.0).expect("Failed to read certificate!");
// Check the certificates sent by the client has been revoked
if let Some(crl) = &self.crl {
let (_rem, crl) =
CertificateRevocationList::from_der(crl).expect("Failed to read CRL!");
for revoked in crl.iter_revoked_certificates() {
if revoked.user_certificate == cert.serial {
log::error!(
"Client attempted to use a revoked certificate! Serial={:?} Subject={}",
cert.serial,
cert.subject
);
return Err(Error::AlertReceived(AlertDescription::CertificateRevoked));
}
}
}
let result = self
.upstream_cert_verifier
.verify_client_cert(end_entity, intermediates, now);
match result.as_ref() {
Err(e) => log::error!(
"FAILED authentication attempt from Serial={} / Subject={} : {}",
cert.serial,
cert.subject,
e
),
Ok(_) => log::info!(
"SUCCESSFUL authentication attempt from Serial={} / Subject={}",
cert.serial,
cert.subject
),
}
result
}
}

View File

@ -0,0 +1,160 @@
use tokio::task;
use crate::tcp_relay_client::client_config::ClientConfig;
use crate::tcp_relay_server::server_config::ServerConfig;
use crate::test::dummy_tcp_sockets::wait_for_port;
use crate::test::pki::Pki;
use crate::test::test_files_utils::create_temp_file_with_random_content;
use crate::test::{get_port_number, PortsAllocation, BAD_PATH, LOCALHOST_IP};
fn port(index: u16) -> u16 {
get_port_number(PortsAllocation::ClientInvalidTlsConfiguration, index)
}
#[tokio::test()]
async fn random_file_for_cert() {
let _ = env_logger::builder().is_test(true).try_init();
let pki = Pki::load();
let random_file = create_temp_file_with_random_content();
crate::tcp_relay_client::run_app(ClientConfig {
token: Some("token".to_string()),
relay_url: format!("https://{}:{}", LOCALHOST_IP, port(0)),
listen_address: LOCALHOST_IP.to_string(),
tls_cert: Some(random_file.to_string_lossy().to_string()),
tls_key: Some(pki.valid_client_key.file_path()),
..Default::default()
})
.await
.unwrap_err();
}
#[tokio::test()]
async fn random_file_for_key() {
let _ = env_logger::builder().is_test(true).try_init();
let pki = Pki::load();
let random_file = create_temp_file_with_random_content();
crate::tcp_relay_client::run_app(ClientConfig {
token: Some("token".to_string()),
relay_url: format!("https://{}:{}", LOCALHOST_IP, port(0)),
listen_address: LOCALHOST_IP.to_string(),
tls_cert: Some(pki.valid_client_crt.file_path()),
tls_key: Some(random_file.to_string_lossy().to_string()),
..Default::default()
})
.await
.unwrap_err();
}
#[tokio::test()]
async fn bad_pem_file_for_cert() {
let _ = env_logger::builder().is_test(true).try_init();
let pki = Pki::load();
crate::tcp_relay_client::run_app(ClientConfig {
token: Some("token".to_string()),
relay_url: format!("https://{}:{}", LOCALHOST_IP, port(0)),
listen_address: LOCALHOST_IP.to_string(),
tls_cert: Some(pki.root_ca_crl.file_path()),
tls_key: Some(pki.valid_client_key.file_path()),
..Default::default()
})
.await
.unwrap_err();
}
#[tokio::test()]
async fn bad_pem_file_for_key() {
let _ = env_logger::builder().is_test(true).try_init();
let pki = Pki::load();
crate::tcp_relay_client::run_app(ClientConfig {
token: Some("token".to_string()),
relay_url: format!("https://{}:{}", LOCALHOST_IP, port(0)),
listen_address: LOCALHOST_IP.to_string(),
tls_cert: Some(pki.valid_client_crt.file_path()),
tls_key: Some(pki.root_ca_crl.file_path()),
..Default::default()
})
.await
.unwrap_err();
}
#[tokio::test()]
async fn non_existing_cert() {
let _ = env_logger::builder().is_test(true).try_init();
let pki = Pki::load();
crate::tcp_relay_client::run_app(ClientConfig {
token: Some("token".to_string()),
relay_url: format!("https://{}:{}", LOCALHOST_IP, port(0)),
listen_address: LOCALHOST_IP.to_string(),
tls_cert: Some(BAD_PATH.to_string()),
tls_key: Some(pki.valid_client_key.file_path()),
..Default::default()
})
.await
.unwrap_err();
}
#[tokio::test()]
async fn non_existing_key() {
let _ = env_logger::builder().is_test(true).try_init();
let pki = Pki::load();
crate::tcp_relay_client::run_app(ClientConfig {
token: Some("token".to_string()),
relay_url: format!("https://{}:{}", LOCALHOST_IP, port(0)),
listen_address: LOCALHOST_IP.to_string(),
tls_cert: Some(pki.valid_client_crt.file_path()),
tls_key: Some(BAD_PATH.to_string()),
..Default::default()
})
.await
.unwrap_err();
}
#[tokio::test()]
async fn unmatched_key_cert_pair() {
let _ = env_logger::builder().is_test(true).try_init();
let pki = Pki::load();
let local_set = task::LocalSet::new();
local_set
.run_until(async move {
// Start server relay
task::spawn_local(crate::tcp_relay_server::run_app(ServerConfig {
tokens: vec!["dqsd".to_string()],
tokens_file: None,
ports: vec![port(1)],
upstream_server: "127.0.0.1".to_string(),
listen_address: format!("127.0.0.1:{}", port(0)),
increment_ports: 1,
tls_cert: Some(pki.localhost_crt.file_path()),
tls_key: Some(pki.localhost_key.file_path()),
tls_client_auth_root_cert: Some(pki.root_ca_crt.file_path()),
tls_revocation_list: None,
}));
wait_for_port(port(0)).await;
crate::tcp_relay_client::run_app(ClientConfig {
token: Some("token".to_string()),
relay_url: format!("https://localhost:{}", port(0)),
listen_address: LOCALHOST_IP.to_string(),
tls_cert: Some(pki.valid_client_crt.file_path()),
tls_key: Some(pki.revoked_client_key.file_path()),
root_certificate: Some(pki.root_ca_crt.file_path()),
..Default::default()
})
.await
.unwrap_err();
})
.await;
}

View File

@ -0,0 +1,59 @@
use crate::tcp_relay_client::client_config::ClientConfig;
use crate::test::pki::Pki;
use crate::test::test_files_utils::create_temp_file_with_random_content;
use crate::test::{get_port_number, PortsAllocation, BAD_PATH, LOCALHOST_IP};
const VALID_TOKEN: &str = "AvalidTOKEN";
fn port(index: u16) -> u16 {
get_port_number(PortsAllocation::TestsWithoutPortOpened, index)
}
#[tokio::test()]
async fn invalid_file_type() {
let _ = env_logger::builder().is_test(true).try_init();
let pki = Pki::load();
crate::tcp_relay_client::run_app(ClientConfig {
token: Some(VALID_TOKEN.to_string()),
relay_url: format!("https://{}:{}", LOCALHOST_IP, port(0)),
listen_address: LOCALHOST_IP.to_string(),
root_certificate: Some(pki.expired_client_key.file_path()),
..Default::default()
})
.await
.unwrap_err();
}
#[tokio::test()]
async fn non_existing_file() {
let _ = env_logger::builder().is_test(true).try_init();
crate::tcp_relay_client::run_app(ClientConfig {
token: Some(VALID_TOKEN.to_string()),
relay_url: format!("https://{}:{}", LOCALHOST_IP, port(0)),
listen_address: LOCALHOST_IP.to_string(),
root_certificate: Some(BAD_PATH.to_string()),
..Default::default()
})
.await
.unwrap_err();
}
#[tokio::test()]
async fn random_file() {
let _ = env_logger::builder().is_test(true).try_init();
let random_file = create_temp_file_with_random_content();
crate::tcp_relay_client::run_app(ClientConfig {
token: Some(VALID_TOKEN.to_string()),
relay_url: format!("https://{}:{}", LOCALHOST_IP, port(0)),
listen_address: LOCALHOST_IP.to_string(),
root_certificate: Some(random_file.to_string_lossy().to_string()),
..Default::default()
})
.await
.unwrap_err();
}

View File

@ -0,0 +1,55 @@
use tokio::task;
use crate::tcp_relay_client::client_config::ClientConfig;
use crate::tcp_relay_server::server_config::ServerConfig;
use crate::test::dummy_tcp_sockets::{wait_for_port, DummyTCPServer};
use crate::test::{get_port_number, PortsAllocation, LOCALHOST_IP};
const VALID_TOKEN: &str = "AvalidTOKEN";
fn port(index: u16) -> u16 {
get_port_number(PortsAllocation::ClientTryTLSWhileThereIsNoTLS, index)
}
#[tokio::test()]
async fn test() {
let _ = env_logger::builder().is_test(true).try_init();
// Start internal service
let local_server = DummyTCPServer::start(port(1)).await;
tokio::spawn(async move {
local_server.loop_conn_square_operations().await;
});
let local_set = task::LocalSet::new();
local_set
.run_until(async move {
wait_for_port(port(1)).await;
// Start server relay
task::spawn_local(crate::tcp_relay_server::run_app(ServerConfig {
tokens: vec![VALID_TOKEN.to_string()],
tokens_file: None,
ports: vec![port(1)],
upstream_server: "127.0.0.1".to_string(),
listen_address: format!("127.0.0.1:{}", port(0)),
increment_ports: 1,
tls_cert: None,
tls_key: None,
tls_client_auth_root_cert: None,
tls_revocation_list: None,
}));
wait_for_port(port(0)).await;
crate::tcp_relay_client::run_app(ClientConfig {
token: Some(VALID_TOKEN.to_string()),
relay_url: format!("https://{}:{}", LOCALHOST_IP, port(0)),
listen_address: LOCALHOST_IP.to_string(),
root_certificate: None,
..Default::default()
})
.await
.unwrap_err();
})
.await;
}

View File

@ -0,0 +1,339 @@
use std::time::Duration;
use rand::Rng;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::{TcpListener, TcpStream};
use tokio::time;
use crate::test::LOCALHOST_IP;
pub struct DummyTCPServer(TcpListener);
impl DummyTCPServer {
pub async fn start(port: u16) -> Self {
let addr = format!("{}:{}", LOCALHOST_IP, port);
println!("[DUMMY TCP] Listen on {}", addr);
let listener = TcpListener::bind(addr)
.await
.expect("Failed to bind dummy TCP listener!");
Self(listener)
}
/// Receive chunk of data from following connection
pub async fn read_next_connection(&self) -> Vec<u8> {
let (mut conn, _addr) = self
.0
.accept()
.await
.expect("Could not open next connection!");
let mut buff = Vec::with_capacity(100);
conn.read_to_end(&mut buff).await.unwrap();
buff
}
/// Receive chunk of data from following connection
pub async fn read_then_write_next_connection(&self, to_send: &[u8]) -> Vec<u8> {
let (mut conn, _addr) = self
.0
.accept()
.await
.expect("Could not open next connection!");
let mut buff: [u8; 100] = [0; 100];
let size = conn.read(&mut buff).await.unwrap();
conn.write_all(to_send).await.unwrap();
buff[0..size].to_vec()
}
/// Receive chunk of data from following connection
pub async fn write_next_connection(&self, to_send: &[u8]) {
let (mut conn, _addr) = self
.0
.accept()
.await
.expect("Could not open next connection!");
conn.write_all(to_send).await.unwrap()
}
/// Perform complex exchange: receive numbers from client and respond with their square
pub async fn next_conn_square_operations(&self) {
let (mut conn, _addr) = self
.0
.accept()
.await
.expect("Could not open next connection!");
let mut buff: [u8; 100] = [0; 100];
loop {
let size = conn.read(&mut buff).await.unwrap();
if size == 0 {
break;
}
let content = String::from_utf8_lossy(&buff[0..size])
.to_string()
.parse::<i64>()
.unwrap();
conn.write_all((content * content).to_string().as_bytes())
.await
.unwrap();
}
}
pub async fn loop_conn_square_operations(&self) {
loop {
self.next_conn_square_operations().await
}
}
/// Perform complex exchange: receive numbers from client and respond with their value + a given number
pub async fn next_conn_add_operations(&self, inc: i32) {
let (mut conn, _addr) = self
.0
.accept()
.await
.expect("Could not open next connection!");
let mut buff: [u8; 100] = [0; 100];
loop {
let size = conn.read(&mut buff).await.unwrap();
if size == 0 {
break;
}
let content = String::from_utf8_lossy(&buff[0..size])
.to_string()
.parse::<i64>()
.unwrap();
conn.write_all((content + inc as i64).to_string().as_bytes())
.await
.unwrap();
}
}
pub async fn loop_next_conn_add_operations(&self, inc: i32) {
loop {
self.next_conn_add_operations(inc).await
}
}
}
pub async fn dummy_tcp_client_read_conn(port: u16) -> Vec<u8> {
let mut socket = TcpStream::connect(format!("127.0.0.1:{}", port))
.await
.expect("Failed to connect to dummy TCP server!");
let mut buff: [u8; 100] = [0; 100];
let size = socket.read(&mut buff).await.unwrap();
buff[0..size].to_vec()
}
pub async fn dummy_tcp_client_write_then_read_conn(port: u16, data: &[u8]) -> Vec<u8> {
let mut socket = TcpStream::connect(format!("127.0.0.1:{}", port))
.await
.expect("Failed to connect to dummy TCP server!");
socket.write_all(data).await.unwrap();
let mut buff: [u8; 100] = [0; 100];
let size = socket.read(&mut buff).await.unwrap();
buff[0..size].to_vec()
}
pub async fn dummy_tcp_client_write_conn(port: u16, data: &[u8]) {
let mut socket = TcpStream::connect(format!("127.0.0.1:{}", port))
.await
.expect("Failed to connect to dummy TCP server!");
socket.write_all(data).await.unwrap()
}
pub async fn dummy_tcp_client_square_root_requests(port: u16, num_exchanges: usize) {
let mut socket = TcpStream::connect(format!("127.0.0.1:{}", port))
.await
.expect("Failed to connect to dummy TCP server!");
let mut rng = rand::thread_rng();
let mut buff: [u8; 100] = [0; 100];
for _ in 0..num_exchanges {
let num = rng.gen::<i32>() % 100;
socket.write_all(num.to_string().as_bytes()).await.unwrap();
let size = socket.read(&mut buff).await.unwrap();
if size == 0 {
panic!("Got empty response!");
}
let got = String::from_utf8_lossy(&buff[0..size])
.to_string()
.parse::<i64>()
.unwrap();
println!("{} * {} = {} (based on server response)", num, num, got);
assert_eq!((num * num) as i64, got);
}
}
pub async fn dummy_tcp_client_additions_requests(port: u16, inc: i32, num_exchanges: usize) {
let mut socket = TcpStream::connect(format!("127.0.0.1:{}", port))
.await
.expect("Failed to connect to dummy TCP server!");
let mut rng = rand::thread_rng();
let mut buff: [u8; 100] = [0; 100];
for _ in 0..num_exchanges {
let num = rng.gen::<i32>() % 100;
socket.write_all(num.to_string().as_bytes()).await.unwrap();
let size = socket.read(&mut buff).await.unwrap();
if size == 0 {
panic!("Got empty response!");
}
let got = String::from_utf8_lossy(&buff[0..size])
.to_string()
.parse::<i64>()
.unwrap();
println!("{} + {} = {} (based on server response)", num, inc, got);
assert_eq!((num + inc) as i64, got);
}
}
/// Check whether a given port is open or not
pub async fn is_port_open(port: u16) -> bool {
match TcpStream::connect(("127.0.0.1", port)).await {
Ok(_) => true,
Err(_) => false,
}
}
/// Wait for a port to become available
pub async fn wait_for_port(port: u16) {
for _ in 0..50 {
if is_port_open(port).await {
return;
}
time::sleep(Duration::from_millis(10)).await;
}
eprintln!("Port {} did not open in time!", port);
std::process::exit(2);
}
mod test {
use crate::test::dummy_tcp_sockets::{
dummy_tcp_client_additions_requests, dummy_tcp_client_read_conn,
dummy_tcp_client_square_root_requests, dummy_tcp_client_write_conn,
dummy_tcp_client_write_then_read_conn, DummyTCPServer,
};
use crate::test::{get_port_number, PortsAllocation};
fn port(index: u16) -> u16 {
get_port_number(PortsAllocation::DummyTCPServer, index)
}
#[tokio::test]
async fn socket_read_from_server() {
const DATA: &[u8] = "Hello world!!!".as_bytes();
let listener = DummyTCPServer::start(port(0)).await;
let handle = tokio::spawn(async move {
listener.write_next_connection(DATA).await;
});
let data = dummy_tcp_client_read_conn(port(0)).await;
assert_eq!(data, DATA);
handle.await.unwrap();
}
#[tokio::test]
async fn socket_write_to_server() {
const DATA: &[u8] = "Hello world 2".as_bytes();
let listener = DummyTCPServer::start(port(1)).await;
tokio::spawn(async move {
dummy_tcp_client_write_conn(port(1), DATA).await;
});
let data = listener.read_next_connection().await;
assert_eq!(data, DATA);
}
#[tokio::test]
async fn socket_read_and_write_to_server() {
const DATA_1: &[u8] = "Hello world 3a".as_bytes();
const DATA_2: &[u8] = "Hello world 3b".as_bytes();
let listener = DummyTCPServer::start(port(2)).await;
let handle = tokio::spawn(async move {
println!("client handle");
let data = dummy_tcp_client_write_then_read_conn(port(2), DATA_1).await;
assert_eq!(data, DATA_2);
});
let h2 = tokio::spawn(async move {
println!("server handle");
let data = listener.read_then_write_next_connection(DATA_2).await;
assert_eq!(data, DATA_1);
});
handle.await.unwrap();
h2.await.unwrap();
}
#[tokio::test]
async fn socket_dummy_root_calculator() {
let listener = DummyTCPServer::start(port(3)).await;
let handle = tokio::spawn(async move {
listener.next_conn_square_operations().await;
});
let data = dummy_tcp_client_write_then_read_conn(port(3), "5".as_bytes()).await;
assert_eq!(data, "25".as_bytes());
handle.await.unwrap();
}
#[tokio::test]
async fn socket_dummy_root_calculator_multiple() {
let listener = DummyTCPServer::start(port(4)).await;
let handle = tokio::spawn(async move {
listener.next_conn_square_operations().await;
});
dummy_tcp_client_square_root_requests(port(4), 10).await;
handle.await.unwrap();
}
#[tokio::test]
async fn socket_dummy_addition_calculator() {
let listener = DummyTCPServer::start(port(5)).await;
let handle = tokio::spawn(async move {
listener.next_conn_add_operations(4).await;
});
let data = dummy_tcp_client_write_then_read_conn(port(5), "5".as_bytes()).await;
assert_eq!(data, "9".as_bytes());
handle.await.unwrap();
}
#[tokio::test]
async fn socket_dummy_addition_calculator_multiple() {
let listener = DummyTCPServer::start(port(6)).await;
let handle = tokio::spawn(async move {
listener.next_conn_add_operations(7).await;
});
dummy_tcp_client_additions_requests(port(6), 7, 10).await;
handle.await.unwrap();
}
}

View File

View File

@ -0,0 +1,57 @@
use tokio::task;
use crate::tcp_relay_client::client_config::ClientConfig;
use crate::tcp_relay_server::server_config::ServerConfig;
use crate::test::dummy_tcp_sockets::{wait_for_port, DummyTCPServer};
use crate::test::{get_port_number, PortsAllocation, LOCALHOST_IP};
const VALID_TOKEN: &str = "AvalidTOKEN";
const INVALID_TOKEN: &str = "AnInvalidTOKEN";
fn port(index: u16) -> u16 {
get_port_number(PortsAllocation::InvalidWithTokenAuth, index)
}
#[tokio::test()]
async fn invalid_with_token_auth() {
let _ = env_logger::builder().is_test(true).try_init();
tokio::spawn(async move {
// Start internal service
let local_server = DummyTCPServer::start(port(1)).await;
local_server.loop_conn_square_operations().await;
});
let local_set = task::LocalSet::new();
local_set
.run_until(async move {
wait_for_port(port(1)).await;
// Start server relay
task::spawn_local(crate::tcp_relay_server::run_app(ServerConfig {
tokens: vec![VALID_TOKEN.to_string()],
tokens_file: None,
ports: vec![port(1)],
upstream_server: "127.0.0.1".to_string(),
listen_address: format!("127.0.0.1:{}", port(0)),
increment_ports: 1,
tls_cert: None,
tls_key: None,
tls_client_auth_root_cert: None,
tls_revocation_list: None,
}));
wait_for_port(port(0)).await;
// Start client relay
crate::tcp_relay_client::run_app(ClientConfig {
token: Some(INVALID_TOKEN.to_string()),
relay_url: format!("http://{}:{}", LOCALHOST_IP, port(0)),
listen_address: LOCALHOST_IP.to_string(),
root_certificate: None,
..Default::default()
})
.await
.unwrap_err();
})
.await;
}

54
src/test/mod.rs Normal file
View File

@ -0,0 +1,54 @@
#[non_exhaustive]
enum PortsAllocation {
TestsWithoutPortOpened,
DummyTCPServer,
ValidWithTokenAuth,
ValidWithTLSAuth,
InvalidWithTokenAuth,
ValidWithMultipleTokenAuth,
ValidWithTokenFile,
ClientTryTLSWhileThereIsNoTLS,
ValidTokenWithCustomIncrement,
ValidWithTokenAuthMultiplePorts,
ValidWithTokenAuthAndServerTLS,
WithTokenAuthAndInvalidServerTLSBadCA,
WithTokenAuthAndInvalidServerTLSExpiredAndBadCN,
TlsAuthExpiredClientCertificate,
TlsAuthRevokedClientCertificate,
TlsAuthInvalidClientCertificate,
ClientInvalidTlsConfiguration,
}
fn get_port_number(alloc: PortsAllocation, index: u16) -> u16 {
30000 + 20 * (alloc as u16) + index
}
const LOCALHOST_IP: &str = "127.0.0.1";
const BAD_PATH: &str = "/bad/path/to/key/file";
mod dummy_tcp_sockets;
mod pki;
mod test_files_utils;
mod client_invalid_tls_configuration;
mod client_invalid_tls_root_certificate_file;
mod client_try_tls_while_there_is_no_tls;
mod invalid_with_token_auth;
mod server_invalid_tls_config_invalid_cert;
mod server_invalid_tls_config_invalid_client_crl;
mod server_invalid_tls_config_invalid_client_root_cert;
mod server_invalid_tls_config_invalid_key;
mod server_invalid_token_file;
mod server_missing_auth;
mod tls_auth_expired_certificate;
mod tls_auth_invalid_certificate;
mod tls_auth_revoked_certificate;
mod valid_token_with_custom_increment;
mod valid_with_multiple_token_auth;
mod valid_with_tls_auth;
mod valid_with_token_auth;
mod valid_with_token_auth_and_server_tls;
mod valid_with_token_auth_multiple_ports;
mod valid_with_token_file;
mod with_token_auth_and_invalid_server_tls_bad_ca;
mod with_token_auth_and_invalid_server_tls_expired_and_bad_cn;

53
src/test/pki.rs Normal file
View File

@ -0,0 +1,53 @@
use mktemp::Temp;
use crate::test::test_files_utils::create_temp_file_with_content;
pub struct PemHolder(Temp);
impl PemHolder {
fn new(b: &[u8]) -> Self {
Self(create_temp_file_with_content(b))
}
pub fn file_path(&self) -> String {
self.0.to_str().unwrap().to_string()
}
}
pub struct Pki {
pub expired_client_key: PemHolder,
pub expired_client_crt: PemHolder,
pub localhost_crt: PemHolder,
pub localhost_key: PemHolder,
pub other_ca_crl: PemHolder,
pub other_ca_crt: PemHolder,
pub other_ca_key: PemHolder,
pub revoked_client_crt: PemHolder,
pub revoked_client_key: PemHolder,
pub root_ca_crl: PemHolder,
pub root_ca_crt: PemHolder,
pub root_ca_key: PemHolder,
pub valid_client_crt: PemHolder,
pub valid_client_key: PemHolder,
}
impl Pki {
pub fn load() -> Self {
Self {
expired_client_key: PemHolder::new(include_bytes!("test_pki/ExpiredClient.key")),
expired_client_crt: PemHolder::new(include_bytes!("test_pki/ExpiredClient.crt")),
localhost_crt: PemHolder::new(include_bytes!("test_pki/localhost.crt")),
localhost_key: PemHolder::new(include_bytes!("test_pki/localhost.key")),
other_ca_crl: PemHolder::new(include_bytes!("test_pki/OtherCA.crl")),
other_ca_crt: PemHolder::new(include_bytes!("test_pki/OtherCA.crt")),
other_ca_key: PemHolder::new(include_bytes!("test_pki/OtherCA.key")),
revoked_client_crt: PemHolder::new(include_bytes!("test_pki/RevokedClient.crt")),
revoked_client_key: PemHolder::new(include_bytes!("test_pki/RevokedClient.key")),
root_ca_crl: PemHolder::new(include_bytes!("test_pki/TCPTunnelTestCA.crl")),
root_ca_crt: PemHolder::new(include_bytes!("test_pki/TCPTunnelTestCA.crt")),
root_ca_key: PemHolder::new(include_bytes!("test_pki/TCPTunnelTestCA.key")),
valid_client_crt: PemHolder::new(include_bytes!("test_pki/ValidClient.crt")),
valid_client_key: PemHolder::new(include_bytes!("test_pki/ValidClient.key")),
}
}
}

View File

@ -0,0 +1,100 @@
use crate::tcp_relay_server::server_config::ServerConfig;
use crate::test::pki::Pki;
use crate::test::test_files_utils::create_temp_file_with_random_content;
use crate::test::{get_port_number, PortsAllocation, BAD_PATH};
const TOKEN: &str = "mytok";
fn port(index: u16) -> u16 {
get_port_number(PortsAllocation::TestsWithoutPortOpened, index)
}
#[tokio::test]
async fn unspecified() {
let _ = env_logger::builder().is_test(true).try_init();
let pki = Pki::load();
crate::tcp_relay_server::run_app(ServerConfig {
tokens: vec![TOKEN.to_string()],
tokens_file: None,
ports: vec![port(1)],
upstream_server: "127.0.0.1".to_string(),
listen_address: format!("127.0.0.1:{}", port(0)),
increment_ports: 1,
tls_cert: None,
tls_key: Some(pki.localhost_key.file_path()),
tls_client_auth_root_cert: None,
tls_revocation_list: None,
})
.await
.unwrap_err();
}
#[tokio::test]
async fn incorrect_pem_type() {
let _ = env_logger::builder().is_test(true).try_init();
let pki = Pki::load();
crate::tcp_relay_server::run_app(ServerConfig {
tokens: vec![TOKEN.to_string()],
tokens_file: None,
ports: vec![port(1)],
upstream_server: "127.0.0.1".to_string(),
listen_address: format!("127.0.0.1:{}", port(0)),
increment_ports: 1,
tls_cert: Some(pki.root_ca_crl.file_path()),
tls_key: Some(pki.localhost_key.file_path()),
tls_client_auth_root_cert: None,
tls_revocation_list: None,
})
.await
.unwrap_err();
}
#[tokio::test]
async fn random_contents() {
let _ = env_logger::builder().is_test(true).try_init();
let pki = Pki::load();
let random_file = create_temp_file_with_random_content();
crate::tcp_relay_server::run_app(ServerConfig {
tokens: vec![TOKEN.to_string()],
tokens_file: None,
ports: vec![port(1)],
upstream_server: "127.0.0.1".to_string(),
listen_address: format!("127.0.0.1:{}", port(0)),
increment_ports: 1,
tls_cert: Some(random_file.to_string_lossy().to_string()),
tls_key: Some(pki.localhost_key.file_path()),
tls_client_auth_root_cert: None,
tls_revocation_list: None,
})
.await
.unwrap_err();
}
#[tokio::test]
async fn invalid_path() {
let _ = env_logger::builder().is_test(true).try_init();
let pki = Pki::load();
crate::tcp_relay_server::run_app(ServerConfig {
tokens: vec![TOKEN.to_string()],
tokens_file: None,
ports: vec![port(1)],
upstream_server: "127.0.0.1".to_string(),
listen_address: format!("127.0.0.1:{}", port(0)),
increment_ports: 1,
tls_cert: Some(BAD_PATH.to_string()),
tls_key: Some(pki.localhost_key.file_path()),
tls_client_auth_root_cert: None,
tls_revocation_list: None,
})
.await
.unwrap_err();
}

View File

@ -0,0 +1,78 @@
use crate::tcp_relay_server::server_config::ServerConfig;
use crate::test::pki::Pki;
use crate::test::test_files_utils::create_temp_file_with_random_content;
use crate::test::{get_port_number, PortsAllocation, BAD_PATH};
const TOKEN: &str = "mytok";
fn port(index: u16) -> u16 {
get_port_number(PortsAllocation::TestsWithoutPortOpened, index)
}
#[tokio::test]
async fn bad_path() {
let _ = env_logger::builder().is_test(true).try_init();
let pki = Pki::load();
crate::tcp_relay_server::run_app(ServerConfig {
tokens: vec![TOKEN.to_string()],
tokens_file: None,
ports: vec![port(1)],
upstream_server: "127.0.0.1".to_string(),
listen_address: format!("127.0.0.1:{}", port(0)),
increment_ports: 1,
tls_cert: Some(pki.localhost_crt.file_path()),
tls_key: Some(pki.localhost_key.file_path()),
tls_client_auth_root_cert: Some(pki.root_ca_crl.file_path()),
tls_revocation_list: Some(BAD_PATH.to_string()),
})
.await
.unwrap_err();
}
#[tokio::test]
async fn random_content() {
let _ = env_logger::builder().is_test(true).try_init();
let pki = Pki::load();
let random_file = create_temp_file_with_random_content();
crate::tcp_relay_server::run_app(ServerConfig {
tokens: vec![TOKEN.to_string()],
tokens_file: None,
ports: vec![port(1)],
upstream_server: "127.0.0.1".to_string(),
listen_address: format!("127.0.0.1:{}", port(0)),
increment_ports: 1,
tls_cert: Some(pki.localhost_crt.file_path()),
tls_key: Some(pki.localhost_key.file_path()),
tls_client_auth_root_cert: Some(pki.root_ca_crl.file_path()),
tls_revocation_list: Some(random_file.to_string_lossy().to_string()),
})
.await
.unwrap_err();
}
#[tokio::test]
async fn invalid_pem() {
let _ = env_logger::builder().is_test(true).try_init();
let pki = Pki::load();
crate::tcp_relay_server::run_app(ServerConfig {
tokens: vec![TOKEN.to_string()],
tokens_file: None,
ports: vec![port(1)],
upstream_server: "127.0.0.1".to_string(),
listen_address: format!("127.0.0.1:{}", port(0)),
increment_ports: 1,
tls_cert: Some(pki.localhost_crt.file_path()),
tls_key: Some(pki.localhost_key.file_path()),
tls_client_auth_root_cert: Some(pki.root_ca_crl.file_path()),
tls_revocation_list: Some(pki.root_ca_crt.file_path()),
})
.await
.unwrap_err();
}

View File

@ -0,0 +1,78 @@
use crate::tcp_relay_server::server_config::ServerConfig;
use crate::test::pki::Pki;
use crate::test::test_files_utils::create_temp_file_with_random_content;
use crate::test::{get_port_number, PortsAllocation, BAD_PATH};
const TOKEN: &str = "mytok";
fn port(index: u16) -> u16 {
get_port_number(PortsAllocation::TestsWithoutPortOpened, index)
}
#[tokio::test]
async fn invalid_path() {
let _ = env_logger::builder().is_test(true).try_init();
let pki = Pki::load();
crate::tcp_relay_server::run_app(ServerConfig {
tokens: vec![TOKEN.to_string()],
tokens_file: None,
ports: vec![port(1)],
upstream_server: "127.0.0.1".to_string(),
listen_address: format!("127.0.0.1:{}", port(0)),
increment_ports: 1,
tls_cert: Some(pki.localhost_crt.file_path()),
tls_key: Some(pki.localhost_key.file_path()),
tls_client_auth_root_cert: Some(BAD_PATH.to_string()),
tls_revocation_list: None,
})
.await
.unwrap_err();
}
#[tokio::test]
async fn other_pem_file_type() {
let _ = env_logger::builder().is_test(true).try_init();
let pki = Pki::load();
crate::tcp_relay_server::run_app(ServerConfig {
tokens: vec![TOKEN.to_string()],
tokens_file: None,
ports: vec![port(1)],
upstream_server: "127.0.0.1".to_string(),
listen_address: format!("127.0.0.1:{}", port(0)),
increment_ports: 1,
tls_cert: Some(pki.localhost_crt.file_path()),
tls_key: Some(pki.localhost_key.file_path()),
tls_client_auth_root_cert: Some(pki.root_ca_crl.file_path()),
tls_revocation_list: None,
})
.await
.unwrap_err();
}
#[tokio::test]
async fn random_content() {
let _ = env_logger::builder().is_test(true).try_init();
let pki = Pki::load();
let random_file = create_temp_file_with_random_content();
crate::tcp_relay_server::run_app(ServerConfig {
tokens: vec![TOKEN.to_string()],
tokens_file: None,
ports: vec![port(1)],
upstream_server: "127.0.0.1".to_string(),
listen_address: format!("127.0.0.1:{}", port(0)),
increment_ports: 1,
tls_cert: Some(pki.localhost_crt.file_path()),
tls_key: Some(pki.localhost_key.file_path()),
tls_client_auth_root_cert: Some(random_file.to_string_lossy().to_string()),
tls_revocation_list: None,
})
.await
.unwrap_err();
}

View File

@ -0,0 +1,100 @@
use crate::tcp_relay_server::server_config::ServerConfig;
use crate::test::pki::Pki;
use crate::test::test_files_utils::create_temp_file_with_random_content;
use crate::test::{get_port_number, PortsAllocation, BAD_PATH};
const TOKEN: &str = "mytok";
fn port(index: u16) -> u16 {
get_port_number(PortsAllocation::TestsWithoutPortOpened, index)
}
#[tokio::test]
async fn invalid_pem_file_type() {
let _ = env_logger::builder().is_test(true).try_init();
let pki = Pki::load();
crate::tcp_relay_server::run_app(ServerConfig {
tokens: vec![TOKEN.to_string()],
tokens_file: None,
ports: vec![port(1)],
upstream_server: "127.0.0.1".to_string(),
listen_address: format!("127.0.0.1:{}", port(0)),
increment_ports: 1,
tls_cert: Some(pki.root_ca_crt.file_path()),
tls_key: Some(pki.root_ca_crt.file_path()),
tls_client_auth_root_cert: None,
tls_revocation_list: None,
})
.await
.unwrap_err();
}
#[tokio::test()]
async fn unspecified() {
let _ = env_logger::builder().is_test(true).try_init();
let pki = Pki::load();
crate::tcp_relay_server::run_app(ServerConfig {
tokens: vec![TOKEN.to_string()],
tokens_file: None,
ports: vec![port(1)],
upstream_server: "127.0.0.1".to_string(),
listen_address: format!("127.0.0.1:{}", port(0)),
increment_ports: 1,
tls_cert: Some(pki.root_ca_crt.file_path()),
tls_key: None,
tls_client_auth_root_cert: None,
tls_revocation_list: None,
})
.await
.unwrap_err();
}
#[tokio::test]
async fn random_content() {
let _ = env_logger::builder().is_test(true).try_init();
let pki = Pki::load();
let random_content = create_temp_file_with_random_content();
crate::tcp_relay_server::run_app(ServerConfig {
tokens: vec![TOKEN.to_string()],
tokens_file: None,
ports: vec![port(1)],
upstream_server: "127.0.0.1".to_string(),
listen_address: format!("127.0.0.1:{}", port(0)),
increment_ports: 1,
tls_cert: Some(pki.root_ca_crt.file_path()),
tls_key: Some(random_content.to_string_lossy().to_string()),
tls_client_auth_root_cert: None,
tls_revocation_list: None,
})
.await
.unwrap_err();
}
#[tokio::test]
async fn invalid_path() {
let _ = env_logger::builder().is_test(true).try_init();
let pki = Pki::load();
crate::tcp_relay_server::run_app(ServerConfig {
tokens: vec![TOKEN.to_string()],
tokens_file: None,
ports: vec![port(1)],
upstream_server: "127.0.0.1".to_string(),
listen_address: format!("127.0.0.1:{}", port(0)),
increment_ports: 1,
tls_cert: Some(pki.localhost_crt.file_path()),
tls_key: Some(BAD_PATH.to_string()),
tls_client_auth_root_cert: None,
tls_revocation_list: None,
})
.await
.unwrap_err();
}

View File

@ -0,0 +1,28 @@
use crate::tcp_relay_server::server_config::ServerConfig;
use crate::test::{get_port_number, PortsAllocation};
const INVALID_TOKEN: &str = "/tmp/a/token/file/that/does/not/exists";
fn port(index: u16) -> u16 {
get_port_number(PortsAllocation::TestsWithoutPortOpened, index)
}
#[tokio::test()]
async fn test() {
let _ = env_logger::builder().is_test(true).try_init();
crate::tcp_relay_server::run_app(ServerConfig {
tokens: vec![],
tokens_file: Some(INVALID_TOKEN.to_string()),
ports: vec![port(1)],
upstream_server: "127.0.0.1".to_string(),
listen_address: format!("127.0.0.1:{}", port(0)),
increment_ports: 1,
tls_cert: None,
tls_key: None,
tls_client_auth_root_cert: None,
tls_revocation_list: None,
})
.await
.unwrap_err();
}

View File

@ -0,0 +1,71 @@
use crate::tcp_relay_server::server_config::ServerConfig;
use crate::test::pki::Pki;
use crate::test::{get_port_number, PortsAllocation};
fn port(index: u16) -> u16 {
get_port_number(PortsAllocation::TestsWithoutPortOpened, index)
}
#[tokio::test]
async fn with_tls_server() {
let _ = env_logger::builder().is_test(true).try_init();
let pki = Pki::load();
crate::tcp_relay_server::run_app(ServerConfig {
tokens: vec![],
tokens_file: None,
ports: vec![port(1)],
upstream_server: "127.0.0.1".to_string(),
listen_address: format!("127.0.0.1:{}", port(0)),
increment_ports: 1,
tls_cert: Some(pki.root_ca_crl.file_path()),
tls_key: Some(pki.localhost_key.file_path()),
tls_client_auth_root_cert: None,
tls_revocation_list: None,
})
.await
.unwrap_err();
}
#[tokio::test]
async fn without_tls_server() {
let _ = env_logger::builder().is_test(true).try_init();
crate::tcp_relay_server::run_app(ServerConfig {
tokens: vec![],
tokens_file: None,
ports: vec![port(1)],
upstream_server: "127.0.0.1".to_string(),
listen_address: format!("127.0.0.1:{}", port(0)),
increment_ports: 1,
tls_cert: None,
tls_key: None,
tls_client_auth_root_cert: None,
tls_revocation_list: None,
})
.await
.unwrap_err();
}
#[tokio::test]
async fn tls_auth_without_tls_config() {
let _ = env_logger::builder().is_test(true).try_init();
let pki = Pki::load();
crate::tcp_relay_server::run_app(ServerConfig {
tokens: vec![],
tokens_file: None,
ports: vec![port(1)],
upstream_server: "127.0.0.1".to_string(),
listen_address: format!("127.0.0.1:{}", port(0)),
increment_ports: 1,
tls_cert: None,
tls_key: None,
tls_client_auth_root_cert: Some(pki.root_ca_crt.file_path()),
tls_revocation_list: None,
})
.await
.unwrap_err();
}

View File

@ -0,0 +1,17 @@
use mktemp::Temp;
use rand::Rng;
/// Create a temporary file and feed it with some specified content
pub fn create_temp_file_with_content(content: &[u8]) -> Temp {
let temp = Temp::new_file().unwrap();
std::fs::write(&temp, content).unwrap();
temp
}
/// Generate a temporary file with some random content
pub fn create_temp_file_with_random_content() -> Temp {
let random_bytes = rand::thread_rng().gen::<[u8; 10]>();
let temp = Temp::new_file().unwrap();
std::fs::write(&temp, random_bytes).unwrap();
temp
}

View File

@ -0,0 +1,25 @@
-----BEGIN CERTIFICATE-----
MIIELjCCAhagAwIBAgIRAOFWCcZCmPv3QHk6MwXfRogwDQYJKoZIhvcNAQELBQAw
GjEYMBYGA1UEAxMPVENQVHVubmVsVGVzdENBMB4XDTIyMDkwMjA3MDkxM1oXDTIy
MDkwMjA4MDkxM1owGDEWMBQGA1UEAxMNRXhwaXJlZENsaWVudDCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBANDTInGsDJ4xq/pSnpeTDSE6B2Z//Had0WQk
Wl6z4k6W5t79xFwjmMa4cfJJijfgC1usbV2+BP0nh+dPxedTlItUhIW8Hjx2BM/r
q1OPvYNu0bB7zcmT+WHddDLdfsxjSMt53b4UMbcWscflLry7V6ahoXccnPKUyt4U
+ZcYaoyPAej32y5Ym8EB2Hv9lMoRVbF02mEoTcdanJdhP/y28NNm9ezMsiv1jtCq
aR1ipVj7XdCW3K+vVLWzdfw75+P9bS5uXcAZHVQsJk37nrtezH/6Zgum9OQYUmIx
TNzhEzZiKfUWa07l0l3SC81KVf1YVKfwO8pQKATLLaauqXIQWZ8CAwEAAaNxMG8w
DgYDVR0PAQH/BAQDAgO4MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAd
BgNVHQ4EFgQUa/z5ULTQT52kxALqprqNhjhIcLswHwYDVR0jBBgwFoAU+53PiQbh
7KSQGc797M71fZg+JDUwDQYJKoZIhvcNAQELBQADggIBAF77OAeuaaW00zZfOuRb
9Eq6/MzS2kEUczFxkg6TZ3/cvx2tj9EQc7O5lRshbPmzjhGkRRLFBvnbL+wJrt93
YS0enQNSGkdivS/q66Vqf0ujL/FhAxZYW5Gc+f7lLt0VYHzp/ChU2ryYx9dH2AJD
AKl9vSqz/e5rUyQm/8lU1gNWbf7zb8rHA5WcHGWzTJGdz/pnUx1Mf29dtcAygzwz
8yWJI1Rb755tGzocSPULvVuQw4Pvnum0fLJusLLBU9BTZzCW2psXUOaTzjwzza5C
WedEPB+/Rtw4cwydEwoI0OvoDXezKcjo8bj8Dna4+UqBz85PFQFZKT23gYBuz4/A
8/G/3pvXKf8DTnIo9370qU9Ce0UlohCu0U3rRQDEiMiTxQgkhHn7CXe0quOem9yt
RUOXymAUz/IdB/Xu0jfuZUF4e6ObF9yULb1SzmHmsxUD7i2h+453KmsYpSDWp2CP
R9UOrhINirSOr1qRm5PCnMO8b+Th7TlhfQBY3u8VTn1l5F4fdzGiIGV5IZmGb1fV
b47WC7y3TdJ6i5fWVt2XtKQBQOjOLgPfZs5qW8GFHWrW1Z2otn6vrNMgquhV/9kd
9TzSFgbymCFKvGkHXZQ70Rqkb8Q5v3dz3VSFfqdE728hvp3GRHqZDSJhcR/FVahm
AKio0jBH1mENEttHndQhXQkE
-----END CERTIFICATE-----

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA0NMicawMnjGr+lKel5MNIToHZn/8dp3RZCRaXrPiTpbm3v3E
XCOYxrhx8kmKN+ALW6xtXb4E/SeH50/F51OUi1SEhbwePHYEz+urU4+9g27RsHvN
yZP5Yd10Mt1+zGNIy3ndvhQxtxaxx+UuvLtXpqGhdxyc8pTK3hT5lxhqjI8B6Pfb
LlibwQHYe/2UyhFVsXTaYShNx1qcl2E//Lbw02b17MyyK/WO0KppHWKlWPtd0Jbc
r69UtbN1/Dvn4/1tLm5dwBkdVCwmTfueu17Mf/pmC6b05BhSYjFM3OETNmIp9RZr
TuXSXdILzUpV/VhUp/A7ylAoBMstpq6pchBZnwIDAQABAoIBACq3Zc5W4WXix0k3
aVWcMQ1g726aM6yX7+NKRGom5d4ppCRtSKOIbJIJ3NUxEeMII4qnJOAOJLscQQKi
INuHD1XI/irVJmI7yhQ2Ix++wYeHPcGaMahQaq0IPeLByFRK4vMshJ2DSAAp1kgL
q5nTwMRHP947ric5JJ51L/Emf3Us1SBXBPppOJjy0yMTYpxGImKv/kelfFg5nHBT
rnhJ2CuyX0H9R/7Quigwif0Ul7Vth6lUlBm5Y5Ouf9SFN6HvBwqp5J0dSRGejFbn
5P7UrKpAL4GR+zocYXi4iv+5ffOj7LKPm47pym5WUJgo04HH+CbajO4R3XFpOyP/
I7cj2uECgYEA5SYMAJDGLepkkSbyWd8pvxrHBYlbEFNXmjPaYdCQUTfLqffFl2wb
saa/WxW9vQwMKLl0oLRtrEoey2ma3Wx65RLBRke4+WDo/6KRe7jA/C6MjbBTutAn
hducVPkw4hKV/ERPb07cGGBA+N3VkS/BaxMu4Ki8oGfOyo53FJ6gvzcCgYEA6Utq
jKN86GSL3Iy3tebhWbHw1vNN6JitQYVmlJ2THiVuQBKT9NK0OfPTQgQoWUWKK0v8
lodQ1VoC0iiDGHYVjTtRwCT3ajS6/3T8mrpTWWi/gQRB6SXIoQrXC6rs/+OPrRbb
uGP/nkLBj1EzPOeldv1jN5nTxxoW634RxuPd3NkCgYEA5Lm9cTMRHfPAvkIp1hsz
CFYqIhSgmQMXhgwMB2avJuKSn+15hVObsQ/IIZrp8TF9UYkMKPzwG/FAG7oloq8N
XGoEEaq1r/ZTnBchMGWR/CZalXNToDz1tl8nBIpXiNEUdOGaiHgmqQ4qzD5hVrJc
Vgyn1geXgGUdvIHHywUrXrECgYEAzrI77+k11Oyoojqm1ep+hKrMOJYO0+LZtnCM
B2ZpH0+IlAohvsskVSg7Z4UpfpbHKT9ExtWS/8SlNTAhnn2Y8K2666OU9itL9uPe
nvQwvsm4yoVMJFaOoGhrSXIiU0F6XaAgAgnPQ5ffyKvn2rFef8NWsb9/zCrIXdMv
yui+/FkCgYB9y+OJQ/CrkHC5zQqsG6PnKw7GZOII0fOrWdCUAJwCG0dv7cZJ03LQ
yONxAVdrzTGGOZTOD2vG0oG3XDie2O75qU8d/OUcdl7OqnIqupGUZMARnW0Xny6U
fpFdGYs8KeohUfw8LSf95VwJwSBb3zjaPPTR/ZZ+LI3k8wStXlOMiQ==
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,16 @@
-----BEGIN X509 CRL-----
MIICgTBrAgEBMA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNVBAMTB090aGVyQ0EXDTIy
MDkwMjA3MTI0MloXDTQyMDkwMjA3MTI0MFowAKAjMCEwHwYDVR0jBBgwFoAUIdv7
GAAmusKCN710x76ODIzpFDswDQYJKoZIhvcNAQELBQADggIBAJ6PEWN9ZdK6V1Z+
qb1lE6UpDwee7Gvu+WmYLc/ySDy8zpt3er5bfJFEI5zLYRvR7C8I77QuHfm6ytny
AcjdZoqLoYn6JkEnbZFj9yddcYfwmo1bxc7YsGKqitQPwUA+Ou2mq9q8pSyAIAY3
d1cAKEqHZgnWm/7D4NZZ8lWGjjFz9hlwhP8jWKqRcGsL/RGylNW9wyroECGRg18R
YiFIqgXiWAG1CAZcbcv2yKlijSm2q8OgBG5mFMClm5yHEmyju4ZyRowySraSkMkc
1lZqOpxRFn59FNE278bm4RJfWFtprvO/1UONq46VIi49q3iykjowGS9enFhd2pDX
JGRiMze5+Y9+MRqB7CkpgWr85a6VB/eZHt1klZDXHVviTPBwf7Sps0u2j63ZgMKl
NZCG4oTyPguyNF+PF76xqwhGqJJB1zK63wizC+1go4It9vn22tg3/C2X1riWiKjN
XimlHyumq1DkRoulwo716m3/DgVbAQD+dfTmGA80QnCMAEpRG0rjBwwrsbuz7TSX
38YiBCBAbgM/L/XhVXzuki0Q5xrrcvH8bhxG6/j+gpAFdI3on2R3rHgWMXS8c9tw
4gqXuPr4Th3Rb3pwZEsWvUXG3vY/5d2Pq9gCGcEUo36CCaZzMCDh7yrJHd1zY5gT
e5zdMjCWD7b5jfM0GpSthrfh7cya
-----END X509 CRL-----

View File

@ -0,0 +1,29 @@
-----BEGIN CERTIFICATE-----
MIIE5DCCAsygAwIBAgIBATANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDEwdPdGhl
ckNBMB4XDTIyMDkwMjA3MTI0MloXDTQyMDkwMjA3MTI0MFowEjEQMA4GA1UEAxMH
T3RoZXJDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAM802FZEmSvZ
A+SfJNWBJsAt7SvWQBxxpzmP8joriDkULG4XCiJGAHY7MsNm6uAk/A2f3TNEghiL
tbfQtJKfOEC2NDe8Y9H7bKo9cVep2YORGuXuDH4dkX4oAYYgKbdYSeMHyOsOkpEG
1FBlA4rw73RuO/aMqF25e1idLWXgi5fk8SUiWgH9Twse8KcYg8v3pA/SZcoZtc2S
rSsJFZJCrEOPZMJpTilW3Sd6KlZ+1niOAyEksYEy+ACQs9PU1H6edn6S+oNxpF24
iy3Orr4u3miU40SDOtO2qtrv/6vlbXZaIju5KyEZSMyve0Vvc4v02xUfdGxNPR2y
r7IDd0lIfewLMohpE2m2g2VPkWvC+EMkW3lA/a5xyDotF6aFGKblABRjHIRwNORT
tx7/jXoX5Cg9zGmLrs3/MhNJvGsErfnNCmDvlP7J7+JbpFgDMJo1uOv1ozLu344Y
R75trQBaOglTNNNs0D2sIgfEJTdwOt4PvGMgClcYGerjRZEKFmiX6//S6JBnlfGp
d5cWDgLv67sHKk9FXbbsZpomoGOqWKF5DuPoUH+0yOEq4LSoqMmaxFIVf3LgIvD5
G+1xV5jxkJsWv9JSY6QpYS9JDSpaOe2FqsQGF8VCd2SOnlzGxnMAISpT9xHrtYu+
fCXnf+gXWUsy5Y01It7CMHnW6cFhP+ATAgMBAAGjRTBDMA4GA1UdDwEB/wQEAwIB
BjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBQh2/sYACa6woI3vXTHvo4M
jOkUOzANBgkqhkiG9w0BAQsFAAOCAgEAHLGe4p4gBwn2vCotnFxNRc/4NKkRkvO7
dlr2jKGCIFfGgU9JsgaYYUckxDzkQadOujpuqeuB4J9OfH+GmbUNG8MOuSJdhtKi
sASnYoaF17Go7cOg/6k0GfN5FuIQPjEOM8yFGhAhP4MfsWlNWxUQPh/3QewjfEUt
TNJXZ/1zyY2Bjt5hygdSJ8eDe7V8fVV+HcLj17bfgfP+ILbgxPhsc0Sqh719j0va
gptqzrLz1eSKjthwVrYh3RuJCBPJJKa51y54TKIqnDkrWEQc0YQf7K3wkJJQ7H6M
UELhZLVF2zjEltxcfDGUCHtxcWYApA6chwsDTNYoeb7KdTAmXgQS7JNTqLuvF773
nGCKQr6JYPwnQ7QOE7oWVEeINGZtSyKBb/+DpTacK0qaw7MymkJBlaRNHAGsTzfI
U0/tKLsi6ItXi8vY/wTxRt4qvlu4mFeGFoTNdTDib6rJKS4D6HoGeRglhefOpv4r
luaJ3MwANCTa0T5H/+vDN1NQTMJa6Iul6gKzDkX1vB1duenPpExAgnjm3QeNCvQ/
yqNCPEAyZBg83L6ZKCEHQWo3SM2nMwV6X+pS0FKCY/z+7EGH6A4FHriaksOnSNeD
HczdA3Kp8jCR9llFknwxvwvIzFbh73E0/KVifIfzmbKakIseohKRNF1kxhFaB+wR
DE1o4VTfHl8=
-----END CERTIFICATE-----

View File

@ -0,0 +1,51 @@
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,25 @@
-----BEGIN CERTIFICATE-----
MIIELjCCAhagAwIBAgIRAMvrVtV8eUCAihX59TzwyVwwDQYJKoZIhvcNAQELBQAw
GjEYMBYGA1UEAxMPVENQVHVubmVsVGVzdENBMB4XDTIyMDkwMjA3MDcwN1oXDTQy
MDkwMjA3MDYxMlowGDEWMBQGA1UEAxMNUmV2b2tlZENsaWVudDCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBAOJ0s0ukj6FaKVQW1rZ7fdT7CqFyBcbQ0yr9
nioaFIICJIiN/RsTROlwEtFBYoy68SP/9w+p4c0T+1QXr2T7JBljZ8I0RotPmUL9
Jy6fM5dD8m4GM44K4oz+Mk6JaVNOcY1+j670KLRJKLhX/gNTiiqFdmMXrLUdl2KF
3qrY2Jh4riygkO0xClKiL57m/8+tCDXI+cycftdfLMDOLkBPA7HCeVdahx2r6mHi
5tSlk+sMeXEJy7kR4w4zDUb/MwP1cQgnSMwtdGE4Xz2zSLwEk0P8xNUe7Qwwx605
syd/Y/lFDasoPeGgCqFvw/zgZE2D+6U8NbywZBAqa/Nd+UA0v+cCAwEAAaNxMG8w
DgYDVR0PAQH/BAQDAgO4MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAd
BgNVHQ4EFgQUOJMPHK9liHjNrIt26DT1pWmat4EwHwYDVR0jBBgwFoAU+53PiQbh
7KSQGc797M71fZg+JDUwDQYJKoZIhvcNAQELBQADggIBAI7d1CIJGwwTATNv1ATl
UawbtuuV2dbasRA3C9kkG34UOmE8m9z01/rJiwXvF+57rbPMTZUvVhqOGajJNN7K
7+S1DDUNjea7snbJO4zsHT6OGV1vw/b0EI4OJKxuYRE5kkUEGPcWSoFbsUEyEXtt
Kl22TDOXCEYkvYW5vN2aJokyPl+rmCrzC6E207lkaKyDDBSBPYXxNApBkMMryxUO
1yqRxYrfayb0CW0JRHzI9dQNOPtpj3Pd8XKxC0liguTnPReoHC1scTp6GR9uP5TT
MlBPuAudcRNd4Kcz4vqBNc3M+ioWt5DBQ4n31beq772AbESpDaM5VBRdDlre6/Q3
WEasplODNer44md+V09LbhT3sDYpHuTIYwvHcf7jOO6wUKl7JulOwEkBD2IiTs+6
RMT2eIavlQjIObqNvLTWoVfm4b32vvBzyXdrZyr1FIlJ+VlhIpvEC1ZPq3ZLC831
sDPtyVI+dA4KV/+ZN3NvP0BfL9+7KE20Ma1V2u8reV51nddjRzNkYt3AdAuO3B9i
CUqauhe5o7Ey7QFRAxYvT4xmg9mRjSJSlX+jwXroKymtxgG3f/14Do+5yyN0bS3O
FC1H3uV1vwQztxkpJdh8PoWoh+1OsqwrRIYSEAx9M1xSBHz5TzgHQJmot5fwLQTn
QgvMyCyS46ciaMjRILqagt6P
-----END CERTIFICATE-----

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA4nSzS6SPoVopVBbWtnt91PsKoXIFxtDTKv2eKhoUggIkiI39
GxNE6XAS0UFijLrxI//3D6nhzRP7VBevZPskGWNnwjRGi0+ZQv0nLp8zl0PybgYz
jgrijP4yTolpU05xjX6PrvQotEkouFf+A1OKKoV2YxestR2XYoXeqtjYmHiuLKCQ
7TEKUqIvnub/z60INcj5zJx+118swM4uQE8DscJ5V1qHHavqYeLm1KWT6wx5cQnL
uRHjDjMNRv8zA/VxCCdIzC10YThfPbNIvASTQ/zE1R7tDDDHrTmzJ39j+UUNqyg9
4aAKoW/D/OBkTYP7pTw1vLBkECpr8135QDS/5wIDAQABAoIBAEtCJWP6KJGi+SEt
BeZXXBYv5/SHhEvyknszFiE/0ZjzRVjsdzVMThaWXGqWpD3I0uL36g+Wkagp/9iO
loekvvaBBraP0PHzXifZIfBokCixOBxAi1mlXG0m/WkEWbCJ3Ur8yJuIIQ7pUVMS
SySn2r8O461C7O60Ct9/ReTZdAIXWRj8uKiJF731RMZ/NFaOZfom5ijFyKcspyQ0
ap6CCpx8cZ3M8IUwHZJFgoET8tJX+6LftYKTKhE2LjBBzmGw1xFDuOEXmkrb62Fd
1HHUOdkgT3+2SLR3Mz8piWdhhvlg57+WTIKsA5Kx9GTDjIUUTXK5s3PsgxObEpc2
JWLhuaECgYEA695jleVohwX1z/I3idmZpSJK1MJOi09Pj4IvR+RXtKN5DpGhQGRO
x5TLGxJ9F2nQMErW8+oVBotl39iaFAlT77+CShBtBS7JfDX76whAvLwnouy8Winz
YV9IBOFl9XT4hVhvkR7BAzm5CsKAiT9OJRPxX0uHdmsWbnTjMwcG0csCgYEA9cil
Pes5ZOQ9Yn+M9wufrOJZ5FnC9NYvgre89OZTQhjISZmX0iW6McVkqEc7Av1S4IGC
t8+jVgq4f2XWle83GYrnWxwItGADJdL/X2YWWqzzEvTeyLs3zuLtZUt4wG5MDJJ/
XJaTiuA+a9r6/fsQto+0LI43R6Ge5UERi91qVtUCgYABvQLY4PbzP8z++lcEchEa
0XThuojfp/b7JMd6bSlkUGwc+l/I3LRj7inNCkbXvFTndjW9WHVNNgvLKYqBKUxw
EOZB63sSNbUQcElqAwaPHYfhQINm2rZLemtKderNc049lVhFJoffoTZG6QYPfOLz
jQETZbga3FEvATeHcb7QHwKBgH0DPzkNSbYNeUN+SP7nBKJ0xvAkz8qknqnINu4B
sNtvq3/0BYq38cqa8iW9hUByBRN4DDrd++Apt8nkzI6ai9YMFrz6t1q3cyJr/cRS
MpCQY1qC/kXvI+Ww+rqI9rQ55aiHYwx+8jCy+kz1prBEYS3aTfRTqb5fcGh+/iO7
zPi5AoGBANvsVAjy0HJxJom8yfCPw2tzMPh7o9v1jMblKN1xX8B249i27S5UOifO
Viy0OR6uiNGT6YLA7Q7esGavkiuK0bWa0M9ezWbGoNh4DmOzn9Q8yEbDz9VF23Pw
fc52Ehiq9zS9cqIXc+cQJe/o2J6YziUnBcJc2Ld7d75TISkkdYrN
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,17 @@
-----BEGIN X509 CRL-----
MIICrjCBlwIBATANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDEw9UQ1BUdW5uZWxU
ZXN0Q0EXDTIyMDkwMjA3MDgwNFoXDTIyMDkwMjA3MDgwNFowJDAiAhEAy+tW1Xx5
QICKFfn1PPDJXBcNMjIwOTAyMDcwODA0WqAjMCEwHwYDVR0jBBgwFoAU+53PiQbh
7KSQGc797M71fZg+JDUwDQYJKoZIhvcNAQELBQADggIBAAT08Q5BJIU+yvPSsNdE
yMBQZSUfTyFOxWYeUiqohpRkCBdhWYAnrZiZN83GArW7rFi1D9p0Cdg5ayDgY1A3
4SsnXklwcEdYxIzaLskN1bRY7Idmu9TXdDssPWCyawTfWfV5AfqnqnuKx71gradf
jMixrOoOWiBqMp3kHO6F2Q5gKGTQcvjYAe9yVeOF/tchMiHEHBw59HigiHmkX4od
7GNbyWyqJlMaVoK13hOt/qnjOFKITsUSzIZ1pI8NY44sBFSIM1SzklfZZ3vBNaeC
gA6JBrBm/vEvbZ/WsfCI0uVJwLgCoY4tupocKCLwyN2tyGFhvPwlv4UFEEkabYuo
9F7/5CG3JO2yJPHMuflebLawyyfXlbjH9fqvjNRnyry3MXsdphU5OV/xavrSNgLW
i8HItaFThCvnMdlMn38UYeGUqp/lgrpQiXEA8K+BX55lJzzNK+UPLNEkf3bROWvR
01tstOAhn0rfPKW01HjqXKU8Si2ExBR+kzdamhiZoaKcxuemK/TPd+vmNXuvwede
3o2qdXycgFddbKmKejV3gy+zptnFyEGlC3E3BgfSdQ2Tdn0BBltzhRdENB6o5SYh
ZUP4Mo3Gr0Hy7eeLGQM7wzmxUxOGmVdqDoWnbOwC2ySEzR6Tsf9id7Sl50DDUcS5
G20W0UM0cWIOyaaHAxKl9frl
-----END X509 CRL-----

View File

@ -0,0 +1,29 @@
-----BEGIN CERTIFICATE-----
MIIE9DCCAtygAwIBAgIBATANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDEw9UQ1BU
dW5uZWxUZXN0Q0EwHhcNMjIwOTAyMDcwNjE0WhcNNDIwOTAyMDcwNjEzWjAaMRgw
FgYDVQQDEw9UQ1BUdW5uZWxUZXN0Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
ggIKAoICAQC5agi1SIe/1SqoBb+p3IstdnZa12IrKtTiSSANV/RtjLgFymqqlvNd
I3OJOglJr/ISSWrldh+ZRb661Ds7USLPYC+ZGUXK4jRoe+CvW+WjqUMKbZu2CrAO
YmlSy09QCARJX1kv1dLDgukfOmXCTz65uMpf6hZzTr/KNCWJImXSfsJLsuUqhRLn
M4mEV3P2TX6hrtAYa8vCVqRO4vlFOvmYdYIOT/TfLTMhmqqodVFQMoUFvl4/ZZEc
dEmJOInd+yktSCO9Ziv+A/24Zb9mY46X80NVSoUmvTYB2FEo3AMqmxq1QHo3I7/k
3NxK2uLE3xFkpXckHI+FfTjuNvYBn+EqR0FNuCiM+YsCapYBZOW2olMHZs3BI+A3
nFS4JGWN53qno5GqKl0mm16b5jt+O7qy6997VvvKlkOgXOFGfa3L3x9lR/i4WUIS
+oK1M94xJtbhUgVSH1N8K6J52jyl1EEGCR/LbW2762Db0jIQXT2/T6k0HsF+CVVR
BLOMdV8V2JrcXCcnW6L0jGl1pXO9idgnlNlGCndjM6E2wvr6livg7Fjpxw+xJLA1
BMhc8gaKxcVZBcHkdmK2G6q49GAO5s6DCiGuNpGgZ1YCAV6OflbKiIJWPV/sGOp9
iLEnxYXTAaYMwM86yfBqkIpQk7dqWa5Qfwfb+o2vDhWY5e6/bHdhGwIDAQABo0Uw
QzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU
+53PiQbh7KSQGc797M71fZg+JDUwDQYJKoZIhvcNAQELBQADggIBAFIqak9dGO/i
mMRZGu9E7fItltodw9Qphixn5SKc1Rgf6RRj/XGj10JrYiG0ULnEsMLMCu9G4GAp
IM2LKYLcirOvP+bM1sWS4ieMrldCVlbJdnhz8TnWInHb1+CNTvXKt41rc/NGsDCp
QODmj2Iwd2/QI13ABKGSxjXUvTWl4Cq9kSUvkDZjV/WFjb8nUs6Y6vNQZTc3rne2
CUb5+xDRmgz6q/SsAtgH8Rrzt8KYhrT5r4kMkpIFssLBWUQgHGdZEaEnt89qnIVb
/mULw7l0716yTkqUBydibyDUsvhgOh1c5Xg/8ICwVptvFzzcbvWFtMjOQCuqB/ud
lBcMPIlM2CyytQ6uJjcjEfoy2O1rAlgEb2QKR7abPinlLFo2d1kx3GwPgSzdpROB
fJalW0QDLkdeSPSX2a/99KTI8GKQKriG5D2kcHVFAY57P7yjbyrLtD2dKdCTp0M5
jPMGjWvFOJ86k8XiNB8yMtABp0K5WZLqqvPFm16sBPaJnpKGo/KUipnLOTnEOpHJ
LWDDH8P+HKjhV99s7IwBu+67sDsKO/AsZGRuLJSGh1j8nl/iKhHGgXPfGPY7oDIZ
6JyqnW0906KrIoUFZ0b8iKMwIu35aVR++rfWIdFcYqW4flNkAZI0XY5IlJ/i9d7N
0ezY2xRAYlJSvefisMIylm0OgUDg0Nv7
-----END CERTIFICATE-----

View File

@ -0,0 +1,51 @@
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,25 @@
-----BEGIN CERTIFICATE-----
MIIELDCCAhSgAwIBAgIRAMBV0/1Yv1gtGnyi/NMvFl0wDQYJKoZIhvcNAQELBQAw
GjEYMBYGA1UEAxMPVENQVHVubmVsVGVzdENBMB4XDTIyMDkwMjA3MDczN1oXDTQy
MDkwMjA3MDYxMlowFjEUMBIGA1UEAxMLVmFsaWRDbGllbnQwggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQCd5PIwp/QUA3UVHDHLBQankyDTOyQxSzKR6CbO
yh2hkTs/l78eI2KewovYgP4oowRsHYUTNcZHBBKm3fE6BoZOVuQg0Tw126opJ5WE
O57nPoeqn/Rlic+lm8r/IM6rUCU0cuPrP3OgzGKgceldlnWmBZ6z6CPtClgv0H0E
gpvW57/gfveW4JfON4w+CjWKFFwAdk7NwgwAVupDeTDvzdK4ExWY/cGDs3NynAS/
xS8C2KBVmK40l9eE0HMY6cFQ54hM9wYVeZFZsCQ+9P/3ywEtdb1xsVjcDzmk5Uhx
wVGrzu9FIowx1K3b/zINQVhefsDPCa/IfMy4NaNxwg65zqjZAgMBAAGjcTBvMA4G
A1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwHQYD
VR0OBBYEFPw35WYKl2KasK9cNi2tROUQFX+RMB8GA1UdIwQYMBaAFPudz4kG4eyk
kBnO/ezO9X2YPiQ1MA0GCSqGSIb3DQEBCwUAA4ICAQAe33X1mHnOIWeCA7XZGBVu
+zbXTheHOSZICrM/pOzNbspTTFkQ68sBOwd2HcFhhm1WX09b05ipYiEbXNZCIELq
RWPN6yr7x7zFNjZyXxZAtL01pOVih8yfyg1WgW2hVB3VH9/9txMRIySfRoD8OMD9
rJfE8mhJcCELY1Fp2G4U6pghoGqRTyalHO5pxVFQuumudYnNlJhdSflcL6Y17Y5F
pclI8vJ3j940x/w1XfAd68xiw/Rc6SZQzIzvl6mjSGyFX5Un814wWXQZ7kAtH9fV
d8l75O02GLoocmkePwPFmhqc09WYAZTZgxJqEPyI6S1VHOUBsGru5rkY44zeRs2p
V2jHSIpcsbP04iwMDNFJV24Fio8A9hV4LFm5Nyv3O6gBgyyiRnYGvfS9R6wazGNW
LXAXQw69Wios4PxdlIX85jIJgyJ5GrjpjTTYmzkhe7fs8s3jdm4a2mFMWQcjbSia
15mF/1TdVNcKqt/M55aYY6HL3AnIc90TDIXr7UWZVJSeYicVZdI8N0Ih/1myOYw7
3NvqUetYLw/FQ7C+763N9QLgSdPlBTMkMSyB2pkXAAzWwJ/UPJ6z5REZmTVHu8Kf
I5UD0GwVnfUpBTLEpUG4oTH39PhKlncCKtmMnaZiu0DzxMy0xeskFT7YZFj0BKQc
JXXeqkcOvTFHibpLR5lQ1Q==
-----END CERTIFICATE-----

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpgIBAAKCAQEAneTyMKf0FAN1FRwxywUGp5Mg0zskMUsykegmzsodoZE7P5e/
HiNinsKL2ID+KKMEbB2FEzXGRwQSpt3xOgaGTlbkINE8NduqKSeVhDue5z6Hqp/0
ZYnPpZvK/yDOq1AlNHLj6z9zoMxioHHpXZZ1pgWes+gj7QpYL9B9BIKb1ue/4H73
luCXzjeMPgo1ihRcAHZOzcIMAFbqQ3kw783SuBMVmP3Bg7NzcpwEv8UvAtigVZiu
NJfXhNBzGOnBUOeITPcGFXmRWbAkPvT/98sBLXW9cbFY3A85pOVIccFRq87vRSKM
MdSt2/8yDUFYXn7AzwmvyHzMuDWjccIOuc6o2QIDAQABAoIBAQCdaZfOzFK49S1v
61j090DIJhVOoaKWhkqXTiQKe1QJNJol7yo5aLu0XW5AXXGFn+gTxWZbXXwcZsIV
nCUXXVPenB/5W8A0TZgaSX11hF8KWbu1bpyf8kGS8Hvz2IhSIKfG31e8u9iSEdGt
9YLbq9oEt4ud/qx6cJq0qJ1Kts+Y8ofAXjTqxa0+LVmCPRJFp1CjCAanq/VBx+cR
TjDMcBAnKB8u1wrMc4Hw8ew693wHaxYQEm1bZkjplQbUCA/IKTr1otIyCHRpNKUJ
XmNTr+zU0zqjGudeeNrEu8vjXMFzlWXoKlbVoYgfJ7lIp/9s2KDa/AjEpsrbmDo6
vAsH9gnFAoGBAMOcEd7LQFoIxdNl2BFV4jDoSLrTeNjTwXFfe4/UQSvb8lAwzYl5
aD7uT6XpkK5PV0vX9w6Wi0JVidbZVRmF0Ml+sXn/SpV9juQxMR5GpCWsCz1H+3Vj
a11GyAy836tX5harxLWhQq/q7HEit7SnNTe5i5Hvin8v1S7jfo6hdQ3TAoGBAM6k
D3q8yBu/JDrruL1SfyKiQT+U+9ccR6OJ713qsM9gZ1HocbFMDwVXLG3U+NRRmhxF
xbY9zyEaLERcNAPbbm/aB+hXCsBAIe5XO5EIYGi5cP2+/2UjDxx/YIZkx71fe/5+
QoVUc+TK1i9lCZUXEvDxnVZdMYsu6dOEHldxvwcjAoGBAMJ/1DERLrqXkIUj9lU+
bXut7GuATOBkpitiAs3AAtFmkSl1bVot0x8H/UB+3rLEB4xNgMYLoQrjXPy5+2k2
aqWACV7CHtpID6YM18c//IXM7RwREBLoOWB1OgOYZlrMOuf+AcmMQHAFivbvy3Sg
8kSnhQUmBzNyT2qhID0Yg/irAoGBAIDfAGhjY8kqI8Y7TDOGR5Op7Vdh6s307Rio
5YeE3k/2p3kFpiIUdSm3fBXjRGvlmF8ZhHxrf8n9MK5Rcn8VUoKfT18vKZ1MYdzq
ulNxDe9B953IiC7i9oGnTuOB5q/L5OCKjaHpUX3Wok1cjeVVRpLNnHpIFKXg1CL9
uo5+ecxRAoGBAKUr4pYT8wmu8BoNNoVkn6/c7m7ssBJxRUsj7cjxNpCIXzUKMzDj
Vqup7ex/tVOXZ10JEE96IMvm+b+Dje32x5oP2qaMYAlAhxJd6P0+5C7eRhZnwqYa
n82eXRq0ij6ggvXHvfhxgpa51hCRtEv6MGNu5qJ9QGKxb8VAFbQT3vPI
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,25 @@
-----BEGIN CERTIFICATE-----
MIIERzCCAi+gAwIBAgIQAtk0UZ5qjqGgxYWL7X9GhDANBgkqhkiG9w0BAQsFADAa
MRgwFgYDVQQDEw9UQ1BUdW5uZWxUZXN0Q0EwHhcNMjIwOTAyMDcwNzUxWhcNNDIw
OTAyMDcwNjEyWjAUMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEB
AQUAA4IBDwAwggEKAoIBAQDLuZElNqvAPIiTBjWJIjD1Ie+Amw1MvsWMY7UP56qC
czkvHI4wfHRJ+mCsUsbKnKR8nYDCa2CiiZpI/oWDZcQZBWmOjaoeBJajw6g+sjFl
+lft4xY6aMSXnpcU71KNelOLZsZmPYs24ZUgmjnQB1s6HZlF1niGabCaNnLtd5z2
HBPqHno2YvvD4r41n/+kDjhKoZ0t0coZnZaBlEPMvnBOlC1Z/Cn41tORTGkgm3rT
+PY3aS8n2q7prLvMc7QD/4kaN5Ep6IydXYIB+gjwIscgSHEdLZq0rAU1Xk/PQrCc
P3ysdeXFnSq4VuvgVSgXPa4pACvY+cNjaSTzk1WRaLW1AgMBAAGjgY4wgYswDgYD
VR0PAQH/BAQDAgO4MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNV
HQ4EFgQU2uwKZmO17EkQ8bLDVMdiTqLlyYEwHwYDVR0jBBgwFoAU+53PiQbh7KSQ
Gc797M71fZg+JDUwGgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/AAABMA0GCSqGSIb3
DQEBCwUAA4ICAQAHf8955HzEOTpmdN34O2jVKC1Riu8Zrpv19Gi1AJpi4WJN3xNv
BR6EeaelYEazf17ia5pj3mlT+95aE9wDYVWyqzrJuni5sT94Vw2wIL87qHxFnnBc
Wd2HhTbVSduYlIBOOFpaY28d1td6S2XsiTVfare7z8HESkcP/JeERtAtCnT8NCaC
vxSPdW+fEQxIXssS+PrlOH3rOcZHj8xUD8SDxgiizf0BZw15aLG4YsEhVU8w292K
mBmV0eYcsVpWTplE71zHDc1oJqmCZtLfYjPDy6gzyikkspPDCDU+MLT6y//WJC4d
onY0JZ9CA6i9DKlSsOvQN0LypcYOFdKjWPMwXD0PXy1Mrte4KqexhxlTJfc8WHNt
GhYOCMtYvScHE0T6XD9ybrFb2u+u8TFqrHCfTabJEaCGBsMMK2XwYQvtbRiTjvtB
sTSJrB4fvKfWahYUXZtM4unll752xRjQawW+/Nt7Bi4CeKlQX/6nlpAJTmKDxLCK
OWyS4oNWrcLmVUIKnPiaXA0AsnlOmwuR1Fsrgo+SYJqCeoe90+oo+GdqOmRuSZU9
N+ry011LZMsNzaHifWqsh1jp3kUQ5XnBA4KWv1Asgg0oCpRnYmUS7GSSdBZkp9a2
0TEp4yh/gUZ+YO3/XQmpDa1/3kojfhD+WcRQoZ5lwMrlwxtvmiOit4JJQA==
-----END CERTIFICATE-----

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAy7mRJTarwDyIkwY1iSIw9SHvgJsNTL7FjGO1D+eqgnM5LxyO
MHx0SfpgrFLGypykfJ2AwmtgoomaSP6Fg2XEGQVpjo2qHgSWo8OoPrIxZfpX7eMW
OmjEl56XFO9SjXpTi2bGZj2LNuGVIJo50AdbOh2ZRdZ4hmmwmjZy7Xec9hwT6h56
NmL7w+K+NZ//pA44SqGdLdHKGZ2WgZRDzL5wTpQtWfwp+NbTkUxpIJt60/j2N2kv
J9qu6ay7zHO0A/+JGjeRKeiMnV2CAfoI8CLHIEhxHS2atKwFNV5Pz0KwnD98rHXl
xZ0quFbr4FUoFz2uKQAr2PnDY2kk85NVkWi1tQIDAQABAoIBAGipZAUPSjtPngaS
iQxzsV0uWwHiJnoIBCt0yf9q0DGGiplGfVIxjfi3ldTSDejngqW2sQCw84ttUAMy
J1ty+8SzACDJbN1RFCb8DMJw/2nZrDS9lpzZWC5gvlN2BB5E+wjB+ylpcsz2JYwD
T7ItJVP9AtJbNb4wLBd945tV+SCCL4wrfaudjDAAXw5YZSIjTucxU4WRm2y8wZ86
do4J+NscjLpUvuIthfGiui75WGHEdtNu5iveM1dUsQWrIsMxk53D425ovd5Szx6x
6UJBjSwhmIAXxtAwzzrlO/U/4JAyMOHJs+hmCu78bLwjSJBzP/fZzG/KhFm0eyMD
RNMDy4ECgYEA6g42ffOGfP/58IxPk8C+xoRjc2a1TAI/z3ymAxbC+iFYPCiuabXf
twJkTl0yioupq3H0yW6dh2/nTtIpA99L2tEYr44R48LcSD2R5UyE8nYohz+LlOJf
U/vx/p7ao6I8mv7xFI5E52ChvEfkvNwmVcUJlmZ1JswGdwNf4WZzb+ECgYEA3tNc
EXdiWPbkzbOZISJwMyA6S5NqIZm5zoBLtU5ChDoqHQMYE6YmI0stgpNEwEvcmO2C
+9cGvB5mhklrYxxIRL9TzqqUi628/DqSTubBm/Xm+WblRKoDCN0dKK6SS/pkrxWw
YyIGbrCHQXWR1KOlvTvq7uHNXixOvpQVElrmkFUCgYEA6EUUhKeAJlosoi/L5NfZ
Os40l1gswHJW+sQ7R0N2WJ1wn7rLYvJvQYFpI29Pcbgpt48OGjvgroA5rrnWpBYb
g9oPQmCdlkZRLouTVlc6dBcYHyfLkAOaEJEtVL42QT8GH9ayTfDlpiv6NQuvjlB2
5pTz78JbrhW4sLCznM577mECgYAcThMC8PxgOrSj4K2SBPLlu7FMCmTP8dwlfCyh
0lgmvdC9sLftPwzXLOSSEq0IFFroXjtmTFFBskbpxgfLJjuT6A34Ubje6Wn5TGNr
fGqZqin2AnkbONF73cKneU2CM0N47jNi1F6mzuvPh+THcyZJnIPiZnKVBOHX2a23
kC57pQKBgQCchLrp2oX0q0jKVb5BqbsJiRMuBhRC96M0IABH6YRaCW372XCvgCWC
jtvXuT0XmqTYbmtpPEw1Pp9eJ3qminK4Z55N2fG+c9wtzJ+Mli8UoS3yFRSzbneD
LtbdqXEoZPYd6dLbTPTe43Pnl45o4epC+46c678nP/TrtfnKAiL1SA==
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,58 @@
use tokio::task;
use crate::tcp_relay_client::client_config::ClientConfig;
use crate::tcp_relay_server::server_config::ServerConfig;
use crate::test::dummy_tcp_sockets::{wait_for_port, DummyTCPServer};
use crate::test::pki::Pki;
use crate::test::{get_port_number, PortsAllocation, LOCALHOST_IP};
fn port(index: u16) -> u16 {
get_port_number(PortsAllocation::TlsAuthExpiredClientCertificate, index)
}
#[tokio::test]
async fn test() {
let _ = env_logger::builder().is_test(true).try_init();
// Start internal service
let local_server = DummyTCPServer::start(port(1)).await;
tokio::spawn(async move {
local_server.loop_conn_square_operations().await;
});
let pki = Pki::load();
let local_set = task::LocalSet::new();
local_set
.run_until(async move {
wait_for_port(port(1)).await;
// Start server relay
task::spawn_local(crate::tcp_relay_server::run_app(ServerConfig {
tokens: vec![],
tokens_file: None,
ports: vec![port(1)],
upstream_server: "127.0.0.1".to_string(),
listen_address: format!("127.0.0.1:{}", port(0)),
increment_ports: 1,
tls_cert: Some(pki.localhost_crt.file_path()),
tls_key: Some(pki.localhost_key.file_path()),
tls_client_auth_root_cert: Some(pki.root_ca_crt.file_path()),
tls_revocation_list: Some(pki.root_ca_crl.file_path()),
}));
wait_for_port(port(0)).await;
// Start client relay
crate::tcp_relay_client::run_app(ClientConfig {
relay_url: format!("https://localhost:{}", port(0)),
listen_address: LOCALHOST_IP.to_string(),
root_certificate: Some(pki.root_ca_crt.file_path()),
tls_cert: Some(pki.expired_client_crt.file_path()),
tls_key: Some(pki.valid_client_key.file_path()),
..Default::default()
})
.await
.unwrap_err();
})
.await;
}

View File

@ -0,0 +1,58 @@
use tokio::task;
use crate::tcp_relay_client::client_config::ClientConfig;
use crate::tcp_relay_server::server_config::ServerConfig;
use crate::test::dummy_tcp_sockets::{wait_for_port, DummyTCPServer};
use crate::test::pki::Pki;
use crate::test::{get_port_number, PortsAllocation, LOCALHOST_IP};
fn port(index: u16) -> u16 {
get_port_number(PortsAllocation::TlsAuthInvalidClientCertificate, index)
}
#[tokio::test]
async fn test() {
let _ = env_logger::builder().is_test(true).try_init();
// Start internal service
let local_server = DummyTCPServer::start(port(1)).await;
tokio::spawn(async move {
local_server.loop_conn_square_operations().await;
});
let pki = Pki::load();
let local_set = task::LocalSet::new();
local_set
.run_until(async move {
wait_for_port(port(1)).await;
// Start server relay
task::spawn_local(crate::tcp_relay_server::run_app(ServerConfig {
tokens: vec![],
tokens_file: None,
ports: vec![port(1)],
upstream_server: "127.0.0.1".to_string(),
listen_address: format!("127.0.0.1:{}", port(0)),
increment_ports: 1,
tls_cert: Some(pki.localhost_crt.file_path()),
tls_key: Some(pki.localhost_key.file_path()),
tls_client_auth_root_cert: Some(pki.other_ca_crt.file_path()),
tls_revocation_list: Some(pki.other_ca_crl.file_path()),
}));
wait_for_port(port(0)).await;
// Start client relay
crate::tcp_relay_client::run_app(ClientConfig {
relay_url: format!("https://localhost:{}", port(0)),
listen_address: LOCALHOST_IP.to_string(),
root_certificate: Some(pki.root_ca_crt.file_path()),
tls_cert: Some(pki.revoked_client_crt.file_path()),
tls_key: Some(pki.revoked_client_key.file_path()),
..Default::default()
})
.await
.unwrap_err();
})
.await;
}

View File

@ -0,0 +1,58 @@
use tokio::task;
use crate::tcp_relay_client::client_config::ClientConfig;
use crate::tcp_relay_server::server_config::ServerConfig;
use crate::test::dummy_tcp_sockets::{wait_for_port, DummyTCPServer};
use crate::test::pki::Pki;
use crate::test::{get_port_number, PortsAllocation, LOCALHOST_IP};
fn port(index: u16) -> u16 {
get_port_number(PortsAllocation::TlsAuthRevokedClientCertificate, index)
}
#[tokio::test]
async fn test() {
let _ = env_logger::builder().is_test(true).try_init();
// Start internal service
let local_server = DummyTCPServer::start(port(1)).await;
tokio::spawn(async move {
local_server.loop_conn_square_operations().await;
});
let pki = Pki::load();
let local_set = task::LocalSet::new();
local_set
.run_until(async move {
wait_for_port(port(1)).await;
// Start server relay
task::spawn_local(crate::tcp_relay_server::run_app(ServerConfig {
tokens: vec![],
tokens_file: None,
ports: vec![port(1)],
upstream_server: "127.0.0.1".to_string(),
listen_address: format!("127.0.0.1:{}", port(0)),
increment_ports: 1,
tls_cert: Some(pki.localhost_crt.file_path()),
tls_key: Some(pki.localhost_key.file_path()),
tls_client_auth_root_cert: Some(pki.root_ca_crt.file_path()),
tls_revocation_list: Some(pki.root_ca_crl.file_path()),
}));
wait_for_port(port(0)).await;
// Start client relay
crate::tcp_relay_client::run_app(ClientConfig {
relay_url: format!("https://localhost:{}", port(0)),
listen_address: LOCALHOST_IP.to_string(),
root_certificate: Some(pki.root_ca_crt.file_path()),
tls_cert: Some(pki.revoked_client_crt.file_path()),
tls_key: Some(pki.revoked_client_key.file_path()),
..Default::default()
})
.await
.unwrap_err();
})
.await;
}

View File

@ -0,0 +1,59 @@
use tokio::task;
use crate::tcp_relay_client::client_config::ClientConfig;
use crate::tcp_relay_server::server_config::ServerConfig;
use crate::test::dummy_tcp_sockets::{
dummy_tcp_client_square_root_requests, wait_for_port, DummyTCPServer,
};
use crate::test::{get_port_number, PortsAllocation, LOCALHOST_IP};
const VALID_TOKEN: &str = "AvalidTOKEN";
fn port(index: u16) -> u16 {
get_port_number(PortsAllocation::ValidTokenWithCustomIncrement, index)
}
#[tokio::test()]
async fn test() {
let _ = env_logger::builder().is_test(true).try_init();
// Start internal service
let local_server = DummyTCPServer::start(port(1)).await;
tokio::spawn(async move {
local_server.loop_conn_square_operations().await;
});
let local_set = task::LocalSet::new();
local_set
.run_until(async move {
wait_for_port(port(1)).await;
// Start server relay
task::spawn_local(crate::tcp_relay_server::run_app(ServerConfig {
tokens: vec![VALID_TOKEN.to_string()],
tokens_file: None,
ports: vec![port(1)],
upstream_server: "127.0.0.1".to_string(),
listen_address: format!("127.0.0.1:{}", port(0)),
increment_ports: 3,
tls_cert: None,
tls_key: None,
tls_client_auth_root_cert: None,
tls_revocation_list: None,
}));
wait_for_port(port(0)).await;
// Start client relay
task::spawn(crate::tcp_relay_client::run_app(ClientConfig {
token: Some(VALID_TOKEN.to_string()),
relay_url: format!("http://{}:{}", LOCALHOST_IP, port(0)),
listen_address: LOCALHOST_IP.to_string(),
root_certificate: None,
..Default::default()
}));
wait_for_port(port(4)).await;
dummy_tcp_client_square_root_requests(port(4), 10).await;
})
.await;
}

View File

@ -0,0 +1,63 @@
use tokio::task;
use crate::tcp_relay_client::client_config::ClientConfig;
use crate::tcp_relay_server::server_config::ServerConfig;
use crate::test::dummy_tcp_sockets::{
dummy_tcp_client_square_root_requests, wait_for_port, DummyTCPServer,
};
use crate::test::{get_port_number, PortsAllocation, LOCALHOST_IP};
const VALID_TOKEN: &str = "AvalidTOKEN";
fn port(index: u16) -> u16 {
get_port_number(PortsAllocation::ValidWithTokenFile, index)
}
#[tokio::test()]
async fn valid_with_multiple_token_auth() {
let _ = env_logger::builder().is_test(true).try_init();
// Start internal service
let local_server = DummyTCPServer::start(port(1)).await;
tokio::spawn(async move {
local_server.loop_conn_square_operations().await;
});
let local_set = task::LocalSet::new();
local_set
.run_until(async move {
wait_for_port(port(1)).await;
// Start server relay
task::spawn_local(crate::tcp_relay_server::run_app(ServerConfig {
tokens: vec![
"tok0".to_string(),
VALID_TOKEN.to_string(),
"tok2".to_string(),
],
tokens_file: None,
ports: vec![port(1)],
upstream_server: "127.0.0.1".to_string(),
listen_address: format!("127.0.0.1:{}", port(0)),
increment_ports: 1,
tls_cert: None,
tls_key: None,
tls_client_auth_root_cert: None,
tls_revocation_list: None,
}));
wait_for_port(port(0)).await;
// Start client relay
task::spawn(crate::tcp_relay_client::run_app(ClientConfig {
token: Some(VALID_TOKEN.to_string()),
relay_url: format!("http://{}:{}", LOCALHOST_IP, port(0)),
listen_address: LOCALHOST_IP.to_string(),
root_certificate: None,
..Default::default()
}));
wait_for_port(port(2)).await;
dummy_tcp_client_square_root_requests(port(2), 10).await;
})
.await;
}

View File

@ -0,0 +1,61 @@
use tokio::task;
use crate::tcp_relay_client::client_config::ClientConfig;
use crate::tcp_relay_server::server_config::ServerConfig;
use crate::test::dummy_tcp_sockets::{
dummy_tcp_client_square_root_requests, wait_for_port, DummyTCPServer,
};
use crate::test::pki::Pki;
use crate::test::{get_port_number, PortsAllocation, LOCALHOST_IP};
fn port(index: u16) -> u16 {
get_port_number(PortsAllocation::ValidWithTLSAuth, index)
}
#[tokio::test]
async fn test() {
let _ = env_logger::builder().is_test(true).try_init();
// Start internal service
let local_server = DummyTCPServer::start(port(1)).await;
tokio::spawn(async move {
local_server.loop_conn_square_operations().await;
});
let pki = Pki::load();
let local_set = task::LocalSet::new();
local_set
.run_until(async move {
wait_for_port(port(1)).await;
// Start server relay
task::spawn_local(crate::tcp_relay_server::run_app(ServerConfig {
tokens: vec![],
tokens_file: None,
ports: vec![port(1)],
upstream_server: "127.0.0.1".to_string(),
listen_address: format!("127.0.0.1:{}", port(0)),
increment_ports: 1,
tls_cert: Some(pki.localhost_crt.file_path()),
tls_key: Some(pki.localhost_key.file_path()),
tls_client_auth_root_cert: Some(pki.root_ca_crt.file_path()),
tls_revocation_list: Some(pki.root_ca_crl.file_path()),
}));
wait_for_port(port(0)).await;
// Start client relay
task::spawn(crate::tcp_relay_client::run_app(ClientConfig {
relay_url: format!("https://localhost:{}", port(0)),
listen_address: LOCALHOST_IP.to_string(),
root_certificate: Some(pki.root_ca_crt.file_path()),
tls_cert: Some(pki.valid_client_crt.file_path()),
tls_key: Some(pki.valid_client_key.file_path()),
..Default::default()
}));
wait_for_port(port(2)).await;
dummy_tcp_client_square_root_requests(port(2), 10).await;
})
.await;
}

View File

@ -0,0 +1,59 @@
use tokio::task;
use crate::tcp_relay_client::client_config::ClientConfig;
use crate::tcp_relay_server::server_config::ServerConfig;
use crate::test::dummy_tcp_sockets::{
dummy_tcp_client_square_root_requests, wait_for_port, DummyTCPServer,
};
use crate::test::{get_port_number, PortsAllocation, LOCALHOST_IP};
const VALID_TOKEN: &str = "AvalidTOKEN";
fn port(index: u16) -> u16 {
get_port_number(PortsAllocation::ValidWithTokenAuth, index)
}
#[tokio::test()]
async fn valid_with_token_auth() {
let _ = env_logger::builder().is_test(true).try_init();
// Start internal service
let local_server = DummyTCPServer::start(port(1)).await;
tokio::spawn(async move {
local_server.loop_conn_square_operations().await;
});
let local_set = task::LocalSet::new();
local_set
.run_until(async move {
wait_for_port(port(1)).await;
// Start server relay
task::spawn_local(crate::tcp_relay_server::run_app(ServerConfig {
tokens: vec![VALID_TOKEN.to_string()],
tokens_file: None,
ports: vec![port(1)],
upstream_server: "127.0.0.1".to_string(),
listen_address: format!("127.0.0.1:{}", port(0)),
increment_ports: 1,
tls_cert: None,
tls_key: None,
tls_client_auth_root_cert: None,
tls_revocation_list: None,
}));
wait_for_port(port(0)).await;
// Start client relay
task::spawn(crate::tcp_relay_client::run_app(ClientConfig {
token: Some(VALID_TOKEN.to_string()),
relay_url: format!("http://{}:{}", LOCALHOST_IP, port(0)),
listen_address: LOCALHOST_IP.to_string(),
root_certificate: None,
..Default::default()
}));
wait_for_port(port(2)).await;
dummy_tcp_client_square_root_requests(port(2), 10).await;
})
.await;
}

View File

@ -0,0 +1,62 @@
use tokio::task;
use crate::tcp_relay_client::client_config::ClientConfig;
use crate::tcp_relay_server::server_config::ServerConfig;
use crate::test::dummy_tcp_sockets::{
dummy_tcp_client_square_root_requests, wait_for_port, DummyTCPServer,
};
use crate::test::pki::Pki;
use crate::test::{get_port_number, PortsAllocation, LOCALHOST_IP};
const VALID_TOKEN: &str = "AvalidTOKEN";
fn port(index: u16) -> u16 {
get_port_number(PortsAllocation::ValidWithTokenAuthAndServerTLS, index)
}
#[tokio::test()]
async fn test() {
let _ = env_logger::builder().is_test(true).try_init();
// Start internal service
let local_server = DummyTCPServer::start(port(1)).await;
tokio::spawn(async move {
local_server.loop_conn_square_operations().await;
});
let pki = Pki::load();
let local_set = task::LocalSet::new();
local_set
.run_until(async move {
wait_for_port(port(1)).await;
// Start server relay
task::spawn_local(crate::tcp_relay_server::run_app(ServerConfig {
tokens: vec![VALID_TOKEN.to_string()],
tokens_file: None,
ports: vec![port(1)],
upstream_server: "127.0.0.1".to_string(),
listen_address: format!("127.0.0.1:{}", port(0)),
increment_ports: 1,
tls_cert: Some(pki.localhost_crt.file_path()),
tls_key: Some(pki.localhost_key.file_path()),
tls_client_auth_root_cert: None,
tls_revocation_list: None,
}));
wait_for_port(port(0)).await;
// Start client relay
task::spawn(crate::tcp_relay_client::run_app(ClientConfig {
token: Some(VALID_TOKEN.to_string()),
relay_url: format!("https://localhost:{}", port(0)),
listen_address: LOCALHOST_IP.to_string(),
root_certificate: Some(pki.root_ca_crt.file_path()),
..Default::default()
}));
wait_for_port(port(2)).await;
dummy_tcp_client_square_root_requests(port(2), 10).await;
})
.await;
}

View File

@ -0,0 +1,67 @@
use tokio::task;
use crate::tcp_relay_client::client_config::ClientConfig;
use crate::tcp_relay_server::server_config::ServerConfig;
use crate::test::dummy_tcp_sockets::{
dummy_tcp_client_additions_requests, dummy_tcp_client_square_root_requests, wait_for_port,
DummyTCPServer,
};
use crate::test::{get_port_number, PortsAllocation, LOCALHOST_IP};
const VALID_TOKEN: &str = "AvalidTOKEN";
const NUM_INC: i32 = 5;
fn port(index: u16) -> u16 {
get_port_number(PortsAllocation::ValidWithTokenAuthMultiplePorts, index)
}
#[tokio::test()]
async fn test() {
let _ = env_logger::builder().is_test(true).try_init();
// Start internal services
let local_server_1 = DummyTCPServer::start(port(1)).await;
tokio::spawn(async move {
local_server_1.loop_conn_square_operations().await;
});
let local_server_2 = DummyTCPServer::start(port(3)).await;
tokio::spawn(async move {
local_server_2.loop_next_conn_add_operations(NUM_INC).await;
});
let local_set = task::LocalSet::new();
local_set
.run_until(async move {
wait_for_port(port(1)).await;
// Start server relay
task::spawn_local(crate::tcp_relay_server::run_app(ServerConfig {
tokens: vec![VALID_TOKEN.to_string()],
tokens_file: None,
ports: vec![port(1), port(3)],
upstream_server: "127.0.0.1".to_string(),
listen_address: format!("127.0.0.1:{}", port(0)),
increment_ports: 1,
tls_cert: None,
tls_key: None,
tls_client_auth_root_cert: None,
tls_revocation_list: None,
}));
wait_for_port(port(0)).await;
// Start client relay
task::spawn(crate::tcp_relay_client::run_app(ClientConfig {
token: Some(VALID_TOKEN.to_string()),
relay_url: format!("http://{}:{}", LOCALHOST_IP, port(0)),
listen_address: LOCALHOST_IP.to_string(),
root_certificate: None,
..Default::default()
}));
wait_for_port(port(2)).await;
dummy_tcp_client_square_root_requests(port(2), 10).await;
dummy_tcp_client_additions_requests(port(4), NUM_INC, 10).await;
})
.await;
}

View File

@ -0,0 +1,62 @@
use tokio::task;
use crate::tcp_relay_client::client_config::ClientConfig;
use crate::tcp_relay_server::server_config::ServerConfig;
use crate::test::dummy_tcp_sockets::{
dummy_tcp_client_square_root_requests, wait_for_port, DummyTCPServer,
};
use crate::test::{get_port_number, PortsAllocation, LOCALHOST_IP};
const VALID_TOKEN: &str = "AvalidTOKEN";
fn port(index: u16) -> u16 {
get_port_number(PortsAllocation::ValidWithMultipleTokenAuth, index)
}
#[tokio::test()]
async fn valid_with_token_file() {
let _ = env_logger::builder().is_test(true).try_init();
// Start internal service
let local_server = DummyTCPServer::start(port(1)).await;
tokio::spawn(async move {
local_server.loop_conn_square_operations().await;
});
let local_set = task::LocalSet::new();
local_set
.run_until(async move {
wait_for_port(port(1)).await;
let token_file = mktemp::Temp::new_file().unwrap();
std::fs::write(&token_file, format!("tok1\ntok2\n{}\ntok4", VALID_TOKEN)).unwrap();
// Start server relay
task::spawn_local(crate::tcp_relay_server::run_app(ServerConfig {
tokens: vec![],
tokens_file: Some(token_file.to_str().unwrap().to_string()),
ports: vec![port(1)],
upstream_server: "127.0.0.1".to_string(),
listen_address: format!("127.0.0.1:{}", port(0)),
increment_ports: 1,
tls_cert: None,
tls_key: None,
tls_client_auth_root_cert: None,
tls_revocation_list: None,
}));
wait_for_port(port(0)).await;
// Start client relay
task::spawn(crate::tcp_relay_client::run_app(ClientConfig {
token: Some(VALID_TOKEN.to_string()),
relay_url: format!("http://{}:{}", LOCALHOST_IP, port(0)),
listen_address: LOCALHOST_IP.to_string(),
root_certificate: None,
..Default::default()
}));
wait_for_port(port(2)).await;
dummy_tcp_client_square_root_requests(port(2), 10).await;
})
.await;
}

View File

@ -0,0 +1,54 @@
use tokio::task;
use crate::tcp_relay_client::client_config::ClientConfig;
use crate::tcp_relay_server::server_config::ServerConfig;
use crate::test::dummy_tcp_sockets::wait_for_port;
use crate::test::pki::Pki;
use crate::test::{get_port_number, PortsAllocation, LOCALHOST_IP};
const VALID_TOKEN: &str = "AvalidTOKEN";
fn port(index: u16) -> u16 {
get_port_number(
PortsAllocation::WithTokenAuthAndInvalidServerTLSBadCA,
index,
)
}
#[tokio::test()]
async fn test() {
let _ = env_logger::builder().is_test(true).try_init();
let pki = Pki::load();
let local_set = task::LocalSet::new();
local_set
.run_until(async move {
// Start server relay
task::spawn_local(crate::tcp_relay_server::run_app(ServerConfig {
tokens: vec![VALID_TOKEN.to_string()],
tokens_file: None,
ports: vec![port(1)],
upstream_server: "127.0.0.1".to_string(),
listen_address: format!("127.0.0.1:{}", port(0)),
increment_ports: 1,
tls_cert: Some(pki.localhost_crt.file_path()),
tls_key: Some(pki.localhost_key.file_path()),
tls_client_auth_root_cert: None,
tls_revocation_list: None,
}));
wait_for_port(port(0)).await;
// Start client relay
crate::tcp_relay_client::run_app(ClientConfig {
token: Some(VALID_TOKEN.to_string()),
relay_url: format!("https://localhost:{}", port(0)),
listen_address: LOCALHOST_IP.to_string(),
root_certificate: Some(pki.other_ca_crt.file_path()),
..Default::default()
})
.await
.unwrap_err();
})
.await;
}

View File

@ -0,0 +1,54 @@
use tokio::task;
use crate::tcp_relay_client::client_config::ClientConfig;
use crate::tcp_relay_server::server_config::ServerConfig;
use crate::test::dummy_tcp_sockets::wait_for_port;
use crate::test::pki::Pki;
use crate::test::{get_port_number, PortsAllocation, LOCALHOST_IP};
const VALID_TOKEN: &str = "AvalidTOKEN";
fn port(index: u16) -> u16 {
get_port_number(
PortsAllocation::WithTokenAuthAndInvalidServerTLSExpiredAndBadCN,
index,
)
}
#[tokio::test()]
async fn test() {
let _ = env_logger::builder().is_test(true).try_init();
let pki = Pki::load();
let local_set = task::LocalSet::new();
local_set
.run_until(async move {
// Start server relay
task::spawn_local(crate::tcp_relay_server::run_app(ServerConfig {
tokens: vec![VALID_TOKEN.to_string()],
tokens_file: None,
ports: vec![port(1)],
upstream_server: "127.0.0.1".to_string(),
listen_address: format!("127.0.0.1:{}", port(0)),
increment_ports: 1,
tls_cert: Some(pki.expired_client_crt.file_path()),
tls_key: Some(pki.expired_client_key.file_path()),
tls_client_auth_root_cert: None,
tls_revocation_list: None,
}));
wait_for_port(port(0)).await;
// Start client relay
crate::tcp_relay_client::run_app(ClientConfig {
token: Some(VALID_TOKEN.to_string()),
relay_url: format!("https://localhost:{}", port(0)),
listen_address: LOCALHOST_IP.to_string(),
root_certificate: Some(pki.root_ca_crt.file_path()),
..Default::default()
})
.await
.unwrap_err();
})
.await;
}

View File

@ -1,15 +0,0 @@
[package]
name = "tcp_relay_client"
version = "0.1.0"
edition = "2021"
[dependencies]
base = { path = "../base" }
clap = { version = "3.2.18", features = ["derive", "env"] }
log = "0.4.17"
env_logger = "0.9.0"
reqwest = { version = "0.11", features = ["json"] }
tokio = { version = "1", features = ["full"] }
futures = "0.3.24"
tokio-tungstenite = "0.17.2"
urlencoding = "2.1.0"

View File

@ -1 +0,0 @@
pub mod relay_client;

View File

@ -1,64 +0,0 @@
use std::sync::Arc;
use clap::Parser;
use futures::future::join_all;
use base::RemoteConfig;
use tcp_relay_client::relay_client::relay_client;
/// TCP relay client
#[derive(Parser, Debug, Clone)]
#[clap(author, version, about, long_about = None)]
pub struct Args {
/// Access token
#[clap(short, long)]
pub token: String,
/// Relay server
#[clap(short, long, default_value = "http://127.0.0.1:8000")]
pub relay_url: String,
/// Listen address
#[clap(short, long, default_value = "127.0.0.1")]
pub listen_address: String,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
let args: Args = Args::parse();
let args = Arc::new(args);
// Get server relay configuration (fetch the list of port to forward)
let url = format!("{}/config", args.relay_url);
log::info!("Retrieving configuration on {}", url);
let req = reqwest::Client::new().get(url)
.header("Authorization", format!("Bearer {}", args.token))
.send()
.await?;
if req.status().as_u16() != 200 {
log::error!("Could not retrieve configuration! (got status {})", req.status());
std::process::exit(2);
}
let conf = req.json::<RemoteConfig>()
.await?;
// Start to listen port
let mut handles = vec![];
for port in conf {
let listen_address = format!("{}:{}", args.listen_address, port.port);
let h = tokio::spawn(relay_client(
format!("{}/ws?id={}&token={}",
args.relay_url, port.id, urlencoding::encode(&args.token))
.replace("http", "ws"),
listen_address,
));
handles.push(h);
}
join_all(handles).await;
Ok(())
}

View File

@ -1,87 +0,0 @@
use futures::{SinkExt, StreamExt};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::{TcpListener, TcpStream};
use tokio_tungstenite::tungstenite::Message;
pub async fn relay_client(ws_url: String, listen_address: String) {
log::info!("Start to listen on {}", listen_address);
let listener = match TcpListener::bind(&listen_address).await {
Ok(l) => l,
Err(e) => {
log::error!("Failed to start to listen on {}! {}", listen_address, e);
std::process::exit(3);
}
};
loop {
let (socket, _) = listener.accept().await
.expect("Failed to accept new connection!");
tokio::spawn(relay_connection(ws_url.clone(), socket));
}
}
/// Relay connection
///
/// WS read => TCP write
/// TCP read => WS write
async fn relay_connection(ws_url: String, socket: TcpStream) {
log::debug!("Connecting to {}...", ws_url);
let (ws_stream, _) = tokio_tungstenite::connect_async(ws_url)
.await.expect("Failed to connect to server relay!");
let (mut tcp_read, mut tcp_write) = socket.into_split();
let (mut ws_write, mut ws_read) =
ws_stream.split();
// TCP read -> WS write
let future = async move {
let mut buff: [u8; 5000] = [0; 5000];
loop {
match tcp_read.read(&mut buff).await {
Ok(s) => {
if let Err(e) = ws_write.send(Message::Binary(Vec::from(&buff[0..s]))).await {
log::error!(
"Failed to write to WS connection! {:?} Exiting TCP read -> WS write loop...",e);
break;
}
if s == 0 {
log::info!("Got empty read TCP buffer. Stopping...");
break;
}
}
Err(e) => {
log::error!(
"Failed to read from TCP connection! {:?} Exitin TCP read -> WS write loop...",
e
);
break;
}
}
}
};
tokio::spawn(future);
// WS read -> TCP write
while let Some(m) = ws_read.next().await {
match m {
Err(e) => {
log::error!("Failed to read from WebSocket. Breaking read loop... {:?}", e);
break;
}
Ok(Message::Binary(b)) => {
if let Err(e) = tcp_write.write_all(&b).await {
log::error!("Failed to forward message to websocket. Closing reading end... {:?}", e);
break;
};
}
Ok(Message::Close(_r)) => {
log::info!("Server asked to close this WebSocket connection");
break;
}
Ok(m) => log::info!("{:?}", m)
}
}
}

View File

@ -1,16 +0,0 @@
[package]
name = "tcp_relay_server"
version = "0.1.0"
edition = "2021"
[dependencies]
base = { path = "../base" }
clap = { version = "3.2.18", features = ["derive", "env"] }
log = "0.4.17"
env_logger = "0.9.0"
actix = "0.13.0"
actix-web = "4"
actix-web-actors = "4.1.0"
serde = { version = "1.0.144", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
futures = "0.3.24"

View File

@ -1,31 +0,0 @@
use clap::Parser;
/// TCP relay server
#[derive(Parser, Debug, Clone)]
#[clap(author, version, about, long_about = None)]
pub struct Args {
/// Access tokens
#[clap(short, long)]
pub tokens: Vec<String>,
/// Access tokens stored in a file, one token per line
#[clap(long)]
pub tokens_file: Option<String>,
/// Forwarded ports
#[clap(short, long)]
pub ports: Vec<u16>,
/// Upstream server
#[clap(short, long, default_value = "127.0.0.1")]
pub upstream_server: String,
/// HTTP server listen address
#[clap(short, long, default_value = "0.0.0.0:8000")]
pub listen_address: String,
/// Increment ports on client. Useful for debugging and running both client and server
/// on the same machine
#[clap(short, long, default_value_t = 0)]
pub increment_ports: u16,
}

View File

@ -1,2 +0,0 @@
pub mod args;
pub mod relay_ws;

View File

@ -1,74 +0,0 @@
use std::sync::Arc;
use actix_web::{App, HttpRequest, HttpResponse, HttpServer, middleware, Responder, web};
use actix_web::web::Data;
use clap::Parser;
use base::RelayedPort;
use tcp_relay_server::args::Args;
use tcp_relay_server::relay_ws::relay_ws;
pub async fn hello_route() -> &'static str {
"Hello world!"
}
pub async fn config_route(req: HttpRequest, data: Data<Arc<Args>>) -> impl Responder {
let token = req.headers().get("Authorization")
.map(|t| t.to_str().unwrap_or_default())
.unwrap_or_default()
.strip_prefix("Bearer ")
.unwrap_or_default();
if !data.tokens.iter().any(|t| t.eq(token)) {
return HttpResponse::Unauthorized().json("Missing / invalid token");
}
HttpResponse::Ok().json(
data.ports.iter()
.enumerate()
.map(|(id, port)| RelayedPort { id, port: port + data.increment_ports })
.collect::<Vec<_>>()
)
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
let mut args: Args = Args::parse();
if args.ports.is_empty() {
log::error!("No port to forward!");
std::process::exit(2);
}
// Read tokens from file, if any
if let Some(file) = &args.tokens_file {
std::fs::read_to_string(file)
.expect("Failed to read tokens file!")
.split('\n')
.filter(|l| !l.is_empty())
.for_each(|t| args.tokens.push(t.to_string()));
}
if args.tokens.is_empty() {
log::error!("No tokens specified!");
std::process::exit(3);
}
log::info!("Starting relay on http://{}", args.listen_address);
let args = Arc::new(args);
let args_clone = args.clone();
HttpServer::new(move || {
App::new()
.wrap(middleware::Logger::default())
.app_data(Data::new(args_clone.clone()))
.route("/", web::get().to(hello_route))
.route("/config", web::get().to(config_route))
.route("/ws", web::get().to(relay_ws))
})
.bind(&args.listen_address)?
.run()
.await
}