mirror of
https://github.com/go-i2p/go-i2p.git
synced 2025-08-19 09:45:28 -04:00
Compare commits
452 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
61008ce988 | ||
![]() |
294cd52343 | ||
![]() |
322b431e8f | ||
![]() |
79df514a2f | ||
![]() |
36762c61c5 | ||
![]() |
a8ac47431e | ||
![]() |
bd947ec2ca | ||
![]() |
61700c8a05 | ||
![]() |
d6b8918a14 | ||
![]() |
43aa3a72a6 | ||
![]() |
5d04d24bc5 | ||
![]() |
f168794ca3 | ||
![]() |
9c9f19b904 | ||
![]() |
f176d4a97f | ||
![]() |
e89876903f | ||
![]() |
c6f8bf6447 | ||
![]() |
32075c20c7 | ||
![]() |
4862c0314c | ||
![]() |
7f57cebd3f | ||
![]() |
c418914e95 | ||
![]() |
0e12cbfb70 | ||
![]() |
a8a3d61a75 | ||
![]() |
96f7958543 | ||
![]() |
230646f34d | ||
![]() |
3b06be5eca | ||
![]() |
f4a89c74e0 | ||
![]() |
1529f18fa1 | ||
![]() |
3be24a6a42 | ||
![]() |
e4e8631b0e | ||
![]() |
2a3cfcfac3 | ||
![]() |
e1756bdf39 | ||
![]() |
975970152e | ||
![]() |
bd6ce7b25f | ||
![]() |
7470d80def | ||
![]() |
4997ceebae | ||
![]() |
637293f13e | ||
![]() |
2d083bfe90 | ||
![]() |
29388af798 | ||
![]() |
f9127c0998 | ||
![]() |
b9e73d816d | ||
![]() |
4edc7b392d | ||
![]() |
d7888ac9be | ||
![]() |
68408bb48e | ||
![]() |
4715b76ade | ||
![]() |
ac7e369b6a | ||
![]() |
7d51d83b40 | ||
![]() |
89c82cb2fe | ||
![]() |
808f7d6fdf | ||
![]() |
537ab808f8 | ||
![]() |
b41bb0eef8 | ||
![]() |
8787fea069 | ||
![]() |
fc9734d43d | ||
![]() |
0a262d5780 | ||
![]() |
2f233e931d | ||
![]() |
e9991099b7 | ||
![]() |
761dcb5f98 | ||
![]() |
f68d9b5606 | ||
![]() |
9fd3400585 | ||
![]() |
c85822163b | ||
![]() |
e2fdb7c4e0 | ||
![]() |
1babf06091 | ||
![]() |
62e565b36c | ||
![]() |
c7a17eac86 | ||
![]() |
89e53fdb9f | ||
![]() |
ebdd1ae0aa | ||
![]() |
b65f6c2682 | ||
![]() |
14a0e56f6a | ||
![]() |
4a89c14734 | ||
![]() |
09fe22178d | ||
![]() |
ef156f6944 | ||
![]() |
a4acb01be9 | ||
![]() |
dd116095aa | ||
![]() |
1922f3a0ab | ||
![]() |
2a28c8ee01 | ||
![]() |
9cb4af8f06 | ||
![]() |
56faebd746 | ||
![]() |
8b035711b6 | ||
![]() |
c93b258844 | ||
![]() |
2df5d23528 | ||
![]() |
98ea3d55c4 | ||
![]() |
b5454a4317 | ||
![]() |
83502face7 | ||
![]() |
c99b15ba7f | ||
![]() |
8e73c36922 | ||
![]() |
89b1995593 | ||
![]() |
4577408d6d | ||
![]() |
e7e26ae021 | ||
![]() |
1d1568de71 | ||
![]() |
b21a6cee9e | ||
![]() |
35b47969b0 | ||
![]() |
816df5642c | ||
![]() |
1bd439f989 | ||
![]() |
6158eb68f3 | ||
![]() |
03eeeab781 | ||
![]() |
0099392f6d | ||
![]() |
a09f155835 | ||
![]() |
fa561fc431 | ||
![]() |
c5125c1bfd | ||
![]() |
9e1bac3ff1 | ||
![]() |
b4e1f3cfdf | ||
![]() |
d4ff0e373c | ||
![]() |
0c9c8270a5 | ||
![]() |
f2bacc5018 | ||
![]() |
94691f1e75 | ||
![]() |
8c4f718601 | ||
![]() |
9a0d164276 | ||
![]() |
f3f5d744ed | ||
![]() |
3b9fb603f4 | ||
![]() |
29d5a20216 | ||
![]() |
3c252e22cd | ||
![]() |
dcb11d1fda | ||
![]() |
a721856688 | ||
![]() |
b66c5813cb | ||
![]() |
441549743d | ||
![]() |
30f84713ea | ||
![]() |
6057677956 | ||
![]() |
c026b9a4a5 | ||
![]() |
9c6cfc14e5 | ||
![]() |
4533c2fd92 | ||
![]() |
89e51820f1 | ||
![]() |
17a789bed7 | ||
![]() |
d236f19f81 | ||
![]() |
d0b81d9ce9 | ||
![]() |
06cf6b41b4 | ||
![]() |
ac8349d083 | ||
![]() |
45296be6d3 | ||
![]() |
1f25f0c9b3 | ||
![]() |
d1a708a594 | ||
![]() |
b153bfc050 | ||
![]() |
d401b06c0f | ||
![]() |
9091834074 | ||
![]() |
8561b3ec69 | ||
![]() |
8aac97351d | ||
![]() |
3142a394aa | ||
![]() |
f2b6d4bc01 | ||
![]() |
fa0a42855c | ||
![]() |
3212cae276 | ||
![]() |
ad7bac666b | ||
![]() |
ba0c89d567 | ||
![]() |
6a64b28bb3 | ||
![]() |
9fa714f648 | ||
![]() |
eda403443d | ||
![]() |
84cc45d3e4 | ||
![]() |
598ee1eb70 | ||
![]() |
bd6edf446d | ||
![]() |
94e43f8aa6 | ||
![]() |
7bdaf6d4ea | ||
![]() |
393263294e | ||
![]() |
55f92bdd8a | ||
![]() |
8ea238f3dd | ||
![]() |
91d8b30495 | ||
![]() |
ea4d126358 | ||
![]() |
f46bd95b68 | ||
![]() |
35eb66084b | ||
![]() |
a9289dd4d3 | ||
![]() |
7f78fdf784 | ||
![]() |
ae4970b3a9 | ||
![]() |
3d6a08a76b | ||
![]() |
18b2afe828 | ||
![]() |
c6867e0b16 | ||
![]() |
d0b4db769e | ||
![]() |
26a9a00b34 | ||
![]() |
99df4c7ce8 | ||
![]() |
b95b0c4fa3 | ||
![]() |
036f9116a5 | ||
![]() |
d97624282e | ||
![]() |
46af6d55ef | ||
![]() |
9591f496eb | ||
![]() |
71fff44d4b | ||
![]() |
6b2f231c36 | ||
![]() |
4eeaf915f0 | ||
![]() |
440b9e8118 | ||
![]() |
8bc5ca162a | ||
![]() |
bd92221d56 | ||
![]() |
22111a6cb7 | ||
![]() |
74d2998e10 | ||
![]() |
0b89baf98b | ||
![]() |
daac1a59b5 | ||
![]() |
6f65a7c068 | ||
![]() |
db91315582 | ||
![]() |
5f3a7f2340 | ||
![]() |
8494da07a7 | ||
![]() |
832e0d9114 | ||
![]() |
8d56d033ae | ||
![]() |
ad22d3e249 | ||
![]() |
f55788e8ab | ||
![]() |
2a4f4d6186 | ||
![]() |
ca1180c57f | ||
![]() |
76c3e5f293 | ||
![]() |
91abe52725 | ||
![]() |
a0ad9e0122 | ||
![]() |
b23edc28d1 | ||
![]() |
b547faf286 | ||
![]() |
a145555bb2 | ||
![]() |
280c877d39 | ||
![]() |
ef4d4658c0 | ||
![]() |
15bf28403e | ||
![]() |
b40c0ab6f9 | ||
![]() |
b952be5e08 | ||
![]() |
aafbf74986 | ||
![]() |
3cdc5676eb | ||
![]() |
d41efdba0e | ||
![]() |
edc436ac39 | ||
![]() |
414b489b37 | ||
![]() |
da875738e4 | ||
![]() |
2a027ebb6c | ||
![]() |
d658dee6de | ||
![]() |
8fde3c9400 | ||
![]() |
9421374384 | ||
![]() |
daad2dcacd | ||
![]() |
5f8dc3f9a2 | ||
![]() |
9cc2e8f410 | ||
![]() |
6ac46aa747 | ||
![]() |
5548b865b4 | ||
![]() |
55245b2aa7 | ||
![]() |
208051f92d | ||
![]() |
8a672ca6ca | ||
![]() |
45def9dd0c | ||
![]() |
cb1da321b9 | ||
![]() |
d291624436 | ||
![]() |
a58f64566f | ||
![]() |
891d915bb2 | ||
![]() |
a0a8704c6c | ||
![]() |
c68acf848e | ||
![]() |
7a6927cf53 | ||
![]() |
37e11ffee1 | ||
![]() |
e15e427f60 | ||
![]() |
f0803a095e | ||
![]() |
bf7e88bec1 | ||
![]() |
065ceeb88f | ||
![]() |
ca4a7a13ea | ||
![]() |
0b0753cac1 | ||
![]() |
40c2c4806c | ||
![]() |
9e3c8bcb98 | ||
![]() |
9b4bf2663d | ||
![]() |
4a6f49d14a | ||
![]() |
5d789973b2 | ||
![]() |
08127861f1 | ||
![]() |
0e6ffd856b | ||
![]() |
10daacbc9b | ||
![]() |
eeb1e215a5 | ||
![]() |
08e599e59a | ||
![]() |
30f5565217 | ||
![]() |
fc3ba17af5 | ||
![]() |
631f8d1850 | ||
![]() |
cc43160bb9 | ||
![]() |
09acf3d23d | ||
![]() |
cbe4af8459 | ||
![]() |
b72ed0a37d | ||
![]() |
07268df720 | ||
![]() |
def8789b77 | ||
![]() |
59c53bc5c1 | ||
![]() |
ee56e0f40f | ||
![]() |
4e2b55ccbe | ||
![]() |
64d90a157c | ||
![]() |
3acff32f17 | ||
![]() |
362513bbe5 | ||
![]() |
c9f3227116 | ||
![]() |
f0702ffba9 | ||
![]() |
11b9018630 | ||
![]() |
f6daa5d9b6 | ||
![]() |
58d1f0d815 | ||
![]() |
62ececf102 | ||
![]() |
1d90db3239 | ||
![]() |
f729bda62d | ||
![]() |
4ad0f97bfe | ||
![]() |
e296441f29 | ||
![]() |
62086c7d04 | ||
![]() |
ddba94d6ae | ||
![]() |
767b91df49 | ||
![]() |
1292098cf0 | ||
![]() |
24bc4c3c17 | ||
![]() |
81eb270351 | ||
![]() |
b6f197cf92 | ||
![]() |
c10d98a3b2 | ||
![]() |
6d16ca5f87 | ||
![]() |
003d6c9ab8 | ||
![]() |
015c4b23e2 | ||
![]() |
e29c3c7abb | ||
![]() |
6f6291a9f6 | ||
![]() |
767864d457 | ||
![]() |
0a98236d85 | ||
![]() |
c1fa63f6ec | ||
![]() |
a75c275b4c | ||
![]() |
d40b3e0cd3 | ||
![]() |
2ee2d77d7c | ||
![]() |
df45c19272 | ||
![]() |
f6894e9064 | ||
![]() |
b36ef65a10 | ||
![]() |
271cf56ded | ||
![]() |
a29fa0bc03 | ||
![]() |
63c48dd3b7 | ||
![]() |
8bec47efd2 | ||
![]() |
69a50e2035 | ||
![]() |
8319444890 | ||
![]() |
b378661e0e | ||
![]() |
f4086e5f68 | ||
![]() |
877fc707c4 | ||
![]() |
98d05e27c8 | ||
![]() |
8c2b952616 | ||
![]() |
4020db8a19 | ||
![]() |
67a02f5d69 | ||
![]() |
ca1280231c | ||
![]() |
02b309df43 | ||
![]() |
a5b3c3f194 | ||
![]() |
0aa7a5554b | ||
![]() |
266a1b71d6 | ||
![]() |
d32f2e78ab | ||
![]() |
9e806bc32e | ||
![]() |
c52112a36f | ||
![]() |
db0fd9f7e9 | ||
![]() |
3ab258cde6 | ||
![]() |
20b9bbd8e4 | ||
![]() |
1fa520613c | ||
![]() |
fb99b98a7e | ||
![]() |
d6b8cd9d4d | ||
![]() |
92e4656774 | ||
![]() |
5f2bfb8d9d | ||
![]() |
9494c226a6 | ||
![]() |
344edc6d41 | ||
![]() |
9eea99b489 | ||
![]() |
c984f94b90 | ||
![]() |
a17f0208dd | ||
![]() |
487815f8f1 | ||
![]() |
24e0baa879 | ||
![]() |
a5d2f0de8c | ||
![]() |
423f616d53 | ||
![]() |
c65048f3c4 | ||
![]() |
39b683dac8 | ||
![]() |
46883f6457 | ||
![]() |
4be55062fc | ||
![]() |
12a3fd4623 | ||
![]() |
80e539930e | ||
![]() |
e58d326d89 | ||
![]() |
e6f84c16f6 | ||
![]() |
971a18de8d | ||
![]() |
833836ae67 | ||
![]() |
3f191db37a | ||
![]() |
6865bae386 | ||
![]() |
f0d9f89ed9 | ||
![]() |
c149eef1de | ||
![]() |
748dc8a66f | ||
![]() |
677aac500e | ||
![]() |
4e06d3d5ed | ||
![]() |
5eaa9cf588 | ||
![]() |
4dbf537e94 | ||
![]() |
882c018c0c | ||
![]() |
5432502852 | ||
![]() |
0ea5743365 | ||
![]() |
a9dc482bda | ||
![]() |
c31d20fec0 | ||
![]() |
647546a374 | ||
![]() |
e468520906 | ||
![]() |
ade80e577c | ||
![]() |
f45d301868 | ||
![]() |
0256908395 | ||
![]() |
3c5aa206d1 | ||
![]() |
a4517cafd7 | ||
![]() |
f4f39ca53c | ||
![]() |
220159476a | ||
![]() |
792cd49208 | ||
![]() |
68051630c0 | ||
![]() |
a3340eb40a | ||
![]() |
465a7787a9 | ||
![]() |
af3bc44dba | ||
![]() |
f850f482cf | ||
![]() |
3f23376d22 | ||
![]() |
aa98589f1c | ||
![]() |
c31e990995 | ||
![]() |
8e97eb5f77 | ||
![]() |
be35267079 | ||
![]() |
013d35b447 | ||
![]() |
e8c9dc17a3 | ||
![]() |
a1d574446b | ||
![]() |
8680acc595 | ||
![]() |
84e3c5accc | ||
![]() |
e772fb5ceb | ||
![]() |
a533cd7ce4 | ||
![]() |
df37d49444 | ||
![]() |
4b2600a065 | ||
![]() |
1c4f937002 | ||
![]() |
5c2b408f65 | ||
![]() |
beb533a09b | ||
![]() |
f022522ad5 | ||
![]() |
2191c40ac6 | ||
![]() |
3bca467f28 | ||
![]() |
a2fd65ee32 | ||
![]() |
b894e8fb17 | ||
![]() |
93a71c7398 | ||
![]() |
b6544ad194 | ||
![]() |
a72b61a886 | ||
![]() |
dda4f90b6f | ||
![]() |
1d1d8126c2 | ||
![]() |
73db39ae50 | ||
![]() |
53e902f491 | ||
![]() |
2f2cd2249c | ||
![]() |
4496c11394 | ||
![]() |
69449a20b5 | ||
![]() |
a7689e801a | ||
![]() |
278bdee277 | ||
![]() |
684e89c957 | ||
![]() |
50fa9fc374 | ||
![]() |
491b25022e | ||
![]() |
677a6b354b | ||
![]() |
9469fd83aa | ||
![]() |
8173ae49e6 | ||
![]() |
2f109d5b4d | ||
![]() |
d7378d7b08 | ||
![]() |
3a51a1229e | ||
![]() |
2b18b2941d | ||
![]() |
1eb29ec4ab | ||
![]() |
d900d7faf8 | ||
![]() |
03c9d60ab9 | ||
![]() |
de2caf499e | ||
![]() |
284dd7287e | ||
![]() |
9f4154ff45 | ||
![]() |
08a0d92742 | ||
![]() |
524526d946 | ||
![]() |
09c7d32797 | ||
![]() |
16961abc96 | ||
![]() |
8fa355f067 | ||
![]() |
0c7a3f0f22 | ||
![]() |
3d535f67a1 | ||
![]() |
bba9350506 | ||
![]() |
cbc0de4e7e | ||
![]() |
310ef07d3c | ||
![]() |
14fc6fc3a8 | ||
![]() |
a3ce9d36c6 | ||
![]() |
58a43cdfaf | ||
![]() |
15a5ca5daf | ||
![]() |
08a41686b6 | ||
![]() |
8318fd8f57 | ||
![]() |
9c0552e236 | ||
![]() |
20b018a708 | ||
![]() |
6c62faa49b | ||
![]() |
a7e31b7833 | ||
![]() |
c09161c824 | ||
![]() |
aca62174e6 | ||
![]() |
bd27f00959 | ||
![]() |
05c4d3d973 | ||
![]() |
40d0ea5ff5 | ||
![]() |
58e8f78c56 | ||
![]() |
65febb5dcf | ||
![]() |
116e22f8da | ||
![]() |
0419665d7b | ||
![]() |
dab108c270 | ||
![]() |
0fcded4c51 | ||
![]() |
7d16b0b257 | ||
![]() |
a689f26d73 | ||
![]() |
fdc34b382e | ||
![]() |
a4ed06e530 | ||
![]() |
6b5ea57cbd |
19
.github/workflows/auto-assign.yml
vendored
Normal file
19
.github/workflows/auto-assign.yml
vendored
Normal 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
60
.github/workflows/page.yml
vendored
Normal 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
62
.github/workflows/tests.yml
vendored
Normal 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
|
5
.gitignore
vendored
5
.gitignore
vendored
@@ -7,3 +7,8 @@
|
|||||||
go-i2p
|
go-i2p
|
||||||
*.exe
|
*.exe
|
||||||
.idea/
|
.idea/
|
||||||
|
router.info
|
||||||
|
log
|
||||||
|
*.gv
|
||||||
|
diff
|
||||||
|
err
|
@@ -1,20 +1,35 @@
|
|||||||
# Contributing
|
# 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
|
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
|
```sh
|
||||||
go get github.com/hkparker/go-i2p
|
# For obtaining, modifying, compiling, and tracking changes to go-i2p, install:
|
||||||
go get github.com/Sirupsen/logrus
|
sudo apt-get install golang-go make git
|
||||||
go get github.com/stretchr/testify/assert
|
# 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
|
## I2P Specifications
|
||||||
|
|
||||||
@@ -26,9 +41,17 @@ The I2P community maintains up-to-date [specifications](https://geti2p.net/spec)
|
|||||||
|
|
||||||
## Conventions
|
## 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
|
#### 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
|
```go
|
||||||
log.WithFields(log.Fields{
|
log.WithFields(log.Fields{
|
||||||
@@ -56,4 +79,4 @@ func TestRouterAddressCountReturnsCorrectCount(t *testing.T) {
|
|||||||
|
|
||||||
## Pull Requests
|
## 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.
|
16
Makefile
16
Makefile
@@ -2,6 +2,8 @@ RELEASE_TAG=0.0.1
|
|||||||
RELEASE_VERSION=${RELEASE_TAG}
|
RELEASE_VERSION=${RELEASE_TAG}
|
||||||
RELEASE_DESCRIPTION=`cat PASTA.md`
|
RELEASE_DESCRIPTION=`cat PASTA.md`
|
||||||
REPO := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
|
REPO := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
|
||||||
|
CGO_ENABLED=0
|
||||||
|
export DEBUG_I2P=debug
|
||||||
|
|
||||||
ifdef GOROOT
|
ifdef GOROOT
|
||||||
GO = $(GOROOT)/bin/go
|
GO = $(GOROOT)/bin/go
|
||||||
@@ -15,19 +17,20 @@ else
|
|||||||
EXE := $(REPO)/go-i2p
|
EXE := $(REPO)/go-i2p
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
#check for gofumpt
|
||||||
|
check_gofumpt:
|
||||||
|
@which gofumpt > /dev/null 2>&1 || (echo "gofumpt is required but not installed. Please install it from https://github.com/mvdan/gofumpt."; exit 1)
|
||||||
|
|
||||||
build: clean $(EXE)
|
build: clean $(EXE)
|
||||||
|
|
||||||
$(EXE):
|
$(EXE):
|
||||||
$(GO) build -v -o $(EXE)
|
$(GO) build --tags netgo,osusergo -v -o $(EXE)
|
||||||
|
|
||||||
test: fmt
|
|
||||||
$(GO) test -vv -failfast ./lib/common/...
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(GO) clean -v
|
$(GO) clean -v
|
||||||
|
|
||||||
fmt:
|
fmt:
|
||||||
find . -name '*.go' -exec gofmt -w -s {} \;
|
find . -name '*.go' -exec gofumpt -w {} \;
|
||||||
|
|
||||||
info:
|
info:
|
||||||
echo "GOROOT: ${GOROOT}"
|
echo "GOROOT: ${GOROOT}"
|
||||||
@@ -36,3 +39,6 @@ info:
|
|||||||
|
|
||||||
release:
|
release:
|
||||||
github-release release -u go-i2p -r go-i2p -n "${RELEASE_VERSION}" -t "${RELEASE_TAG}" -d "${RELEASE_DESCRIPTION}" -p
|
github-release release -u go-i2p -r go-i2p -n "${RELEASE_VERSION}" -t "${RELEASE_TAG}" -d "${RELEASE_DESCRIPTION}" -p
|
||||||
|
|
||||||
|
godoc:
|
||||||
|
./callgraph.sh
|
||||||
|
18
PASTA.md
18
PASTA.md
@@ -1,18 +0,0 @@
|
|||||||
At long last... something useful
|
|
||||||
================================
|
|
||||||
|
|
||||||
It's been 2 years of me mostly not having time to work on go-i2p itself since my last update.
|
|
||||||
However, after much waiting, this library is actually **useful** for something.
|
|
||||||
It is now being used in the `reseed-tools` application to examine RouterInfos prior to including them in reseed bundles.
|
|
||||||
Routers that self-report as unreachable or congested will be excluded from future reseed bundles.
|
|
||||||
Additionally, routers that self-report an old version will be excluded from reseed bundles.
|
|
||||||
This should help new users build better connections faster with the existing, working router implementations.
|
|
||||||
|
|
||||||
This is not a working release of a go-i2p router
|
|
||||||
------------------------------------------------
|
|
||||||
|
|
||||||
It is a numbered version of the go-i2p library, which is pre-release, expressly for use in the `reseed-tools` application.
|
|
||||||
The common library works, and so do some of the cryptographic primitives, however the API is unstable and the software itself is certain to have serious bugs outside of a few well-tested areas.
|
|
||||||
If you're using it for something other than parsing and analyzing RouterInfos and LeaseSets, you'll probably encounter bugs.
|
|
||||||
Please report them to the https://github.com/go-i2p/go-i2p
|
|
||||||
Use any part of it at your own risk.
|
|
124
README.md
124
README.md
@@ -15,71 +15,78 @@ please keep up with these changes, as they will not be backward compatible and r
|
|||||||
- [ ] Datagrams
|
- [ ] Datagrams
|
||||||
- [ ] I2CP
|
- [ ] I2CP
|
||||||
- [ ] Message routing
|
- [ ] Message routing
|
||||||
- [ ] SAM
|
|
||||||
- [ ] Streaming
|
- [ ] Streaming
|
||||||
- [ ] Tunnel Manager
|
- [Cryptographic primitives(see also: https://github.com/go-i2p/crypto)](https://github.com/go-i2p/crypto)
|
||||||
- Cryptographic primitives
|
|
||||||
- Signing
|
- Signing
|
||||||
- [ ] ECDSA_SHA256_P256
|
- [X] ECDSA_SHA256_P256
|
||||||
- [ ] ECDSA_SHA384_P384
|
- [X] ECDSA_SHA384_P384
|
||||||
- [ ] ECDSA_SHA512_P521
|
- [X] ECDSA_SHA512_P521
|
||||||
- [ ] Ed25519
|
- [X] Ed25519
|
||||||
- Verifying
|
- Verifying
|
||||||
- [ ] DSA
|
- [X] DSA
|
||||||
- [ ] ECDSA_SHA256_P256
|
- [X] ECDSA_SHA256_P256
|
||||||
- [ ] ECDSA_SHA384_P384
|
- [X] ECDSA_SHA384_P384
|
||||||
- [ ] ECDSA_SHA512_P521
|
- [X] ECDSA_SHA512_P521
|
||||||
- [ ] RSA_SHA256_2048
|
- [X] RSA_SHA256_2048
|
||||||
- [ ] RSA_SHA384_3072
|
- [X] RSA_SHA384_3072
|
||||||
- [ ] RSA_SHA512_4096
|
- [X] RSA_SHA512_4096
|
||||||
- [ ] Ed25519
|
- [X] Ed25519
|
||||||
- [ ] Red25519
|
- [ ] Red25519
|
||||||
- [ ] ElGamal
|
- [X] ElGamal
|
||||||
- [ ] AES256
|
- [X] AES256
|
||||||
- [ ] X25519
|
- [X] X25519
|
||||||
- [ ] ChaCha20/Poly1305
|
- [X] ChaCha20/Poly1305
|
||||||
- [ ] Elligator2
|
- [ ] Elligator2
|
||||||
- [ ] HKDF
|
- [X] HKDF
|
||||||
- [ ] HMAC
|
- [X] HMAC
|
||||||
- [ ] Noise subsystem
|
- [X] Noise subsystem
|
||||||
- End-to-End Crypto
|
- End-to-End Crypto
|
||||||
- [ ] Garlic messages
|
- [ ] Garlic messages
|
||||||
- [ ] ElGamal/AES+SessionTag
|
- [ ] ElGamal/AES+SessionTag
|
||||||
- [ ] Ratchet/X25519
|
- [ ] Ratchet/X25519
|
||||||
- I2NP
|
- I2NP
|
||||||
- [ ] Message parsing
|
- [X] Message parsing and serialization
|
||||||
- [ ] Message handling
|
- [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
|
- NetDB
|
||||||
- [ ] Local storage
|
- [X] Local storage interface
|
||||||
- [/] Persistence to disk
|
- [X] Reseed functionality (basic implementation)
|
||||||
- [X] Reseeding
|
- [~] Persistence to disk
|
||||||
|
- [ ] RouterInfo management
|
||||||
|
- [ ] LeaseSet management
|
||||||
- [ ] Lookups
|
- [ ] Lookups
|
||||||
- [ ] Expiry
|
- [ ] Expiry
|
||||||
- [ ] Exploration
|
- [ ] Exploration
|
||||||
- [ ] Publishing
|
- [ ] Publishing
|
||||||
- [ ] Floodfill
|
- [ ] Floodfill
|
||||||
- [ ] LS2 and Encrypted Leasesets
|
- [ ] LS2 and Encrypted Leasesets
|
||||||
- Transports
|
- Transport Layer
|
||||||
- [X] Transport manager
|
- [X] Transport manager and interfaces
|
||||||
- NTCP2
|
- NTCP2
|
||||||
- [ ] Handshake
|
- [X] Session handshake using noise protocol
|
||||||
- [ ] Session tracking
|
- [X] Connection management
|
||||||
- [ ] Automatic session creation
|
- [X] I2NP message framing and unframing
|
||||||
|
- [X] Session lifecycle management
|
||||||
|
- [X] Message queuing and worker threads
|
||||||
- SSU2
|
- SSU2
|
||||||
- [ ] Handshake
|
- [ ] Session handshake
|
||||||
- [ ] Session tracking
|
- [ ] Connection management
|
||||||
- [ ] Automatic session creation
|
|
||||||
- [ ] Peer Tests
|
- [ ] Peer Tests
|
||||||
- [ ] Introducers
|
- [ ] Introducers
|
||||||
- Tunnels
|
- Tunnels
|
||||||
- [ ] Building
|
- [X] Message structure parsing (delivery instructions)
|
||||||
- [ ] Build Message Crypto (ElGamal)
|
- [X] Fragment handling and reassembly
|
||||||
- [ ] Build Message Crypto (ECIES)
|
- [X] Build Request/Response record interfaces
|
||||||
- [ ] Participating
|
- [ ] Tunnel building and management
|
||||||
- [ ] Tunnel Message Crypto
|
- [ ] Tunnel cryptography (layered encryption)
|
||||||
- [ ] Tunnel Message Fragmentation/Reassembly
|
- [ ] Gateway and endpoint implementation
|
||||||
- Common Data Structures
|
- [ ] Participant functionality
|
||||||
- [/] Keys and Cert
|
- [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] Key Certificates
|
||||||
- [X] Certificate
|
- [X] Certificate
|
||||||
- [X] Lease
|
- [X] Lease
|
||||||
@@ -93,6 +100,37 @@ please keep up with these changes, as they will not be backward compatible and r
|
|||||||
- [X] Data Types
|
- [X] Data Types
|
||||||
- [X] Session Tag
|
- [X] Session Tag
|
||||||
|
|
||||||
|
## Verbosity ##
|
||||||
|
Logging can be enabled and configured using the `DEBUG_I2P` environment variable. By default, logging is disabled.
|
||||||
|
|
||||||
|
There are three available log levels:
|
||||||
|
|
||||||
|
- Debug
|
||||||
|
```shell
|
||||||
|
export DEBUG_I2P=debug
|
||||||
|
```
|
||||||
|
- Warn
|
||||||
|
```shell
|
||||||
|
export DEBUG_I2P=warn
|
||||||
|
```
|
||||||
|
- Error
|
||||||
|
```shell
|
||||||
|
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
|
## Contributing
|
||||||
|
|
||||||
See CONTRIBUTING.md for more information.
|
See CONTRIBUTING.md for more information.
|
||||||
|
89
ROADMAP.md
Normal file
89
ROADMAP.md
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
# go-i2p Implementation Roadmap
|
||||||
|
|
||||||
|
## Completed Components ✅
|
||||||
|
|
||||||
|
### 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
|
||||||
|
|
||||||
|
### 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 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
|
||||||
|
|
||||||
|
### 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
19
callgraph.sh
Executable 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
|
52
go.mod
52
go.mod
@@ -1,11 +1,53 @@
|
|||||||
module github.com/go-i2p/go-i2p
|
module github.com/go-i2p/go-i2p
|
||||||
|
|
||||||
go 1.16
|
go 1.24.2
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/emirpasic/gods v1.18.1
|
github.com/beevik/ntp v1.4.3
|
||||||
github.com/flynn/noise v1.1.0
|
github.com/eyedeekay/go-unzip v0.0.0-20240201194209-560d8225b50e
|
||||||
|
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/sirupsen/logrus v1.9.3
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/spf13/cobra v1.9.1
|
||||||
golang.org/x/crypto v0.23.0
|
github.com/spf13/viper v1.19.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/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.9 // indirect
|
||||||
|
github.com/mitchellh/mapstructure v1.5.0 // 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.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.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.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
|
||||||
)
|
)
|
||||||
|
158
go.sum
158
go.sum
@@ -1,71 +1,111 @@
|
|||||||
|
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.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.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg=
|
github.com/dchest/siphash v1.2.3 h1:QXwFc8cFOR2dSa/gE6o/HokBMWtLUaNDVd+22aKHeEA=
|
||||||
github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag=
|
github.com/dchest/siphash v1.2.3/go.mod h1:0NvQU092bT0ipiFN++/rXm69QG9tVxLAlQHIXMPAkHc=
|
||||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
github.com/eyedeekay/go-unzip v0.0.0-20240201194209-560d8225b50e h1:NMjWYVkgcQHGOy0/VxU0TU6smrcoxzj9hwDesx2sB0w=
|
||||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
github.com/eyedeekay/go-unzip v0.0.0-20240201194209-560d8225b50e/go.mod h1:fKfFM3BsOOyjtZmEty7FsGzGabXo8Eb/dHjyIhTtxsE=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
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.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
|
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.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/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.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.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 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
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.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.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
|
||||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
|
||||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
|
||||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
go.step.sm/crypto v0.67.0 h1:1km9LmxMKG/p+mKa1R4luPN04vlJYnRLlLQrWv7egGU=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
go.step.sm/crypto v0.67.0/go.mod h1:+AoDpB0mZxbW/PmOXuwkPSpXRgaUaoIK+/Wx/HGgtAU=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
|
||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
|
||||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
|
||||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
|
||||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
|
||||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
|
||||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
|
||||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
|
||||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
|
||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
|
||||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
|
||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
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 h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||||
|
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
57
lib/bootstrap/README.md
Normal file
57
lib/bootstrap/README.md
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
# 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(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)
|
@@ -1,6 +1,10 @@
|
|||||||
package bootstrap
|
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
|
// interface defining a way to bootstrap into the i2p network
|
||||||
type Bootstrap interface {
|
type Bootstrap interface {
|
||||||
@@ -9,5 +13,5 @@ type Bootstrap interface {
|
|||||||
// if n is 0 then try obtaining as many router infos as possible
|
// 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 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
|
// 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
258
lib/bootstrap/bootstrap.svg
Normal 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-i2p/go-i2p/lib/netdb/reseed.Reseed</title>
|
||||||
|
<g id="a_clust5"><a xlink:title="type: github.com/go-i2p/go-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-i2p/logger.Logger</title>
|
||||||
|
<g id="a_clust3"><a xlink:title="type: *github.com/go-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-i2p/go-i2p/lib/bootstrap.ReseedBootstrap</title>
|
||||||
|
<g id="a_clust2"><a xlink:title="type: *github.com/go-i2p/go-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-i2p/go-i2p/lib/bootstrap.init -->
|
||||||
|
<g id="node1" class="node">
|
||||||
|
<title>github.com/go-i2p/go-i2p/lib/bootstrap.init</title>
|
||||||
|
<g id="a_node1"><a xlink:title="github.com/go-i2p/go-i2p/lib/bootstrap.init | defined in .:0 at reseed_bootstrap.go:15: calling [github.com/go-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-i2p/logger.GetGoI2PLogger -->
|
||||||
|
<g id="node2" class="node">
|
||||||
|
<title>github.com/go-i2p/logger.GetGoI2PLogger</title>
|
||||||
|
<g id="a_node2"><a xlink:title="github.com/go-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-i2p/go-i2p/lib/bootstrap.init->github.com/go-i2p/logger.GetGoI2PLogger -->
|
||||||
|
<g id="edge1" class="edge">
|
||||||
|
<title>github.com/go-i2p/go-i2p/lib/bootstrap.init->github.com/go-i2p/logger.GetGoI2PLogger</title>
|
||||||
|
<g id="a_edge1"><a xlink:title="at reseed_bootstrap.go:15: calling [github.com/go-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-i2p/go-i2p/lib/netdb/reseed.NewReseed -->
|
||||||
|
<g id="node4" class="node">
|
||||||
|
<title>github.com/go-i2p/go-i2p/lib/netdb/reseed.NewReseed</title>
|
||||||
|
<g id="a_node4"><a xlink:title="github.com/go-i2p/go-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-i2p/go-i2p/lib/bootstrap.ReseedBootstrap).GetPeers -->
|
||||||
|
<g id="node5" class="node">
|
||||||
|
<title>(*github.com/go-i2p/go-i2p/lib/bootstrap.ReseedBootstrap).GetPeers</title>
|
||||||
|
<g id="a_node5"><a xlink:title="(*github.com/go-i2p/go-i2p/lib/bootstrap.ReseedBootstrap).GetPeers | defined in reseed_bootstrap.go:32 at reseed_bootstrap.go:40: calling [github.com/samber/oops.Errorf] at reseed_bootstrap.go:52: calling [github.com/samber/oops.Errorf] at reseed_bootstrap.go:72: calling [github.com/samber/oops.Errorf] at reseed_bootstrap.go:46: calling [github.com/go-i2p/go-i2p/lib/netdb/reseed.NewReseed] at reseed_bootstrap.go:49: calling [(github.com/go-i2p/go-i2p/lib/netdb/reseed.Reseed).SingleReseed] at reseed_bootstrap.go:51: calling [(*github.com/go-i2p/logger.Logger).WithError] at reseed_bootstrap.go:58: calling [(*github.com/go-i2p/logger.Logger).WithFields] at reseed_bootstrap.go:62: calling [(*github.com/sirupsen/logrus.Logger).Info] at reseed_bootstrap.go:43: calling [(*github.com/go-i2p/logger.Logger).WithField] at reseed_bootstrap.go:51: calling [(*github.com/go-i2p/logger.Logger).WithField] at reseed_bootstrap.go:43: calling [(*github.com/sirupsen/logrus.Logger).Debug] at reseed_bootstrap.go:51: calling [(*github.com/go-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-i2p/go-i2p/lib/bootstrap.ReseedBootstrap).GetPeers->github.com/samber/oops.Errorf -->
|
||||||
|
<g id="edge2" class="edge">
|
||||||
|
<title>(*github.com/go-i2p/go-i2p/lib/bootstrap.ReseedBootstrap).GetPeers->github.com/samber/oops.Errorf</title>
|
||||||
|
<g id="a_edge2"><a xlink:title="at reseed_bootstrap.go:40: calling [github.com/samber/oops.Errorf] at reseed_bootstrap.go:52: calling [github.com/samber/oops.Errorf] 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-i2p/go-i2p/lib/bootstrap.ReseedBootstrap).GetPeers->github.com/go-i2p/go-i2p/lib/netdb/reseed.NewReseed -->
|
||||||
|
<g id="edge3" class="edge">
|
||||||
|
<title>(*github.com/go-i2p/go-i2p/lib/bootstrap.ReseedBootstrap).GetPeers->github.com/go-i2p/go-i2p/lib/netdb/reseed.NewReseed</title>
|
||||||
|
<g id="a_edge3"><a xlink:title="at reseed_bootstrap.go:46: calling [github.com/go-i2p/go-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-i2p/logger.Logger).WithField -->
|
||||||
|
<g id="node6" class="node">
|
||||||
|
<title>(*github.com/go-i2p/logger.Logger).WithField</title>
|
||||||
|
<g id="a_node6"><a xlink:title="(*github.com/go-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-i2p/go-i2p/lib/bootstrap.ReseedBootstrap).GetPeers->(*github.com/go-i2p/logger.Logger).WithField -->
|
||||||
|
<g id="edge8" class="edge">
|
||||||
|
<title>(*github.com/go-i2p/go-i2p/lib/bootstrap.ReseedBootstrap).GetPeers->(*github.com/go-i2p/logger.Logger).WithField</title>
|
||||||
|
<g id="a_edge8"><a xlink:title="at reseed_bootstrap.go:43: calling [(*github.com/go-i2p/logger.Logger).WithField] at reseed_bootstrap.go:51: calling [(*github.com/go-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-i2p/logger.Logger).WithError -->
|
||||||
|
<g id="node7" class="node">
|
||||||
|
<title>(*github.com/go-i2p/logger.Logger).WithError</title>
|
||||||
|
<g id="a_node7"><a xlink:title="(*github.com/go-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-i2p/go-i2p/lib/bootstrap.ReseedBootstrap).GetPeers->(*github.com/go-i2p/logger.Logger).WithError -->
|
||||||
|
<g id="edge5" class="edge">
|
||||||
|
<title>(*github.com/go-i2p/go-i2p/lib/bootstrap.ReseedBootstrap).GetPeers->(*github.com/go-i2p/logger.Logger).WithError</title>
|
||||||
|
<g id="a_edge5"><a xlink:title="at reseed_bootstrap.go:51: calling [(*github.com/go-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-i2p/logger.Logger).Warn -->
|
||||||
|
<g id="node8" class="node">
|
||||||
|
<title>(*github.com/go-i2p/logger.Logger).Warn</title>
|
||||||
|
<g id="a_node8"><a xlink:title="(*github.com/go-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-i2p/go-i2p/lib/bootstrap.ReseedBootstrap).GetPeers->(*github.com/go-i2p/logger.Logger).Warn -->
|
||||||
|
<g id="edge10" class="edge">
|
||||||
|
<title>(*github.com/go-i2p/go-i2p/lib/bootstrap.ReseedBootstrap).GetPeers->(*github.com/go-i2p/logger.Logger).Warn</title>
|
||||||
|
<g id="a_edge10"><a xlink:title="at reseed_bootstrap.go:51: calling [(*github.com/go-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-i2p/logger.Logger).WithFields -->
|
||||||
|
<g id="node9" class="node">
|
||||||
|
<title>(*github.com/go-i2p/logger.Logger).WithFields</title>
|
||||||
|
<g id="a_node9"><a xlink:title="(*github.com/go-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-i2p/go-i2p/lib/bootstrap.ReseedBootstrap).GetPeers->(*github.com/go-i2p/logger.Logger).WithFields -->
|
||||||
|
<g id="edge6" class="edge">
|
||||||
|
<title>(*github.com/go-i2p/go-i2p/lib/bootstrap.ReseedBootstrap).GetPeers->(*github.com/go-i2p/logger.Logger).WithFields</title>
|
||||||
|
<g id="a_edge6"><a xlink:title="at reseed_bootstrap.go:58: calling [(*github.com/go-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-i2p/go-i2p/lib/bootstrap.ReseedBootstrap).GetPeers->(*github.com/sirupsen/logrus.Logger).Debug -->
|
||||||
|
<g id="edge9" class="edge">
|
||||||
|
<title>(*github.com/go-i2p/go-i2p/lib/bootstrap.ReseedBootstrap).GetPeers->(*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-i2p/go-i2p/lib/bootstrap.ReseedBootstrap).GetPeers->(*github.com/sirupsen/logrus.Logger).Info -->
|
||||||
|
<g id="edge7" class="edge">
|
||||||
|
<title>(*github.com/go-i2p/go-i2p/lib/bootstrap.ReseedBootstrap).GetPeers->(*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-i2p/go-i2p/lib/netdb/reseed.Reseed).SingleReseed -->
|
||||||
|
<g id="node12" class="node">
|
||||||
|
<title>(github.com/go-i2p/go-i2p/lib/netdb/reseed.Reseed).SingleReseed</title>
|
||||||
|
<g id="a_node12"><a xlink:title="(github.com/go-i2p/go-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-i2p/go-i2p/lib/bootstrap.ReseedBootstrap).GetPeers->(github.com/go-i2p/go-i2p/lib/netdb/reseed.Reseed).SingleReseed -->
|
||||||
|
<g id="edge4" class="edge">
|
||||||
|
<title>(*github.com/go-i2p/go-i2p/lib/bootstrap.ReseedBootstrap).GetPeers->(github.com/go-i2p/go-i2p/lib/netdb/reseed.Reseed).SingleReseed</title>
|
||||||
|
<g id="a_edge4"><a xlink:title="at reseed_bootstrap.go:49: calling [(github.com/go-i2p/go-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 |
76
lib/bootstrap/reseed_bootstrap.go
Normal file
76
lib/bootstrap/reseed_bootstrap.go
Normal 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
|
||||||
|
}
|
@@ -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)
|
|
||||||
}
|
|
@@ -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)
|
|
||||||
}
|
|
@@ -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)
|
|
||||||
}
|
|
@@ -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)
|
|
||||||
}
|
|
@@ -1,173 +0,0 @@
|
|||||||
// Package certificate implements the certificate common-structure of I2P.
|
|
||||||
|
|
||||||
package certificate
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
|
|
||||||
. "github.com/go-i2p/go-i2p/lib/common/data"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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...)
|
|
||||||
return bytes
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExcessBytes returns the excess bytes in a certificate found after the specified payload length.
|
|
||||||
func (c *Certificate) ExcessBytes() []byte {
|
|
||||||
return c.payload[c.len.Int():]
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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()...)
|
|
||||||
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()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Length returns the payload length of a Certificate.
|
|
||||||
func (c *Certificate) Length() (length int) {
|
|
||||||
length = c.len.Int()
|
|
||||||
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
|
|
||||||
} else {
|
|
||||||
data = c.payload[0:lastElement]
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 NewCertificate(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(log.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(log.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])
|
|
||||||
payleng := 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(log.Fields{
|
|
||||||
"at": "(Certificate) NewCertificate",
|
|
||||||
"certificate_bytes_length": certificate.len.Int(),
|
|
||||||
"certificate_payload_length": payleng,
|
|
||||||
"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
|
|
||||||
}
|
|
||||||
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 = NewCertificate(data)
|
|
||||||
if err != nil && err.Error() == "certificate parsing warning: certificate data is longer than specified by length" {
|
|
||||||
err = nil
|
|
||||||
}
|
|
||||||
remainder = certificate.ExcessBytes()
|
|
||||||
return
|
|
||||||
}
|
|
@@ -1,149 +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 := NewCertificate(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 := NewCertificate(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 := NewCertificate(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 length: 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 := NewCertificate(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 := NewCertificate(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, err := NewCertificate(bytes)
|
|
||||||
cert_data := certificate.Data()
|
|
||||||
|
|
||||||
if assert.NotNil(err) {
|
|
||||||
assert.Equal("certificate parsing warning: certificate data is longer than specified by length", err.Error(), "correct error message should be returned")
|
|
||||||
}
|
|
||||||
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 := NewCertificate(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 length: certificate is too short", err.Error(), "correct error message should be returned")
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,71 +0,0 @@
|
|||||||
// Package data implements common data structures used in higher level structures.
|
|
||||||
package data
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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(log.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:]
|
|
||||||
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)
|
|
||||||
date = &objdate
|
|
||||||
return
|
|
||||||
}
|
|
@@ -1,16 +0,0 @@
|
|||||||
package data
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestTimeFromMiliseconds(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")
|
|
||||||
}
|
|
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,42 +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
|
|
||||||
|
|
||||||
// HashData returns the SHA256 sum of a []byte input as Hash.
|
|
||||||
func HashData(data []byte) (h Hash) {
|
|
||||||
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
|
|
||||||
}
|
|
@@ -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
|
|
||||||
}
|
|
@@ -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")
|
|
||||||
}
|
|
@@ -1,180 +0,0 @@
|
|||||||
package data
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
log "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 {
|
|
||||||
return MappingValues{}
|
|
||||||
}
|
|
||||||
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 {
|
|
||||||
seen_values := make(map[string]bool)
|
|
||||||
values := mapping.Values()
|
|
||||||
for _, pair := range values {
|
|
||||||
key, _ := pair[0].Data()
|
|
||||||
if _, present := seen_values[key]; present {
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
seen_values[key] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// GoMapToMapping converts a Go map of unformatted strings to *Mapping.
|
|
||||||
func GoMapToMapping(gomap map[string]string) (mapping *Mapping, err error) {
|
|
||||||
map_vals := MappingValues{}
|
|
||||||
for k, v := range gomap {
|
|
||||||
key_str, kerr := ToI2PString(k)
|
|
||||||
if kerr != nil {
|
|
||||||
err = kerr
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val_str, verr := ToI2PString(v)
|
|
||||||
if verr != nil {
|
|
||||||
err = verr
|
|
||||||
return
|
|
||||||
}
|
|
||||||
map_vals = append(
|
|
||||||
map_vals,
|
|
||||||
[2]I2PString{key_str, val_str},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
mapping = ValuesToMapping(map_vals)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the string parsing error indicates that the Mapping
|
|
||||||
// should no longer be parsed.
|
|
||||||
func stopValueRead(err error) bool {
|
|
||||||
return err.Error() == "error parsing string: zero length"
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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) {
|
|
||||||
if len(bytes) < 3 {
|
|
||||||
log.WithFields(log.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 {
|
|
||||||
err = append(err, e)
|
|
||||||
}
|
|
||||||
if size.Int() == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
mapping.size = size
|
|
||||||
map_bytes := remainder[:mapping.size.Int()]
|
|
||||||
remainder = remainder[mapping.size.Int():]
|
|
||||||
if len(remainder) == 0 {
|
|
||||||
log.WithFields(log.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(log.Fields{
|
|
||||||
"at": "ReadMapping",
|
|
||||||
"reason": "error parsing mapping values",
|
|
||||||
}).Warn("mapping format violation")
|
|
||||||
e := errors.New("error parsing mapping values")
|
|
||||||
err = append(err, e)
|
|
||||||
}
|
|
||||||
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) {
|
|
||||||
objvalues, remainder, err := ReadMapping(bytes)
|
|
||||||
values = &objvalues
|
|
||||||
return
|
|
||||||
}
|
|
@@ -1,193 +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")
|
|
||||||
}
|
|
@@ -1,194 +0,0 @@
|
|||||||
package data
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"sort"
|
|
||||||
|
|
||||||
log "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()
|
|
||||||
for _, pair := range m {
|
|
||||||
kb, _ := pair[0][0:].Data()
|
|
||||||
if kb == keyBytes {
|
|
||||||
return pair[1][1:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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 =
|
|
||||||
baseLength := 2 * len(values)
|
|
||||||
for _, mappingVals := range values {
|
|
||||||
for _, keyOrVal := range mappingVals {
|
|
||||||
baseLength += len(keyOrVal)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
if remainder == nil || len(remainder) < 1 {
|
|
||||||
log.WithFields(log.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(log.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(log.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(log.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(log.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(log.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(log.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
|
|
||||||
return
|
|
||||||
|
|
||||||
}
|
|
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,125 +0,0 @@
|
|||||||
package data
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
log "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(log.Fields{
|
|
||||||
"at": "(I2PString) Length",
|
|
||||||
"reason": "no data",
|
|
||||||
}).Error("error parsing string")
|
|
||||||
err = errors.New("error parsing string: zero length")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
l, _, _ := NewInteger(str, 1)
|
|
||||||
length = l.Int()
|
|
||||||
str_len := len(str) - 1
|
|
||||||
if length != str_len {
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"at": "(I2PString) Length",
|
|
||||||
"string_bytes_length": str_len,
|
|
||||||
"string_length_field": length,
|
|
||||||
"reason": "data less than specified by length",
|
|
||||||
}).Error("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":
|
|
||||||
return
|
|
||||||
case "string parsing warning: string data is shorter than specified by length":
|
|
||||||
data = string(str[1:])
|
|
||||||
return
|
|
||||||
case "string parsing warning: string contains data beyond length":
|
|
||||||
data = string(str[1:])
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if length == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
data = string(str[1 : length+1])
|
|
||||||
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) {
|
|
||||||
data_len := len(data)
|
|
||||||
if data_len > STRING_MAX_SIZE {
|
|
||||||
log.WithFields(log.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)
|
|
||||||
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) {
|
|
||||||
length, _, err := NewInteger(data, 1)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
data_len := length.Int()
|
|
||||||
str = data[:data_len+1]
|
|
||||||
remainder = data[data_len+1:]
|
|
||||||
_, err = str.Length()
|
|
||||||
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
|
|
||||||
}
|
|
@@ -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")
|
|
||||||
}
|
|
@@ -1,64 +0,0 @@
|
|||||||
// Package destination implements the I2P Destination common data structure
|
|
||||||
package destination
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
. "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"
|
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
|
||||||
[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) {
|
|
||||||
dest := destination.KeysAndCert.KeyCertificate.Bytes()
|
|
||||||
hash := crypto.SHA256(dest)
|
|
||||||
str = strings.Trim(base32.EncodeToString(hash[:]), "=")
|
|
||||||
str = str + ".b32.i2p"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Base64 returns the I2P base64 address for this Destination.
|
|
||||||
func (destination Destination) Base64() string {
|
|
||||||
dest := destination.KeysAndCert.KeyCertificate.Bytes()
|
|
||||||
return base64.EncodeToString(dest)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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) {
|
|
||||||
keys_and_cert, remainder, err := NewKeysAndCert(data)
|
|
||||||
destination = Destination{
|
|
||||||
keys_and_cert,
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDestination creates a new *Destination from []byte using ReadDestination.
|
|
||||||
// Returns a pointer to Destination unlike ReadDestination.
|
|
||||||
func NewDestination(data []byte) (destination *Destination, remainder []byte, err error) {
|
|
||||||
objdestination, remainder, err := ReadDestination(data)
|
|
||||||
destination = &objdestination
|
|
||||||
return destination, remainder, err
|
|
||||||
}
|
|
@@ -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"]
|
|
@@ -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
|
|
@@ -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
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +0,0 @@
|
|||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +0,0 @@
|
|||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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
|
|
||||||
}
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +0,0 @@
|
|||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,10 +0,0 @@
|
|||||||
package exportable
|
|
||||||
|
|
||||||
import common "github.com/go-i2p/go-i2p/lib/common/destination"
|
|
||||||
|
|
||||||
func Fuzz(data []byte) int {
|
|
||||||
destination, _, _ := common.ReadDestination(data)
|
|
||||||
destination.Base32Address()
|
|
||||||
destination.Base64()
|
|
||||||
return 0
|
|
||||||
}
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +0,0 @@
|
|||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user