272 Commits
10k ... main

Author SHA1 Message Date
eyedeekay
61008ce988 fix test 2025-08-14 16:43:16 -04:00
eyedeekay
294cd52343 fix test 2025-08-14 16:40:12 -04:00
eyedeekay
322b431e8f move constants to own file 2025-08-14 16:34:01 -04:00
eyedeekay
79df514a2f Refactor ReadBuilRequestRecord 2025-08-14 16:27:11 -04:00
eyedeekay
36762c61c5 fix race in sntp 2025-08-14 16:22:20 -04:00
eyedeekay
a8ac47431e reorganize netDb directory 2025-08-14 16:15:46 -04:00
eyedeekay
bd947ec2ca gofmt 2025-08-14 15:58:59 -04:00
eyedeekay
61700c8a05 refactor long ReSeed function in lib/netdb 2025-08-14 15:53:38 -04:00
eyedeekay
d6b8918a14 refactor long ReadFrom and GetRouterInfo function in lib/netdb 2025-08-14 15:46:20 -04:00
eyedeekay
43aa3a72a6 refactor long WriteTo function in lib/netdb 2025-08-14 15:33:23 -04:00
eyedeekay
5d04d24bc5 Refactor long functions Lookup and findClosestPeers in the netdb package 2025-08-14 15:28:16 -04:00
eyedeekay
f168794ca3 start working on the netDb 2025-08-14 15:12:34 -04:00
eyedeekay
9c9f19b904 update godoc 2025-08-13 03:15:49 -04:00
eyedeekay
f176d4a97f am eliminate make test target 2025-08-13 03:15:06 -04:00
eyedeekay
e89876903f update README.md and ROADMAP.md with current post-NTCP2 status 2025-08-13 03:12:03 -04:00
eyedeekay
c6f8bf6447 Test outbound transport 2025-08-13 01:47:21 -04:00
eyedeekay
32075c20c7 NTCP2 Outbound connections 2025-08-12 20:51:00 -04:00
eyedeekay
4862c0314c Check in NTCP2 Transport/Session implementation. We can now listen. 2025-08-09 00:12:50 -04:00
eyedeekay
7f57cebd3f i2np interface-driven refactor 2025-08-08 23:23:13 -04:00
eyedeekay
c418914e95 Work on I2NP messages 2025-08-08 22:58:20 -04:00
eyedeekay
0e12cbfb70 fmt 2025-08-05 22:06:06 -04:00
eyedeekay
a8a3d61a75 start migrating to the ntcp2 library in go-noise for most layers of NTCP2 library 2025-08-05 22:05:31 -04:00
eyedeekay
96f7958543 more doc updates 2025-08-05 17:04:17 -04:00
eyedeekay
230646f34d update modules and README.md 2025-07-24 13:50:27 -04:00
eyedeekay
3b06be5eca remove su3 library to other location 2025-07-16 14:34:29 -04:00
eyedeekay
f4a89c74e0 Refactor long reseed functions to smaller functions 2025-07-15 20:46:48 -04:00
eyedeekay
1529f18fa1 Refactor long ntcp2 functions to smaller functions 2025-07-15 20:42:13 -04:00
eyedeekay
3be24a6a42 Refactor long su3 function to smaller functions 2025-07-15 20:33:27 -04:00
eyedeekay
e4e8631b0e Re-organized noise package 2025-07-15 20:28:03 -04:00
eyedeekay
2a3cfcfac3 re-generate godoc 2025-07-15 19:58:45 -04:00
eyedeekay
e1756bdf39 Fix documentation: mark I2NP message parsing as implemented 2025-07-15 19:53:27 -04:00
eyedeekay
975970152e secure RouterInfoKeystore private key file permissions 2025-07-15 19:48:39 -04:00
eyedeekay
bd6ce7b25f replace error string with safe fallback IDs in KeyID generation 2025-07-15 19:46:40 -04:00
eyedeekay
7470d80def Fix critical security issue: secure private key file permissions and path construction 2025-07-15 19:41:59 -04:00
eyedeekay
4997ceebae fix test failures 2025-07-15 19:36:05 -04:00
eyedeekay
637293f13e fix test 2025-07-15 19:14:55 -04:00
eyedeekay
2d083bfe90 fix length bit related encr/decr bug 2025-07-15 19:04:22 -04:00
eyedeekay
29388af798 give noise test it the whole packet with the length bit 2025-07-15 18:58:27 -04:00
eyedeekay
f9127c0998 Update various things to post-refactor API interfaces 2025-07-15 18:28:02 -04:00
eyedeekay
b9e73d816d update modules 2025-07-08 21:55:30 -04:00
eyedeekay
4edc7b392d move common into it's own package, because it's getting hard to keep track of everything in here. Also going to move crypto into it's own package soon. This way common and crypto will have their own CI and will be able to present stable interfaces before the rest of go-i2p is ready. 2025-07-07 15:15:27 -04:00
eyedeekay
d7888ac9be return corrected size 2025-06-28 13:53:13 -04:00
eyedeekay
68408bb48e Expose WriteMessageToConn and start work on sessions 2025-05-31 13:40:33 -04:00
eyedeekay
4715b76ade IGNORE THIS CHECKIN: regenerate call graphs, regenerate godoc 2025-05-15 20:30:26 -04:00
eyedeekay
ac7e369b6a work on reseeding 2025-05-15 20:20:46 -04:00
eyedeekay
7d51d83b40 Fix nil return in when performing noise handshake to return a session 2025-05-15 19:20:37 -04:00
eyedeekay
89c82cb2fe Remove unused function, fix spelling, update godoc 2025-05-15 19:17:42 -04:00
eyedeekay
808f7d6fdf move processors back due to import cycle 2025-05-15 19:03:41 -04:00
eyedeekay
537ab808f8 fix issues with transports 2025-05-15 18:56:10 -04:00
eyedeekay
b41bb0eef8 move sessionmessageprocessors to own directory 2025-05-15 18:42:39 -04:00
eyedeekay
8787fea069 Put an X over handshake. It's broken, but it's there! 2025-05-10 23:22:43 -04:00
eyedeekay
fc9734d43d fix page workflow 2025-05-10 23:19:50 -04:00
eyedeekay
0a262d5780 Add GitHub Actions workflow for page generation 2025-05-10 23:15:45 -04:00
eyedeekay
2f233e931d delete more now-unused functions 2025-05-10 23:13:47 -04:00
eyedeekay
e9991099b7 update godoc again, delete more now-unused functions 2025-05-10 23:13:11 -04:00
eyedeekay
761dcb5f98 get rid of math/rand usages 2025-05-10 23:09:22 -04:00
eyedeekay
f68d9b5606 check in utility functions 2025-05-10 23:03:53 -04:00
eyedeekay
9fd3400585 More function deletions 2025-05-10 22:55:39 -04:00
eyedeekay
c85822163b Regenerate godoc 2025-05-10 22:36:36 -04:00
eyedeekay
e2fdb7c4e0 Move to SessionProcessors 2025-05-10 22:33:43 -04:00
eyedeekay
1babf06091 More code deduplication 2025-05-10 22:18:50 -04:00
eyedeekay
62e565b36c More code deduplication 2025-05-10 22:16:25 -04:00
eyedeekay
c7a17eac86 fmt 2025-05-10 21:55:30 -04:00
eyedeekay
89e53fdb9f More migration to processors 2025-05-10 21:55:06 -04:00
eyedeekay
ebdd1ae0aa Work on implementing and migrating to message processors 2025-05-10 21:46:07 -04:00
eyedeekay
b65f6c2682 Work on implementing and migrating to message processors 2025-05-10 21:43:30 -04:00
eyedeekay
14a0e56f6a Work on implementing and migrating to message processors 2025-05-10 21:37:47 -04:00
eyedeekay
4a89c14734 Work on implementing and migrating to message processors 2025-05-10 21:23:05 -04:00
eyedeekay
09fe22178d more method consolidation 2025-05-10 21:12:49 -04:00
eyedeekay
ef156f6944 more method consolidation 2025-05-10 21:11:46 -04:00
eyedeekay
a4acb01be9 handshake interface implementation stuff 2025-05-10 20:25:02 -04:00
eyedeekay
dd116095aa More duplicated code reduction, interface improvement 2025-05-10 20:09:42 -04:00
eyedeekay
1922f3a0ab Start implementing messages as message processors 2025-05-08 23:22:42 -04:00
eyedeekay
2a28c8ee01 Start implementing the message handlers 2025-05-08 22:59:36 -04:00
eyedeekay
9cb4af8f06 plan new handshake interfaces 2025-05-08 21:41:09 -04:00
eyedeekay
56faebd746 Plan re-org of handshake functions 2025-05-08 20:29:46 -04:00
eyedeekay
8b035711b6 Move sessionRequest methods to own file, organization changes 2025-05-08 18:01:58 -04:00
eyedeekay
c93b258844 Move ntcp2 messages into ntcp2 directory 2025-05-08 16:22:22 -04:00
eyedeekay
2df5d23528 Implement findClosestPeers 2025-05-08 14:24:08 -04:00
eyedeekay
98ea3d55c4 Implement lookup for kadResolver, change kadresolver to KademliaResolver 2025-05-07 21:19:46 -04:00
eyedeekay
b5454a4317 Implement lookup for kadResolver, change kadresolver to KademliaResolver 2025-05-07 21:17:38 -04:00
eyedeekay
83502face7 change lookup interface, needs to be more intuitive to use, we can thread elsewhere 2025-05-07 20:51:30 -04:00
eyedeekay
c99b15ba7f NetDB entry serialization and deserialization, TODO: leaseset struct port 2025-05-07 20:14:18 -04:00
eyedeekay
8e73c36922 check in the stuff I have locally that I haven't yet, mostly ECDSA stuff which is not very useful 2025-05-05 22:37:46 -04:00
eyedeekay
89b1995593 ecdsa_p256_private impl, rest of ecdsa to follow 2025-04-04 11:00:59 -04:00
eyedeekay
4577408d6d return a descriptive error upon a hash size mismatch 2025-04-03 17:00:10 -04:00
eyedeekay
e7e26ae021 Fix unimplemented funcs in rsa3072 2025-04-03 15:53:17 -04:00
eyedeekay
1d1568de71 Add rsa4096 implementation and use the same functin for all key reads 2025-04-03 15:30:06 -04:00
eyedeekay
b21a6cee9e Add rsa2048 implementation 2025-04-03 15:04:39 -04:00
eyedeekay
35b47969b0 Add rsa3072 implementation 2025-04-03 14:57:08 -04:00
eyedeekay
816df5642c implement first handshake message sender and reciever, create a test file 2025-03-31 21:49:31 -04:00
eyedeekay
1bd439f989 Implement Sender for Handshake Message 1 2025-03-31 17:33:01 -04:00
eyedeekay
6158eb68f3 fix some interfaces 2025-03-31 14:56:04 -04:00
eyedeekay
03eeeab781 reorganized old hansdhake stuff 2025-03-31 14:55:05 -04:00
eyedeekay
0099392f6d fix some interfaces 2025-03-31 14:51:53 -04:00
eyedeekay
a09f155835 Add quantized padding file and my notes on quantized padding 2025-03-31 13:46:45 -04:00
eyedeekay
fa561fc431 Merge branch 'master' of github.com:go-i2p/go-i2p 2025-03-29 17:54:58 -04:00
eyedeekay
c5125c1bfd more ntcp2 progress, figure out what the rules of the crypto library interfaces need to be, etc 2025-03-29 17:54:23 -04:00
idk
9e1bac3ff1 Merge pull request #37 from satk0/add-database-lookup
Add DatabaseLookup
2025-03-29 14:41:44 -04:00
eyedeekay
b4e1f3cfdf THIS LARGE CHECKIN CONTAINS REGENERATED DOCS ONLY. update/regenerate docs. 2025-03-27 22:18:24 -04:00
eyedeekay
d4ff0e373c stub out more methods 2025-03-27 22:01:34 -04:00
eyedeekay
0c9c8270a5 migrate hmac to crypto/hmac, I swear we do everything the hard way... 2025-03-27 21:56:23 -04:00
eyedeekay
f2bacc5018 Add basic chacha20-poly1305 implementation 2025-03-27 21:45:23 -04:00
eyedeekay
94691f1e75 Stub out ECDSA requirements 2025-03-27 20:30:31 -04:00
eyedeekay
8c4f718601 Make all the tests compile again, some of the elgamal ones might fail but mixing up our packages with third-party elgamal packages was causing problems. We should bring crypto in-house as dependencies, wrap our interfaces around it per our requirements, and not touch the upstream library if we can help it. That means wrap private keys, public keys, signing and encryption operations with our own code reporting our own errors. 2025-03-27 20:13:17 -04:00
eyedeekay
9a0d164276 Use curve25519+ChaCha20-Poly1305 instead of AES-GCM in curve25519, I think we might need to override it sometimes but it's the thing that makes sense right now 2025-03-27 19:50:55 -04:00
eyedeekay
f3f5d744ed Fix curve25519 decrypter 2025-03-27 19:24:23 -04:00
eyedeekay
3b9fb603f4 fix a few more compile errors and sync 2025-03-26 21:10:16 -04:00
eyedeekay
29d5a20216 Fix compile errors in NTCP handshake 2025-03-26 19:38:01 -04:00
eyedeekay
3c252e22cd split the rsa stub package into one file per component 2025-03-26 19:32:54 -04:00
eyedeekay
dcb11d1fda split the rsa stub package into one file per component 2025-03-26 19:31:32 -04:00
eyedeekay
a721856688 split the elgamal package into one file per component 2025-03-26 19:26:03 -04:00
eyedeekay
b66c5813cb split the ed25519 package into one file per component 2025-03-26 19:19:24 -04:00
eyedeekay
441549743d Fix some of the compile errors in routerinfo_keystore.go 2025-03-26 18:57:27 -04:00
eyedeekay
30f84713ea split the ecdsa package into one file per component 2025-03-26 18:52:51 -04:00
eyedeekay
6057677956 split the dsa package into one file per component 2025-03-26 18:48:12 -04:00
eyedeekay
c026b9a4a5 split the curve25519 package into one file per component 2025-03-26 18:40:38 -04:00
eyedeekay
9c6cfc14e5 split the curve25519 package into one file per component 2025-03-26 18:40:31 -04:00
eyedeekay
4533c2fd92 split the aes package into one file per component 2025-03-26 18:24:31 -04:00
satk0
89e51820f1 Add DatabaseLookup and test it 2025-03-26 20:32:44 +01:00
eyedeekay
17a789bed7 refactor crypto library into smaller components 2025-03-25 19:08:47 -04:00
eyedeekay
d236f19f81 add custom handshake manager 2025-03-25 18:37:14 -04:00
eyedeekay
d0b81d9ce9 add remaining session messages 2025-03-25 18:17:34 -04:00
eyedeekay
06cf6b41b4 add remaining session messages 2025-03-25 18:15:44 -04:00
eyedeekay
ac8349d083 Add SessionCreated implementation 2025-03-25 17:02:25 -04:00
eyedeekay
45296be6d3 let the machine find simple errors in the common library and call it a night 2025-03-24 23:55:04 -04:00
eyedeekay
1f25f0c9b3 Finish initialization of NTCP2Sessions 2025-03-24 23:22:23 -04:00
eyedeekay
d1a708a594 Actually use the message objects, duh 2025-03-24 23:16:12 -04:00
eyedeekay
b153bfc050 Refactor and comment ComposeInitiatorHandshakeMessage 2025-03-24 19:36:14 -04:00
eyedeekay
d401b06c0f Remove dot-imports from LeaseSets 2025-03-22 18:49:26 -04:00
eyedeekay
9091834074 fix more tests 2025-03-22 18:12:13 -04:00
eyedeekay
8561b3ec69 fmt 2025-03-22 18:03:24 -04:00
eyedeekay
8aac97351d fix some tests 2025-03-22 18:03:06 -04:00
idk
3142a394aa Merge pull request #31 from go-i2p/ntcp
NTCP2 Handshake Development
2025-03-21 15:48:13 -04:00
eyedeekay
f2b6d4bc01 Refactor noise locked read/write, move handshake out to own interface 2025-03-19 22:28:14 -04:00
eyedeekay
fa0a42855c move padding 2025-03-19 17:20:33 -04:00
eyedeekay
3212cae276 fix tests that failed because of inconsistent usage of crypto API 2025-03-09 14:04:43 -04:00
eyedeekay
ad7bac666b Merge branch 'ntcp' of github.com:go-i2p/go-i2p into ntcp 2025-03-09 14:02:42 -04:00
eyedeekay
ba0c89d567 fix tests that failed because of inconsistent usage of crypto API 2025-03-09 14:02:10 -04:00
idk
6a64b28bb3 Merge pull request #39 from urgentquest/better-config-file-handling
Better config file handling
2025-03-09 13:52:15 -04:00
ungrentquest
9fa714f648 typo 2025-03-05 20:03:31 +00:00
ungrentquest
eda403443d Some additional tweaks. Split out actual config handling. Add an auxiliary func to build i2p base directory path 2025-03-05 00:40:43 +00:00
ungrentquest
84cc45d3e4 Refactor config handling
- Replace low-level operations like file existance checks, file io with viper calls.
That also allows to get rid of manual config structure initialization.
- Split out UserHome() into itil/home.go to reduce code duplicacy.
- Better error handling and general readbility.
2025-03-04 23:59:38 +00:00
eyedeekay
598ee1eb70 Merge branch 'ntcp' of github.com:go-i2p/go-i2p into ntcp 2025-03-02 16:44:43 -05:00
eyedeekay
bd6edf446d Fix some tests 2025-03-02 16:43:47 -05:00
idk
94e43f8aa6 Merge pull request #38 from urgentquest/ntcp-go-fix-null-pointer-dereferences
ntcp/session.go: fixes and imrovements
2025-03-02 15:46:45 -05:00
ungrentquest
7bdaf6d4ea ntcp/session.go: fixes and imrovements
- Stop using deprecated (and probably
not cryptographically secure) exp/rand, switch to crypto/rand instead
- Reduce code duplicacy by defining `buildAesStaticKey()` method
- Properly handle pointer to `crypto.AESSymmetricKey` struct
to prevent nil pointer dereferences
- go mod tidy
2025-03-01 21:19:53 +00:00
eyedeekay
393263294e update CONTRIBUTING.md 2025-02-27 12:53:55 -05:00
eyedeekay
55f92bdd8a update CONTRIBUTING.md 2025-02-27 11:17:57 -05:00
eyedeekay
8ea238f3dd add template for docs 2025-02-27 10:33:01 -05:00
eyedeekay
91d8b30495 Add callgraphs to docs 2025-02-26 21:03:51 -05:00
eyedeekay
ea4d126358 Add callgraphs to docs 2025-02-26 20:58:20 -05:00
eyedeekay
f46bd95b68 Add callgraphs to docs 2025-02-26 20:52:16 -05:00
eyedeekay
35eb66084b add the ability to generate callgraphs 2025-02-26 20:38:46 -05:00
eyedeekay
a9289dd4d3 add the ability to generate callgraphs 2025-02-26 20:38:29 -05:00
eyedeekay
7f78fdf784 Add new, address generation functions 2025-02-26 19:31:57 -05:00
eyedeekay
ae4970b3a9 Switch to oops for error configuration so we can get more info about failures 2025-02-26 19:22:48 -05:00
eyedeekay
3d6a08a76b start building NTCP2 addresses 2025-02-26 19:13:05 -05:00
eyedeekay
18b2afe828 create and store our own RI with private keys 2025-02-26 14:44:02 -05:00
eyedeekay
c6867e0b16 more keystore work 2025-02-25 16:15:18 -05:00
eyedeekay
d0b4db769e Work on setting up a routerinfo from a keystore 2025-02-16 15:09:12 -05:00
eyedeekay
26a9a00b34 Work on setting up a routerinfo from a keystore 2025-02-16 14:38:06 -05:00
eyedeekay
99df4c7ce8 Little more RI private key stuff just to be sure where I think it should go 2025-02-15 22:19:46 -05:00
eyedeekay
b95b0c4fa3 start working on basic key storage for own RI private keys 2025-02-15 22:17:32 -05:00
eyedeekay
036f9116a5 start working on basic key storage for own RI private keys 2025-02-15 22:16:31 -05:00
idk
d97624282e Merge pull request #35 from satk0/i2np-build-res
Add i2np Build Response Record
2025-02-11 14:12:08 -05:00
satk0
46af6d55ef Update upload-artifact in workflow 2025-02-11 13:19:39 +01:00
satk0
9591f496eb Add BuildResponseRecord 2025-02-11 13:15:47 +01:00
eyedeekay
71fff44d4b Merge branch 'master' of github.com:go-i2p/go-i2p into ntcp 2025-02-10 16:44:55 -05:00
eyedeekay
6b2f231c36 spk and cpk reads were reversed 2025-02-10 16:41:59 -05:00
eyedeekay
4eeaf915f0 sam and tunnel manager are now freestanding apps 2025-02-09 12:29:17 -05:00
eyedeekay
440b9e8118 revise logging around SPK stuff in router_info.go 2025-01-30 15:49:28 -05:00
eyedeekay
8bc5ca162a NTCP2: Change noise interface so we get static keys from better places 2024-12-21 22:13:03 -05:00
eyedeekay
bd92221d56 Merge branch 'master' of github.com:go-i2p/go-i2p into ntcp 2024-12-21 19:52:28 -05:00
idk
22111a6cb7 Merge pull request #30 from satk0/add-signature-tests
Add signature tests
2024-12-14 00:19:14 +00:00
eyedeekay
74d2998e10 Try and reason with the ways of getting local and remote static keys in the transports 2024-12-13 16:59:46 -05:00
satk0
0b89baf98b Add signature tests to doc/tests and actions 2024-12-13 22:42:29 +01:00
satk0
daac1a59b5 Add more signatures 2024-12-13 18:30:15 +01:00
satk0
6f65a7c068 Add signature tests 2024-12-13 15:26:21 +01:00
eyedeekay
db91315582 Make the arguments to ComposeInitatorHandshakeMessage comprehensible 2024-12-12 14:55:40 -05:00
idk
5f3a7f2340 Merge pull request #26 from hkh4n/tests
Refactoring tests
2024-12-04 21:18:57 +00:00
Haris Khan
8494da07a7 deprecate unused functions, deferring non-working test functions for later 2024-12-04 03:37:31 -05:00
Haris Khan
832e0d9114 Ed25519PrivateKey Public() modification 2024-12-04 02:22:54 -05:00
Haris Khan
8d56d033ae flux 2024-12-04 01:40:23 -05:00
Haris Khan
ad22d3e249 flux 2024-12-04 01:28:13 -05:00
Haris Khan
f55788e8ab flux 2024-12-04 01:18:54 -05:00
Haris Khan
2a4f4d6186 successful flux 2024-12-04 01:14:38 -05:00
Haris Khan
ca1180c57f added cert tests and experimental function NewCertificateDeux 2024-12-04 00:55:53 -05:00
Haris Khan
76c3e5f293 WHAT IS HAPPENING RIGHT NOW 2024-12-04 00:02:33 -05:00
Haris Khan
91abe52725 flux 2024-12-03 23:22:14 -05:00
Haris Khan
a0ad9e0122 flux 2024-12-03 23:12:34 -05:00
Haris Khan
b23edc28d1 flux 2024-12-03 23:07:52 -05:00
Haris Khan
b547faf286 flux 2024-12-03 21:24:32 -05:00
Haris Khan
a145555bb2 flux 2024-12-03 19:27:41 -05:00
eyedeekay
280c877d39 Merge branch 'master' of github.com:go-i2p/go-i2p into ntcp 2024-12-01 15:41:24 -05:00
eyedeekay
ef4d4658c0 NTCP2: Add CreateSessionRequest to implement handshake 1 message, modify ComposeInitiatorHandshakeMessage to actually send it 2024-12-01 15:27:42 -05:00
Haris Khan
15bf28403e exported KeyCertificate 2024-12-01 01:28:38 -05:00
Haris Khan
b40c0ab6f9 fixed crypto public key size 2024-12-01 01:13:53 -05:00
Haris Khan
b952be5e08 build test (redo) 2024-11-30 18:33:39 -05:00
Haris Khan
aafbf74986 revert build test 2024-11-30 18:30:02 -05:00
Haris Khan
3cdc5676eb build test 2024-11-30 18:27:54 -05:00
Haris Khan
d41efdba0e adjusted tests.yml and Makefile 2024-11-30 17:43:51 -05:00
Haris Khan
edc436ac39 Merge branch 'master' into tests
# Conflicts:
#	Makefile
2024-11-30 17:30:47 -05:00
idk
414b489b37 Merge pull request #29 from hkh4n/workflow2
Adjust github workflows
2024-11-30 22:11:49 +00:00
Haris Khan
da875738e4 fix typos 2024-11-28 22:46:48 -05:00
Haris Khan
2a027ebb6c added lease_set.mk + add to Makefile 2024-11-28 22:44:51 -05:00
Haris Khan
d658dee6de correct filename + add to Makefile 2024-11-28 22:43:20 -05:00
Haris Khan
8fde3c9400 updated lease_set.mk 2024-11-28 22:40:20 -05:00
Haris Khan
9421374384 are tests running? 2024-11-28 20:18:03 -05:00
Haris Khan
daad2dcacd dont fail fast on CI 2024-11-28 20:16:10 -05:00
Haris Khan
5f8dc3f9a2 matrix x2 2024-11-28 20:14:05 -05:00
Haris Khan
9cc2e8f410 matrix 2024-11-28 20:13:21 -05:00
Haris Khan
6ac46aa747 Run aggregated tests 2024-11-28 20:07:37 -05:00
Haris Khan
5548b865b4 Adjusted makefile
-moved make test-all to just make test
-removed make test-all from tests.yml
2024-11-28 18:42:23 -05:00
Haris Khan
55245b2aa7 added more logging 2024-11-26 23:06:21 -05:00
Haris Khan
208051f92d strange error: publicKey has invalid size: expected 0, got 256 2024-11-26 23:03:17 -05:00
Haris Khan
8a672ca6ca adjust var names 2024-11-26 22:10:53 -05:00
Haris Khan
45def9dd0c Merge branch 'master' into tests 2024-11-26 22:08:46 -05:00
Haris Khan
cb1da321b9 added tests.yml 2024-11-26 22:02:31 -05:00
Haris Khan
d291624436 fixed auto-assign.yml 2024-11-26 22:01:52 -05:00
Haris Khan
a58f64566f Destination size 363 -> Fail 2024-11-26 21:28:02 -05:00
Haris Khan
891d915bb2 TODO 2024-11-26 20:30:37 -05:00
Haris Khan
a0a8704c6c mapping.size = size to fix dereference panic 2024-11-26 20:30:31 -05:00
Haris Khan
c68acf848e Corrected ValuesToMapping to order correctly 2024-11-26 19:56:32 -05:00
Haris Khan
7a6927cf53 gofumpt 2024-11-26 19:47:17 -05:00
Haris Khan
37e11ffee1 adjust generateTestRouterInfo 2024-11-26 15:56:41 -05:00
Haris Khan
e15e427f60 return error + uniform naming 2024-11-26 15:56:29 -05:00
Haris Khan
f0803a095e tweaks 2024-11-26 15:55:50 -05:00
Haris Khan
bf7e88bec1 updated test functions to not panic 2024-11-24 14:34:14 -05:00
Haris Khan
065ceeb88f Various changes
-removed outdated test functions (to be replaced later)
-added working experimental ReadKeysAndCert replacement candidate ReadKeysAndCertDeux
-added readCertificateFromEnd
-added constructPublicKey
-exported SpkType and CpkType in KeyCertificate
-added CryptoPublicKeySize() method
-added SigningPublicKeySize() method
2024-11-24 14:25:40 -05:00
Haris Khan
ca4a7a13ea experimental functions, tests pass 2024-11-23 23:54:01 -05:00
Haris Khan
0b0753cac1 tweaks 2024-11-23 22:48:58 -05:00
Haris Khan
40c2c4806c fix padding + fail on invalid padding instead of warn. 2024-11-23 22:45:32 -05:00
eyedeekay
9e3c8bcb98 move logger out of go-i2p so we can re-use it without importing the entire module 2024-11-21 17:16:48 -05:00
Haris Khan
9b4bf2663d clear artifact 2024-11-21 14:25:39 -05:00
eyedeekay
4a6f49d14a NTCP: fix IV functions 2024-11-20 16:02:14 -05:00
eyedeekay
5d789973b2 DRY: use obfs library to ofuscate and deobfuscate ephemeral keys 2024-11-20 15:55:07 -05:00
eyedeekay
08127861f1 Refactor: Fix constants. 2024-11-20 15:37:44 -05:00
eyedeekay
0e6ffd856b Refactor: move Compose* onto the NoiseSession struct. Fix constants. 2024-11-20 15:34:48 -05:00
idk
10daacbc9b Merge pull request #28 from satk0/add-lease-tests
Add lease tests and make names more clear
2024-11-20 17:36:07 +00:00
satk0
eeb1e215a5 Add lease tests and make names more clear 2024-11-19 17:31:34 +01:00
Haris Khan
08e599e59a create Ed25519PublicKeyFromBytes 2024-11-18 12:34:03 -05:00
Haris Khan
30f5565217 .Type -> .Type() 2024-11-18 12:27:55 -05:00
Haris Khan
fc3ba17af5 ReadKeysAndCert is not working as expected 2024-11-18 12:25:31 -05:00
Haris Khan
631f8d1850 nuked lease_set_test.go -> BROKEN 2024-11-17 23:04:07 -05:00
Haris Khan
cc43160bb9 nuked & revived router_info_test.go
-TestRouterInfoCapabilities() fails
-TestRouterInfoVersion() fails
2024-11-17 22:23:31 -05:00
Haris Khan
09acf3d23d adjusted router_info2_test.go 2024-11-17 22:04:27 -05:00
Haris Khan
cbe4af8459 added AsDestination() 2024-11-17 21:44:32 -05:00
Haris Khan
b72ed0a37d remove recovery attempt in mapping 2024-11-17 21:39:31 -05:00
Haris Khan
07268df720 CRITICAL: Reverted mapping.go 2024-11-17 21:03:42 -05:00
Haris Khan
def8789b77 verification 2024-11-17 14:13:38 -05:00
Haris Khan
59c53bc5c1 Added constructors and readers
-NewLeaseSet()
-NewLeaseSetFromBytes()
-ReadLease()
-NewLeaseFromBytes()
2024-11-17 14:00:41 -05:00
Haris Khan
ee56e0f40f corrected TestPublicKeyWithBadCertificate that had fault error matching 2024-11-17 13:32:08 -05:00
Haris Khan
4e2b55ccbe add new tests to router_info.mk 2024-11-17 13:01:46 -05:00
Haris Khan
64d90a157c Fixed array bounds error in handling short input in NewKeyCertificate 2024-11-17 12:55:34 -05:00
Haris Khan
3acff32f17 adjusted vars, all tests pass for mapping 2024-11-17 12:36:26 -05:00
Haris Khan
362513bbe5 Handle extra bytes beyond mapping length 2024-11-17 12:32:46 -05:00
Haris Khan
c9f3227116 added length check to ReadMapping 2024-11-17 12:23:21 -05:00
Haris Khan
f0702ffba9 Various changes
-we're dropping errors instead of trying to recover
-revamp TestReadI2PStringErrWhenDataTooShort to reflect drops instead of recoveries
2024-11-17 11:52:47 -05:00
Haris Khan
11b9018630 implement uniform errors 2024-11-17 11:26:02 -05:00
Haris Khan
f6daa5d9b6 Various changes
-in func (str I2PString) Data(): remove recovery attempts causing tests to fail
-added more universal errors
2024-11-17 11:16:43 -05:00
Haris Khan
58d1f0d815 fixed func (str I2PString) Data()
-replace actual length expected by TestI2PStringDataReportsExtraDataError, which is an invalid length
-added note to see if we should trim instead
2024-11-17 10:52:47 -05:00
Haris Khan
62ececf102 fixed func(str I2pString) Length()
-Previously incorrectly checked length causing TestI2PStringReportsExtraDataError to fail
2024-11-17 10:35:22 -05:00
idk
1d90db3239 Merge pull request #23 from hkh4n/routerinfo
Routerinfo
2024-11-17 14:28:44 +00:00
idk
f729bda62d Merge branch 'master' into routerinfo 2024-11-16 18:17:10 +00:00
eyedeekay
4ad0f97bfe Fail-fast switch for logging Logging, format 2024-11-16 13:15:33 -05:00
idk
e296441f29 Merge branch 'master' into routerinfo 2024-11-16 03:56:57 +00:00
Haris Khan
62086c7d04 make fmt 2024-11-15 22:52:17 -05:00
idk
df45c19272 Merge pull request #24 from satk0/fix-key-certificate-tests
Fix key certificate tests
2024-11-14 15:50:16 +00:00
satk0
f6894e9064 Fix PubKeyWithP521 test 2024-11-12 23:54:50 +01:00
satk0
b36ef65a10 Fix test when data is too small 2024-11-11 23:04:21 +01:00
eyedeekay
8c2b952616 setup auto-assign workflow 2024-11-08 15:01:05 -05:00
395 changed files with 17132 additions and 15799 deletions

19
.github/workflows/auto-assign.yml vendored Normal file
View File

@@ -0,0 +1,19 @@
name: Auto Assign
on:
issues:
types: [opened]
pull_request:
types: [opened]
jobs:
run:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- name: 'Auto-assign issue'
uses: pozil/auto-assign-issue@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
assignees: eyedeekay
numOfAssignee: 1

60
.github/workflows/page.yml vendored Normal file
View File

@@ -0,0 +1,60 @@
name: Generate and Deploy GitHub Pages
on:
# Run once hourly
schedule:
- cron: '0 * * * *'
# Allow manual trigger
workflow_dispatch:
# Run on pushes to main branch
push:
branches:
- main
jobs:
build-and-deploy:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch all history for proper repo data
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.24.x'
cache: true
- name: Build Site Generator
run: |
go install github.com/go-i2p/go-gh-page/cmd/github-site-gen@latest
export GOBIN=$(go env GOPATH)/bin
cp -v "$GOBIN/github-site-gen" ./github-site-gen
# Ensure the binary is executable
chmod +x github-site-gen
- name: Generate Site
run: |
# Determine current repository owner and name
REPO_OWNER=$(echo $GITHUB_REPOSITORY | cut -d '/' -f 1)
REPO_NAME=$(echo $GITHUB_REPOSITORY | cut -d '/' -f 2)
# Generate the site
./github-site-gen -repo "${REPO_OWNER}/${REPO_NAME}" -output ./site
# Create a .nojekyll file to disable Jekyll processing
touch ./site/.nojekyll
# Add a .gitattributes file to ensure consistent line endings
echo "* text=auto" > ./site/.gitattributes
- name: Deploy to GitHub Pages
uses: JamesIves/github-pages-deploy-action@v4
with:
folder: site # The folder the action should deploy
branch: gh-pages # The branch the action should deploy to
clean: true # Automatically remove deleted files from the deploy branch
commit-message: "Deploy site generated on ${{ github.sha }}"

62
.github/workflows/tests.yml vendored Normal file
View File

@@ -0,0 +1,62 @@
name: Go Tests
on:
push:
branches: [ main, master ]
pull_request:
branches: [ main, master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v4
with:
go-version: '1.21'
- run: make build
env:
GO: go
CGO_ENABLED: 0
test:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.21' # Adjust this version as needed
- name: Cache Go modules
uses: actions/cache@v3
with:
path: |
~/go/pkg/mod
~/.cache/go-build
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Install gofumpt
run: go install mvdan.cc/gofumpt@latest
- name: Go mod tidy
run: go mod tidy
- name: Run all tests
run: go test -v ./...
env:
GO: go
DEBUG_I2P: debug
CGO_ENABLED: 0
- name: Upload Test Logs
if: always()
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.test_target }}-logs
path: ./test-logs/${{ matrix.test_target }}.log # Adjust this path as needed

3
.gitignore vendored
View File

@@ -9,3 +9,6 @@ go-i2p
.idea/
router.info
log
*.gv
diff
err

View File

@@ -1,20 +1,35 @@
# Contributing
Thanks for taking a look at go-i2p! Please reach out if you have any questions or need help getting started.
Thanks for taking a look at go-i2p! Please reach out if you have any questions or need help getting started. We have an IRC channel on IRC2P: #go-i2p-dev and we're reachable here at github.com/go-i2p also.
## Getting Starting
## Getting Started
Install required dependencies
This example assumes Ubuntu 16.04
This example assumes Ubuntu or Debian based Linux, a reasonably modern version.
The instructions will be similar for other Linux distributions with slightly different package managers and package names.
```sh
go get github.com/hkparker/go-i2p
go get github.com/Sirupsen/logrus
go get github.com/stretchr/testify/assert
# For obtaining, modifying, compiling, and tracking changes to go-i2p, install:
sudo apt-get install golang-go make git
# If you want to generate markdown versions of the godoc locally, also install:
go install github.com/robertkrimen/godocdown/godocdown@master
# If you want to generate call graphs locally, also install:
go install github.com/ofabry/go-callvis@master
```
Fork go-i2p and clone it into your workspace. Make sure you can execute `go test ./...` in the project's root directory. At that point you should have everything you need to start making changes and opening pull requests. If you aren't sure what to work on, take a look at some good [getting started issues](https://github.com/hkparker/go-i2p/issues?q=is%3Aopen+is%3Aissue+label%3A%22start+here%22).
On Windows, one must install the latest versions of Go and Git Bash from their respective sources.
## Set up your workspace:
```sh
github_username=yourusername
cd $(go env GOPATH)
git clone git@github.com:$github_username/go-i2p github.com/go-i2p/go-i2p
github.com/go-i2p/go-i2p
```
Fork go-i2p and clone it into your workspace. Make sure you can execute `go test ./...` in the project's root directory. At that point you should have everything you need to start making changes and opening pull requests.
## I2P Specifications
@@ -26,9 +41,17 @@ The I2P community maintains up-to-date [specifications](https://geti2p.net/spec)
## Conventions
#### Errors
We use oops to provide context to the errors we return. Do not use `errors.New` or `fmt.Errorf` when returning errors from functions. Instead, wrap raw errors in oops errors. When an error is recieved, used oops to supplement the log output.
It is OK to use `fmt.Errorf` for declaring custom error types.
#### Logging
Logrus is used for logging across all of go-i2p. All log statements should contain an `at` fields and a `reason` field. Here is a good example from the go-i2p implementation of a LeaseSet:
Logrus is used for logging across all of go-i2p. We have a small extension of logrus at https://github.com/go-i2p/logger which we use to add a "Fail Fast mode." We are mostly converted over to using it.
All log statements should contain an `at` fields and a `reason` field. Here is a good example from the go-i2p implementation of a LeaseSet:
```go
log.WithFields(log.Fields{
@@ -56,4 +79,4 @@ func TestRouterAddressCountReturnsCorrectCount(t *testing.T) {
## Pull Requests
Pull requests should pass all tests, test all new behavior, and be correctly formatted by `gofmt` before merge. Feel free to open incomplete pull requests if you are struggling, I will enthusiasticlly help you complete the PR in any way needed.
Pull requests should pass all tests, test all new behavior, and be correctly formatted by `gofumpt -w -s -extra` before merge. Feel free to open incomplete pull requests and ask for help and advice.

View File

@@ -26,9 +26,6 @@ build: clean $(EXE)
$(EXE):
$(GO) build --tags netgo,osusergo -v -o $(EXE)
test: check_gofumpt fmt
$(GO) test -v -failfast ./lib/common/...
clean:
$(GO) clean -v
@@ -43,35 +40,5 @@ info:
release:
github-release release -u go-i2p -r go-i2p -n "${RELEASE_VERSION}" -t "${RELEASE_TAG}" -d "${RELEASE_DESCRIPTION}" -p
callvis:
go-callvis -format svg -focus upgrade -group pkg,type -limit github.com/go-i2p/go-i2p github.com/go-i2p/go-i2p
godoc:
find lib -type d -exec bash -c "ls {}/*.go && godocdown -o ./{}/doc.md ./{}" \;
# Include test definitions
-include doc/tests/*.mk
# Define the all-tests target that runs every test suite
test-all: test-string-all \
test-mapping-all \
test-crypto-aes-all \
test-crypto-dsa-all \
test-crypto-ed25519-all \
test-crypto-elg-all \
test-crypto-hmac-all \
test-i2np-header-all \
test-i2np-build-request-all \
test-key-cert-all \
test-keys-cert-all \
test-lease-set-all \
test-noise-transport-all \
test-router-address-all \
test-router-info-all \
test-su3-all \
test-tunnel-all
#-include $(shell find doc/tests -type f -name '*.mk') #search for .mk files recursively
#test-base64-encode-decode-not-mangled:
#go test -v ./lib/common/base64 -run TestEncodeDecodeNotMangled
./callgraph.sh

102
README.md
View File

@@ -15,70 +15,77 @@ please keep up with these changes, as they will not be backward compatible and r
- [ ] Datagrams
- [ ] I2CP
- [ ] Message routing
- [ ] SAM
- [ ] Streaming
- [ ] Tunnel Manager
- Cryptographic primitives
- [Cryptographic primitives(see also: https://github.com/go-i2p/crypto)](https://github.com/go-i2p/crypto)
- Signing
- [ ] ECDSA_SHA256_P256
- [ ] ECDSA_SHA384_P384
- [ ] ECDSA_SHA512_P521
- [ ] Ed25519
- [X] ECDSA_SHA256_P256
- [X] ECDSA_SHA384_P384
- [X] ECDSA_SHA512_P521
- [X] Ed25519
- Verifying
- [ ] DSA
- [ ] ECDSA_SHA256_P256
- [ ] ECDSA_SHA384_P384
- [ ] ECDSA_SHA512_P521
- [ ] RSA_SHA256_2048
- [ ] RSA_SHA384_3072
- [ ] RSA_SHA512_4096
- [ ] Ed25519
- [X] DSA
- [X] ECDSA_SHA256_P256
- [X] ECDSA_SHA384_P384
- [X] ECDSA_SHA512_P521
- [X] RSA_SHA256_2048
- [X] RSA_SHA384_3072
- [X] RSA_SHA512_4096
- [X] Ed25519
- [ ] Red25519
- [ ] ElGamal
- [ ] AES256
- [ ] X25519
- [ ] ChaCha20/Poly1305
- [X] ElGamal
- [X] AES256
- [X] X25519
- [X] ChaCha20/Poly1305
- [ ] Elligator2
- [ ] HKDF
- [ ] HMAC
- [X] HKDF
- [X] HMAC
- [X] Noise subsystem
- End-to-End Crypto
- [ ] Garlic messages
- [ ] ElGamal/AES+SessionTag
- [ ] Ratchet/X25519
- I2NP
- [ ] Message parsing
- [ ] Message handling
- [X] Message parsing and serialization
- [X] Message interfaces and factory patterns
- [X] Database Store/Lookup message structures
- [X] Tunnel Build message structures
- [X] Data, DeliveryStatus, TunnelData messages
- [X] Build Request/Response Record parsing
- [ ] Message routing and handling
- NetDB
- [/] Local storage
- [/] Persistence to disk
- [X] Reseeding
- [X] Local storage interface
- [X] Reseed functionality (basic implementation)
- [~] Persistence to disk
- [ ] RouterInfo management
- [ ] LeaseSet management
- [ ] Lookups
- [ ] Expiry
- [ ] Exploration
- [ ] Publishing
- [ ] Floodfill
- [ ] LS2 and Encrypted Leasesets
- Transports
- [X] Transport manager
- Transport Layer
- [X] Transport manager and interfaces
- NTCP2
- [ ] Handshake
- [ ] Session tracking
- [ ] Automatic session creation
- [X] Session handshake using noise protocol
- [X] Connection management
- [X] I2NP message framing and unframing
- [X] Session lifecycle management
- [X] Message queuing and worker threads
- SSU2
- [ ] Handshake
- [ ] Session tracking
- [ ] Automatic session creation
- [ ] Session handshake
- [ ] Connection management
- [ ] Peer Tests
- [ ] Introducers
- Tunnels
- [ ] Building
- [ ] Build Message Crypto (ElGamal)
- [ ] Build Message Crypto (ECIES)
- [ ] Participating
- [ ] Tunnel Message Crypto
- [ ] Tunnel Message Fragmentation/Reassembly
- Common Data Structures
- [X] Message structure parsing (delivery instructions)
- [X] Fragment handling and reassembly
- [X] Build Request/Response record interfaces
- [ ] Tunnel building and management
- [ ] Tunnel cryptography (layered encryption)
- [ ] Gateway and endpoint implementation
- [ ] Participant functionality
- [Common Data Structures(see also: https://github.com/go-i2p/common](https://github.com/go-i2p/common)
- [X] Keys and Cert
- [X] Key Certificates
- [X] Certificate
@@ -94,7 +101,7 @@ please keep up with these changes, as they will not be backward compatible and r
- [X] Session Tag
## Verbosity ##
Logging can be enabled and configured using the DEBUG_I2P environment variable. By default, logging is disabled.
Logging can be enabled and configured using the `DEBUG_I2P` environment variable. By default, logging is disabled.
There are three available log levels:
@@ -113,6 +120,17 @@ export DEBUG_I2P=error
If DEBUG_I2P is set to an unrecognized variable, it will fall back to "debug".
## Fast-Fail mode ##
Fast-Fail mode can be activated by setting `WARNFAIL_I2P` to any non-empty value. When set, every warning or error is Fatal.
It is unsafe for production use, and intended only for debugging and testing purposes.
```shell
export WARNFAIL_I2P=true
```
If `WARNFAIL_I2P` is set and `DEBUG_I2P` is unset, `DEBUG_I2P` will be set to `debug`.
## Contributing
See CONTRIBUTING.md for more information.

View File

@@ -1,41 +1,89 @@
# go-i2p Implementation Roadmap
## Transport Layer (NTCP2)
- Build on existing lib/transport/noise implementation
- Core NTCP2 components:
* Session handshake using noise protocol
* Connection management
* I2NP message transport
## Completed Components ✅
## Reseed System
- SU3 file format implementation:
* Format parsing and validation(Much of this work is done in reseed-tools, may need to be moved here)
* Signature verification system(Much of this work is done in reseed-tools, may need to be moved here)
- Local reseed functionality:
* File-based reseed operations
- Self-signed/Package-pinned X.509 certificate handling for reseed validation
### Transport Layer (NTCP2)
- **Core NTCP2 Implementation**: Complete functional NTCP2 transport
* ✅ Session handshake using noise protocol
* ✅ Inbound and outbound connection management
* ✅ I2NP message framing and unframing
* ✅ Session lifecycle management with proper cleanup
* ✅ Message queuing with background workers
* ✅ RouterInfo compatibility checking
* ✅ Error handling and session recovery
## NetDb and Database Store
- Database Store message handling:
* Message structure implementation
* Message handling implementation
- NetDb core implementation:
* RouterInfo management
* LeaseSet management
* Lookup system
* Storage interface
* Peer selection logic?(Maybe do something very basic for now like i2pd used to do, and then improve it later, the important part will be interface design at first)
### I2NP Message System
- **Core Message Infrastructure**: Complete I2NP message framework
* Message parsing and serialization (NTCP format)
* ✅ Interface-based message system with factory patterns
* ✅ Data, DeliveryStatus, TunnelData message implementations
* ✅ Database Store/Lookup message structures
* ✅ Tunnel Build/Reply message structures
* ✅ Build Request/Response Record parsing and interfaces
## Tunnel Implementation
- Tunnel cryptography:
* Key generation and management
* Layered encryption scheme
- Message processing:
* Build request/response handling
* Gateway implementation
* Message forwarding logic
### Tunnel Message Processing
- **Message Structure Handling**: Tunnel message framework
* ✅ Delivery Instructions parsing and validation
* ✅ Fragment handling and reassembly logic
* ✅ Tunnel message structure parsing
* Build record interface implementations
Notes:
- Excluding legacy protocols (SSU1, NTCP1, elgamal, DSA)
- Leveraging existing noise protocol implementation
- SSU2 is not on this roadmap but is fair game for implementation as soon as NTCP2 is done. We're focused on NTCP2 to get this thing sending I2NP messages.
### Common Data Structures
- **Complete Data Structure Support**: All I2P data types implemented
* ✅ Keys and Certificates, Router Info/Address
* ✅ Session Keys, Hashes, Signatures
* ✅ Lease and LeaseSet structures
## In Progress Components 🚧
### NetDb Implementation
- **Database Store Integration**:
* 📋 Database Store message handling implementation
* 📋 RouterInfo storage and retrieval
* 📋 LeaseSet management and storage
* 📋 Database lookup system
* 📋 Peer selection logic (basic implementation)
## Next Priority Components 🎯
### Tunnel Building System
- **Active Tunnel Management**:
* 📋 Tunnel building coordination
* 📋 Build request/response handling
* 📋 Gateway and endpoint implementations
* 📋 Participant tunnel processing
### Tunnel Cryptography
- **Security Layer Implementation**:
* 📋 Layered encryption/decryption
* 📋 Key generation and management
* 📋 Tunnel message forwarding logic
## Future Components 📅
### SSU2 Transport (Post-NTCP2)
- **Secondary Transport Protocol**:
* 📋 SSU2 handshake implementation
* 📋 UDP-based session management
* 📋 Peer testing mechanisms
* 📋 Introducer functionality
### Advanced NetDb Features
- **Enhanced Database Operations**:
* 📋 Floodfill router functionality
* 📋 Database exploration and publishing
* 📋 LS2 and Encrypted LeaseSet support
* 📋 Advanced peer selection algorithms
### Application Layer
- **Client Applications**:
* 📋 I2CP implementation
* 📋 Streaming library
* 📋 Datagram support
* 📋 End-to-end encryption (Garlic routing)
## Current Status
**Primary Goal**: NTCP2 transport is feature-complete and actively sending/receiving I2NP messages. The foundation for tunnel building and NetDb integration is in place. Next major milestone is implementing database operations and tunnel building.
**Test Coverage**: Core components have basic test coverage including NTCP2 sessions, I2NP message processing, and tunnel message parsing.

19
callgraph.sh Executable file
View File

@@ -0,0 +1,19 @@
#! /usr/bin/env sh
dirs=$(find lib/ -type d)
for dir in $dirs; do
files=$(find "$dir" -maxdepth 2 -type f -name "*.go" -not -name "fuzz")
#echo "Files in $dir: $files"
file=$(echo $files | awk '{print $1}')
if [ -z "$file" ]; then
echo "no go files, skipping"
continue
fi
packageLine=$(grep -E "^package" $file)
package=$(echo $packageLine | awk '{print $2}')
echo "Generating callgraph for $package"
go-callvis -nostd -focus "$package" -group type -format svg -file $dir/$package "github.com/go-i2p/go-i2p/$dir"
godocdown -template template.md -o "$dir/README.md" "./$dir"
git add -v "$dir/README.md"
git add -v "$dir/$package.svg" "$dir/README.md"
done

View File

@@ -1,17 +0,0 @@
test-crypto-aes-all: test-crypto-aes-core test-crypto-aes-validation test-crypto-aes-padding
test-crypto-aes-core:
$(GO) test -v ./lib/crypto -run TestAESEncryptDecrypt
test-crypto-aes-validation:
$(GO) test -v ./lib/crypto -run TestAESEncryptInvalidKey
$(GO) test -v ./lib/crypto -run TestAESDecryptInvalidInput
test-crypto-aes-padding:
$(GO) test -v ./lib/crypto -run TestPKCS7PadUnpad
$(GO) test -v ./lib/crypto -run TestPKCS7UnpadInvalidInput
.PHONY: test-crypto-aes-all \
test-crypto-aes-core \
test-crypto-aes-validation \
test-crypto-aes-padding

View File

@@ -1,4 +0,0 @@
test-base32-encode-decode-not-mangled:
$(GO) test -v ./lib/common/base32 -run TestEncodeDecodeNotMangled
.PHONY: test-base32-encode-decode-not-mangled

View File

@@ -1,4 +0,0 @@
test-base64-encode-decode-not-mangled:
$(GO) test -v ./lib/common/base64 -run TestEncodeDecodeNotMangled
.PHONY: test-base64-encode-decode-not-mangled

View File

@@ -1,24 +0,0 @@
test-build-request-all: test-build-request-receive test-build-request-ident test-build-request-components
test-build-request-receive:
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordReceiveTunnel
test-build-request-ident:
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordOurIdent
test-build-request-components:
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordNextTunnel
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordNextIdent
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordLayerKey
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordIVKey
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordReplyKey
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordReplyIV
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordFlag
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordRequestTime
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordSendMessageID
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordPadding
.PHONY: test-build-request-all \
test-build-request-receive \
test-build-request-ident \
test-build-request-components

View File

@@ -1,61 +0,0 @@
test-cert-all: test-cert-type test-cert-length test-cert-data test-cert-read test-cert-length-correct test-cert-length-too-short test-cert-length-data-short test-cert-data-correct test-cert-data-too-long test-cert-data-too-short test-cert-read-correct test-cert-read-short test-cert-read-remainder test-cert-read-invalid
test-cert-type:
$(GO) test -v ./lib/common/certificate -run TestCertificateTypeIsFirstByte
test-cert-length:
$(GO) test -v ./lib/common/certificate -run TestCertificateLength
test-cert-data:
$(GO) test -v ./lib/common/certificate -run TestCertificateData
test-cert-read:
$(GO) test -v ./lib/common/certificate -run TestReadCertificate
test-cert-length-correct:
$(GO) test -v ./lib/common/certificate -run TestCertificateLengthCorrect
test-cert-length-too-short:
$(GO) test -v ./lib/common/certificate -run TestCertificateLengthErrWhenTooShort
test-cert-length-data-short:
$(GO) test -v ./lib/common/certificate -run TestCertificateLengthErrWhenDataTooShort
test-cert-data-correct:
$(GO) test -v ./lib/common/certificate -run TestCertificateDataWhenCorrectSize
test-cert-data-too-long:
$(GO) test -v ./lib/common/certificate -run TestCertificateDataWhenTooLong
test-cert-data-too-short:
$(GO) test -v ./lib/common/certificate -run TestCertificateDataWhenTooShort
test-cert-read-correct:
$(GO) test -v ./lib/common/certificate -run TestReadCertificateWithCorrectData
test-cert-read-short:
$(GO) test -v ./lib/common/certificate -run TestReadCertificateWithDataTooShort
test-cert-read-remainder:
$(GO) test -v ./lib/common/certificate -run TestReadCertificateWithRemainder
test-cert-read-invalid:
$(GO) test -v ./lib/common/certificate -run TestReadCertificateWithInvalidLength
# Declare all targets as PHONY
.PHONY: test-cert-all \
test-cert-type \
test-cert-length \
test-cert-data \
test-cert-read \
test-cert-length-correct \
test-cert-length-too-short \
test-cert-length-data-short \
test-cert-data-correct \
test-cert-data-too-long \
test-cert-data-too-short \
test-cert-read-correct \
test-cert-read-short \
test-cert-read-remainder \
test-cert-read-invalid

View File

@@ -1,2 +0,0 @@
test-date-time-from-milliseconds:
$(GO) test -v ./lib/common/data -run TestTimeFromMilliseconds

View File

@@ -1,20 +0,0 @@
test-crypto-dsa-all: test-crypto-dsa test-crypto-dsa-benchmarks
test-crypto-dsa:
$(GO) test -v ./lib/crypto -run TestDSA
test-crypto-dsa-benchmarks:
$(GO) test -v ./lib/crypto -bench=DSA -run=^$
# Individual benchmarks
test-crypto-dsa-bench-generate:
$(GO) test -v ./lib/crypto -bench=DSAGenerate -run=^$
test-crypto-dsa-bench-sign-verify:
$(GO) test -v ./lib/crypto -bench=DSASignVerify -run=^$
.PHONY: test-crypto-dsa-all \
test-crypto-dsa \
test-crypto-dsa-benchmarks \
test-crypto-dsa-bench-generate \
test-crypto-dsa-bench-sign-verify

View File

@@ -1,7 +0,0 @@
test-crypto-ed25519-all: test-crypto-ed25519
test-crypto-ed25519:
$(GO) test -v ./lib/crypto -run TestEd25519
.PHONY: test-crypto-ed25519-all \
test-crypto-ed25519

View File

@@ -1,24 +0,0 @@
test-crypto-elg-all: test-crypto-elg test-crypto-elg-benchmarks
test-crypto-elg:
$(GO) test -v ./lib/crypto -run TestElg
test-crypto-elg-benchmarks:
$(GO) test -v ./lib/crypto -bench=Elg -run=^$
# Individual benchmarks
test-crypto-elg-bench-generate:
$(GO) test -v ./lib/crypto -bench=ElgGenerate -run=^$
test-crypto-elg-bench-encrypt:
$(GO) test -v ./lib/crypto -bench=ElgEncrypt -run=^$
test-crypto-elg-bench-decrypt:
$(GO) test -v ./lib/crypto -bench=ElgDecrypt -run=^$
.PHONY: test-crypto-elg-all \
test-crypto-elg \
test-crypto-elg-benchmarks \
test-crypto-elg-bench-generate \
test-crypto-elg-bench-encrypt \
test-crypto-elg-bench-decrypt

View File

@@ -1,30 +0,0 @@
test-i2np-header-all: test-i2np-type test-i2np-message test-i2np-expiration test-i2np-ntcp-components test-i2np-data test-i2np-regression
test-i2np-type:
$(GO) test -v ./lib/i2np -run TestReadI2NPTypeWith
test-i2np-message:
$(GO) test -v ./lib/i2np -run TestReadI2NPNTCPMessageID
test-i2np-expiration:
$(GO) test -v ./lib/i2np -run TestReadI2NPNTCPMessageExpiration
$(GO) test -v ./lib/i2np -run TestReadI2NPSSUMessageExpiration
test-i2np-ntcp-components:
$(GO) test -v ./lib/i2np -run TestReadI2NPNTCPMessageSize
$(GO) test -v ./lib/i2np -run TestReadI2NPNTCPMessageChecksum
test-i2np-data:
$(GO) test -v ./lib/i2np -run TestReadI2NPNTCPData
test-i2np-regression:
$(GO) test -v ./lib/i2np -run TestCrasherRegression123781
.PHONY: test-i2np-header-all \
test-i2np-type \
test-i2np-message \
test-i2np-expiration \
test-i2np-ntcp-components \
test-i2np-data \
test-i2np-regression

View File

@@ -1,7 +0,0 @@
test-crypto-hmac-all: test-crypto-hmac
test-crypto-hmac:
$(GO) test -v ./lib/crypto -run Test_I2PHMAC
.PHONY: test-crypto-hmac-all \
test-crypto-hmac

View File

@@ -1,15 +0,0 @@
test-integer-all: test-integer-big-endian test-integer-one-byte test-integer-zero
test-integer-big-endian:
$(GO) test -v ./lib/common/integer -run TestIntegerBigEndian
test-integer-one-byte:
$(GO) test -v ./lib/common/integer -run TestWorksWithOneByte
test-integer-zero:
$(GO) test -v ./lib/common/integer -run TestIsZeroWithNoData
.PHONY: test-integer-all \
test-integer-big-endian \
test-integer-one-byte \
test-integer-zero

View File

@@ -1,23 +0,0 @@
test-key-cert-all: test-key-cert-signing test-key-cert-public test-key-cert-construct
test-key-cert-signing:
$(GO) test -v ./lib/common/key_certificate -run TestSingingPublicKeyTypeReturnsCorrectInteger
$(GO) test -v ./lib/common/key_certificate -run TestSingingPublicKeyTypeReportsWhenDataTooSmall
$(GO) test -v ./lib/common/key_certificate -run TestConstructSigningPublicKeyReportsWhenDataTooSmall
$(GO) test -v ./lib/common/key_certificate -run TestConstructSigningPublicKeyWithDSASHA1
$(GO) test -v ./lib/common/key_certificate -run TestConstructSigningPublicKeyWithP256
$(GO) test -v ./lib/common/key_certificate -run TestConstructSigningPublicKeyWithP384
$(GO) test -v ./lib/common/key_certificate -run TestConstructSigningPublicKeyWithP521
test-key-cert-public:
$(GO) test -v ./lib/common/key_certificate -run TestPublicKeyTypeReturnsCorrectInteger
$(GO) test -v ./lib/common/key_certificate -run TestPublicKeyTypeReportsWhenDataTooSmall
test-key-cert-construct:
$(GO) test -v ./lib/common/key_certificate -run TestConstructPublicKeyReportsWhenDataTooSmall
$(GO) test -v ./lib/common/key_certificate -run TestConstructPublicKeyReturnsCorrectDataWithElg
.PHONY: test-key-cert-all \
test-key-cert-signing \
test-key-cert-public \
test-key-cert-construct

View File

@@ -1,30 +0,0 @@
test-keys-cert-all: test-keys-cert-certificate test-keys-cert-public test-keys-cert-signing test-keys-cert-creation
test-keys-cert-certificate:
$(GO) test -v ./lib/common/keys_and_cert -run TestCertificateWithValidData
test-keys-cert-public:
$(GO) test -v ./lib/common/keys_and_cert -run TestPublicKeyWithBadData
$(GO) test -v ./lib/common/keys_and_cert -run TestPublicKeyWithBadCertificate
$(GO) test -v ./lib/common/keys_and_cert -run TestPublicKeyWithNullCertificate
$(GO) test -v ./lib/common/keys_and_cert -run TestPublicKeyWithKeyCertificate
test-keys-cert-signing:
$(GO) test -v ./lib/common/keys_and_cert -run TestSigningPublicKeyWithBadData
$(GO) test -v ./lib/common/keys_and_cert -run TestSigningPublicKeyWithBadCertificate
$(GO) test -v ./lib/common/keys_and_cert -run TestSigningPublicKeyWithNullCertificate
$(GO) test -v ./lib/common/keys_and_cert -run TestSigningPublicKeyWithKeyCertificate
test-keys-cert-creation:
$(GO) test -v ./lib/common/keys_and_cert -run TestNewKeysAndCertWithMissingData
$(GO) test -v ./lib/common/keys_and_cert -run TestNewKeysAndCertWithMissingCertData
$(GO) test -v ./lib/common/keys_and_cert -run TestNewKeysAndCertWithValidDataWithCertificate
$(GO) test -v ./lib/common/keys_and_cert -run TestNewKeysAndCertWithValidDataWithoutCertificate
$(GO) test -v ./lib/common/keys_and_cert -run TestNewKeysAndCertWithValidDataWithCertificateAndRemainder
$(GO) test -v ./lib/common/keys_and_cert -run TestNewKeysAndCertWithValidDataWithoutCertificateAndRemainder
.PHONY: test-keys-cert-all \
test-keys-cert-certificate \
test-keys-cert-public \
test-keys-cert-signing \
test-keys-cert-creation

View File

@@ -1,22 +0,0 @@
test-lease-set-all: test-lease-set-basic test-lease-set-leases test-lease-set-expiration
test-lease-set-basic:
$(GO) test -v ./lib/common/lease_set -run TestDestinationIsCorrect
$(GO) test -v ./lib/common/lease_set -run TestPublicKeyIsCorrect
$(GO) test -v ./lib/common/lease_set -run TestSigningKeyIsCorrect
$(GO) test -v ./lib/common/lease_set -run TestSignatureIsCorrect
test-lease-set-leases:
$(GO) test -v ./lib/common/lease_set -run TestLeaseCountCorrect
$(GO) test -v ./lib/common/lease_set -run TestLeaseCountCorrectWithMultiple
$(GO) test -v ./lib/common/lease_set -run TestLeaseCountErrorWithTooMany
$(GO) test -v ./lib/common/lease_set -run TestLeasesHaveCorrectData
test-lease-set-expiration:
$(GO) test -v ./lib/common/lease_set -run TestNewestExpirationIsCorrect
$(GO) test -v ./lib/common/lease_set -run TestOldestExpirationIsCorrect
.PHONY: test-lease-set-all \
test-lease-set-basic \
test-lease-set-leases \
test-lease-set-expiration

View File

@@ -1,28 +0,0 @@
test-mapping-all: test-mapping-values test-mapping-duplicates test-mapping-conversion test-mapping-utils
test-mapping-values:
$(GO) test -v ./lib/common/data -run TestValuesExclusesPairWithBadData
$(GO) test -v ./lib/common/data -run TestValuesWarnsMissingData
$(GO) test -v ./lib/common/data -run TestValuesWarnsExtraData
$(GO) test -v ./lib/common/data -run TestValuesEnforcesEqualDelimitor
$(GO) test -v ./lib/common/data -run TestValuesEnforcedSemicolonDelimitor
$(GO) test -v ./lib/common/data -run TestValuesReturnsValues
test-mapping-duplicates:
$(GO) test -v ./lib/common/data -run TestHasDuplicateKeysTrueWhenDuplicates
$(GO) test -v ./lib/common/data -run TestHasDuplicateKeysFalseWithoutDuplicates
$(GO) test -v ./lib/common/data -run TestReadMappingHasDuplicateKeys
test-mapping-conversion:
$(GO) test -v ./lib/common/data -run TestGoMapToMappingProducesCorrectMapping
$(GO) test -v ./lib/common/data -run TestFullGoMapToMappingProducesCorrectMapping
test-mapping-utils:
$(GO) test -v ./lib/common/data -run TestStopValueRead
$(GO) test -v ./lib/common/data -run TestBeginsWith
.PHONY: test-mapping-all \
test-mapping-values \
test-mapping-duplicates \
test-mapping-conversion \
test-mapping-utils

View File

@@ -1,2 +0,0 @@
test-mapping-values-order:
$(GO) test -v ./lib/common/data -run TestMappingOrderSortsValuesThenKeys

View File

@@ -1,19 +0,0 @@
test-noise-transport-all: test-noise-packet-encryption test-noise-transport-connection test-noise-packet-obfuscation test-noise-packet-obfuscation-func
test-noise-packet-encryption:
$(GO) test -v ./lib/transport/noise -run TestEncryptDecryptPacketOffline
test-noise-transport-connection:
$(GO) test -v ./lib/transport/noise -run TestTransport
test-noise-packet-obfuscation:
$(GO) test -v ./lib/transport/noise -run TestEncryptDecryptPacketObfsOffline
test-noise-packet-obfuscation-func:
$(GO) test -v ./lib/transport/noise -run TestEncryptDecryptPacketObfsOfflineWithFunc
.PHONY: test-noise-transport-all \
test-noise-packet-encryption \
test-noise-transport-connection \
test-noise-packet-obfuscation \
test-noise-packet-obfuscation-func

View File

@@ -1,19 +0,0 @@
test-router-address-all: test-router-address-validation test-router-address-functionality test-router-address-fuzz
test-router-address-validation:
$(GO) test -v ./lib/common/router_address -run TestCheckValidReportsEmptySlice
$(GO) test -v ./lib/common/router_address -run TestCheckRouterAddressValidReportsDataMissing
$(GO) test -v ./lib/common/router_address -run TestCheckRouterAddressValidNoErrWithValidData
test-router-address-functionality:
$(GO) test -v ./lib/common/router_address -run TestRouterAddressCostReturnsFirstByte
$(GO) test -v ./lib/common/router_address -run TestRouterAddressExpirationReturnsCorrectData
$(GO) test -v ./lib/common/router_address -run TestReadRouterAddressReturnsCorrectRemainderWithoutError
test-router-address-fuzz:
$(GO) test -v ./lib/common/router_address -run TestCorrectsFuzzCrasher1
.PHONY: test-router-address-all \
test-router-address-validation \
test-router-address-functionality \
test-router-address-fuzz

View File

@@ -1,26 +0,0 @@
test-router-info-all: test-router-info-published test-router-info-addresses test-router-info-identity test-router-info-misc
test-router-info-published:
$(GO) test -v ./lib/common/router_info -run TestPublishedReturnsCorrectDate
$(GO) test -v ./lib/common/router_info -run TestPublishedReturnsCorrectErrorWithPartialDate
$(GO) test -v ./lib/common/router_info -run TestPublishedReturnsCorrectErrorWithInvalidData
test-router-info-addresses:
$(GO) test -v ./lib/common/router_info -run TestRouterAddressCountReturnsCorrectCount
$(GO) test -v ./lib/common/router_info -run TestRouterAddressCountReturnsCorrectErrorWithInvalidData
$(GO) test -v ./lib/common/router_info -run TestRouterAddressesReturnsAddresses
$(GO) test -v ./lib/common/router_info -run TestRouterAddressesReturnsAddressesWithMultiple
test-router-info-identity:
$(GO) test -v ./lib/common/router_info -run TestRouterIdentityIsCorrect
test-router-info-misc:
$(GO) test -v ./lib/common/router_info -run TestPeerSizeIsZero
$(GO) test -v ./lib/common/router_info -run TestOptionsAreCorrect
$(GO) test -v ./lib/common/router_info -run TestSignatureIsCorrectSize
.PHONY: test-router-info-all \
test-router-info-published \
test-router-info-addresses \
test-router-info-identity \
test-router-info-misc

View File

@@ -1,27 +0,0 @@
test-string-all: test-string-length test-string-data test-string-conversion test-string-read
test-string-length:
$(GO) test -v ./lib/common/data -run TestStringReportsCorrectLength
$(GO) test -v ./lib/common/data -run TestI2PStringReportsLengthZeroError
$(GO) test -v ./lib/common/data -run TestI2PStringReportsExtraDataError
$(GO) test -v ./lib/common/data -run TestI2PStringDataReportsLengthZeroError
test-string-data:
$(GO) test -v ./lib/common/data -run TestI2PStringDataReportsExtraDataError
$(GO) test -v ./lib/common/data -run TestI2PStringDataEmptyWhenZeroLength
$(GO) test -v ./lib/common/data -run TestI2PStringDataErrorWhenNonZeroLengthOnly
test-string-conversion:
$(GO) test -v ./lib/common/data -run TestToI2PI2PStringFormatsCorrectly
$(GO) test -v ./lib/common/data -run TestToI2PStringReportsOverflows
test-string-read:
$(GO) test -v ./lib/common/data -run TestReadStringReadsLength
$(GO) test -v ./lib/common/data -run TestReadI2PStringErrWhenEmptySlice
$(GO) test -v ./lib/common/data -run TestReadI2PStringErrWhenDataTooShort
.PHONY: test-string-all \
test-string-length \
test-string-data \
test-string-conversion \
test-string-read

View File

@@ -1,11 +0,0 @@
test-su3-all: test-su3-read test-su3-signature
test-su3-read:
$(GO) test -v ./lib/su3 -run TestRead
test-su3-signature:
$(GO) test -v ./lib/su3 -run TestReadSignatureFirst
.PHONY: test-su3-all \
test-su3-read \
test-su3-signature

View File

@@ -1,22 +0,0 @@
test-tunnel-all: test-tunnel-delivery-instructions test-tunnel-message
# Tests from delivery_test.go
test-tunnel-delivery-instructions:
$(GO) test -v ./lib/tunnel -run TestReadDeliveryInstructions
# Tests from message_test.go
test-tunnel-message: test-tunnel-message-padding test-tunnel-message-fragments
test-tunnel-message-padding:
$(GO) test -v ./lib/tunnel -run TestDeliveryInstructionDataWithNoPadding
$(GO) test -v ./lib/tunnel -run TestDeliveryInstructionDataWithSomePadding
$(GO) test -v ./lib/tunnel -run TestDeliveryInstructionDataWithOnlyPadding
test-tunnel-message-fragments:
$(GO) test -v ./lib/tunnel -run TestDeliveryInstructionsWithFragments
.PHONY: test-tunnel-all \
test-tunnel-delivery-instructions \
test-tunnel-message \
test-tunnel-message-padding \
test-tunnel-message-fragments

50
go.mod
View File

@@ -1,43 +1,53 @@
module github.com/go-i2p/go-i2p
go 1.23.1
go 1.24.2
require (
github.com/beevik/ntp v1.4.3
github.com/emirpasic/gods v1.18.1
github.com/eyedeekay/go-unzip v0.0.0-20240201194209-560d8225b50e
github.com/flynn/noise v1.1.0
github.com/go-i2p/common v0.0.0-20250715213359-dfa5527ece83
github.com/go-i2p/crypto v0.0.0-20250716230511-565a0995440c
github.com/go-i2p/go-noise v0.0.0-20250805210353-74f980a2439d
github.com/go-i2p/logger v0.0.0-20241123010126-3050657e5d0c
github.com/go-i2p/su3 v0.0.0-20250716183548-497fadf45e84
github.com/go-i2p/util v0.0.0-20250806013618-d0b686a4f694
github.com/samber/oops v1.19.0
github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.8.1
github.com/spf13/cobra v1.9.1
github.com/spf13/viper v1.19.0
github.com/stretchr/testify v1.9.0
go.step.sm/crypto v0.53.0
golang.org/x/crypto v0.27.0
github.com/stretchr/testify v1.10.0
gopkg.in/yaml.v3 v3.0.1
)
require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/dchest/siphash v1.2.3 // indirect
github.com/fsnotify/fsnotify v1.8.0 // indirect
github.com/go-i2p/noise v0.0.0-20250805205922-091c71f48c43 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/magiconair/properties v1.8.9 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/oklog/ulid/v2 v2.1.1 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/locafero v0.7.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/samber/lo v1.51.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.7.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/afero v1.12.0 // indirect
github.com/spf13/cast v1.7.1 // indirect
github.com/spf13/pflag v1.0.6 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/net v0.29.0 // indirect
golang.org/x/sys v0.25.0 // indirect
golang.org/x/text v0.18.0 // indirect
go.opentelemetry.io/otel v1.37.0 // indirect
go.opentelemetry.io/otel/trace v1.37.0 // indirect
go.step.sm/crypto v0.67.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.40.0 // indirect
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect
golang.org/x/net v0.41.0 // indirect
golang.org/x/sys v0.34.0 // indirect
golang.org/x/text v0.27.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
)

119
go.sum
View File

@@ -2,100 +2,105 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/beevik/ntp v1.4.3 h1:PlbTvE5NNy4QHmA4Mg57n7mcFTmr1W1j3gcK7L1lqho=
github.com/beevik/ntp v1.4.3/go.mod h1:Unr8Zg+2dRn7d8bHFuehIMSvvUYssHMxW3Q5Nx4RW5Q=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
github.com/dchest/siphash v1.2.3 h1:QXwFc8cFOR2dSa/gE6o/HokBMWtLUaNDVd+22aKHeEA=
github.com/dchest/siphash v1.2.3/go.mod h1:0NvQU092bT0ipiFN++/rXm69QG9tVxLAlQHIXMPAkHc=
github.com/eyedeekay/go-unzip v0.0.0-20240201194209-560d8225b50e h1:NMjWYVkgcQHGOy0/VxU0TU6smrcoxzj9hwDesx2sB0w=
github.com/eyedeekay/go-unzip v0.0.0-20240201194209-560d8225b50e/go.mod h1:fKfFM3BsOOyjtZmEty7FsGzGabXo8Eb/dHjyIhTtxsE=
github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg=
github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/go-i2p/common v0.0.0-20250715213359-dfa5527ece83 h1:F6xM06QyqR+qMYA4SzWzUzfVmkSE1P41tHK32TmGxP8=
github.com/go-i2p/common v0.0.0-20250715213359-dfa5527ece83/go.mod h1:e6X6esQk0zaevdZPZecKY7n8+wOfOLukQfWw558DYfk=
github.com/go-i2p/crypto v0.0.0-20250716230511-565a0995440c h1:s+bMNveuZg8rhIolwy7w451Y4qirhhYZbbmvLfBIDw4=
github.com/go-i2p/crypto v0.0.0-20250716230511-565a0995440c/go.mod h1:5felGikM6K5D95TLvVxew1UfR0BdtPpfmJLZa8cuY5U=
github.com/go-i2p/go-noise v0.0.0-20250805210353-74f980a2439d h1:4DKwGZZ2yalAjrrOTw9Zoz31lOMXysw5PZTqKYazlVw=
github.com/go-i2p/go-noise v0.0.0-20250805210353-74f980a2439d/go.mod h1:lNh+uKTp1nBVhY1MqJ7sNQWORRf1SMmYvu10Suv0zT8=
github.com/go-i2p/logger v0.0.0-20241123010126-3050657e5d0c h1:VTiECn3dFEmUlZjto+wOwJ7SSJTHPLyNprQMR5HzIMI=
github.com/go-i2p/logger v0.0.0-20241123010126-3050657e5d0c/go.mod h1:te7Zj3g3oMeIl8uBXAgO62UKmZ6m6kHRNg1Mm+X8Hzk=
github.com/go-i2p/noise v0.0.0-20250805205922-091c71f48c43 h1:wHDEEr99CEe+2xQ/cqCt8g8QYw1JBqc8Fb/sg2A+K6U=
github.com/go-i2p/noise v0.0.0-20250805205922-091c71f48c43/go.mod h1:yxzyP2upqal6mXWPWIPy7kuc1uuLzDrA21PSO5op9nE=
github.com/go-i2p/su3 v0.0.0-20250716183548-497fadf45e84 h1:aEDC9JJGnPsUCOzyCuiOoGN8ByZ64xVs7dOKOawfImg=
github.com/go-i2p/su3 v0.0.0-20250716183548-497fadf45e84/go.mod h1:khgAcQvD8LNY33zwha+ODxEdnHZRkDjQsdnnwojr7Ek=
github.com/go-i2p/util v0.0.0-20250806013618-d0b686a4f694 h1:uRw0dKhNKXJI9yP9XfpkkMlkE2Cz3NBeWFOvAhb4CKA=
github.com/go-i2p/util v0.0.0-20250806013618-d0b686a4f694/go.mod h1:y8THMwrKFrIW+GGwhZHJmm7jBO1dHwegh5L1HQVu49o=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM=
github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/oklog/ulid/v2 v2.1.1 h1:suPZ4ARWLOJLegGFiZZ1dFAkqzhMjL3J1TzI+5wHz8s=
github.com/oklog/ulid/v2 v2.1.1/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=
github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo=
github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/samber/lo v1.51.0 h1:kysRYLbHy/MB7kQZf5DSN50JHmMsNEdeY24VzJFu7wI=
github.com/samber/lo v1.51.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0=
github.com/samber/oops v1.19.0 h1:sfZAwC8MmTXBRRyNc4Z1utuTPBx+hFKF5fJ9DEQRZfw=
github.com/samber/oops v1.19.0/go.mod h1:+f+61dbiMxEMQ8gw/zTxW2pk+YGobaDM4glEHQtPOww=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs=
github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4=
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
go.step.sm/crypto v0.53.0 h1:+1as1ogzuCzx15/468M4mEC5juogI5a0Fzbsyh1CuYY=
go.step.sm/crypto v0.53.0/go.mod h1:AqLU78RqNUHepLzyOWZuNN/2++Lu7dZENdO9UzWOGSk=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
go.step.sm/crypto v0.67.0 h1:1km9LmxMKG/p+mKa1R4luPN04vlJYnRLlLQrWv7egGU=
go.step.sm/crypto v0.67.0/go.mod h1:+AoDpB0mZxbW/PmOXuwkPSpXRgaUaoIK+/Wx/HGgtAU=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM=
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8=
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=

57
lib/bootstrap/README.md Normal file
View File

@@ -0,0 +1,57 @@
# bootstrap
--
import "github.com/go-i2p/go-i2p/lib/bootstrap"
![bootstrap.svg](bootstrap.svg)
provides generic interfaces for initial bootstrap into network and network
### reseeding
## Usage
#### type Bootstrap
```go
type Bootstrap interface {
// get more peers for bootstrap
// try obtaining at most n router infos
// if n is 0 then try obtaining as many router infos as possible
// returns nil and error if we cannot fetch ANY router infos
// returns a channel that yields 1 slice of router infos containing n or fewer router infos, caller must close channel after use
GetPeers(ctx context.Context, n int) ([]router_info.RouterInfo, error)
}
```
interface defining a way to bootstrap into the i2p network
#### type ReseedBootstrap
```go
type ReseedBootstrap struct {
}
```
ReseedBootstrap implements the Bootstrap interface using HTTP reseeding
#### func NewReseedBootstrap
```go
func NewReseedBootstrap(config *config.BootstrapConfig) *ReseedBootstrap
```
NewReseedBootstrap creates a new reseeder with the provided configuration
#### func (*ReseedBootstrap) GetPeers
```go
func (rb *ReseedBootstrap) GetPeers(ctx context.Context, n int) ([]router_info.RouterInfo, error)
```
GetPeers implements the Bootstrap interface by obtaining RouterInfos from
configured reseed servers
bootstrap
github.com/go-i2p/go-i2p/lib/bootstrap
[go-i2p template file](/template.md)

View File

@@ -1,6 +1,10 @@
package bootstrap
import "github.com/go-i2p/go-i2p/lib/common/router_info"
import (
"context"
"github.com/go-i2p/common/router_info"
)
// interface defining a way to bootstrap into the i2p network
type Bootstrap interface {
@@ -9,5 +13,5 @@ type Bootstrap interface {
// if n is 0 then try obtaining as many router infos as possible
// returns nil and error if we cannot fetch ANY router infos
// returns a channel that yields 1 slice of router infos containing n or fewer router infos, caller must close channel after use
GetPeers(n int) (chan []router_info.RouterInfo, error)
GetPeers(ctx context.Context, n int) ([]router_info.RouterInfo, error)
}

258
lib/bootstrap/bootstrap.svg Normal file
View File

@@ -0,0 +1,258 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.40.1 (20161225.0304)
-->
<!-- Title: gocallvis Pages: 1 -->
<svg width="365pt" height="722pt"
viewBox="0.00 0.00 364.72 722.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(0 722)">
<title>gocallvis</title>
<polygon fill="#d3d3d3" stroke="transparent" points="0,0 0,-722 364.7182,-722 364.7182,0 0,0"/>
<g id="clust1" class="cluster">
<title>cluster_focus</title>
<polygon fill="#e6ecfa" stroke="#000000" stroke-width=".5" points="0,-8 0,-714 356.7182,-714 356.7182,-8 0,-8"/>
<text text-anchor="middle" x="178.3591" y="-693.8" font-family="Arial" font-size="18.00" fill="#000000">bootstrap</text>
</g>
<g id="clust5" class="cluster">
<title>cluster_github.com/go&#45;i2p/go&#45;i2p/lib/netdb/reseed.Reseed</title>
<g id="a_clust5"><a xlink:title="type: github.com/go&#45;i2p/go&#45;i2p/lib/netdb/reseed.Reseed">
<path fill="#eed8ae" stroke="#000000" stroke-width=".5" d="M242.0218,-598C242.0218,-598 334.2252,-598 334.2252,-598 340.2252,-598 346.2252,-604 346.2252,-610 346.2252,-610 346.2252,-664 346.2252,-664 346.2252,-670 340.2252,-676 334.2252,-676 334.2252,-676 242.0218,-676 242.0218,-676 236.0218,-676 230.0218,-670 230.0218,-664 230.0218,-664 230.0218,-610 230.0218,-610 230.0218,-604 236.0218,-598 242.0218,-598"/>
<text text-anchor="middle" x="288.1235" y="-606.5" font-family="Arial" font-size="15.00" fill="#222222">(Reseed)</text>
</a>
</g>
</g>
<g id="clust4" class="cluster">
<title>cluster_*github.com/sirupsen/logrus.Logger</title>
<g id="a_clust4"><a xlink:title="type: *github.com/sirupsen/logrus.Logger">
<path fill="#eed8ae" stroke="#000000" stroke-width=".5" d="M261.4629,-451C261.4629,-451 315.7841,-451 315.7841,-451 321.7841,-451 327.7841,-457 327.7841,-463 327.7841,-463 327.7841,-578 327.7841,-578 327.7841,-584 321.7841,-590 315.7841,-590 315.7841,-590 261.4629,-590 261.4629,-590 255.4629,-590 249.4629,-584 249.4629,-578 249.4629,-578 249.4629,-463 249.4629,-463 249.4629,-457 255.4629,-451 261.4629,-451"/>
<text text-anchor="middle" x="288.6235" y="-459.5" font-family="Arial" font-size="15.00" fill="#222222">(*Logger)</text>
</a>
</g>
</g>
<g id="clust3" class="cluster">
<title>cluster_*github.com/go&#45;i2p/logger.Logger</title>
<g id="a_clust3"><a xlink:title="type: *github.com/go&#45;i2p/logger.Logger">
<path fill="#eed8ae" stroke="#000000" stroke-width=".5" d="M249.0141,-182C249.0141,-182 327.2329,-182 327.2329,-182 333.2329,-182 339.2329,-188 339.2329,-194 339.2329,-194 339.2329,-431 339.2329,-431 339.2329,-437 333.2329,-443 327.2329,-443 327.2329,-443 249.0141,-443 249.0141,-443 243.0141,-443 237.0141,-437 237.0141,-431 237.0141,-431 237.0141,-194 237.0141,-194 237.0141,-188 243.0141,-182 249.0141,-182"/>
<text text-anchor="middle" x="288.1235" y="-190.5" font-family="Arial" font-size="15.00" fill="#222222">(*Logger)</text>
</a>
</g>
</g>
<g id="clust2" class="cluster">
<title>cluster_*github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap</title>
<g id="a_clust2"><a xlink:title="type: *github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap">
<path fill="#b0c4de" stroke="#000000" stroke-width=".5" d="M20,-304C20,-304 143.5288,-304 143.5288,-304 149.5288,-304 155.5288,-310 155.5288,-316 155.5288,-316 155.5288,-370 155.5288,-370 155.5288,-376 149.5288,-382 143.5288,-382 143.5288,-382 20,-382 20,-382 14,-382 8,-376 8,-370 8,-370 8,-316 8,-316 8,-310 14,-304 20,-304"/>
<text text-anchor="middle" x="81.7644" y="-312.5" font-family="Arial" font-size="15.00" fill="#222222">(*ReseedBootstrap)</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.init -->
<g id="node1" class="node">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.init</title>
<g id="a_node1"><a xlink:title="github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.init | defined in .:0&#10;at reseed_bootstrap.go:15: calling [github.com/go&#45;i2p/logger.GetGoI2PLogger]">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M96.2644,-52C96.2644,-52 66.2644,-52 66.2644,-52 60.2644,-52 54.2644,-46 54.2644,-40 54.2644,-40 54.2644,-28 54.2644,-28 54.2644,-22 60.2644,-16 66.2644,-16 66.2644,-16 96.2644,-16 96.2644,-16 102.2644,-16 108.2644,-22 108.2644,-28 108.2644,-28 108.2644,-40 108.2644,-40 108.2644,-46 102.2644,-52 96.2644,-52"/>
<text text-anchor="middle" x="81.2644" y="-29.8" font-family="Verdana" font-size="14.00" fill="#000000">init</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/logger.GetGoI2PLogger -->
<g id="node2" class="node">
<title>github.com/go&#45;i2p/logger.GetGoI2PLogger</title>
<g id="a_node2"><a xlink:title="github.com/go&#45;i2p/logger.GetGoI2PLogger | defined in log.go:120">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M336.813,-52C336.813,-52 239.434,-52 239.434,-52 233.434,-52 227.434,-46 227.434,-40 227.434,-40 227.434,-28 227.434,-28 227.434,-22 233.434,-16 239.434,-16 239.434,-16 336.813,-16 336.813,-16 342.813,-16 348.813,-22 348.813,-28 348.813,-28 348.813,-40 348.813,-40 348.813,-46 342.813,-52 336.813,-52"/>
<text text-anchor="middle" x="288.1235" y="-38.2" font-family="Verdana" font-size="14.00" fill="#000000">logger</text>
<text text-anchor="middle" x="288.1235" y="-21.4" font-family="Verdana" font-size="14.00" fill="#000000">GetGoI2PLogger</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.init&#45;&gt;github.com/go&#45;i2p/logger.GetGoI2PLogger -->
<g id="edge1" class="edge">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.init&#45;&gt;github.com/go&#45;i2p/logger.GetGoI2PLogger</title>
<g id="a_edge1"><a xlink:title="at reseed_bootstrap.go:15: calling [github.com/go&#45;i2p/logger.GetGoI2PLogger]">
<path fill="none" stroke="#8b4513" d="M108.3076,-34C135.736,-34 179.3573,-34 216.7663,-34"/>
<polygon fill="#8b4513" stroke="#8b4513" points="217.1342,-37.5001 227.1342,-34 217.1341,-30.5001 217.1342,-37.5001"/>
</a>
</g>
</g>
<!-- github.com/samber/oops.Errorf -->
<g id="node3" class="node">
<title>github.com/samber/oops.Errorf</title>
<g id="a_node3"><a xlink:title="github.com/samber/oops.Errorf | defined in oops.go:34">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M305.3188,-113C305.3188,-113 270.9282,-113 270.9282,-113 264.9282,-113 258.9282,-107 258.9282,-101 258.9282,-101 258.9282,-89 258.9282,-89 258.9282,-83 264.9282,-77 270.9282,-77 270.9282,-77 305.3188,-77 305.3188,-77 311.3188,-77 317.3188,-83 317.3188,-89 317.3188,-89 317.3188,-101 317.3188,-101 317.3188,-107 311.3188,-113 305.3188,-113"/>
<text text-anchor="middle" x="288.1235" y="-99.2" font-family="Verdana" font-size="14.00" fill="#000000">oops</text>
<text text-anchor="middle" x="288.1235" y="-82.4" font-family="Verdana" font-size="14.00" fill="#000000">Errorf</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/netdb/reseed.NewReseed -->
<g id="node4" class="node">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/netdb/reseed.NewReseed</title>
<g id="a_node4"><a xlink:title="github.com/go&#45;i2p/go&#45;i2p/lib/netdb/reseed.NewReseed | defined in new.go:10">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M321.4764,-174C321.4764,-174 254.7706,-174 254.7706,-174 248.7706,-174 242.7706,-168 242.7706,-162 242.7706,-162 242.7706,-150 242.7706,-150 242.7706,-144 248.7706,-138 254.7706,-138 254.7706,-138 321.4764,-138 321.4764,-138 327.4764,-138 333.4764,-144 333.4764,-150 333.4764,-150 333.4764,-162 333.4764,-162 333.4764,-168 327.4764,-174 321.4764,-174"/>
<text text-anchor="middle" x="288.1235" y="-160.2" font-family="Verdana" font-size="14.00" fill="#000000">reseed</text>
<text text-anchor="middle" x="288.1235" y="-143.4" font-family="Verdana" font-size="14.00" fill="#000000">NewReseed</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap).GetPeers -->
<g id="node5" class="node">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap).GetPeers</title>
<g id="a_node5"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap).GetPeers | defined in reseed_bootstrap.go:32&#10;at reseed_bootstrap.go:40: calling [github.com/samber/oops.Errorf]&#10;at reseed_bootstrap.go:52: calling [github.com/samber/oops.Errorf]&#10;at reseed_bootstrap.go:72: calling [github.com/samber/oops.Errorf]&#10;at reseed_bootstrap.go:46: calling [github.com/go&#45;i2p/go&#45;i2p/lib/netdb/reseed.NewReseed]&#10;at reseed_bootstrap.go:49: calling [(github.com/go&#45;i2p/go&#45;i2p/lib/netdb/reseed.Reseed).SingleReseed]&#10;at reseed_bootstrap.go:51: calling [(*github.com/go&#45;i2p/logger.Logger).WithError]&#10;at reseed_bootstrap.go:58: calling [(*github.com/go&#45;i2p/logger.Logger).WithFields]&#10;at reseed_bootstrap.go:62: calling [(*github.com/sirupsen/logrus.Logger).Info]&#10;at reseed_bootstrap.go:43: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at reseed_bootstrap.go:51: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at reseed_bootstrap.go:43: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at reseed_bootstrap.go:51: calling [(*github.com/go&#45;i2p/logger.Logger).Warn]">
<path fill="#add8e6" stroke="#000000" stroke-width="1.5" d="M106.2947,-374C106.2947,-374 56.2341,-374 56.2341,-374 50.2341,-374 44.2341,-368 44.2341,-362 44.2341,-362 44.2341,-350 44.2341,-350 44.2341,-344 50.2341,-338 56.2341,-338 56.2341,-338 106.2947,-338 106.2947,-338 112.2947,-338 118.2947,-344 118.2947,-350 118.2947,-350 118.2947,-362 118.2947,-362 118.2947,-368 112.2947,-374 106.2947,-374"/>
<text text-anchor="middle" x="81.2644" y="-351.8" font-family="Verdana" font-size="14.00" fill="#000000">GetPeers</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap).GetPeers&#45;&gt;github.com/samber/oops.Errorf -->
<g id="edge2" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap).GetPeers&#45;&gt;github.com/samber/oops.Errorf</title>
<g id="a_edge2"><a xlink:title="at reseed_bootstrap.go:40: calling [github.com/samber/oops.Errorf]&#10;at reseed_bootstrap.go:52: calling [github.com/samber/oops.Errorf]&#10;at reseed_bootstrap.go:72: calling [github.com/samber/oops.Errorf]">
<path fill="none" stroke="#8b4513" d="M118.4074,-352.073C131.5385,-349.0001 145.5161,-343.5697 155.5288,-334 190.8891,-300.2044 195.4391,-162.9154 227.5288,-126 233.5557,-119.0668 241.5102,-113.4857 249.6658,-109.0748"/>
<polygon fill="#8b4513" stroke="#8b4513" points="251.4166,-112.115 258.8672,-104.5824 248.3454,-105.8247 251.4166,-112.115"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap).GetPeers&#45;&gt;github.com/go&#45;i2p/go&#45;i2p/lib/netdb/reseed.NewReseed -->
<g id="edge3" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap).GetPeers&#45;&gt;github.com/go&#45;i2p/go&#45;i2p/lib/netdb/reseed.NewReseed</title>
<g id="a_edge3"><a xlink:title="at reseed_bootstrap.go:46: calling [github.com/go&#45;i2p/go&#45;i2p/lib/netdb/reseed.NewReseed]">
<path fill="none" stroke="#8b4513" d="M118.6751,-351.3434C131.5313,-348.1844 145.2575,-342.8857 155.5288,-334 213.2793,-284.0401 171.3098,-229.6772 227.5288,-178 229.4394,-176.2438 231.5009,-174.6252 233.6705,-173.1338"/>
<polygon fill="#8b4513" stroke="#8b4513" points="235.6115,-176.0535 242.4829,-167.9892 232.0823,-170.0083 235.6115,-176.0535"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/logger.Logger).WithField -->
<g id="node6" class="node">
<title>(*github.com/go&#45;i2p/logger.Logger).WithField</title>
<g id="a_node6"><a xlink:title="(*github.com/go&#45;i2p/logger.Logger).WithField | defined in log.go:54">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M316.398,-252C316.398,-252 259.849,-252 259.849,-252 253.849,-252 247.849,-246 247.849,-240 247.849,-240 247.849,-228 247.849,-228 247.849,-222 253.849,-216 259.849,-216 259.849,-216 316.398,-216 316.398,-216 322.398,-216 328.398,-222 328.398,-228 328.398,-228 328.398,-240 328.398,-240 328.398,-246 322.398,-252 316.398,-252"/>
<text text-anchor="middle" x="288.1235" y="-238.2" font-family="Verdana" font-size="14.00" fill="#000000">logger</text>
<text text-anchor="middle" x="288.1235" y="-221.4" font-family="Verdana" font-size="14.00" fill="#000000">WithField</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap).GetPeers&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithField -->
<g id="edge8" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap).GetPeers&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithField</title>
<g id="a_edge8"><a xlink:title="at reseed_bootstrap.go:43: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at reseed_bootstrap.go:51: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]">
<path fill="none" stroke="#8b4513" d="M118.5683,-348.6617C130.8549,-345.2944 144.2489,-340.5496 155.5288,-334 193.8581,-311.7444 191.4175,-290.6986 227.5288,-265 231.4159,-262.2337 235.5842,-259.5689 239.8482,-257.0424"/>
<polygon fill="#8b4513" stroke="#8b4513" points="241.6859,-260.0242 248.6757,-252.0623 238.2464,-253.9275 241.6859,-260.0242"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/logger.Logger).WithError -->
<g id="node7" class="node">
<title>(*github.com/go&#45;i2p/logger.Logger).WithError</title>
<g id="a_node7"><a xlink:title="(*github.com/go&#45;i2p/logger.Logger).WithError | defined in log.go:66">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M316.655,-313C316.655,-313 259.592,-313 259.592,-313 253.592,-313 247.592,-307 247.592,-301 247.592,-301 247.592,-289 247.592,-289 247.592,-283 253.592,-277 259.592,-277 259.592,-277 316.655,-277 316.655,-277 322.655,-277 328.655,-283 328.655,-289 328.655,-289 328.655,-301 328.655,-301 328.655,-307 322.655,-313 316.655,-313"/>
<text text-anchor="middle" x="288.1235" y="-299.2" font-family="Verdana" font-size="14.00" fill="#000000">logger</text>
<text text-anchor="middle" x="288.1235" y="-282.4" font-family="Verdana" font-size="14.00" fill="#000000">WithError</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap).GetPeers&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithError -->
<g id="edge5" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap).GetPeers&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithError</title>
<g id="a_edge5"><a xlink:title="at reseed_bootstrap.go:51: calling [(*github.com/go&#45;i2p/logger.Logger).WithError]">
<path fill="none" stroke="#8b4513" d="M118.725,-344.9534C151.9288,-335.162 200.7001,-320.78 237.3948,-309.9592"/>
<polygon fill="#8b4513" stroke="#8b4513" points="238.7997,-313.194 247.4014,-307.0084 236.8198,-306.4798 238.7997,-313.194"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/logger.Logger).Warn -->
<g id="node8" class="node">
<title>(*github.com/go&#45;i2p/logger.Logger).Warn</title>
<g id="a_node8"><a xlink:title="(*github.com/go&#45;i2p/logger.Logger).Warn | defined in log.go:30">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M305.8898,-374C305.8898,-374 270.3572,-374 270.3572,-374 264.3572,-374 258.3572,-368 258.3572,-362 258.3572,-362 258.3572,-350 258.3572,-350 258.3572,-344 264.3572,-338 270.3572,-338 270.3572,-338 305.8898,-338 305.8898,-338 311.8898,-338 317.8898,-344 317.8898,-350 317.8898,-350 317.8898,-362 317.8898,-362 317.8898,-368 311.8898,-374 305.8898,-374"/>
<text text-anchor="middle" x="288.1235" y="-360.2" font-family="Verdana" font-size="14.00" fill="#000000">logger</text>
<text text-anchor="middle" x="288.1235" y="-343.4" font-family="Verdana" font-size="14.00" fill="#000000">Warn</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap).GetPeers&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).Warn -->
<g id="edge10" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap).GetPeers&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).Warn</title>
<g id="a_edge10"><a xlink:title="at reseed_bootstrap.go:51: calling [(*github.com/go&#45;i2p/logger.Logger).Warn]">
<path fill="none" stroke="#8b4513" d="M118.725,-356C155.3343,-356 210.8683,-356 248.2746,-356"/>
<polygon fill="#8b4513" stroke="#8b4513" points="248.3136,-359.5001 258.3136,-356 248.3135,-352.5001 248.3136,-359.5001"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/logger.Logger).WithFields -->
<g id="node9" class="node">
<title>(*github.com/go&#45;i2p/logger.Logger).WithFields</title>
<g id="a_node9"><a xlink:title="(*github.com/go&#45;i2p/logger.Logger).WithFields | defined in log.go:60">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M319.3426,-435C319.3426,-435 256.9044,-435 256.9044,-435 250.9044,-435 244.9044,-429 244.9044,-423 244.9044,-423 244.9044,-411 244.9044,-411 244.9044,-405 250.9044,-399 256.9044,-399 256.9044,-399 319.3426,-399 319.3426,-399 325.3426,-399 331.3426,-405 331.3426,-411 331.3426,-411 331.3426,-423 331.3426,-423 331.3426,-429 325.3426,-435 319.3426,-435"/>
<text text-anchor="middle" x="288.1235" y="-421.2" font-family="Verdana" font-size="14.00" fill="#000000">logger</text>
<text text-anchor="middle" x="288.1235" y="-404.4" font-family="Verdana" font-size="14.00" fill="#000000">WithFields</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap).GetPeers&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithFields -->
<g id="edge6" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap).GetPeers&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithFields</title>
<g id="a_edge6"><a xlink:title="at reseed_bootstrap.go:58: calling [(*github.com/go&#45;i2p/logger.Logger).WithFields]">
<path fill="none" stroke="#8b4513" d="M118.725,-367.0466C151.1839,-376.6183 198.5195,-390.577 234.9071,-401.3072"/>
<polygon fill="#8b4513" stroke="#8b4513" points="234.2768,-404.7703 244.8585,-404.2417 236.2568,-398.0561 234.2768,-404.7703"/>
</a>
</g>
</g>
<!-- (*github.com/sirupsen/logrus.Logger).Debug -->
<g id="node10" class="node">
<title>(*github.com/sirupsen/logrus.Logger).Debug</title>
<g id="a_node10"><a xlink:title="(*github.com/sirupsen/logrus.Logger).Debug | defined in logger.go:221">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M306.9455,-521C306.9455,-521 269.3015,-521 269.3015,-521 263.3015,-521 257.3015,-515 257.3015,-509 257.3015,-509 257.3015,-497 257.3015,-497 257.3015,-491 263.3015,-485 269.3015,-485 269.3015,-485 306.9455,-485 306.9455,-485 312.9455,-485 318.9455,-491 318.9455,-497 318.9455,-497 318.9455,-509 318.9455,-509 318.9455,-515 312.9455,-521 306.9455,-521"/>
<text text-anchor="middle" x="288.1235" y="-507.2" font-family="Verdana" font-size="14.00" fill="#000000">logrus</text>
<text text-anchor="middle" x="288.1235" y="-490.4" font-family="Verdana" font-size="14.00" fill="#000000">Debug</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap).GetPeers&#45;&gt;(*github.com/sirupsen/logrus.Logger).Debug -->
<g id="edge9" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap).GetPeers&#45;&gt;(*github.com/sirupsen/logrus.Logger).Debug</title>
<g id="a_edge9"><a xlink:title="at reseed_bootstrap.go:43: calling [(*github.com/sirupsen/logrus.Logger).Debug]">
<path fill="none" stroke="#8b4513" d="M106.6294,-374.0251C143.6948,-400.3648 212.738,-449.4289 254.1541,-478.8604"/>
<polygon fill="#8b4513" stroke="#8b4513" points="252.3722,-481.8878 262.551,-484.8275 256.427,-476.1818 252.3722,-481.8878"/>
</a>
</g>
</g>
<!-- (*github.com/sirupsen/logrus.Logger).Info -->
<g id="node11" class="node">
<title>(*github.com/sirupsen/logrus.Logger).Info</title>
<g id="a_node11"><a xlink:title="(*github.com/sirupsen/logrus.Logger).Info | defined in logger.go:225">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M305.6193,-582C305.6193,-582 270.6277,-582 270.6277,-582 264.6277,-582 258.6277,-576 258.6277,-570 258.6277,-570 258.6277,-558 258.6277,-558 258.6277,-552 264.6277,-546 270.6277,-546 270.6277,-546 305.6193,-546 305.6193,-546 311.6193,-546 317.6193,-552 317.6193,-558 317.6193,-558 317.6193,-570 317.6193,-570 317.6193,-576 311.6193,-582 305.6193,-582"/>
<text text-anchor="middle" x="288.1235" y="-568.2" font-family="Verdana" font-size="14.00" fill="#000000">logrus</text>
<text text-anchor="middle" x="288.1235" y="-551.4" font-family="Verdana" font-size="14.00" fill="#000000">Info</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap).GetPeers&#45;&gt;(*github.com/sirupsen/logrus.Logger).Info -->
<g id="edge7" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap).GetPeers&#45;&gt;(*github.com/sirupsen/logrus.Logger).Info</title>
<g id="a_edge7"><a xlink:title="at reseed_bootstrap.go:62: calling [(*github.com/sirupsen/logrus.Logger).Info]">
<path fill="none" stroke="#8b4513" d="M92.3256,-374.0399C114.3749,-408.7975 166.9292,-485.8578 227.5288,-534 234.1285,-539.243 241.7932,-543.9051 249.4061,-547.8995"/>
<polygon fill="#8b4513" stroke="#8b4513" points="248.0753,-551.1458 258.5915,-552.435 251.1745,-544.8692 248.0753,-551.1458"/>
</a>
</g>
</g>
<!-- (github.com/go&#45;i2p/go&#45;i2p/lib/netdb/reseed.Reseed).SingleReseed -->
<g id="node12" class="node">
<title>(github.com/go&#45;i2p/go&#45;i2p/lib/netdb/reseed.Reseed).SingleReseed</title>
<g id="a_node12"><a xlink:title="(github.com/go&#45;i2p/go&#45;i2p/lib/netdb/reseed.Reseed).SingleReseed | defined in reseed.go:31">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M326.3271,-668C326.3271,-668 249.9199,-668 249.9199,-668 243.9199,-668 237.9199,-662 237.9199,-656 237.9199,-656 237.9199,-644 237.9199,-644 237.9199,-638 243.9199,-632 249.9199,-632 249.9199,-632 326.3271,-632 326.3271,-632 332.3271,-632 338.3271,-638 338.3271,-644 338.3271,-644 338.3271,-656 338.3271,-656 338.3271,-662 332.3271,-668 326.3271,-668"/>
<text text-anchor="middle" x="288.1235" y="-654.2" font-family="Verdana" font-size="14.00" fill="#000000">reseed</text>
<text text-anchor="middle" x="288.1235" y="-637.4" font-family="Verdana" font-size="14.00" fill="#000000">SingleReseed</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap).GetPeers&#45;&gt;(github.com/go&#45;i2p/go&#45;i2p/lib/netdb/reseed.Reseed).SingleReseed -->
<g id="edge4" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap).GetPeers&#45;&gt;(github.com/go&#45;i2p/go&#45;i2p/lib/netdb/reseed.Reseed).SingleReseed</title>
<g id="a_edge4"><a xlink:title="at reseed_bootstrap.go:49: calling [(github.com/go&#45;i2p/go&#45;i2p/lib/netdb/reseed.Reseed).SingleReseed]">
<path fill="none" stroke="#8b4513" d="M89.919,-374.0435C110.3702,-415.6822 164.7136,-520.678 227.5288,-596 236.2167,-606.4176 246.9389,-616.6363 256.9371,-625.3325"/>
<polygon fill="#8b4513" stroke="#8b4513" points="254.8567,-628.1572 264.7475,-631.9549 259.3837,-622.8181 254.8567,-628.1572"/>
</a>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 23 KiB

View File

@@ -1,23 +0,0 @@
# bootstrap
--
import "github.com/go-i2p/go-i2p/lib/bootstrap"
provides generic interfaces for initial bootstrap into network and network
### reseeding
## Usage
#### type Bootstrap
```go
type Bootstrap interface {
// get more peers for bootstrap
// try obtaining at most n router infos
// if n is 0 then try obtaining as many router infos as possible
// returns nil and error if we cannot fetch ANY router infos
// returns a channel that yields 1 slice of router infos containing n or fewer router infos, caller must close channel after use
GetPeers(n int) (chan []router_info.RouterInfo, error)
}
```
interface defining a way to bootstrap into the i2p network

View File

@@ -0,0 +1,76 @@
package bootstrap
import (
"context"
"github.com/go-i2p/common/router_info"
"github.com/go-i2p/go-i2p/lib/config"
"github.com/go-i2p/go-i2p/lib/netdb/reseed"
"github.com/go-i2p/logger"
"github.com/sirupsen/logrus"
"github.com/samber/oops"
)
var log = logger.GetGoI2PLogger()
// ReseedBootstrap implements the Bootstrap interface using HTTP reseeding
type ReseedBootstrap struct {
// Configuration containing reseed servers
config *config.BootstrapConfig
}
// NewReseedBootstrap creates a new reseeder with the provided configuration
func NewReseedBootstrap(config *config.BootstrapConfig) *ReseedBootstrap {
return &ReseedBootstrap{
config: config,
}
}
// GetPeers implements the Bootstrap interface by obtaining RouterInfos
// from configured reseed servers
func (rb *ReseedBootstrap) GetPeers(ctx context.Context, n int) ([]router_info.RouterInfo, error) {
var allRouterInfos []router_info.RouterInfo
var lastErr error
// Try each reseed server until we get enough routerInfos or exhaust all servers
for _, server := range rb.config.ReseedServers {
// Check if context is canceled before making request
if ctx.Err() != nil {
return nil, oops.Errorf("reseed canceled: %v", ctx.Err())
}
log.WithField("server", server.Url).Debug("Attempting to reseed from server")
// Use the existing Reseed implementation with a timeout context
reseeder := reseed.NewReseed()
// Perform the actual reseeding operation synchronously
serverRIs, err := reseeder.SingleReseed(server.Url)
if err != nil {
log.WithError(err).WithField("server", server.Url).Warn("Reseed attempt failed")
lastErr = oops.Errorf("reseed from %s failed: %v", server.Url, err)
continue
}
// Add the retrieved RouterInfos to our collection
allRouterInfos = append(allRouterInfos, serverRIs...)
log.WithFields(logrus.Fields{
"server": server.Url,
"count": len(serverRIs),
"total": len(allRouterInfos),
}).Info("Successfully obtained router infos from reseed server")
// Check if we have enough RouterInfos
if n > 0 && len(allRouterInfos) >= n {
break
}
}
// If we couldn't get any RouterInfos from any server, return the last error
if len(allRouterInfos) == 0 && lastErr != nil {
return nil, oops.Errorf("all reseed attempts failed: %w", lastErr)
}
return allRouterInfos, nil
}

View File

@@ -1,23 +0,0 @@
// Package base32 implmenets utilities for encoding and decoding text using I2P's alphabet
package base32
import (
b32 "encoding/base32"
)
// I2PEncodeAlphabet is the base32 encoding used throughout I2P.
// RFC 3548 using lowercase characters.
const I2PEncodeAlphabet = "abcdefghijklmnopqrstuvwxyz234567"
// I2PEncoding is the standard base32 encoding used through I2P.
var I2PEncoding *b32.Encoding = b32.NewEncoding(I2PEncodeAlphabet)
// EncodeToString encodes []byte to a base32 string using I2PEncoding
func EncodeToString(data []byte) string {
return I2PEncoding.EncodeToString(data)
}
// DecodeString decodes base64 string to []byte I2PEncoding
func DecodeString(data string) ([]byte, error) {
return I2PEncoding.DecodeString(data)
}

View File

@@ -1,20 +0,0 @@
package base32
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestEncodeDecodeNotMangled(t *testing.T) {
assert := assert.New(t)
// Random pangram
testInput := []byte("How vexingly quick daft zebras jump!")
encodedString := EncodeToString(testInput)
decodedString, err := DecodeString(encodedString)
assert.Nil(err)
assert.ElementsMatch(testInput, decodedString)
}

View File

@@ -1,33 +0,0 @@
# base32
--
import "github.com/go-i2p/go-i2p/lib/common/base32"
Package base32 implmenets utilities for encoding and decoding text using I2P's
### alphabet
## Usage
```go
const I2PEncodeAlphabet = "abcdefghijklmnopqrstuvwxyz234567"
```
I2PEncodeAlphabet is the base32 encoding used throughout I2P. RFC 3548 using
lowercase characters.
```go
var I2PEncoding *b32.Encoding = b32.NewEncoding(I2PEncodeAlphabet)
```
I2PEncoding is the standard base32 encoding used through I2P.
#### func DecodeString
```go
func DecodeString(data string) ([]byte, error)
```
DecodeString decodes base64 string to []byte I2PEncoding
#### func EncodeToString
```go
func EncodeToString(data []byte) string
```
EncodeToString encodes []byte to a base32 string using I2PEncoding

View File

@@ -1,23 +0,0 @@
// Package base64 implmenets utilities for encoding and decoding text using I2P's alphabet
package base64
import (
b64 "encoding/base64"
)
// I2PEncodeAlphabet is the base64 encoding used throughout I2P.
// RFC 4648 with "/"" replaced with "~", and "+" replaced with "-".
const I2PEncodeAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-~"
// I2PEncoding is the standard base64 encoding used through I2P.
var I2PEncoding *b64.Encoding = b64.NewEncoding(I2PEncodeAlphabet)
// I2PEncoding is the standard base64 encoding used through I2P.
func EncodeToString(data []byte) string {
return I2PEncoding.EncodeToString(data)
}
// DecodeString decodes base64 string to []byte I2PEncoding
func DecodeString(str string) ([]byte, error) {
return I2PEncoding.DecodeString(str)
}

View File

@@ -1,20 +0,0 @@
package base64
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestEncodeDecodeNotMangled(t *testing.T) {
assert := assert.New(t)
// Random pangram
testInput := []byte("Glib jocks quiz nymph to vex dwarf.")
encodedString := EncodeToString(testInput)
decodedString, err := DecodeString(encodedString)
assert.Nil(err)
assert.ElementsMatch(testInput, decodedString)
}

View File

@@ -1,33 +0,0 @@
# base64
--
import "github.com/go-i2p/go-i2p/lib/common/base64"
Package base64 implmenets utilities for encoding and decoding text using I2P's
### alphabet
## Usage
```go
const I2PEncodeAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-~"
```
I2PEncodeAlphabet is the base64 encoding used throughout I2P. RFC 4648 with "/""
replaced with "~", and "+" replaced with "-".
```go
var I2PEncoding *b64.Encoding = b64.NewEncoding(I2PEncodeAlphabet)
```
I2PEncoding is the standard base64 encoding used through I2P.
#### func DecodeString
```go
func DecodeString(str string) ([]byte, error)
```
DecodeString decodes base64 string to []byte I2PEncoding
#### func EncodeToString
```go
func EncodeToString(data []byte) string
```
I2PEncoding is the standard base64 encoding used through I2P.

View File

@@ -1,262 +0,0 @@
// Package certificate implements the certificate common-structure of I2P.
package certificate
import (
"encoding/binary"
"errors"
"fmt"
"github.com/sirupsen/logrus"
// log "github.com/sirupsen/logrus"
"github.com/go-i2p/go-i2p/lib/util/logger"
. "github.com/go-i2p/go-i2p/lib/common/data"
)
var log = logger.GetGoI2PLogger()
// Certificate Types
const (
CERT_NULL = iota
CERT_HASHCASH
CERT_HIDDEN
CERT_SIGNED
CERT_MULTIPLE
CERT_KEY
)
// CERT_MIN_SIZE is the minimum size of a valid Certificate in []byte
// 1 byte for type
// 2 bytes for payload length
const CERT_MIN_SIZE = 3
/*
[I2P Certificate]
Accurate for version 0.9.49
Description
A certifificate is a container for various receipts of proof of works used throughout the I2P network.
Contents
1 byte Integer specifying certificate type, followed by a 2 byte Integer specifying the size of the certificate playload, then that many bytes.
+----+----+----+----+----+-//
|type| length | payload
+----+----+----+----+----+-//
type :: Integer
length -> 1 byte
case 0 -> NULL
case 1 -> HASHCASH
case 2 -> HIDDEN
case 3 -> SIGNED
case 4 -> MULTIPLE
case 5 -> KEY
length :: Integer
length -> 2 bytes
payload :: data
length -> $length bytes
*/
// Certificate is the representation of an I2P Certificate.
//
// https://geti2p.net/spec/common-structures#certificate
type Certificate struct {
kind Integer
len Integer
payload []byte
}
// RawBytes returns the entire certificate in []byte form, includes excess payload data.
func (c *Certificate) RawBytes() []byte {
bytes := c.kind.Bytes()
bytes = append(bytes, c.len.Bytes()...)
bytes = append(bytes, c.payload...)
log.WithFields(logrus.Fields{
"raw_bytes_length": len(bytes),
}).Debug("Generated raw bytes for certificate")
return bytes
}
// ExcessBytes returns the excess bytes in a certificate found after the specified payload length.
func (c *Certificate) ExcessBytes() []byte {
if len(c.payload) >= c.len.Int() {
excess := c.payload[c.len.Int():]
log.WithFields(logrus.Fields{
"excess_bytes_length": len(excess),
}).Debug("Found excess bytes in certificate")
return excess
}
log.Debug("No excess bytes found in certificate")
return nil
}
// Bytes returns the entire certificate in []byte form, trims payload to specified length.
func (c *Certificate) Bytes() []byte {
bytes := c.kind.Bytes()
bytes = append(bytes, c.len.Bytes()...)
bytes = append(bytes, c.Data()...)
log.WithFields(logrus.Fields{
"bytes_length": len(bytes),
}).Debug("Generated bytes for certificate")
return bytes
}
func (c *Certificate) length() (cert_len int) {
cert_len = len(c.Bytes())
return
}
// Type returns the Certificate type specified in the first byte of the Certificate,
func (c *Certificate) Type() (cert_type int) {
cert_type = c.kind.Int()
log.WithFields(logrus.Fields{
"cert_type": cert_type,
}).Debug("Retrieved certificate type")
return
}
// Length returns the payload length of a Certificate.
func (c *Certificate) Length() (length int) {
length = c.len.Int()
log.WithFields(logrus.Fields{
"length": length,
}).Debug("Retrieved certificate length")
return
}
// Data returns the payload of a Certificate, payload is trimmed to the specified length.
func (c *Certificate) Data() (data []byte) {
lastElement := c.Length()
if lastElement > len(c.payload) {
data = c.payload
log.Warn("Certificate payload shorter than specified length")
} else {
data = c.payload[0:lastElement]
}
log.WithFields(logrus.Fields{
"data_length": len(data),
}).Debug("Retrieved certificate data")
return
}
// readCertificate creates a new Certficiate from []byte
// returns err if the certificate is too short or if the payload doesn't match specified length.
func readCertificate(data []byte) (certificate Certificate, err error) {
certificate = Certificate{}
switch len(data) {
case 0:
certificate.kind = Integer([]byte{0})
certificate.len = Integer([]byte{0})
log.WithFields(logrus.Fields{
"at": "(Certificate) NewCertificate",
"certificate_bytes_length": len(data),
"reason": "too short (len < CERT_MIN_SIZE)" + fmt.Sprintf("%d", certificate.kind.Int()),
}).Error("invalid certificate, empty")
err = fmt.Errorf("error parsing certificate: certificate is empty")
return
case 1, 2:
certificate.kind = Integer(data[0 : len(data)-1])
certificate.len = Integer([]byte{0})
log.WithFields(logrus.Fields{
"at": "(Certificate) NewCertificate",
"certificate_bytes_length": len(data),
"reason": "too short (len < CERT_MIN_SIZE)" + fmt.Sprintf("%d", certificate.kind.Int()),
}).Error("invalid certificate, too short")
err = fmt.Errorf("error parsing certificate: certificate is too short")
return
default:
certificate.kind = Integer(data[0:1])
certificate.len = Integer(data[1:3])
payloadLength := len(data) - CERT_MIN_SIZE
certificate.payload = data[CERT_MIN_SIZE:]
if certificate.len.Int() > len(data)-CERT_MIN_SIZE {
err = fmt.Errorf("certificate parsing warning: certificate data is shorter than specified by length")
log.WithFields(logrus.Fields{
"at": "(Certificate) NewCertificate",
"certificate_bytes_length": certificate.len.Int(),
"certificate_payload_length": payloadLength,
"data_bytes:": string(data),
"kind_bytes": data[0:1],
"len_bytes": data[1:3],
"reason": err.Error(),
}).Error("invalid certificate, shorter than specified by length")
return
}
log.WithFields(logrus.Fields{
"type": certificate.kind.Int(),
"length": certificate.len.Int(),
}).Debug("Successfully created new certificate")
return
}
}
// ReadCertificate creates a Certificate from []byte and returns any ExcessBytes at the end of the input.
// returns err if the certificate could not be read.
func ReadCertificate(data []byte) (certificate Certificate, remainder []byte, err error) {
certificate, err = readCertificate(data)
if err != nil && err.Error() == "certificate parsing warning: certificate data is longer than specified by length" {
log.Warn("Certificate data longer than specified length")
err = nil
}
remainder = certificate.ExcessBytes()
log.WithFields(logrus.Fields{
"remainder_length": len(remainder),
}).Debug("Read certificate and extracted remainder")
return
}
// NewCertificate creates a new Certificate with default NULL type
func NewCertificate() *Certificate {
return &Certificate{
kind: Integer([]byte{CERT_NULL}),
len: Integer([]byte{0}),
payload: make([]byte, 0),
}
}
// NewCertificateWithType creates a new Certificate with specified type and payload
func NewCertificateWithType(certType uint8, payload []byte) (*Certificate, error) {
// Validate certificate type
switch certType {
case CERT_NULL, CERT_HASHCASH, CERT_HIDDEN, CERT_SIGNED, CERT_MULTIPLE, CERT_KEY:
// Valid type
default:
return nil, fmt.Errorf("invalid certificate type: %d", certType)
}
// For NULL certificates, payload should be empty
if certType == CERT_NULL && len(payload) > 0 {
return nil, errors.New("NULL certificates must have empty payload")
}
length, _ := NewIntegerFromInt(len(payload), 2)
cert := &Certificate{
kind: Integer([]byte{certType}),
len: *length,
payload: make([]byte, len(payload)),
}
// Copy payload if present
if len(payload) > 0 {
copy(cert.payload, payload)
}
return cert, nil
}
func GetSignatureTypeFromCertificate(cert Certificate) (int, error) {
if cert.Type() != CERT_KEY {
return 0, fmt.Errorf("unexpected certificate type: %d", cert.Type)
}
if len(cert.payload) < 2 {
return 0, fmt.Errorf("certificate payload too short to contain signature type")
}
sigType := int(binary.BigEndian.Uint16(cert.payload[0:2]))
return sigType, nil
}

View File

@@ -1,146 +0,0 @@
package certificate
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestCertificateTypeIsFirstByte(t *testing.T) {
assert := assert.New(t)
bytes := []byte{0x03, 0x00, 0x00}
certificate, err := readCertificate(bytes)
cert_type := certificate.Type()
assert.Equal(cert_type, 3, "certificate.Type() should be the first bytes in a certificate")
assert.Nil(err)
}
func TestCertificateLengthCorrect(t *testing.T) {
assert := assert.New(t)
bytes := []byte{0x03, 0x00, 0x02, 0xff, 0xff}
certificate, err := readCertificate(bytes)
cert_len := certificate.Length()
assert.Equal(cert_len, 2, "certificate.Length() should return integer from second two bytes")
assert.Nil(err)
}
func TestCertificateLengthErrWhenTooShort(t *testing.T) {
assert := assert.New(t)
bytes := []byte{0x03, 0x01}
certificate, _, err := ReadCertificate(bytes)
cert_len := certificate.Length()
assert.Equal(cert_len, 0, "certificate.Length() did not return zero length for missing length data")
if assert.NotNil(err) {
assert.Equal("error parsing certificate: certificate is too short", err.Error(), "correct error message should be returned")
}
}
func TestCertificateLengthErrWhenDataTooShort(t *testing.T) {
assert := assert.New(t)
bytes := []byte{0x03, 0x00, 0x02, 0xff}
certificate, err := readCertificate(bytes)
cert_len := certificate.Length()
assert.Equal(cert_len, 2, "certificate.Length() did not return indicated length when data was actually missing")
if assert.NotNil(err) {
assert.Equal("certificate parsing warning: certificate data is shorter than specified by length", err.Error(), "correct error message should be returned")
}
}
func TestCertificateDataWhenCorrectSize(t *testing.T) {
assert := assert.New(t)
bytes := []byte{0x03, 0x00, 0x01, 0xaa}
certificate, err := readCertificate(bytes)
cert_data := certificate.Data()
assert.Nil(err, "certificate.Data() returned error with valid data")
cert_len := len(cert_data)
assert.Equal(cert_len, 1, "certificate.Length() did not return indicated length when data was valid")
assert.Equal(170, int(cert_data[0]), "certificate.Data() returned incorrect data")
}
func TestCertificateDataWhenTooLong(t *testing.T) {
assert := assert.New(t)
bytes := []byte{0x03, 0x00, 0x02, 0xff, 0xff, 0xaa, 0xaa}
certificate, _, _ := ReadCertificate(bytes)
cert_data := certificate.Data()
cert_len := certificate.Length() // len(cert_data)
assert.Equal(cert_len, 2, "certificate.Length() did not return indicated length when data was too long")
if cert_data[0] != 0xff || cert_data[1] != 0xff {
t.Fatal("certificate.Data() returned incorrect data when data was too long")
}
}
func TestCertificateDataWhenTooShort(t *testing.T) {
assert := assert.New(t)
bytes := []byte{0x03, 0x00, 0x02, 0xff}
certificate, err := readCertificate(bytes)
cert_data := certificate.Data()
if assert.NotNil(err) {
assert.Equal("certificate parsing warning: certificate data is shorter than specified by length", err.Error(), "correct error message should be returned")
}
cert_len := len(cert_data)
assert.Equal(cert_len, 1, "certificate.Data() did not return correct amount of data when data too short")
assert.Equal(255, int(cert_data[0]), "certificate.Data() did not return correct data values when data was too short")
}
func TestReadCertificateWithCorrectData(t *testing.T) {
assert := assert.New(t)
bytes := []byte{0x00, 0x00, 0x02, 0xff, 0xff}
cert, remainder, err := ReadCertificate(bytes)
assert.Equal(cert.length(), 5, "ReadCertificate() did not return correct amount of data for valid certificate")
assert.Equal(len(remainder), 0, "ReadCertificate() did not return a zero length remainder on a valid certificate")
assert.Nil(err, "ReadCertificate() should not return an error with valid data")
}
func TestReadCertificateWithDataTooShort(t *testing.T) {
assert := assert.New(t)
bytes := []byte{0x00, 0x00, 0x02, 0xff}
cert, remainder, err := ReadCertificate(bytes)
assert.Equal(cert.length(), 4, "ReadCertificate() did not return correct amount of data for certificate with missing data")
assert.Equal(len(remainder), 0, "ReadCertificate() did not return a zero length remainder on certificate with missing data")
if assert.NotNil(err) {
assert.Equal("certificate parsing warning: certificate data is shorter than specified by length", err.Error(), "correct error message should be returned")
}
}
func TestReadCertificateWithRemainder(t *testing.T) {
assert := assert.New(t)
bytes := []byte{0x00, 0x00, 0x02, 0xff, 0xff, 0x01}
cert, remainder, err := ReadCertificate(bytes)
assert.Equal(cert.length(), 5, "ReadCertificate() did not return correct amount of data for certificate with extra data")
assert.Equal(len(remainder), 1, "ReadCertificate() returned incorrect length remainder on certificate with extra data")
// assert.Equal(1, int(remainder[0]), "ReadCertificate() did not return correct remainder value")
assert.Nil(err)
}
func TestReadCertificateWithInvalidLength(t *testing.T) {
assert := assert.New(t)
bytes := []byte{0x00, 0x00}
cert, remainder, err := ReadCertificate(bytes)
assert.Equal(cert.length(), 2, "ReadCertificate() should populate the certificate with the provided data even when invalid")
assert.Equal(len(remainder), 0, "ReadCertificate() returned non-zero length remainder on invalid certificate")
if assert.NotNil(err) {
assert.Equal("error parsing certificate: certificate is too short", err.Error(), "correct error message should be returned")
}
}

View File

@@ -1,98 +0,0 @@
# certificate
--
import "github.com/go-i2p/go-i2p/lib/common/certificate"
## Usage
```go
const (
CERT_NULL = iota
CERT_HASHCASH
CERT_HIDDEN
CERT_SIGNED
CERT_MULTIPLE
CERT_KEY
)
```
Certificate Types
```go
const CERT_MIN_SIZE = 3
```
CERT_MIN_SIZE is the minimum size of a valid Certificate in []byte 1 byte for
type 2 bytes for payload length
#### type Certificate
```go
type Certificate struct {
}
```
Certificate is the representation of an I2P Certificate.
https://geti2p.net/spec/common-structures#certificate
#### func NewCertificate
```go
func NewCertificate(data []byte) (certificate Certificate, err error)
```
NewCertificate creates a new Certficiate from []byte returns err if the
certificate is too short or if the payload doesn't match specified length.
#### func ReadCertificate
```go
func ReadCertificate(data []byte) (certificate Certificate, remainder []byte, err error)
```
ReadCertificate creates a Certificate from []byte and returns any ExcessBytes at
the end of the input. returns err if the certificate could not be read.
#### func (*Certificate) Bytes
```go
func (c *Certificate) Bytes() []byte
```
Bytes returns the entire certificate in []byte form, trims payload to specified
length.
#### func (*Certificate) Data
```go
func (c *Certificate) Data() (data []byte)
```
Data returns the payload of a Certificate, payload is trimmed to the specified
length.
#### func (*Certificate) ExcessBytes
```go
func (c *Certificate) ExcessBytes() []byte
```
ExcessBytes returns the excess bytes in a certificate found after the specified
payload length.
#### func (*Certificate) Length
```go
func (c *Certificate) Length() (length int)
```
Length returns the payload length of a Certificate.
#### func (*Certificate) RawBytes
```go
func (c *Certificate) RawBytes() []byte
```
RawBytes returns the entire certificate in []byte form, includes excess payload
data.
#### func (*Certificate) Type
```go
func (c *Certificate) Type() (cert_type int)
```
Type returns the Certificate type specified in the first byte of the
Certificate,

View File

@@ -1,87 +0,0 @@
// Package data implements common data structures used in higher level structures.
package data
import (
"errors"
"time"
"github.com/go-i2p/go-i2p/lib/util/logger"
"github.com/sirupsen/logrus"
)
var log = logger.GetGoI2PLogger()
// DATE_SIZE is the length in bytes of an I2P Date.
const DATE_SIZE = 8
/*
[I2P Date]
Accurate for version 0.9.49
Description
The number of milliseconds since midnight on Januyar 1, 1970 in the GMT timezone.
If the number is 0, the date is undefined or null.
Contents
8 byte Integer
*/
// Date is the represenation of an I2P Date.
//
// https://geti2p.net/spec/common-structures#date
type Date [8]byte
// Bytes returns the raw []byte content of a Date.
func (i Date) Bytes() []byte {
return i[:]
}
// Int returns the Date as a Go integer.
func (i Date) Int() int {
return intFromBytes(i.Bytes())
}
// Time takes the value stored in date as an 8 byte big-endian integer representing the
// number of milliseconds since the beginning of unix time and converts it to a Go time.Time
// struct.
func (date Date) Time() (date_time time.Time) {
seconds := Integer(date[:])
date_time = time.Unix(0, int64(seconds.Int()*1000000))
return
}
// ReadDate creates a Date from []byte using the first DATE_SIZE bytes.
// Any data after DATE_SIZE is returned as a remainder.
func ReadDate(data []byte) (date Date, remainder []byte, err error) {
if len(data) < 8 {
log.WithFields(logrus.Fields{
"data": data,
}).Error("ReadDate: data is too short")
err = errors.New("ReadDate: data is too short")
return
}
copy(date[:], data[:8])
remainder = data[8:]
log.WithFields(logrus.Fields{
"date_value": date.Int(),
"remainder_length": len(remainder),
}).Debug("Successfully read Date from data")
return
}
// NewDate creates a new Date from []byte using ReadDate.
// Returns a pointer to Date unlike ReadDate.
func NewDate(data []byte) (date *Date, remainder []byte, err error) {
objdate, remainder, err := ReadDate(data)
if err != nil {
log.WithError(err).Error("Failed to create new Date")
return nil, remainder, err
}
date = &objdate
log.WithFields(logrus.Fields{
"date_value": date.Int(),
"remainder_length": len(remainder),
}).Debug("Successfully created new Date")
return
}

View File

@@ -1,16 +0,0 @@
package data
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestTimeFromMilliseconds(t *testing.T) {
assert := assert.New(t)
next_day := Date{0x00, 0x00, 0x00, 0x00, 0x05, 0x26, 0x5c, 0x00}
go_time := next_day.Time()
assert.Equal(int64(86400), go_time.Unix(), "Date.Time() did not parse time in milliseconds")
}

View File

@@ -1,297 +0,0 @@
# data
--
import "github.com/go-i2p/go-i2p/lib/common/data"
Package data implements common data structures used in higher level structures.
## Usage
```go
const DATE_SIZE = 8
```
DATE_SIZE is the length in bytes of an I2P Date.
```go
const MAX_INTEGER_SIZE = 8
```
MAX_INTEGER_SIZE is the maximum length of an I2P integer in bytes.
```go
const STRING_MAX_SIZE = 255
```
STRING_MAX_SIZE is the maximum number of bytes that can be stored in an I2P
string
#### func PrintErrors
```go
func PrintErrors(errs []error)
```
PrintErrors prints a formatted list of errors to the console.
#### func WrapErrors
```go
func WrapErrors(errs []error) error
```
WrapErrors compiles a slice of errors and returns them wrapped together as a
single error.
#### type Date
```go
type Date [8]byte
```
Date is the represenation of an I2P Date.
https://geti2p.net/spec/common-structures#date
#### func NewDate
```go
func NewDate(data []byte) (date *Date, remainder []byte, err error)
```
NewDate creates a new Date from []byte using ReadDate. Returns a pointer to Date
unlike ReadDate.
#### func ReadDate
```go
func ReadDate(data []byte) (date Date, remainder []byte, err error)
```
ReadDate creates a Date from []byte using the first DATE_SIZE bytes. Any data
after DATE_SIZE is returned as a remainder.
#### func (Date) Bytes
```go
func (i Date) Bytes() []byte
```
Bytes returns the raw []byte content of a Date.
#### func (Date) Int
```go
func (i Date) Int() int
```
Int returns the Date as a Go integer.
#### func (Date) Time
```go
func (date Date) Time() (date_time time.Time)
```
Time takes the value stored in date as an 8 byte big-endian integer representing
the number of milliseconds since the beginning of unix time and converts it to a
Go time.Time struct.
#### type Hash
```go
type Hash [32]byte
```
Hash is the represenation of an I2P Hash.
https://geti2p.net/spec/common-structures#hash
#### func HashData
```go
func HashData(data []byte) (h Hash)
```
HashData returns the SHA256 sum of a []byte input as Hash.
#### func HashReader
```go
func HashReader(r io.Reader) (h Hash, err error)
```
HashReader returns the SHA256 sum from all data read from an io.Reader. return
error if one occurs while reading from reader
#### func (Hash) Bytes
```go
func (h Hash) Bytes() [32]byte
```
#### type I2PString
```go
type I2PString []byte
```
I2PString is the represenation of an I2P String.
https://geti2p.net/spec/common-structures#string
#### func ReadI2PString
```go
func ReadI2PString(data []byte) (str I2PString, remainder []byte, err error)
```
ReadI2PString returns I2PString from a []byte. The remaining bytes after the
specified length are also returned. Returns a list of errors that occurred
during parsing.
#### func ToI2PString
```go
func ToI2PString(data string) (str I2PString, err error)
```
ToI2PString converts a Go string to an I2PString. Returns error if the string
exceeds STRING_MAX_SIZE.
#### func (I2PString) Data
```go
func (str I2PString) Data() (data string, err error)
```
Data returns the I2PString content as a string trimmed to the specified length
and not including the length byte. Returns error encountered by Length.
#### func (I2PString) Length
```go
func (str I2PString) Length() (length int, err error)
```
Length returns the length specified in the first byte. Returns error if the
specified does not match the actual length or the string is otherwise invalid.
#### type Integer
```go
type Integer []byte
```
Integer is the represenation of an I2P Integer.
https://geti2p.net/spec/common-structures#integer
#### func NewInteger
```go
func NewInteger(bytes []byte, size int) (integer *Integer, remainder []byte, err error)
```
NewInteger creates a new Integer from []byte using ReadInteger. Limits the
length of the created Integer to MAX_INTEGER_SIZE. Returns a pointer to Integer
unlike ReadInteger.
#### func NewIntegerFromInt
```go
func NewIntegerFromInt(value int, size int) (integer *Integer, err error)
```
NewIntegerFromInt creates a new Integer from a Go integer of a specified []byte
length.
#### func ReadInteger
```go
func ReadInteger(bytes []byte, size int) (Integer, []byte)
```
ReadInteger returns an Integer from a []byte of specified length. The remaining
bytes after the specified length are also returned.
#### func (Integer) Bytes
```go
func (i Integer) Bytes() []byte
```
Bytes returns the raw []byte content of an Integer.
#### func (Integer) Int
```go
func (i Integer) Int() int
```
Int returns the Date as a Go integer
#### type Mapping
```go
type Mapping struct {
}
```
Mapping is the represenation of an I2P Mapping.
https://geti2p.net/spec/common-structures#mapping
#### func GoMapToMapping
```go
func GoMapToMapping(gomap map[string]string) (mapping *Mapping, err error)
```
GoMapToMapping converts a Go map of unformatted strings to *Mapping.
#### func NewMapping
```go
func NewMapping(bytes []byte) (values *Mapping, remainder []byte, err []error)
```
NewMapping creates a new *Mapping from []byte using ReadMapping. Returns a
pointer to Mapping unlike ReadMapping.
#### func ReadMapping
```go
func ReadMapping(bytes []byte) (mapping Mapping, remainder []byte, err []error)
```
ReadMapping returns Mapping from a []byte. The remaining bytes after the
specified length are also returned. Returns a list of errors that occurred
during parsing.
#### func ValuesToMapping
```go
func ValuesToMapping(values MappingValues) *Mapping
```
ValuesToMapping creates a *Mapping using MappingValues. The values are sorted in
the order defined in mappingOrder.
#### func (*Mapping) Data
```go
func (mapping *Mapping) Data() []byte
```
Data returns a Mapping in its []byte form.
#### func (*Mapping) HasDuplicateKeys
```go
func (mapping *Mapping) HasDuplicateKeys() bool
```
HasDuplicateKeys returns true if two keys in a mapping are identical.
#### func (Mapping) Values
```go
func (mapping Mapping) Values() MappingValues
```
Values returns the values contained in a Mapping as MappingValues.
#### type MappingValues
```go
type MappingValues [][2]I2PString
```
MappingValues represents the parsed key value pairs inside of an I2P Mapping.
#### func ReadMappingValues
```go
func ReadMappingValues(remainder []byte, map_length Integer) (values *MappingValues, remainder_bytes []byte, errs []error)
```
ReadMappingValues returns *MappingValues from a []byte. The remaining bytes
after the specified length are also returned. Returns a list of errors that
occurred during parsing.
#### func (MappingValues) Get
```go
func (m MappingValues) Get(key I2PString) I2PString
```

View File

@@ -1,19 +0,0 @@
package data
import "fmt"
// WrapErrors compiles a slice of errors and returns them wrapped together as a single error.
func WrapErrors(errs []error) error {
var err error
for i, e := range errs {
err = fmt.Errorf("%v\n\t%d: %v", err, i, e)
}
return err
}
// PrintErrors prints a formatted list of errors to the console.
func PrintErrors(errs []error) {
for i, e := range errs {
fmt.Printf("\t%d: %v\n", i, e)
}
}

View File

@@ -1,47 +0,0 @@
package data
import (
"crypto/sha256"
"io"
)
/*
[I2P Hash]
Accurate for version 0.9.49
Description
Represents the SHA256 of some data.
Contents
32 bytes
[I2P Hash]:
*/
// Hash is the represenation of an I2P Hash.
//
// https://geti2p.net/spec/common-structures#hash
type Hash [32]byte
func (h Hash) Bytes() [32]byte {
return h
}
// HashData returns the SHA256 sum of a []byte input as Hash.
func HashData(data []byte) (h Hash) {
// log.Println("Hashing Data:", data)
h = sha256.Sum256(data)
return
}
// HashReader returns the SHA256 sum from all data read from an io.Reader.
// return error if one occurs while reading from reader
func HashReader(r io.Reader) (h Hash, err error) {
sha := sha256.New()
_, err = io.Copy(sha, r)
if err == nil {
d := sha.Sum(nil)
copy(h[:], d)
}
return
}

View File

@@ -1,85 +0,0 @@
package data
import (
"encoding/binary"
)
// MAX_INTEGER_SIZE is the maximum length of an I2P integer in bytes.
const MAX_INTEGER_SIZE = 8
/*
[I2P Hash]
Accurate for version 0.9.49
Description
Represents a non-negative integer.
Contents
1 to 8 bytes in network byte order (big endian) representing an unsigned integer.
*/
// Integer is the represenation of an I2P Integer.
//
// https://geti2p.net/spec/common-structures#integer
type Integer []byte
// Bytes returns the raw []byte content of an Integer.
func (i Integer) Bytes() []byte {
return i[:]
}
// Int returns the Date as a Go integer
func (i Integer) Int() int {
return intFromBytes(i.Bytes())
}
// ReadInteger returns an Integer from a []byte of specified length.
// The remaining bytes after the specified length are also returned.
func ReadInteger(bytes []byte, size int) (Integer, []byte) {
if len(bytes) < size {
return bytes[:size], bytes[len(bytes):]
}
return bytes[:size], bytes[size:]
}
// NewInteger creates a new Integer from []byte using ReadInteger.
// Limits the length of the created Integer to MAX_INTEGER_SIZE.
// Returns a pointer to Integer unlike ReadInteger.
func NewInteger(bytes []byte, size int) (integer *Integer, remainder []byte, err error) {
integerSize := MAX_INTEGER_SIZE
if size < MAX_INTEGER_SIZE {
integerSize = size
}
intBytes := bytes[:integerSize]
remainder = bytes[integerSize:]
i, _ := ReadInteger(intBytes, integerSize)
integer = &i
return
}
// NewIntegerFromInt creates a new Integer from a Go integer of a specified []byte length.
func NewIntegerFromInt(value int, size int) (integer *Integer, err error) {
bytes := make([]byte, MAX_INTEGER_SIZE)
binary.BigEndian.PutUint64(bytes, uint64(value))
integerSize := MAX_INTEGER_SIZE
if size < MAX_INTEGER_SIZE {
integerSize = size
}
objinteger, _, err := NewInteger(bytes[MAX_INTEGER_SIZE-integerSize:], integerSize)
integer = objinteger
return
}
// Interpret a slice of bytes from length 0 to length 8 as a big-endian
// integer and return an int representation.
func intFromBytes(number []byte) (value int) {
num_len := len(number)
if num_len < MAX_INTEGER_SIZE {
number = append(
make([]byte, MAX_INTEGER_SIZE-num_len),
number...,
)
}
value = int(binary.BigEndian.Uint64(number))
return
}

View File

@@ -1,32 +0,0 @@
package data
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestIntegerBigEndian(t *testing.T) {
assert := assert.New(t)
bytes := []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}
integer := Integer(bytes)
assert.Equal(integer.Int(), 1, "Integer() did not parse bytes big endian")
}
func TestWorksWithOneByte(t *testing.T) {
assert := assert.New(t)
integer := Integer([]byte{0x01})
assert.Equal(integer.Int(), 1, "Integer() did not correctly parse single byte slice")
}
func TestIsZeroWithNoData(t *testing.T) {
assert := assert.New(t)
integer := Integer([]byte{})
assert.Equal(integer.Int(), 0, "Integer() did not correctly parse zero length byte slice")
}

View File

@@ -1,233 +0,0 @@
package data
import (
"errors"
"github.com/sirupsen/logrus"
)
/*
[I2P Mapping]
Accurate for version 0.9.49
Description
A set of key/value mappings or properties
Contents
A 2-byte size Integer followed by a series of String=String; pairs
+----+----+----+----+----+----+----+----+
| size |key_string (len + data) | = |
+----+----+----+----+----+----+----+----+
| val_string (len + data) | ; | ...
+----+----+----+----+----+----+----+
size :: Integer
length -> 2 bytes
Total number of bytes that follow
key_string :: String
A string (one byte length followed by UTF-8 encoded characters)
= :: A single byte containing '='
val_string :: String
A string (one byte length followed by UTF-8 encoded characters)
; :: A single byte containing ';'
*/
// Mapping is the represenation of an I2P Mapping.
//
// https://geti2p.net/spec/common-structures#mapping
type Mapping struct {
size *Integer
vals *MappingValues
}
// Values returns the values contained in a Mapping as MappingValues.
func (mapping Mapping) Values() MappingValues {
if mapping.vals == nil {
log.Debug("Mapping values are nil, returning empty MappingValues")
return MappingValues{}
}
log.WithFields(logrus.Fields{
"values_count": len(*mapping.vals),
}).Debug("Retrieved Mapping values")
return *mapping.vals
}
// Data returns a Mapping in its []byte form.
func (mapping *Mapping) Data() []byte {
keyOrValIntegerLength := 1
bytes := mapping.size.Bytes()
for _, pair := range mapping.Values() {
klen, _ := pair[0].Length()
keylen, _ := NewIntegerFromInt(klen, keyOrValIntegerLength)
bytes = append(bytes, keylen.Bytes()...)
bytes = append(bytes, pair[0][1:]...)
bytes = append(bytes, 0x3d)
vlen, _ := pair[1].Length()
vallen, _ := NewIntegerFromInt(vlen, keyOrValIntegerLength)
bytes = append(bytes, vallen.Bytes()...)
bytes = append(bytes, pair[1][1:]...)
bytes = append(bytes, 0x3b)
}
return bytes
}
// HasDuplicateKeys returns true if two keys in a mapping are identical.
func (mapping *Mapping) HasDuplicateKeys() bool {
log.Debug("Checking for duplicate keys in Mapping")
seen_values := make(map[string]bool)
values := mapping.Values()
for _, pair := range values {
key, _ := pair[0].Data()
if _, present := seen_values[key]; present {
log.WithFields(logrus.Fields{
"duplicate_key": key,
}).Warn("Found duplicate key in Mapping")
return true
} else {
seen_values[key] = true
}
}
log.Debug("No duplicate keys found in Mapping")
return false
}
// GoMapToMapping converts a Go map of unformatted strings to *Mapping.
func GoMapToMapping(gomap map[string]string) (mapping *Mapping, err error) {
log.WithFields(logrus.Fields{
"input_map_size": len(gomap),
}).Debug("Converting Go map to Mapping")
map_vals := MappingValues{}
for k, v := range gomap {
key_str, kerr := ToI2PString(k)
if kerr != nil {
log.WithError(kerr).Error("Failed to convert key to I2PString")
err = kerr
return
}
val_str, verr := ToI2PString(v)
if verr != nil {
log.WithError(verr).Error("Failed to convert value to I2PString")
err = verr
return
}
map_vals = append(
map_vals,
[2]I2PString{key_str, val_str},
)
}
mapping = ValuesToMapping(map_vals)
log.WithFields(logrus.Fields{
"mapping_size": len(map_vals),
}).Debug("Successfully converted Go map to Mapping")
return
}
// Check if the string parsing error indicates that the Mapping
// should no longer be parsed.
func stopValueRead(err error) bool {
result := err.Error() == "error parsing string: zero length"
if result {
log.WithError(err).Debug("Stopping value read due to zero length error")
}
return result
}
// Determine if the first byte in a slice of bytes is the provided byte.
func beginsWith(bytes []byte, chr byte) bool {
/*
return len(bytes) != 0 &&
bytes[0] == chr
*/
result := len(bytes) != 0 && bytes[0] == chr
log.WithFields(logrus.Fields{
"bytes_length": len(bytes),
"expected_char": string(chr),
"result": result,
}).Debug("Checked if bytes begin with specific character")
return result
}
// ReadMapping returns Mapping from a []byte.
// The remaining bytes after the specified length are also returned.
// Returns a list of errors that occurred during parsing.
func ReadMapping(bytes []byte) (mapping Mapping, remainder []byte, err []error) {
log.WithFields(logrus.Fields{
"input_length": len(bytes),
}).Debug("Reading Mapping from bytes")
if len(bytes) < 3 {
log.WithFields(logrus.Fields{
"at": "ReadMapping",
"reason": "zero length",
}).Warn("mapping format violation")
e := errors.New("zero length")
err = append(err, e)
return
}
size, remainder, e := NewInteger(bytes, 2)
if e != nil {
log.WithError(e).Error("Failed to read Mapping size")
err = append(err, e)
}
if size.Int() == 0 {
log.Warn("Mapping size is zero")
return
}
mapping.size = size
map_bytes := remainder[:mapping.size.Int()]
remainder = remainder[mapping.size.Int():]
if len(remainder) == 0 {
log.WithFields(logrus.Fields{
"at": "ReadMapping",
"reason": "zero length",
}).Warn("mapping format violation")
e := errors.New("zero length")
err = append(err, e)
}
// TODO: this should take the remainder and the length we already parsed above, as a parameter.
// Like tomorrow morning.
// ReadMappingValues should not attempt to figure out the length of the bytes it's reading over.
vals, _, mappingValueErrs := ReadMappingValues(map_bytes, *mapping.size)
err = append(err, mappingValueErrs...)
mapping.vals = vals
if len(mappingValueErrs) > 0 {
log.WithFields(logrus.Fields{
"at": "ReadMapping",
"reason": "error parsing mapping values",
}).Warn("mapping format violation")
e := errors.New("error parsing mapping values")
err = append(err, e)
}
log.WithFields(logrus.Fields{
"mapping_size": mapping.size.Int(),
"values_count": len(*mapping.vals),
"remainder_length": len(remainder),
"error_count": len(err),
}).Debug("Finished reading Mapping")
return
}
// NewMapping creates a new *Mapping from []byte using ReadMapping.
// Returns a pointer to Mapping unlike ReadMapping.
func NewMapping(bytes []byte) (values *Mapping, remainder []byte, err []error) {
log.WithFields(logrus.Fields{
"input_length": len(bytes),
}).Debug("Creating new Mapping")
objvalues, remainder, err := ReadMapping(bytes)
values = &objvalues
log.WithFields(logrus.Fields{
"values_count": len(values.Values()),
"remainder_length": len(remainder),
"error_count": len(err),
}).Debug("Finished creating new Mapping")
return
}

View File

@@ -1,192 +0,0 @@
package data
import (
"bytes"
"errors"
"testing"
"github.com/stretchr/testify/assert"
)
func TestValuesExclusesPairWithBadData(t *testing.T) {
assert := assert.New(t)
bad_key, _, errs := NewMapping([]byte{0x00, 0x0c, 0x01, 0x61, 0x3d, 0x01, 0x62, 0x3b, 0x00})
values := bad_key.Values()
e := WrapErrors(errs)
t.Log(e)
assert.NotNil(errs, "Values() did not return errors when some values had bad key")
if assert.Equal(1, len(values), "Values() did not return valid values when some values had bad key") {
k := values[0][0]
key, _ := k.Data()
v := values[0][1]
val, _ := v.Data()
assert.Equal(key, "a", "Values() returned by data with invalid key contains incorrect present key")
assert.Equal(val, "b", "Values() returned by data with invalid key contains incorrect present key")
}
}
func TestValuesWarnsMissingData(t *testing.T) {
assert := assert.New(t)
_, _, errs := NewMapping([]byte{0x00, 0x06, 0x01, 0x61, 0x3d, 0x01, 0x62})
if assert.Equal(2, len(errs), "Values() reported wrong error count when mapping had missing data") {
assert.Equal(errs[0].Error(), "warning parsing mapping: mapping length exceeds provided data")
}
}
func TestValuesWarnsExtraData(t *testing.T) {
assert := assert.New(t)
mapping, _, errs := NewMapping([]byte{0x00, 0x06, 0x01, 0x61, 0x3d, 0x01, 0x62, 0x3b, 0x00})
values := mapping.Values()
key, kerr := values[0][0].Data()
val, verr := values[0][1].Data()
assert.Nil(kerr)
assert.Nil(verr)
assert.Equal(key, "a", "Values() did not return key in valid data")
assert.Equal(val, "b", "Values() did not return value in valid data")
if assert.Equal(2, len(errs), "Values() reported wrong error count when mapping had extra data") {
assert.Equal("warning parsing mapping: data exists beyond length of mapping", errs[0].Error(), "correct error message should be returned")
}
}
func TestValuesEnforcesEqualDelimitor(t *testing.T) {
assert := assert.New(t)
mapping, _, errs := NewMapping([]byte{0x00, 0x06, 0x01, 0x61, 0x30, 0x01, 0x62, 0x3b})
values := mapping.Values()
if assert.Equal(2, len(errs), "Values() reported wrong error count when mapping had = format error") {
assert.Equal("mapping format violation, expected =", errs[0].Error(), "correct error message should be returned")
}
assert.Equal(0, len(values), "Values() not empty with invalid data due to = format error")
}
func TestValuesEnforcedSemicolonDelimitor(t *testing.T) {
assert := assert.New(t)
mapping, _, errs := NewMapping([]byte{0x00, 0x06, 0x01, 0x61, 0x3d, 0x01, 0x62, 0x30})
values := mapping.Values()
if assert.Equal(2, len(errs), "Values() reported wrong error count when mapping had ; format error") {
assert.Equal("mapping format violation, expected ;", errs[0].Error(), "correct error message should be returned")
}
assert.Equal(0, len(values), "Values() not empty with invalid data due to ; format error")
}
func TestValuesReturnsValues(t *testing.T) {
assert := assert.New(t)
mapping, _, errs := NewMapping([]byte{0x00, 0x06, 0x01, 0x61, 0x3d, 0x01, 0x62, 0x3b})
values := mapping.Values()
key, kerr := values[0][0].Data()
val, verr := values[0][1].Data()
assert.Nil(errs, "Values() returned a errors with parsing valid data")
assert.Nil(kerr)
assert.Nil(verr)
assert.Equal("a", key, "Values() did not return key in valid data")
assert.Equal("b", val, "Values() did not return value in valid data")
}
func TestHasDuplicateKeysTrueWhenDuplicates(t *testing.T) {
assert := assert.New(t)
dups, _, _ := NewMapping([]byte{0x00, 0x0c, 0x01, 0x61, 0x3d, 0x01, 0x62, 0x3b, 0x01, 0x61, 0x3d, 0x01, 0x62, 0x3b})
assert.Equal(true, dups.HasDuplicateKeys(), "HasDuplicateKeys() did not report true when duplicate keys present")
}
func TestHasDuplicateKeysFalseWithoutDuplicates(t *testing.T) {
assert := assert.New(t)
mapping, _, _ := NewMapping([]byte{0x00, 0x06, 0x01, 0x61, 0x3d, 0x01, 0x62, 0x3b})
assert.Equal(false, mapping.HasDuplicateKeys(), "HasDuplicateKeys() did not report false when no duplicate keys present")
}
func TestReadMappingHasDuplicateKeys(t *testing.T) {
assert := assert.New(t)
_, _, errs := NewMapping([]byte{0x00, 0x0c, 0x01, 0x61, 0x3d, 0x01, 0x62, 0x3b, 0x01, 0x61, 0x3d, 0x01, 0x62, 0x3b})
assert.Equal("mapping format violation, duplicate key in mapping", errs[0].Error(), "ReadMapping should throw an error when duplicate keys are present.")
}
func TestGoMapToMappingProducesCorrectMapping(t *testing.T) {
assert := assert.New(t)
gomap := map[string]string{"a": "b"}
mapping, err := GoMapToMapping(gomap)
assert.Nil(err, "GoMapToMapping() returned error with valid data")
expected := []byte{0x00, 0x06, 0x01, 0x61, 0x3d, 0x01, 0x62, 0x3b}
if bytes.Compare(mapping.Data(), expected) != 0 {
t.Fatal("GoMapToMapping did not produce correct Mapping", mapping, expected)
}
}
func TestFullGoMapToMappingProducesCorrectMapping(t *testing.T) {
assert := assert.New(t)
gomap := map[string]string{
"a": "b",
"c": "d",
}
mapping, err := GoMapToMapping(gomap)
assert.Nil(err, "GoMapToMapping() returned error with valid data")
expected := []byte{0x00, 0x0c, 0x01, 0x61, 0x3d, 0x01, 0x62, 0x3b, 0x01, 0x63, 0x3d, 0x01, 0x64, 0x3b}
if bytes.Compare(mapping.Data(), expected) != 0 {
t.Fatal("GoMapToMapping did not produce correct Mapping", mapping, expected)
}
}
func TestStopValueReadTrueWhenCorrectErr(t *testing.T) {
assert := assert.New(t)
status := stopValueRead(errors.New("error parsing string: zero length"))
assert.Equal(true, status, "stopValueRead() did not return true when String error found")
}
func TestStopValueReadFalseWhenWrongErr(t *testing.T) {
assert := assert.New(t)
status := stopValueRead(errors.New("something else"))
assert.Equal(false, status, "stopValueRead() did not return false when non String error found")
}
func TestBeginsWithCorrectWhenTrue(t *testing.T) {
assert := assert.New(t)
slice := []byte{0x41}
assert.Equal(true, beginsWith(slice, 0x41), "beginsWith() did not return true when correct")
}
func TestBeginsWithCorrectWhenFalse(t *testing.T) {
assert := assert.New(t)
slice := []byte{0x00}
assert.Equal(false, beginsWith(slice, 0x41), "beginsWith() did not false when incorrect")
}
func TestBeginsWithCorrectWhenNil(t *testing.T) {
assert := assert.New(t)
slice := make([]byte, 0)
assert.Equal(false, beginsWith(slice, 0x41), "beginsWith() did not return false on empty slice")
}

View File

@@ -1,222 +0,0 @@
package data
import (
"errors"
"sort"
"github.com/sirupsen/logrus"
)
// MappingValues represents the parsed key value pairs inside of an I2P Mapping.
type MappingValues [][2]I2PString
func (m MappingValues) Get(key I2PString) I2PString {
keyBytes, _ := key.Data()
log.WithFields(logrus.Fields{
"key": string(keyBytes),
}).Debug("Searching for key in MappingValues")
for _, pair := range m {
kb, _ := pair[0][0:].Data()
if kb == keyBytes {
log.WithFields(logrus.Fields{
"key": string(keyBytes),
"value": string(pair[1][1:]),
}).Debug("Found matching key in MappingValues")
return pair[1]
}
}
log.WithFields(logrus.Fields{
"key": string(keyBytes),
}).Debug("Key not found in MappingValues")
return nil
}
// ValuesToMapping creates a *Mapping using MappingValues.
// The values are sorted in the order defined in mappingOrder.
func ValuesToMapping(values MappingValues) *Mapping {
// Default length to 2 * len
// 1 byte for ;
// 1 byte for =
log.WithFields(logrus.Fields{
"values_count": len(values),
}).Debug("Converting MappingValues to Mapping")
baseLength := 2 * len(values)
for _, mappingVals := range values {
for _, keyOrVal := range mappingVals {
baseLength += len(keyOrVal)
}
}
log.WithFields(logrus.Fields{
"mapping_size": baseLength,
}).Debug("Created Mapping from MappingValues")
mappingSize, _ := NewIntegerFromInt(baseLength, 2)
return &Mapping{
size: mappingSize,
vals: &values,
}
}
// I2P Mappings require consistent order in some cases for cryptographic signing, and sorting
// by keys. The Mapping is sorted lexographically by keys. Duplicate keys are allowed in general,
// but in implementations where they must be sorted like I2CP SessionConfig duplicate keys are not allowed.
// In practice routers do not seem to allow duplicate keys.
func mappingOrder(values MappingValues) {
sort.SliceStable(values, func(i, j int) bool {
// Lexographic sort on keys only
data1, _ := values[i][0].Data()
data2, _ := values[j][0].Data()
return data1 < data2
})
}
// ReadMappingValues returns *MappingValues from a []byte.
// The remaining bytes after the specified length are also returned.
// Returns a list of errors that occurred during parsing.
func ReadMappingValues(remainder []byte, map_length Integer) (values *MappingValues, remainder_bytes []byte, errs []error) {
// mapping := remainder
// var remainder = mapping
// var err error
log.WithFields(logrus.Fields{
"input_length": len(remainder),
"map_length": map_length.Int(),
}).Debug("Reading MappingValues")
if remainder == nil || len(remainder) < 1 {
log.WithFields(logrus.Fields{
"at": "(Mapping) Values",
"reason": "data shorter than expected",
}).Error("mapping contained no data")
errs = []error{errors.New("mapping contained no data")}
return
}
map_values := make(MappingValues, 0)
int_map_length := map_length.Int()
mapping_len := len(remainder)
if mapping_len > int_map_length {
log.WithFields(logrus.Fields{
"at": "(Mapping) Values",
"mapping_bytes_length": mapping_len,
"mapping_length_field": int_map_length,
"reason": "data longer than expected",
}).Warn("mapping format warning")
errs = append(errs, errors.New("warning parsing mapping: data exists beyond length of mapping"))
} else if int_map_length > mapping_len {
log.WithFields(logrus.Fields{
"at": "(Mapping) Values",
"mapping_bytes_length": mapping_len,
"mapping_length_field": int_map_length,
"reason": "data shorter than expected",
}).Warn("mapping format warning")
errs = append(errs, errors.New("warning parsing mapping: mapping length exceeds provided data"))
}
encounteredKeysMap := map[string]bool{}
// pop off length bytes before parsing kv pairs
// remainder = remainder[2:]
for {
// Read a key, breaking on fatal errors
// and appending warnings
// Minimum byte length required for another KV pair.
// Two bytes for each string length
// At least 1 byte per string
// One byte for =
// One byte for ;
if len(remainder) < 6 {
// Not returning an error here as the issue is already flagged by mapping length being wrong.
log.WithFields(logrus.Fields{
"at": "(Mapping) Values",
"reason": "mapping format violation",
}).Warn("mapping format violation, too few bytes for a kv pair")
break
}
key_str, more, err := ReadI2PString(remainder)
if err != nil {
if stopValueRead(err) {
errs = append(errs, err)
// return
}
}
// overwriting remainder with more as another var to prevent memory weirdness in loops
remainder = more
// log.Printf("(MAPPING VALUES DEBUG) Remainder: %s\n", remainder)
// Check if key has already been encountered in this mapping
keyBytes, _ := key_str.Data()
keyAsString := string(keyBytes)
_, ok := encounteredKeysMap[keyAsString]
if ok {
log.WithFields(logrus.Fields{
"at": "(Mapping) Values",
"reason": "duplicate key in mapping",
"key": string(key_str),
}).Error("mapping format violation")
log.Printf("DUPE: %s", key_str)
errs = append(errs, errors.New("mapping format violation, duplicate key in mapping"))
// Based on other implementations this does not seem to happen often?
// Java throws an exception in this case, the base object is a Hashmap so the value is overwritten and an exception is thrown.
// i2pd as far as I can tell just overwrites the original value
// Continue on, we can check if the Mapping contains duplicate keys later.
}
if !beginsWith(remainder, 0x3d) {
log.WithFields(logrus.Fields{
"at": "(Mapping) Values",
"reason": "expected =",
"value:": string(remainder),
}).Warn("mapping format violation")
errs = append(errs, errors.New("mapping format violation, expected ="))
log.Printf("ERRVAL: %s", remainder)
break
} else {
remainder = remainder[1:]
}
// Read a value, breaking on fatal errors
// and appending warnings
val_str, more, err := ReadI2PString(remainder)
if err != nil {
if stopValueRead(err) {
errs = append(errs, err)
// return
}
}
// overwriting remainder with more as another var to prevent memory weirdness in loops
remainder = more
// log.Printf("(MAPPING VALUES DEBUG) Remainder: %s\n", remainder)
// log.Printf("(MAPPING VALUES DEBUG) String: value: %s", val_str)
if !beginsWith(remainder, 0x3b) {
log.WithFields(logrus.Fields{
"at": "(Mapping) Values",
"reason": "expected ;",
"value:": string(remainder),
}).Warn("mapping format violation")
errs = append(errs, errors.New("mapping format violation, expected ;"))
break
} else {
remainder = remainder[1:]
}
// Append the key-value pair and break if there is no more data to read
map_values = append(map_values, [2]I2PString{key_str, val_str})
if len(remainder) == 0 {
break
}
// Store the encountered key with arbitrary data
encounteredKeysMap[keyAsString] = true
}
values = &map_values
log.WithFields(logrus.Fields{
"values_count": len(map_values),
"remainder_length": len(remainder_bytes),
"error_count": len(errs),
}).Debug("Finished reading MappingValues")
return
}

View File

@@ -1,47 +0,0 @@
package data
import (
"fmt"
"testing"
)
func TestMappingOrderSortsValuesThenKeys(t *testing.T) {
a, _ := ToI2PString("a")
b, _ := ToI2PString("b")
aa, _ := ToI2PString("aa")
ab, _ := ToI2PString("ab")
ac, _ := ToI2PString("ac")
values := MappingValues{
[2]I2PString{b, b},
[2]I2PString{ac, a},
[2]I2PString{ab, b},
[2]I2PString{aa, a},
[2]I2PString{a, a},
}
mappingOrder(values)
for i, pair := range values {
key, _ := pair[0].Data()
switch i {
case 0:
if !(key == "a") {
t.Fatal(fmt.Sprintf("mappingOrder expected key a, got %s at index", key), i)
}
case 1:
if !(key == "aa") {
t.Fatal(fmt.Sprintf("mappingOrder expected key aa, got %s at index", key), i)
}
case 2:
if !(key == "ab") {
t.Fatal(fmt.Sprintf("mappingOrder expected key ab, got %s at index", key), i)
}
case 3:
if !(key == "ac") {
t.Fatal(fmt.Sprintf("mappingOrder expected key ac, got %s at index", key), i)
}
case 4:
if !(key == "b") {
t.Fatal(fmt.Sprintf("mappingOrder expected key b, got %s at index", key), i)
}
}
}
}

View File

@@ -1,180 +0,0 @@
package data
import (
"errors"
"fmt"
"github.com/sirupsen/logrus"
)
// STRING_MAX_SIZE is the maximum number of bytes that can be stored in an I2P string
const STRING_MAX_SIZE = 255
/*
[I2P String]
Accurate for version 0.9.49
Description
Represents a UTF-8 encoded string.
Contents
1 or more bytes where the first byte is the number of bytes (not characters!) in the string
and the remaining 0-255 bytes are the non-null terminated UTF-8 encoded character array.
Length limit is 255 bytes (not characters). Length may be 0.
*/
// I2PString is the represenation of an I2P String.
//
// https://geti2p.net/spec/common-structures#string
type I2PString []byte
// Length returns the length specified in the first byte.
// Returns error if the specified does not match the actual length or the string is otherwise invalid.
func (str I2PString) Length() (length int, err error) {
if len(str) == 0 {
log.WithFields(logrus.Fields{
"at": "(I2PString) Length",
"reason": "no data",
}).Error("error parsing string")
err = errors.New("error parsing string: zero length")
return
}
l, _, err := NewInteger(str[:], 1)
if err != nil {
log.WithError(err).Error("Failed to create Integer from I2PString")
return l.Int(), err
}
length = l.Int()
str_len := len(str)
if length > str_len {
/*log.WithFields(log.Fields{
"at": "(I2PString) Length",
"string_bytes_length": str_len,
"string_length_field": length,
"data": string(str),
"reason": "data less than specified by length",
}).Error("string format warning")*/
log.WithFields(logrus.Fields{
"at": "(I2PString) Length",
"string_bytes_length": str_len,
"string_length_field": length,
"reason": "data less than specified by length",
}).Warn("string format warning")
err = errors.New("string parsing warning: string data is shorter than specified by length")
}
return
}
// Data returns the I2PString content as a string trimmed to the specified length and not including the length byte.
// Returns error encountered by Length.
func (str I2PString) Data() (data string, err error) {
length, err := str.Length()
if err != nil {
switch err.Error() {
case "error parsing string: zero length":
log.WithError(err).Warn("Zero length I2PString")
return
case "string parsing warning: string data is shorter than specified by length":
log.WithError(err).Warn("I2PString data shorter than specified length")
if is, e := ToI2PString(string(str[:])); e != nil {
log.WithError(e).Error("Failed to convert short I2PString")
return "", e
} else {
return is.Data()
}
case "string parsing warning: string contains data beyond length":
log.WithError(err).Warn("I2PString contains data beyond specified length")
data = string(str[1:])
return
}
}
if length == 0 {
log.Debug("I2PString is empty")
return
}
data = string(str[1 : length+1])
log.WithFields(logrus.Fields{
"data_length": len(data),
}).Debug("Retrieved I2PString data")
return
}
// ToI2PString converts a Go string to an I2PString.
// Returns error if the string exceeds STRING_MAX_SIZE.
func ToI2PString(data string) (str I2PString, err error) {
log.WithFields(logrus.Fields{
"input_length": len(data),
}).Debug("Converting string to I2PString")
data_len := len(data)
if data_len > STRING_MAX_SIZE {
log.WithFields(logrus.Fields{
"at": "ToI2PI2PString",
"string_len": data_len,
"max_len": STRING_MAX_SIZE,
"reason": "too much data",
}).Error("cannot create I2P string")
err = errors.New("cannot store that much data in I2P string")
return
}
i2p_string := []byte{byte(data_len)}
i2p_string = append(i2p_string, []byte(data)...)
str = I2PString(i2p_string)
log.WithFields(logrus.Fields{
"i2pstring_length": len(str),
}).Debug("Successfully converted string to I2PString")
return
}
//
// Read a string from a slice of bytes, returning any extra data on the end
// of the slice and any errors encountered parsing the I2PString.
//
// ReadI2PString returns I2PString from a []byte.
// The remaining bytes after the specified length are also returned.
// Returns a list of errors that occurred during parsing.
func ReadI2PString(data []byte) (str I2PString, remainder []byte, err error) {
if len(data) == 0 {
err = errors.New("data slice is empty")
log.WithError(err).Error("Passed data with len == 0")
return
}
log.WithFields(logrus.Fields{
"input_length": len(data),
}).Debug("Reading I2PString from bytes")
length, _, err := NewInteger(data, 1)
if err != nil {
log.WithError(err).Error("Failed to read I2PString length")
return
}
data_len := length.Int() + 1
if data_len > len(data) {
err = fmt.Errorf("I2PString length %d exceeds available data %d", data_len-1, len(data)-1)
log.WithError(err).Error("Failed to read I2PString")
return
}
str = data[:data_len]
remainder = data[data_len:]
l, err := str.Length()
if l != data_len-1 {
err = fmt.Errorf("error reading I2P string, length does not match data")
log.WithFields(logrus.Fields{
"expected_length": data_len - 1,
"actual_length": l,
}).Error("I2PString length mismatch")
return
}
log.WithFields(logrus.Fields{
"string_length": l,
"remainder_length": len(remainder),
}).Debug("Successfully read I2PString from bytes")
return
}
// NewI2PString creates a new *I2PString from []byte using ReadI2PString.
// Returns a pointer to I2PString unlike ReadI2PString.
/*func NewI2PString(data []byte) (str *I2PString, remainder []byte, err error) {
objstr, remainder, err := ReadI2PString(data)
str = &objstr
return
}*/

View File

@@ -1,149 +0,0 @@
package data
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestStringReportsCorrectLength(t *testing.T) {
assert := assert.New(t)
str_len, err := I2PString([]byte{0x02, 0x00, 0x00}).Length()
assert.Equal(str_len, 2, "Length() did not report correct length")
assert.Nil(err, "Length() reported an error on valid string")
}
func TestI2PStringReportsLengthZeroError(t *testing.T) {
assert := assert.New(t)
str_len, err := I2PString(make([]byte, 0)).Length()
assert.Equal(str_len, 0, "Length() reported non-zero length on empty slice")
if assert.NotNil(err) {
assert.Equal(err.Error(), "error parsing string: zero length", "correct error message should be returned")
}
}
func TestI2PStringReportsExtraDataError(t *testing.T) {
assert := assert.New(t)
str_len, err := I2PString([]byte{0x01, 0x00, 0x00}).Length()
assert.Equal(str_len, 1, "Length() reported wrong size when extra data present")
if assert.NotNil(err) {
assert.Equal(err.Error(), "string parsing warning: string contains data beyond length", "correct error message should be returned")
}
}
func TestI2PStringDataReportsLengthZeroError(t *testing.T) {
assert := assert.New(t)
str_len, err := I2PString([]byte{0x01}).Length()
assert.Equal(str_len, 1, "Length() reported wrong size with missing data")
if assert.NotNil(err) {
assert.Equal(err.Error(), "string parsing warning: string data is shorter than specified by length", "correct error message should be returned")
}
}
func TestI2PStringDataReportsExtraDataError(t *testing.T) {
assert := assert.New(t)
data, err := I2PString([]byte{0x01, 0x00, 0x01}).Data()
data_len := len(data)
assert.Equal(data_len, 1, "Data() reported wrong size on string with extra data")
if assert.NotNil(err) {
assert.Equal(err.Error(), "string parsing warning: string contains data beyond length", "correct error message should be returned")
}
}
func TestI2PStringDataEmptyWhenZeroLength(t *testing.T) {
assert := assert.New(t)
data, err := I2PString(make([]byte, 0)).Data()
assert.Equal(len(data), 0, "Data() returned data when none was present:")
if assert.NotNil(err) {
assert.Equal(err.Error(), "error parsing string: zero length", "correct error message should be returned")
}
}
func TestI2PStringDataErrorWhenNonZeroLengthOnly(t *testing.T) {
assert := assert.New(t)
data, err := I2PString([]byte{0x01}).Data()
assert.Equal(len(data), 0, "Data() returned data when only length was present")
if assert.NotNil(err) {
assert.Equal(err.Error(), "string parsing warning: string data is shorter than specified by length", "correct error message should be returned")
}
}
func TestToI2PI2PStringFormatsCorrectly(t *testing.T) {
assert := assert.New(t)
i2p_string, err := ToI2PString(string([]byte{0x08, 0x09}))
assert.Nil(err, "ToI2PString() returned error on valid data")
assert.Equal(2, int(i2p_string[0]), "ToI2PString() did not prepend the correct length")
assert.Equal(8, int(i2p_string[1]), "ToI2PString() did not include string")
assert.Equal(9, int(i2p_string[2]), "ToI2PString() did not include string")
}
func TestToI2PStringReportsOverflows(t *testing.T) {
assert := assert.New(t)
i2p_string, err := ToI2PString(string(make([]byte, 256)))
assert.Equal(len(i2p_string), 0, "ToI2PString() returned data when overflowed")
if assert.NotNil(err) {
assert.Equal(err.Error(), "cannot store that much data in I2P string", "correct error message should be returned")
}
_, err = ToI2PString(string(make([]byte, 255)))
assert.Nil(err, "ToI2PString() reported error with acceptable size")
}
func TestReadStringReadsLength(t *testing.T) {
assert := assert.New(t)
bytes := []byte{0x01, 0x04, 0x06}
str, remainder, err := ReadI2PString(bytes)
assert.Nil(err, "ReadI2PString() returned error reading string with extra data")
assert.Equal(len(str), 2, "ReadI2PString() did not return correct string length")
assert.Equal(1, int(str[0]), "ReadI2PString() did not return correct string")
assert.Equal(4, int(str[1]), "ReadI2PString() did not return correct string")
assert.Equal(len(remainder), 1, "ReadI2PString() did not return correct remainder length")
assert.Equal(6, int(remainder[0]), "ReadI2PString() did not return correct remainder")
}
func TestReadI2PStringErrWhenEmptySlice(t *testing.T) {
assert := assert.New(t)
bytes := make([]byte, 0)
_, _, err := ReadI2PString(bytes)
if assert.NotNil(err) {
assert.Equal(err.Error(), "error parsing string: zero length", "correct error message should be returned")
}
}
func TestReadI2PStringErrWhenDataTooShort(t *testing.T) {
assert := assert.New(t)
short_str := []byte{0x03, 0x01}
str, remainder, err := ReadI2PString(short_str)
if assert.NotNil(err) {
assert.Equal(err.Error(), "string parsing warning: string data is shorter than specified by length", "correct error message should be returned")
}
assert.Equal(len(str), 2, "ReadI2PString() did not return the slice as string when too long")
assert.Equal(3, int(str[0]), "ReadI2PString() did not return the correct partial string")
assert.Equal(1, int(str[1]), "ReadI2PString() did not return the correct partial string")
assert.Equal(len(remainder), 0, "ReadI2PString() returned a remainder when the string data was too short")
}

View File

@@ -1,87 +0,0 @@
// Package destination implements the I2P Destination common data structure
package destination
import (
"strings"
"github.com/go-i2p/go-i2p/lib/util/logger"
"github.com/sirupsen/logrus"
. "github.com/go-i2p/go-i2p/lib/common/keys_and_cert"
"github.com/go-i2p/go-i2p/lib/common/base32"
"github.com/go-i2p/go-i2p/lib/common/base64"
"github.com/go-i2p/go-i2p/lib/crypto"
)
var log = logger.GetGoI2PLogger()
/*
[Destination]
Accurate for version 0.9.49
Description
A Destination defines a particular endpoint to which messages can be directed for secure delivery.
Contents
Identical to KeysAndCert.
*/
// Destination is the represenation of an I2P Destination.
//
// https://geti2p.net/spec/common-structures#destination
type Destination struct {
KeysAndCert
}
// Base32Address returns the I2P base32 address for this Destination.
func (destination Destination) Base32Address() (str string) {
log.Debug("Generating Base32 address for Destination")
cert := destination.KeysAndCert.Certificate()
dest := cert.Bytes()
hash := crypto.SHA256(dest)
str = strings.Trim(base32.EncodeToString(hash[:]), "=")
str = str + ".b32.i2p"
log.WithFields(logrus.Fields{
"base32_address": str,
}).Debug("Generated Base32 address for Destination")
return
}
// Base64 returns the I2P base64 address for this Destination.
func (destination Destination) Base64() string {
log.Debug("Generating Base64 address for Destination")
cert := destination.KeysAndCert.Certificate()
dest := cert.Bytes()
base64Address := base64.EncodeToString(dest)
log.WithFields(logrus.Fields{
"base64_address_length": len(base64Address),
}).Debug("Generated Base64 address for Destination")
return base64Address
}
// ReadDestination returns Destination from a []byte.
// The remaining bytes after the specified length are also returned.
// Returns a list of errors that occurred during parsing.
func ReadDestination(data []byte) (destination Destination, remainder []byte, err error) {
log.WithFields(logrus.Fields{
"input_length": len(data),
}).Debug("Reading Destination from bytes")
keys_and_cert, remainder, err := ReadKeysAndCert(data)
destination = Destination{
keys_and_cert,
}
log.WithFields(logrus.Fields{
"remainder_length": len(remainder),
}).Debug("Successfully read Destination from bytes")
return
}

View File

@@ -1,42 +0,0 @@
# destination
--
import "github.com/go-i2p/go-i2p/lib/common/destination"
Package destination implements the I2P Destination common data structure
## Usage
#### type Destination
```go
type Destination struct {
KeysAndCert
}
```
Destination is the represenation of an I2P Destination.
https://geti2p.net/spec/common-structures#destination
#### func ReadDestination
```go
func ReadDestination(data []byte) (destination Destination, remainder []byte, err error)
```
ReadDestination returns Destination from a []byte. The remaining bytes after the
specified length are also returned. Returns a list of errors that occurred
during parsing.
#### func (Destination) Base32Address
```go
func (destination Destination) Base32Address() (str string)
```
Base32Address returns the I2P base32 address for this Destination.
#### func (Destination) Base64
```go
func (destination Destination) Base64() string
```
Base64 returns the I2P base64 address for this Destination.

View File

@@ -1,13 +0,0 @@
FROM golang
RUN apt-get update && \
apt-get upgrade -y
RUN go get github.com/dvyukov/go-fuzz/go-fuzz
RUN go get github.com/dvyukov/go-fuzz/go-fuzz-build
RUN go get github.com/hkparker/go-i2p
RUN go get github.com/ddollar/forego
WORKDIR /go/src/github.com/hkparker/go-i2p
ENTRYPOINT ["make", "fuzz"]

View File

@@ -1,8 +0,0 @@
fuzz:
go-fuzz-build -o keys_and_cert/exportable-fuzz.zip github.com/hkparker/go-i2p/lib/common/fuzz/keys_and_cert
go-fuzz-build -o certificate/exportable-fuzz.zip github.com/hkparker/go-i2p/lib/common/fuzz/certificate
go-fuzz-build -o destination/exportable-fuzz.zip github.com/hkparker/go-i2p/lib/common/fuzz/destination
go-fuzz-build -o router_address/exportable-fuzz.zip github.com/hkparker/go-i2p/lib/common/fuzz/router_address
go-fuzz-build -o router_identity/exportable-fuzz.zip github.com/hkparker/go-i2p/lib/common/fuzz/router_identity
go-fuzz-build -o string/exportable-fuzz.zip github.com/hkparker/go-i2p/lib/common/fuzz/string
forego start

View File

@@ -1,6 +0,0 @@
keys_and_cert: go-fuzz -bin=keys_and_cert/exportable-fuzz.zip -workdir=lib/common/fuzz/keys_and_cert -procs=2
certificate: go-fuzz -bin=certificate/exportable-fuzz.zip -workdir=lib/common/fuzz/certificate -procs=2
destination: go-fuzz -bin=destination/exportable-fuzz.zip -workdir=lib/common/fuzz/destination -procs=2
router_address: go-fuzz -bin=router_address/exportable-fuzz.zip -workdir=lib/common/fuzz/router_address -procs=2
router_identity: go-fuzz -bin=router_identity/exportable-fuzz.zip -workdir=lib/common/fuzz/router_identity -procs=2
string: go-fuzz -bin=string/exportable-fuzz.zip -workdir=lib/common/fuzz/string -procs=2

View File

@@ -1 +0,0 @@


View File

@@ -1,12 +0,0 @@
# exportable
--
import "github.com/go-i2p/go-i2p/lib/common/fuzz/certificate"
## Usage
#### func Fuzz
```go
func Fuzz(data []byte) int
```

View File

@@ -1,11 +0,0 @@
package exportable
import common "github.com/go-i2p/go-i2p/lib/common/certificate"
func Fuzz(data []byte) int {
cert, _, _ := common.ReadCertificate(data)
cert.Data()
cert.Length()
cert.Type()
return 0
}

Some files were not shown because too many files have changed in this diff Show More