diff --git a/.gitignore b/.gitignore
index 60c7ea2..634dad5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,3 +9,6 @@ go-i2p
.idea/
router.info
log
+*.gv
+diff
+err
\ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 6dec5c7..4d8dfb5 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,20 +1,35 @@
# Contributing
-Thanks for taking a look at go-i2p! Please reach out if you have any questions or need help getting started.
+Thanks for taking a look at go-i2p! Please reach out if you have any questions or need help getting started. We have an IRC channel on IRC2P: #go-i2p-dev and we're reachable here at github.com/go-i2p also.
-## Getting Starting
+## Getting Started
Install required dependencies
-This example assumes Ubuntu 16.04
+This example assumes Ubuntu or Debian based Linux, a reasonably modern version.
+The instructions will be similar for other Linux distributions with slightly different package managers and package names.
```sh
-go get github.com/hkparker/go-i2p
-go get github.com/Sirupsen/logrus
-go get github.com/stretchr/testify/assert
+# For obtaining, modifying, compiling, and tracking changes to go-i2p, install:
+sudo apt-get install golang-go make git
+# If you want to generate markdown versions of the godoc locally, also install:
+go install github.com/robertkrimen/godocdown/godocdown@master
+# If you want to generate call graphs locally, also install:
+go install github.com/ofabry/go-callvis@master
```
-Fork go-i2p and clone it into your workspace. Make sure you can execute `go test ./...` in the project's root directory. At that point you should have everything you need to start making changes and opening pull requests. If you aren't sure what to work on, take a look at some good [getting started issues](https://github.com/hkparker/go-i2p/issues?q=is%3Aopen+is%3Aissue+label%3A%22start+here%22).
+On Windows, one must install the latest versions of Go and Git Bash from their respective sources.
+
+## Set up your workspace:
+
+```sh
+github_username=yourusername
+cd $(go env GOPATH)
+git clone git@github.com:$github_username/go-i2p github.com/go-i2p/go-i2p
+github.com/go-i2p/go-i2p
+```
+
+Fork go-i2p and clone it into your workspace. Make sure you can execute `go test ./...` in the project's root directory. At that point you should have everything you need to start making changes and opening pull requests.
## I2P Specifications
@@ -26,9 +41,17 @@ The I2P community maintains up-to-date [specifications](https://geti2p.net/spec)
## Conventions
+#### Errors
+
+We use oops to provide context to the errors we return. Do not use `errors.New` or `fmt.Errorf` when returning errors from functions. Instead, wrap raw errors in oops errors. When an error is recieved, used oops to supplement the log output.
+
+It is OK to use `fmt.Errorf` for declaring custom error types.
+
#### Logging
-Logrus is used for logging across all of go-i2p. All log statements should contain an `at` fields and a `reason` field. Here is a good example from the go-i2p implementation of a LeaseSet:
+Logrus is used for logging across all of go-i2p. We have a small extension of logrus at https://github.com/go-i2p/logger which we use to add a "Fail Fast mode." We are mostly converted over to using it.
+
+All log statements should contain an `at` fields and a `reason` field. Here is a good example from the go-i2p implementation of a LeaseSet:
```go
log.WithFields(log.Fields{
@@ -56,4 +79,4 @@ func TestRouterAddressCountReturnsCorrectCount(t *testing.T) {
## Pull Requests
-Pull requests should pass all tests, test all new behavior, and be correctly formatted by `gofmt` before merge. Feel free to open incomplete pull requests if you are struggling, I will enthusiasticlly help you complete the PR in any way needed.
+Pull requests should pass all tests, test all new behavior, and be correctly formatted by `gofumpt -w -s -extra` before merge. Feel free to open incomplete pull requests and ask for help and advice.
\ No newline at end of file
diff --git a/Makefile b/Makefile
index 32fabed..1155718 100644
--- a/Makefile
+++ b/Makefile
@@ -64,9 +64,5 @@ info:
release:
github-release release -u go-i2p -r go-i2p -n "${RELEASE_VERSION}" -t "${RELEASE_TAG}" -d "${RELEASE_DESCRIPTION}" -p
-callvis:
- go-callvis -format svg -focus upgrade -group pkg,type -limit github.com/go-i2p/go-i2p github.com/go-i2p/go-i2p
-
godoc:
- find lib -type d -exec bash -c "ls {}/*.go && godocdown -o ./{}/doc.md ./{}" \;
-
+ ./callgraph.sh
diff --git a/README.md b/README.md
index 0fac996..d907772 100644
--- a/README.md
+++ b/README.md
@@ -15,9 +15,7 @@ please keep up with these changes, as they will not be backward compatible and r
- [ ] Datagrams
- [ ] I2CP
- [ ] Message routing
- - [ ] SAM
- [ ] Streaming
- - [ ] Tunnel Manager
- Cryptographic primitives
- Signing
- [ ] ECDSA_SHA256_P256
diff --git a/callgraph.sh b/callgraph.sh
new file mode 100755
index 0000000..c1eee21
--- /dev/null
+++ b/callgraph.sh
@@ -0,0 +1,19 @@
+#! /usr/bin/env sh
+
+dirs=$(find lib/ -type d)
+for dir in $dirs; do
+ files=$(find "$dir" -maxdepth 1 -type f -name "*.go")
+ #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"
+ git mv -v "$dir/doc.md" "$dir/README.md"
+ godocdown -template template.md -o "$dir/README.md" "./$dir"
+ git add -v "$dir/$package.svg" "$dir/README.md"
+done
\ No newline at end of file
diff --git a/go.mod b/go.mod
index 8caedac..aedeb48 100644
--- a/go.mod
+++ b/go.mod
@@ -1,43 +1,50 @@
module github.com/go-i2p/go-i2p
-go 1.23.1
+go 1.23.3
+
+toolchain go1.23.5
require (
github.com/beevik/ntp v1.4.3
github.com/emirpasic/gods v1.18.1
github.com/eyedeekay/go-unzip v0.0.0-20240201194209-560d8225b50e
github.com/flynn/noise v1.1.0
+ github.com/go-i2p/logger v0.0.0-20241123010126-3050657e5d0c
+ github.com/samber/oops v1.16.1
github.com/sirupsen/logrus v1.9.3
- github.com/spf13/cobra v1.8.1
+ github.com/spf13/cobra v1.9.1
github.com/spf13/viper v1.19.0
- github.com/stretchr/testify v1.9.0
- go.step.sm/crypto v0.53.0
- golang.org/x/crypto v0.27.0
+ github.com/stretchr/testify v1.10.0
+ go.step.sm/crypto v0.58.1
+ golang.org/x/crypto v0.35.0
gopkg.in/yaml.v3 v3.0.1
)
require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
- github.com/fsnotify/fsnotify v1.7.0 // indirect
+ github.com/fsnotify/fsnotify v1.8.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
- github.com/magiconair/properties v1.8.7 // indirect
+ github.com/magiconair/properties v1.8.9 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
- github.com/pelletier/go-toml/v2 v2.2.2 // indirect
+ github.com/oklog/ulid/v2 v2.1.0 // indirect
+ github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
- github.com/sagikazarmark/locafero v0.4.0 // indirect
+ github.com/sagikazarmark/locafero v0.7.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
+ github.com/samber/lo v1.49.1 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
- github.com/spf13/afero v1.11.0 // indirect
- github.com/spf13/cast v1.7.0 // indirect
- github.com/spf13/pflag v1.0.5 // indirect
+ github.com/spf13/afero v1.12.0 // indirect
+ github.com/spf13/cast v1.7.1 // indirect
+ github.com/spf13/pflag v1.0.6 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
- go.uber.org/atomic v1.9.0 // indirect
- go.uber.org/multierr v1.9.0 // indirect
- golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
- golang.org/x/net v0.29.0 // indirect
- golang.org/x/sys v0.25.0 // indirect
- golang.org/x/text v0.18.0 // indirect
+ go.opentelemetry.io/otel v1.34.0 // indirect
+ go.opentelemetry.io/otel/trace v1.34.0 // indirect
+ go.uber.org/multierr v1.11.0 // indirect
+ golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa // indirect
+ golang.org/x/net v0.35.0 // indirect
+ golang.org/x/sys v0.30.0 // indirect
+ golang.org/x/text v0.22.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
)
diff --git a/go.sum b/go.sum
index 6f45394..6a04797 100644
--- a/go.sum
+++ b/go.sum
@@ -2,7 +2,7 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/beevik/ntp v1.4.3 h1:PlbTvE5NNy4QHmA4Mg57n7mcFTmr1W1j3gcK7L1lqho=
github.com/beevik/ntp v1.4.3/go.mod h1:Unr8Zg+2dRn7d8bHFuehIMSvvUYssHMxW3Q5Nx4RW5Q=
-github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
+github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
@@ -15,10 +15,12 @@ github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg=
github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
-github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
-github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
-github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
-github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
+github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
+github.com/go-i2p/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/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
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=
@@ -30,71 +32,73 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
-github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
+github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM=
+github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
-github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
-github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
+github.com/oklog/ulid/v2 v2.1.0 h1:+9lhoxAP56we25tyYETBBY1YLA2SaoLvUFgrP2miPJU=
+github.com/oklog/ulid/v2 v2.1.0/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=
+github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
+github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
+github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
-github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
-github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
+github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo=
+github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
+github.com/samber/lo v1.49.1 h1:4BIFyVfuQSEpluc7Fua+j1NolZHiEHEpaSEKdsH0tew=
+github.com/samber/lo v1.49.1/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd6o=
+github.com/samber/oops v1.16.1 h1:XlKkXsWM5g8hE4C+sEV9n0X282fZn3XabVmAKU2RiHI=
+github.com/samber/oops v1.16.1/go.mod h1:8eXgMAJcDXRAijQsFRhfy/EHDOTiSvwkg6khFqFK078=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
-github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
-github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
-github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
-github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
-github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
-github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
-github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
-github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs=
+github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4=
+github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
+github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
+github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
+github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
+github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
+github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
-github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
-github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
-github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
-github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
-github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
+github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
-go.step.sm/crypto v0.53.0 h1:+1as1ogzuCzx15/468M4mEC5juogI5a0Fzbsyh1CuYY=
-go.step.sm/crypto v0.53.0/go.mod h1:AqLU78RqNUHepLzyOWZuNN/2++Lu7dZENdO9UzWOGSk=
-go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
-go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
-go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
-go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
+go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
+go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
+go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
+go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
+go.step.sm/crypto v0.58.1 h1:2PpEYTbytA3el9dW0gh9uJEe/CR/J6wS+x2vWYLG83M=
+go.step.sm/crypto v0.58.1/go.mod h1:yluOL5OqY7mXGGQ7JUmAv/6h8T8Ge3yXdlEESWHOqDQ=
+go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
+go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
-golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
-golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
-golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
-golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
+golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
+golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
+golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa h1:t2QcU6V556bFjYgu4L6C+6VrCPyJZ+eyRsABUPs1mz4=
+golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa/go.mod h1:BHOTPb3L19zxehTsLoJXVaTktb06DFgmdW6Wb9s8jqk=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
-golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
+golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
+golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
-golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
+golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
-golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
+golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
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=
diff --git a/lib/bootstrap/doc.md b/lib/bootstrap/README.md
similarity index 88%
rename from lib/bootstrap/doc.md
rename to lib/bootstrap/README.md
index 091cdcd..176f59b 100644
--- a/lib/bootstrap/doc.md
+++ b/lib/bootstrap/README.md
@@ -2,6 +2,8 @@
--
import "github.com/go-i2p/go-i2p/lib/bootstrap"
+
+
provides generic interfaces for initial bootstrap into network and network
### reseeding
@@ -21,3 +23,9 @@ type Bootstrap interface {
```
interface defining a way to bootstrap into the i2p network
+
+
+
+bootstrap
+
+github.com/go-i2p/go-i2p/lib/bootstrap
diff --git a/lib/bootstrap/bootstrap.svg b/lib/bootstrap/bootstrap.svg
new file mode 100644
index 0000000..947c327
--- /dev/null
+++ b/lib/bootstrap/bootstrap.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
diff --git a/lib/common/base32/doc.md b/lib/common/base32/README.md
similarity index 90%
rename from lib/common/base32/doc.md
rename to lib/common/base32/README.md
index b77c56a..66ec180 100644
--- a/lib/common/base32/doc.md
+++ b/lib/common/base32/README.md
@@ -2,6 +2,8 @@
--
import "github.com/go-i2p/go-i2p/lib/common/base32"
+
+
Package base32 implmenets utilities for encoding and decoding text using I2P's
### alphabet
@@ -31,3 +33,9 @@ DecodeString decodes base64 string to []byte I2PEncoding
func EncodeToString(data []byte) string
```
EncodeToString encodes []byte to a base32 string using I2PEncoding
+
+
+
+base32
+
+github.com/go-i2p/go-i2p/lib/common/base32
diff --git a/lib/common/base32/base32.svg b/lib/common/base32/base32.svg
new file mode 100644
index 0000000..947c327
--- /dev/null
+++ b/lib/common/base32/base32.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
diff --git a/lib/common/base64/doc.md b/lib/common/base64/README.md
similarity index 91%
rename from lib/common/base64/doc.md
rename to lib/common/base64/README.md
index 511b4ce..03798fb 100644
--- a/lib/common/base64/doc.md
+++ b/lib/common/base64/README.md
@@ -2,6 +2,8 @@
--
import "github.com/go-i2p/go-i2p/lib/common/base64"
+
+
Package base64 implmenets utilities for encoding and decoding text using I2P's
### alphabet
@@ -31,3 +33,9 @@ DecodeString decodes base64 string to []byte I2PEncoding
func EncodeToString(data []byte) string
```
I2PEncoding is the standard base64 encoding used through I2P.
+
+
+
+base64
+
+github.com/go-i2p/go-i2p/lib/common/base64
diff --git a/lib/common/base64/base64.svg b/lib/common/base64/base64.svg
new file mode 100644
index 0000000..947c327
--- /dev/null
+++ b/lib/common/base64/base64.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
diff --git a/lib/common/certificate/doc.md b/lib/common/certificate/README.md
similarity index 74%
rename from lib/common/certificate/doc.md
rename to lib/common/certificate/README.md
index 24712f2..1244c14 100644
--- a/lib/common/certificate/doc.md
+++ b/lib/common/certificate/README.md
@@ -2,6 +2,9 @@
--
import "github.com/go-i2p/go-i2p/lib/common/certificate"
+
+
+
## Usage
@@ -23,6 +26,12 @@ const CERT_MIN_SIZE = 3
CERT_MIN_SIZE is the minimum size of a valid Certificate in []byte 1 byte for
type 2 bytes for payload length
+#### func GetSignatureTypeFromCertificate
+
+```go
+func GetSignatureTypeFromCertificate(cert Certificate) (int, error)
+```
+
#### type Certificate
```go
@@ -37,10 +46,22 @@ https://geti2p.net/spec/common-structures#certificate
#### func NewCertificate
```go
-func NewCertificate(data []byte) (certificate Certificate, err error)
+func NewCertificate() *Certificate
```
-NewCertificate creates a new Certficiate from []byte returns err if the
-certificate is too short or if the payload doesn't match specified length.
+NewCertificate creates a new Certificate with default NULL type
+
+#### func NewCertificateDeux
+
+```go
+func NewCertificateDeux(certType int, payload []byte) (*Certificate, error)
+```
+
+#### func NewCertificateWithType
+
+```go
+func NewCertificateWithType(certType uint8, payload []byte) (*Certificate, error)
+```
+NewCertificateWithType creates a new Certificate with specified type and payload
#### func ReadCertificate
@@ -96,3 +117,9 @@ func (c *Certificate) Type() (cert_type int)
```
Type returns the Certificate type specified in the first byte of the
Certificate,
+
+
+
+certificate
+
+github.com/go-i2p/go-i2p/lib/common/certificate
diff --git a/lib/common/certificate/certificate.go b/lib/common/certificate/certificate.go
index 2256646..fc45d38 100644
--- a/lib/common/certificate/certificate.go
+++ b/lib/common/certificate/certificate.go
@@ -4,13 +4,13 @@ package certificate
import (
"encoding/binary"
- "errors"
"fmt"
+ "github.com/samber/oops"
"github.com/sirupsen/logrus"
// log "github.com/sirupsen/logrus"
- "github.com/go-i2p/go-i2p/lib/util/logger"
+ "github.com/go-i2p/logger"
. "github.com/go-i2p/go-i2p/lib/common/data"
)
@@ -158,7 +158,7 @@ func readCertificate(data []byte) (certificate Certificate, err error) {
"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")
+ err = oops.Errorf("error parsing certificate: certificate is empty")
return
case 1, 2:
certificate.kind = Integer(data[0 : len(data)-1])
@@ -168,7 +168,7 @@ func readCertificate(data []byte) (certificate Certificate, err error) {
"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")
+ err = oops.Errorf("error parsing certificate: certificate is too short")
return
default:
certificate.kind = Integer(data[0:1])
@@ -176,7 +176,7 @@ func readCertificate(data []byte) (certificate Certificate, err error) {
payloadLength := len(data) - CERT_MIN_SIZE
certificate.payload = data[CERT_MIN_SIZE:]
if certificate.len.Int() > len(data)-CERT_MIN_SIZE {
- err = fmt.Errorf("certificate parsing warning: certificate data is shorter than specified by length")
+ err = oops.Errorf("certificate parsing warning: certificate data is shorter than specified by length")
log.WithFields(logrus.Fields{
"at": "(Certificate) NewCertificate",
"certificate_bytes_length": certificate.len.Int(),
@@ -222,12 +222,12 @@ func NewCertificate() *Certificate {
func NewCertificateDeux(certType int, payload []byte) (*Certificate, error) {
if certType < 0 || certType > 255 {
- return nil, fmt.Errorf("invalid certificate type: %d", certType)
+ return nil, oops.Errorf("invalid certificate type: %d", certType)
}
certTypeByte := byte(certType)
if len(payload) > 65535 {
- return nil, fmt.Errorf("payload too long: %d bytes", len(payload))
+ return nil, oops.Errorf("payload too long: %d bytes", len(payload))
}
_len, err := NewIntegerFromInt(len(payload), 2)
@@ -255,12 +255,12 @@ func NewCertificateWithType(certType uint8, payload []byte) (*Certificate, error
case CERT_NULL, CERT_HASHCASH, CERT_HIDDEN, CERT_SIGNED, CERT_MULTIPLE, CERT_KEY:
// Valid type
default:
- return nil, fmt.Errorf("invalid certificate type: %d", certType)
+ return nil, oops.Errorf("invalid certificate type: %d", certType)
}
// For NULL certificates, payload should be empty
if certType == CERT_NULL && len(payload) > 0 {
- return nil, errors.New("NULL certificates must have empty payload")
+ return nil, oops.Errorf("NULL certificates must have empty payload")
}
length, _ := NewIntegerFromInt(len(payload), 2)
@@ -280,10 +280,10 @@ func NewCertificateWithType(certType uint8, payload []byte) (*Certificate, error
func GetSignatureTypeFromCertificate(cert Certificate) (int, error) {
if cert.Type() != CERT_KEY {
- return 0, fmt.Errorf("unexpected certificate type: %d", cert.Type())
+ return 0, oops.Errorf("unexpected certificate type: %d", cert.Type())
}
if len(cert.payload) < 4 {
- return 0, fmt.Errorf("certificate payload too short to contain signature type")
+ return 0, oops.Errorf("certificate payload too short to contain signature type")
}
sigType := int(binary.BigEndian.Uint16(cert.payload[2:4])) // Changed offset to read signing key type
return sigType, nil
diff --git a/lib/common/certificate/certificate.svg b/lib/common/certificate/certificate.svg
new file mode 100644
index 0000000..f72624c
--- /dev/null
+++ b/lib/common/certificate/certificate.svg
@@ -0,0 +1,617 @@
+
+
+
+
+
diff --git a/lib/common/data/doc.md b/lib/common/data/README.md
similarity index 91%
rename from lib/common/data/doc.md
rename to lib/common/data/README.md
index c972402..d7b7ba7 100644
--- a/lib/common/data/doc.md
+++ b/lib/common/data/README.md
@@ -2,6 +2,8 @@
--
import "github.com/go-i2p/go-i2p/lib/common/data"
+
+
Package data implements common data structures used in higher level structures.
## Usage
@@ -22,6 +24,16 @@ const STRING_MAX_SIZE = 255
STRING_MAX_SIZE is the maximum number of bytes that can be stored in an I2P
string
+```go
+var (
+ ErrZeroLength = oops.Errorf("error parsing string: zero length")
+ ErrDataTooShort = oops.Errorf("string parsing warning: string data is shorter than specified by length")
+ ErrDataTooLong = oops.Errorf("string parsing warning: string contains data beyond length")
+ ErrLengthMismatch = oops.Errorf("error reading I2P string, length does not match data")
+ ErrMappingLengthMismatch = oops.Errorf("warning parsing mapping: mapping length exceeds provided data")
+)
+```
+
#### func PrintErrors
```go
@@ -207,7 +219,7 @@ Bytes returns the raw []byte content of an Integer.
```go
func (i Integer) Int() int
```
-Int returns the Date as a Go integer
+Int returns the Integer as a Go integer
#### type Mapping
@@ -295,3 +307,9 @@ occurred during parsing.
```go
func (m MappingValues) Get(key I2PString) I2PString
```
+
+
+
+data
+
+github.com/go-i2p/go-i2p/lib/common/data
diff --git a/lib/common/data/data.svg b/lib/common/data/data.svg
new file mode 100644
index 0000000..b7f4ac2
--- /dev/null
+++ b/lib/common/data/data.svg
@@ -0,0 +1,1306 @@
+
+
+
+
+
diff --git a/lib/common/data/date.go b/lib/common/data/date.go
index a97df40..a25aeec 100644
--- a/lib/common/data/date.go
+++ b/lib/common/data/date.go
@@ -2,10 +2,10 @@
package data
import (
- "errors"
"time"
- "github.com/go-i2p/go-i2p/lib/util/logger"
+ "github.com/go-i2p/logger"
+ "github.com/samber/oops"
"github.com/sirupsen/logrus"
)
@@ -57,7 +57,7 @@ func ReadDate(data []byte) (date Date, remainder []byte, err error) {
log.WithFields(logrus.Fields{
"data": data,
}).Error("ReadDate: data is too short")
- err = errors.New("ReadDate: data is too short")
+ err = oops.Errorf("ReadDate: data is too short")
return
}
copy(date[:], data[:8])
diff --git a/lib/common/data/errors.go b/lib/common/data/errors.go
index f8b17de..88332c6 100644
--- a/lib/common/data/errors.go
+++ b/lib/common/data/errors.go
@@ -1,23 +1,24 @@
package data
import (
- "errors"
"fmt"
+
+ "github.com/samber/oops"
)
var (
- ErrZeroLength = errors.New("error parsing string: zero length")
- ErrDataTooShort = errors.New("string parsing warning: string data is shorter than specified by length")
- ErrDataTooLong = errors.New("string parsing warning: string contains data beyond length")
- ErrLengthMismatch = errors.New("error reading I2P string, length does not match data")
- ErrMappingLengthMismatch = errors.New("warning parsing mapping: mapping length exceeds provided data")
+ ErrZeroLength = fmt.Errorf("error parsing string: zero length")
+ ErrDataTooShort = fmt.Errorf("string parsing warning: string data is shorter than specified by length")
+ ErrDataTooLong = fmt.Errorf("string parsing warning: string contains data beyond length")
+ ErrLengthMismatch = fmt.Errorf("error reading I2P string, length does not match data")
+ ErrMappingLengthMismatch = fmt.Errorf("warning parsing mapping: mapping length exceeds provided data")
)
// 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)
+ err = oops.Errorf("%v\n\t%d: %v", err, i, e)
}
return err
}
diff --git a/lib/common/data/mapping.go b/lib/common/data/mapping.go
index 1b322c2..d9aa9b4 100644
--- a/lib/common/data/mapping.go
+++ b/lib/common/data/mapping.go
@@ -1,8 +1,7 @@
package data
import (
- "errors"
-
+ "github.com/samber/oops"
"github.com/sirupsen/logrus"
)
@@ -164,7 +163,7 @@ func ReadMapping(bytes []byte) (mapping Mapping, remainder []byte, err []error)
"at": "ReadMapping",
"reason": "zero length",
}).Warn("mapping format violation")
- e := errors.New("zero length")
+ e := oops.Errorf("zero length")
err = append(err, e)
return
}
@@ -184,7 +183,7 @@ func ReadMapping(bytes []byte) (mapping Mapping, remainder []byte, err []error)
"expected_size": size.Int(),
"actual_size": len(remainder),
}).Warn("mapping format violation: mapping length exceeds provided data")
- e := errors.New("warning parsing mapping: mapping length exceeds provided data")
+ e := oops.Errorf("warning parsing mapping: mapping length exceeds provided data")
err = append(err, e)
// Use whatever data is available (recovery)
@@ -209,7 +208,7 @@ func ReadMapping(bytes []byte) (mapping Mapping, remainder []byte, err []error)
"at": "ReadMapping",
"reason": "error parsing mapping values",
}).Warn("mapping format violation")
- e := errors.New("error parsing mapping values")
+ e := oops.Errorf("error parsing mapping values")
err = append(err, e)
}
if len(remainder) > 0 { // Handle extra bytes beyond mapping length
@@ -217,7 +216,7 @@ func ReadMapping(bytes []byte) (mapping Mapping, remainder []byte, err []error)
"expected_size": size.Int(),
"actual_size": len(remainder),
}).Error("mapping format violation: data exists beyond length of mapping")
- e := errors.New("warning parsing mapping: data exists beyond length of mapping")
+ e := oops.Errorf("warning parsing mapping: data exists beyond length of mapping")
err = append(err, e)
// Slice the exact mapping bytes
diff --git a/lib/common/data/mapping_test.go b/lib/common/data/mapping_test.go
index 69065c5..0b76685 100644
--- a/lib/common/data/mapping_test.go
+++ b/lib/common/data/mapping_test.go
@@ -2,9 +2,9 @@ package data
import (
"bytes"
- "errors"
"testing"
+ "github.com/samber/oops"
"github.com/stretchr/testify/assert"
)
@@ -154,7 +154,7 @@ func TestFullGoMapToMappingProducesCorrectMapping(t *testing.T) {
func TestStopValueReadTrueWhenCorrectErr(t *testing.T) {
assert := assert.New(t)
- status := stopValueRead(errors.New("error parsing string: zero length"))
+ status := stopValueRead(oops.Errorf("error parsing string: zero length"))
assert.Equal(true, status, "stopValueRead() did not return true when String error found")
}
@@ -162,7 +162,7 @@ func TestStopValueReadTrueWhenCorrectErr(t *testing.T) {
func TestStopValueReadFalseWhenWrongErr(t *testing.T) {
assert := assert.New(t)
- status := stopValueRead(errors.New("something else"))
+ status := stopValueRead(oops.Errorf("something else"))
assert.Equal(false, status, "stopValueRead() did not return false when non String error found")
}
diff --git a/lib/common/data/mapping_values.go b/lib/common/data/mapping_values.go
index 7c84cf5..c81bec5 100644
--- a/lib/common/data/mapping_values.go
+++ b/lib/common/data/mapping_values.go
@@ -1,9 +1,9 @@
package data
import (
- "errors"
"sort"
+ "github.com/samber/oops"
"github.com/sirupsen/logrus"
)
@@ -90,7 +90,7 @@ func ReadMappingValues(remainder []byte, map_length Integer) (values *MappingVal
"at": "(Mapping) Values",
"reason": "data shorter than expected",
}).Error("mapping contained no data")
- errs = []error{errors.New("mapping contained no data")}
+ errs = []error{oops.Errorf("mapping contained no data")}
return
}
map_values := make(MappingValues, 0)
@@ -103,7 +103,7 @@ func ReadMappingValues(remainder []byte, map_length Integer) (values *MappingVal
"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"))
+ errs = append(errs, oops.Errorf("warning parsing mapping: data exists beyond length of mapping"))
} else if int_map_length > mapping_len {
log.WithFields(logrus.Fields{
"at": "(Mapping) Values",
@@ -111,7 +111,7 @@ func ReadMappingValues(remainder []byte, map_length Integer) (values *MappingVal
"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"))
+ errs = append(errs, oops.Errorf("warning parsing mapping: mapping length exceeds provided data"))
}
encounteredKeysMap := map[string]bool{}
@@ -158,7 +158,7 @@ func ReadMappingValues(remainder []byte, map_length Integer) (values *MappingVal
"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"))
+ errs = append(errs, oops.Errorf("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
@@ -171,7 +171,7 @@ func ReadMappingValues(remainder []byte, map_length Integer) (values *MappingVal
"reason": "expected =",
"value:": string(remainder),
}).Warn("mapping format violation")
- errs = append(errs, errors.New("mapping format violation, expected ="))
+ errs = append(errs, oops.Errorf("mapping format violation, expected ="))
log.Printf("ERRVAL: %s", remainder)
break
} else {
@@ -197,7 +197,7 @@ func ReadMappingValues(remainder []byte, map_length Integer) (values *MappingVal
"reason": "expected ;",
"value:": string(remainder),
}).Warn("mapping format violation")
- errs = append(errs, errors.New("mapping format violation, expected ;"))
+ errs = append(errs, oops.Errorf("mapping format violation, expected ;"))
break
} else {
remainder = remainder[1:]
diff --git a/lib/common/data/string.go b/lib/common/data/string.go
index a8ffd57..69f1b33 100644
--- a/lib/common/data/string.go
+++ b/lib/common/data/string.go
@@ -1,8 +1,7 @@
package data
import (
- "errors"
-
+ "github.com/samber/oops"
"github.com/sirupsen/logrus"
)
@@ -124,7 +123,7 @@ func ToI2PString(data string) (str I2PString, err error) {
"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")
+ err = oops.Errorf("cannot store that much data in I2P string")
return
}
i2p_string := []byte{byte(data_len)}
diff --git a/lib/common/destination/doc.md b/lib/common/destination/README.md
similarity index 90%
rename from lib/common/destination/doc.md
rename to lib/common/destination/README.md
index fff8c39..c6d734f 100644
--- a/lib/common/destination/doc.md
+++ b/lib/common/destination/README.md
@@ -2,6 +2,8 @@
--
import "github.com/go-i2p/go-i2p/lib/common/destination"
+
+
Package destination implements the I2P Destination common data structure
## Usage
@@ -40,3 +42,9 @@ Base32Address returns the I2P base32 address for this Destination.
func (destination Destination) Base64() string
```
Base64 returns the I2P base64 address for this Destination.
+
+
+
+destination
+
+github.com/go-i2p/go-i2p/lib/common/destination
diff --git a/lib/common/destination/destination.go b/lib/common/destination/destination.go
index cc3ae14..e2d05ab 100644
--- a/lib/common/destination/destination.go
+++ b/lib/common/destination/destination.go
@@ -4,7 +4,7 @@ package destination
import (
"strings"
- "github.com/go-i2p/go-i2p/lib/util/logger"
+ "github.com/go-i2p/logger"
"github.com/sirupsen/logrus"
. "github.com/go-i2p/go-i2p/lib/common/keys_and_cert"
@@ -31,7 +31,7 @@ Identical to KeysAndCert.
//
// https://geti2p.net/spec/common-structures#destination
type Destination struct {
- KeysAndCert
+ *KeysAndCert
}
// Base32Address returns the I2P base32 address for this Destination.
diff --git a/lib/common/destination/destination.svg b/lib/common/destination/destination.svg
new file mode 100644
index 0000000..33af07b
--- /dev/null
+++ b/lib/common/destination/destination.svg
@@ -0,0 +1,300 @@
+
+
+
+
+
diff --git a/lib/common/fuzz/certificate/doc.md b/lib/common/fuzz/certificate/README.md
similarity index 58%
rename from lib/common/fuzz/certificate/doc.md
rename to lib/common/fuzz/certificate/README.md
index 64dd643..ece1dd2 100644
--- a/lib/common/fuzz/certificate/doc.md
+++ b/lib/common/fuzz/certificate/README.md
@@ -2,6 +2,9 @@
--
import "github.com/go-i2p/go-i2p/lib/common/fuzz/certificate"
+
+
+
## Usage
@@ -10,3 +13,9 @@
```go
func Fuzz(data []byte) int
```
+
+
+
+exportable
+
+github.com/go-i2p/go-i2p/lib/common/fuzz/certificate
diff --git a/lib/common/fuzz/certificate/exportable.svg b/lib/common/fuzz/certificate/exportable.svg
new file mode 100644
index 0000000..19f74a3
--- /dev/null
+++ b/lib/common/fuzz/certificate/exportable.svg
@@ -0,0 +1,111 @@
+
+
+
+
+
diff --git a/lib/common/fuzz/destination/doc.md b/lib/common/fuzz/destination/README.md
similarity index 58%
rename from lib/common/fuzz/destination/doc.md
rename to lib/common/fuzz/destination/README.md
index 5b01e3e..a5136e8 100644
--- a/lib/common/fuzz/destination/doc.md
+++ b/lib/common/fuzz/destination/README.md
@@ -2,6 +2,9 @@
--
import "github.com/go-i2p/go-i2p/lib/common/fuzz/destination"
+
+
+
## Usage
@@ -10,3 +13,9 @@
```go
func Fuzz(data []byte) int
```
+
+
+
+exportable
+
+github.com/go-i2p/go-i2p/lib/common/fuzz/destination
diff --git a/lib/common/fuzz/destination/exportable.svg b/lib/common/fuzz/destination/exportable.svg
new file mode 100644
index 0000000..716fc57
--- /dev/null
+++ b/lib/common/fuzz/destination/exportable.svg
@@ -0,0 +1,92 @@
+
+
+
+
+
diff --git a/lib/common/fuzz/keys_and_cert/doc.md b/lib/common/fuzz/keys_and_cert/README.md
similarity index 58%
rename from lib/common/fuzz/keys_and_cert/doc.md
rename to lib/common/fuzz/keys_and_cert/README.md
index bc92c71..9a38f1e 100644
--- a/lib/common/fuzz/keys_and_cert/doc.md
+++ b/lib/common/fuzz/keys_and_cert/README.md
@@ -2,6 +2,9 @@
--
import "github.com/go-i2p/go-i2p/lib/common/fuzz/keys_and_cert"
+
+
+
## Usage
@@ -10,3 +13,9 @@
```go
func Fuzz(data []byte) int
```
+
+
+
+exportable
+
+github.com/go-i2p/go-i2p/lib/common/fuzz/keys_and_cert
diff --git a/lib/common/fuzz/keys_and_cert/exportable.svg b/lib/common/fuzz/keys_and_cert/exportable.svg
new file mode 100644
index 0000000..a127884
--- /dev/null
+++ b/lib/common/fuzz/keys_and_cert/exportable.svg
@@ -0,0 +1,111 @@
+
+
+
+
+
diff --git a/lib/common/fuzz/router_address/doc.md b/lib/common/fuzz/router_address/README.md
similarity index 58%
rename from lib/common/fuzz/router_address/doc.md
rename to lib/common/fuzz/router_address/README.md
index a221b33..3aed03f 100644
--- a/lib/common/fuzz/router_address/doc.md
+++ b/lib/common/fuzz/router_address/README.md
@@ -2,6 +2,9 @@
--
import "github.com/go-i2p/go-i2p/lib/common/fuzz/router_address"
+
+
+
## Usage
@@ -10,3 +13,9 @@
```go
func Fuzz(data []byte) int
```
+
+
+
+exportable
+
+github.com/go-i2p/go-i2p/lib/common/fuzz/router_address
diff --git a/lib/common/fuzz/router_address/exportable.svg b/lib/common/fuzz/router_address/exportable.svg
new file mode 100644
index 0000000..b417bd3
--- /dev/null
+++ b/lib/common/fuzz/router_address/exportable.svg
@@ -0,0 +1,130 @@
+
+
+
+
+
diff --git a/lib/common/fuzz/router_identity/doc.md b/lib/common/fuzz/router_identity/README.md
similarity index 58%
rename from lib/common/fuzz/router_identity/doc.md
rename to lib/common/fuzz/router_identity/README.md
index 18208d6..3dec724 100644
--- a/lib/common/fuzz/router_identity/doc.md
+++ b/lib/common/fuzz/router_identity/README.md
@@ -2,6 +2,9 @@
--
import "github.com/go-i2p/go-i2p/lib/common/fuzz/router_identity"
+
+
+
## Usage
@@ -10,3 +13,9 @@
```go
func Fuzz(data []byte) int
```
+
+
+
+exportable
+
+github.com/go-i2p/go-i2p/lib/common/fuzz/router_identity
diff --git a/lib/common/fuzz/router_identity/exportable.svg b/lib/common/fuzz/router_identity/exportable.svg
new file mode 100644
index 0000000..722d469
--- /dev/null
+++ b/lib/common/fuzz/router_identity/exportable.svg
@@ -0,0 +1,73 @@
+
+
+
+
+
diff --git a/lib/common/fuzz/string/doc.md b/lib/common/fuzz/string/README.md
similarity index 59%
rename from lib/common/fuzz/string/doc.md
rename to lib/common/fuzz/string/README.md
index c432f87..5f66060 100644
--- a/lib/common/fuzz/string/doc.md
+++ b/lib/common/fuzz/string/README.md
@@ -2,6 +2,9 @@
--
import "github.com/go-i2p/go-i2p/lib/common/fuzz/string"
+
+
+
## Usage
@@ -10,3 +13,9 @@
```go
func Fuzz(data []byte) int
```
+
+
+
+exportable
+
+github.com/go-i2p/go-i2p/lib/common/fuzz/string
diff --git a/lib/common/fuzz/string/exportable.svg b/lib/common/fuzz/string/exportable.svg
new file mode 100644
index 0000000..f43d576
--- /dev/null
+++ b/lib/common/fuzz/string/exportable.svg
@@ -0,0 +1,92 @@
+
+
+
+
+
diff --git a/lib/common/key_certificate/doc.md b/lib/common/key_certificate/README.md
similarity index 51%
rename from lib/common/key_certificate/doc.md
rename to lib/common/key_certificate/README.md
index 6d189a0..d66851a 100644
--- a/lib/common/key_certificate/doc.md
+++ b/lib/common/key_certificate/README.md
@@ -2,32 +2,34 @@
--
import "github.com/go-i2p/go-i2p/lib/common/key_certificate"
+
+
Package key_certificate implements the I2P Destination common data structure
## Usage
```go
const (
- KEYCERT_SIGN_DSA_SHA1 = iota
- KEYCERT_SIGN_P256
- KEYCERT_SIGN_P384
- KEYCERT_SIGN_P521
- KEYCERT_SIGN_RSA2048
- KEYCERT_SIGN_RSA3072
- KEYCERT_SIGN_RSA4096
- KEYCERT_SIGN_ED25519
- KEYCERT_SIGN_ED25519PH
+ KEYCERT_SIGN_DSA_SHA1 = 0
+ KEYCERT_SIGN_P256 = 1
+ KEYCERT_SIGN_P384 = 2
+ KEYCERT_SIGN_P521 = 3
+ KEYCERT_SIGN_RSA2048 = 4
+ KEYCERT_SIGN_RSA3072 = 5
+ KEYCERT_SIGN_RSA4096 = 6
+ KEYCERT_SIGN_ED25519 = 7
+ KEYCERT_SIGN_ED25519PH = 8
)
```
Key Certificate Signing Key Types
```go
const (
- KEYCERT_CRYPTO_ELG = iota
- KEYCERT_CRYPTO_P256
- KEYCERT_CRYPTO_P384
- KEYCERT_CRYPTO_P521
- KEYCERT_CRYPTO_X25519
+ KEYCERT_CRYPTO_ELG = 0
+ KEYCERT_CRYPTO_P256 = 1
+ KEYCERT_CRYPTO_P384 = 2
+ KEYCERT_CRYPTO_P521 = 3
+ KEYCERT_CRYPTO_X25519 = 4
)
```
Key Certificate Public Key Types
@@ -45,7 +47,7 @@ const (
KEYCERT_SIGN_ED25519PH_SIZE = 32
)
```
-SigningPublicKey sizes for Signing Key Types
+signingPublicKey sizes for Signing Key Types
```go
const (
@@ -56,7 +58,7 @@ const (
KEYCERT_CRYPTO_X25519_SIZE = 32
)
```
-PublicKey sizes for Public Key Types
+publicKey sizes for Public Key Types
```go
const (
@@ -66,17 +68,42 @@ const (
```
Sizes of structures in KeyCertificates
+```go
+const (
+ CRYPTO_KEY_TYPE_ELGAMAL = 0 // ElGamal
+
+ // Signature Types
+ SIGNATURE_TYPE_DSA_SHA1 = 0 // DSA-SHA1
+ SIGNATURE_TYPE_ED25519_SHA512 = 7 // Ed25519
+)
+```
+
```go
const (
KEYCERT_MIN_SIZE = 7
)
```
+```go
+var CryptoPublicKeySizes = map[uint16]int{
+ CRYPTO_KEY_TYPE_ELGAMAL: 256,
+}
+```
+
+```go
+var SignaturePublicKeySizes = map[uint16]int{
+ SIGNATURE_TYPE_DSA_SHA1: 128,
+ SIGNATURE_TYPE_ED25519_SHA512: 32,
+}
+```
+
#### type KeyCertificate
```go
type KeyCertificate struct {
Certificate
+ SpkType Integer
+ CpkType Integer
}
```
@@ -85,9 +112,8 @@ type KeyCertificate []byte
#### func KeyCertificateFromCertificate
```go
-func KeyCertificateFromCertificate(certificate Certificate) *KeyCertificate
+func KeyCertificateFromCertificate(cert Certificate) (*KeyCertificate, error)
```
-KeyCertificateFromCertificate returns a *KeyCertificate from a *Certificate.
#### func NewKeyCertificate
@@ -101,54 +127,72 @@ returned. Returns a list of errors that occurred during parsing.
#### func (KeyCertificate) ConstructPublicKey
```go
-func (key_certificate KeyCertificate) ConstructPublicKey(data []byte) (public_key crypto.PublicKey, err error)
+func (keyCertificate KeyCertificate) ConstructPublicKey(data []byte) (public_key crypto.RecievingPublicKey, err error)
```
-ConstructPublicKey returns a PublicKey constructed using any excess data that
+ConstructPublicKey returns a publicKey constructed using any excess data that
may be stored in the KeyCertififcate. Returns enr errors encountered while
parsing.
#### func (KeyCertificate) ConstructSigningPublicKey
```go
-func (key_certificate KeyCertificate) ConstructSigningPublicKey(data []byte) (signing_public_key crypto.SigningPublicKey, err error)
+func (keyCertificate KeyCertificate) ConstructSigningPublicKey(data []byte) (signing_public_key crypto.SigningPublicKey, err error)
```
ConstructSigningPublicKey returns a SingingPublicKey constructed using any
excess data that may be stored in the KeyCertificate. Returns any errors
encountered while parsing.
+#### func (*KeyCertificate) CryptoPublicKeySize
+
+```go
+func (keyCertificate *KeyCertificate) CryptoPublicKeySize() (int, error)
+```
+
#### func (KeyCertificate) CryptoSize
```go
-func (key_certificate KeyCertificate) CryptoSize() (size int)
+func (keyCertificate KeyCertificate) CryptoSize() (size int)
```
CryptoSize return the size of a Public Key corresponding to the Key
-Certificate's PublicKey type.
+Certificate's publicKey type.
#### func (KeyCertificate) Data
```go
-func (key_certificate KeyCertificate) Data() ([]byte, error)
+func (keyCertificate KeyCertificate) Data() ([]byte, error)
```
Data returns the raw []byte contained in the Certificate.
#### func (KeyCertificate) PublicKeyType
```go
-func (key_certificate KeyCertificate) PublicKeyType() (pubkey_type int)
+func (keyCertificate KeyCertificate) PublicKeyType() (pubkey_type int)
```
-PublicKeyType returns the PublicKey type as a Go integer.
+PublicKeyType returns the publicKey type as a Go integer.
#### func (KeyCertificate) SignatureSize
```go
-func (key_certificate KeyCertificate) SignatureSize() (size int)
+func (keyCertificate KeyCertificate) SignatureSize() (size int)
```
SignatureSize return the size of a Signature corresponding to the Key
-Certificate's SigningPublicKey type.
+Certificate's signingPublicKey type.
+
+#### func (*KeyCertificate) SigningPublicKeySize
+
+```go
+func (keyCertificate *KeyCertificate) SigningPublicKeySize() int
+```
#### func (KeyCertificate) SigningPublicKeyType
```go
-func (key_certificate KeyCertificate) SigningPublicKeyType() (signing_pubkey_type int)
+func (keyCertificate KeyCertificate) SigningPublicKeyType() (signing_pubkey_type int)
```
-SigningPublicKeyType returns the SigningPublicKey type as a Go integer.
+SigningPublicKeyType returns the signingPublicKey type as a Go integer.
+
+
+
+key_certificate
+
+github.com/go-i2p/go-i2p/lib/common/key_certificate
diff --git a/lib/common/key_certificate/key_certificate.go b/lib/common/key_certificate/key_certificate.go
index 3fcafeb..bba4fed 100644
--- a/lib/common/key_certificate/key_certificate.go
+++ b/lib/common/key_certificate/key_certificate.go
@@ -31,8 +31,9 @@ import (
"fmt"
"github.com/go-i2p/go-i2p/lib/common/signature"
+ "github.com/samber/oops"
- "github.com/go-i2p/go-i2p/lib/util/logger"
+ "github.com/go-i2p/logger"
"github.com/sirupsen/logrus"
. "github.com/go-i2p/go-i2p/lib/common/certificate"
@@ -132,7 +133,7 @@ func (keyCertificate KeyCertificate) PublicKeyType() (pubkey_type int) {
// ConstructPublicKey returns a publicKey constructed using any excess data that may be stored in the KeyCertififcate.
// Returns enr errors encountered while parsing.
-func (keyCertificate KeyCertificate) ConstructPublicKey(data []byte) (public_key crypto.PublicKey, err error) {
+func (keyCertificate KeyCertificate) ConstructPublicKey(data []byte) (public_key crypto.RecievingPublicKey, err error) {
log.WithFields(logrus.Fields{
"input_length": len(data),
}).Debug("Constructing publicKey from keyCertificate")
@@ -148,7 +149,7 @@ func (keyCertificate KeyCertificate) ConstructPublicKey(data []byte) (public_key
"required_len": KEYCERT_PUBKEY_SIZE,
"reason": "not enough data",
}).Error("error constructing public key")
- err = fmt.Errorf("error constructing public key: not enough data")
+ err = oops.Errorf("error constructing public key: not enough data")
return
}
switch key_type {
@@ -191,7 +192,7 @@ var SignaturePublicKeySizes = map[uint16]int{
func (keyCertificate *KeyCertificate) CryptoPublicKeySize() (int, error) {
size, exists := CryptoPublicKeySizes[uint16(keyCertificate.CpkType.Int())]
if !exists {
- return 0, fmt.Errorf("unknown crypto key type: %d", keyCertificate.CpkType.Int())
+ return 0, oops.Errorf("unknown crypto key type: %d", keyCertificate.CpkType.Int())
}
return size, nil
}
@@ -240,7 +241,7 @@ func (keyCertificate KeyCertificate) ConstructSigningPublicKey(data []byte) (sig
"required_len": KEYCERT_SPK_SIZE,
"reason": "not enough data",
}).Error("error constructing signing public key")
- err = fmt.Errorf("error constructing signing public key: not enough data")
+ err = oops.Errorf("error constructing signing public key: not enough data")
return
}
switch signing_key_type {
@@ -297,7 +298,7 @@ func (keyCertificate KeyCertificate) ConstructSigningPublicKey(data []byte) (sig
log.WithFields(logrus.Fields{
"signing_key_type": signing_key_type,
}).Warn("Unknown signing key type")
- return nil, fmt.Errorf("unknown signing key type")
+ return nil, oops.Errorf("unknown signing key type")
}
return
@@ -365,11 +366,11 @@ func NewKeyCertificate(bytes []byte) (key_certificate *KeyCertificate, remainder
}
if certificate.Type() != CERT_KEY {
- return nil, remainder, fmt.Errorf("invalid certificate type: %d", certificate.Type())
+ return nil, remainder, oops.Errorf("invalid certificate type: %d", certificate.Type())
}
if len(certificate.Data()) < 4 {
- return nil, remainder, fmt.Errorf("key certificate data too short")
+ return nil, remainder, oops.Errorf("key certificate data too short")
}
log.Println("Certificate Data in NewKeyCertificate: ", certificate.Data()[0:2], certificate.Data()[2:4])
@@ -393,7 +394,7 @@ func NewKeyCertificate(bytes []byte) (key_certificate *KeyCertificate, remainder
func KeyCertificateFromCertificate(cert Certificate) (*KeyCertificate, error) {
if cert.Type() != CERT_KEY {
- return nil, fmt.Errorf("expected Key Certificate type, got %d", cert.Type())
+ return nil, oops.Errorf("expected Key Certificate type, got %d", cert.Type())
}
data := cert.Data()
@@ -401,7 +402,7 @@ func KeyCertificateFromCertificate(cert Certificate) (*KeyCertificate, error) {
fmt.Printf("Certificate Data Bytes in KeyCertificateFromCertificate: %v\n", data)
if len(data) < 4 {
- return nil, fmt.Errorf("certificate payload too short in KeyCertificateFromCertificate")
+ return nil, oops.Errorf("certificate payload too short in KeyCertificateFromCertificate")
}
cpkTypeBytes := data[0:2]
diff --git a/lib/common/key_certificate/key_certificate.svg b/lib/common/key_certificate/key_certificate.svg
new file mode 100644
index 0000000..78c55a9
--- /dev/null
+++ b/lib/common/key_certificate/key_certificate.svg
@@ -0,0 +1,764 @@
+
+
+
+
+
diff --git a/lib/common/key_certificate/key_certificate_test.go b/lib/common/key_certificate/key_certificate_test.go
index 49f2d07..6f08f65 100644
--- a/lib/common/key_certificate/key_certificate_test.go
+++ b/lib/common/key_certificate/key_certificate_test.go
@@ -14,7 +14,7 @@ func TestSigningPublicKeyTypeReturnsCorrectInteger(t *testing.T) {
assert.Nil(err)
pk_type := key_cert.SigningPublicKeyType()
- assert.Equal(KEYCERT_SIGN_ED25519, pk_type, "SigningPublicKeyType() did not return correct type")
+ assert.Equal(KEYCERT_SIGN_P521, pk_type, "SigningPublicKeyType() did not return correct type")
}
func TestSigningPublicKeyTypeWithInvalidData(t *testing.T) {
@@ -44,7 +44,7 @@ func TestPublicKeyTypeWithInvalidData(t *testing.T) {
// Test with invalid short data
key_cert, _, err := NewKeyCertificate([]byte{0x05, 0x00, 0x02})
assert.NotNil(err)
- assert.Contains(err.Error(), "key certificate data too short", "Expected error for invalid data")
+ assert.Contains(err.Error(), "certificate parsing warning: certificate data is shorter than specified by length", "Expected error for invalid data")
assert.Nil(key_cert)
}
@@ -61,6 +61,7 @@ func TestConstructPublicKeyWithInsufficientData(t *testing.T) {
assert.NotNil(err)
assert.Equal("error constructing public key: not enough data", err.Error())
}
+
func TestConstructPublicKeyReturnsCorrectDataWithElg(t *testing.T) {
assert := assert.New(t)
diff --git a/lib/common/keys_and_cert/README.md b/lib/common/keys_and_cert/README.md
new file mode 100644
index 0000000..93875d9
--- /dev/null
+++ b/lib/common/keys_and_cert/README.md
@@ -0,0 +1,116 @@
+# keys_and_cert
+--
+ import "github.com/go-i2p/go-i2p/lib/common/keys_and_cert"
+
+
+
+Package keys_and_cert implements the I2P KeysAndCert common data structure
+
+## Usage
+
+```go
+const (
+ KEYS_AND_CERT_PUBKEY_SIZE = 256
+ KEYS_AND_CERT_SPK_SIZE = 128
+ KEYS_AND_CERT_MIN_SIZE = 387
+ KEYS_AND_CERT_DATA_SIZE = 384
+)
+```
+Sizes of various KeysAndCert structures and requirements
+
+#### type KeysAndCert
+
+```go
+type KeysAndCert struct {
+ KeyCertificate *KeyCertificate
+ ReceivingPublic crypto.RecievingPublicKey
+ Padding []byte
+ SigningPublic crypto.SigningPublicKey
+}
+```
+
+KeysAndCert is the represenation of an I2P KeysAndCert.
+
+https://geti2p.net/spec/common-structures#keysandcert
+
+#### func NewKeysAndCert
+
+```go
+func NewKeysAndCert(
+ keyCertificate *KeyCertificate,
+ publicKey crypto.RecievingPublicKey,
+ padding []byte,
+ signingPublicKey crypto.SigningPublicKey,
+) (*KeysAndCert, error)
+```
+NewKeysAndCert creates a new KeysAndCert instance with the provided parameters.
+It validates the sizes of the provided keys and padding before assembling the
+struct.
+
+#### func ReadKeysAndCert
+
+```go
+func ReadKeysAndCert(data []byte) (keys_and_cert KeysAndCert, remainder []byte, err error)
+```
+ReadKeysAndCert creates a new *KeysAndCert from []byte using ReadKeysAndCert.
+Returns a pointer to KeysAndCert unlike ReadKeysAndCert.
+
+#### func ReadKeysAndCertElgAndEd25519
+
+```go
+func ReadKeysAndCertElgAndEd25519(data []byte) (keysAndCert *KeysAndCert, remainder []byte, err error)
+```
+
+#### func (KeysAndCert) Bytes
+
+```go
+func (keys_and_cert KeysAndCert) Bytes() []byte
+```
+Bytes returns the entire keyCertificate in []byte form, trims payload to
+specified length.
+
+#### func (*KeysAndCert) Certificate
+
+```go
+func (keys_and_cert *KeysAndCert) Certificate() (cert Certificate)
+```
+Certfificate returns the certificate.
+
+#### func (*KeysAndCert) PublicKey
+
+```go
+func (keys_and_cert *KeysAndCert) PublicKey() (key crypto.RecievingPublicKey)
+```
+publicKey returns the public key as a crypto.publicKey.
+
+#### func (*KeysAndCert) SigningPublicKey
+
+```go
+func (keys_and_cert *KeysAndCert) SigningPublicKey() (signing_public_key crypto.SigningPublicKey)
+```
+signingPublicKey returns the signing public key.
+
+#### type PrivateKeysAndCert
+
+```go
+type PrivateKeysAndCert struct {
+ KeysAndCert
+ PK_KEY crypto.PrivateKey
+ SPK_KEY crypto.PrivateKey
+}
+```
+
+PrivateKeysAndCert contains a KeysAndCert along with the corresponding private
+keys for the Public Key and the Signing Public Key
+
+#### func NewPrivateKeysAndCert
+
+```go
+func NewPrivateKeysAndCert() (*PrivateKeysAndCert, error)
+```
+
+
+
+keys_and_cert
+
+github.com/go-i2p/go-i2p/lib/common/keys_and_cert
diff --git a/lib/common/keys_and_cert/doc.md b/lib/common/keys_and_cert/doc.md
deleted file mode 100644
index a113c02..0000000
--- a/lib/common/keys_and_cert/doc.md
+++ /dev/null
@@ -1,66 +0,0 @@
-# keys_and_cert
---
- import "github.com/go-i2p/go-i2p/lib/common/keys_and_cert"
-
-Package keys_and_cert implements the I2P KeysAndCert common data structure
-
-## Usage
-
-```go
-const (
- KEYS_AND_CERT_PUBKEY_SIZE = 256
- KEYS_AND_CERT_SPK_SIZE = 128
- KEYS_AND_CERT_MIN_SIZE = 387
- KEYS_AND_CERT_DATA_SIZE = 384
-)
-```
-Sizes of various KeysAndCert structures and requirements
-
-#### type KeysAndCert
-
-```go
-type KeysAndCert struct {
- KeyCertificate *KeyCertificate
-}
-```
-
-KeysAndCert is the represenation of an I2P KeysAndCert.
-
-https://geti2p.net/spec/common-structures#keysandcert
-
-#### func ReadKeysAndCert
-
-```go
-func ReadKeysAndCert(data []byte) (keys_and_cert KeysAndCert, remainder []byte, err error)
-```
-ReadKeysAndCert creates a new *KeysAndCert from []byte using ReadKeysAndCert.
-Returns a pointer to KeysAndCert unlike ReadKeysAndCert.
-
-#### func (KeysAndCert) Bytes
-
-```go
-func (keys_and_cert KeysAndCert) Bytes() []byte
-```
-Bytes returns the entire KeyCertificate in []byte form, trims payload to
-specified length.
-
-#### func (*KeysAndCert) Certificate
-
-```go
-func (keys_and_cert *KeysAndCert) Certificate() (cert Certificate)
-```
-Certfificate returns the certificate.
-
-#### func (*KeysAndCert) PublicKey
-
-```go
-func (keys_and_cert *KeysAndCert) PublicKey() (key crypto.PublicKey)
-```
-PublicKey returns the public key as a crypto.PublicKey.
-
-#### func (*KeysAndCert) SigningPublicKey
-
-```go
-func (keys_and_cert *KeysAndCert) SigningPublicKey() (signing_public_key crypto.SigningPublicKey)
-```
-SigningPublicKey returns the signing public key.
diff --git a/lib/common/keys_and_cert/keys_and_cert.go b/lib/common/keys_and_cert/keys_and_cert.go
index 9e2a694..261c6ec 100644
--- a/lib/common/keys_and_cert/keys_and_cert.go
+++ b/lib/common/keys_and_cert/keys_and_cert.go
@@ -2,10 +2,8 @@
package keys_and_cert
import (
- "errors"
- "fmt"
-
- "github.com/go-i2p/go-i2p/lib/util/logger"
+ "github.com/go-i2p/logger"
+ "github.com/samber/oops"
. "github.com/go-i2p/go-i2p/lib/common/certificate"
. "github.com/go-i2p/go-i2p/lib/common/key_certificate"
@@ -79,38 +77,59 @@ total length: 387+ bytes
//
// https://geti2p.net/spec/common-structures#keysandcert
type KeysAndCert struct {
- KeyCertificate *KeyCertificate
- publicKey crypto.PublicKey
- Padding []byte
- signingPublicKey crypto.SigningPublicKey
+ KeyCertificate *KeyCertificate
+ ReceivingPublic crypto.RecievingPublicKey
+ Padding []byte
+ SigningPublic crypto.SigningPublicKey
}
// Bytes returns the entire keyCertificate in []byte form, trims payload to specified length.
func (keys_and_cert KeysAndCert) Bytes() []byte {
- bytes := keys_and_cert.publicKey.Bytes()
- bytes = append(bytes, keys_and_cert.Padding...)
- bytes = append(bytes, keys_and_cert.signingPublicKey.Bytes()...)
- bytes = append(bytes, keys_and_cert.KeyCertificate.Bytes()...)
+ bytes := []byte{}
+ rpublen := 0
+ if keys_and_cert.ReceivingPublic != nil {
+ bytes = append(bytes, keys_and_cert.ReceivingPublic.Bytes()...)
+ rpublen = len(keys_and_cert.ReceivingPublic.Bytes())
+ }
+ // bytes = append(bytes, keys_and_cert.ReceivingPublic.Bytes()...)
+ padlen := 0
+ if keys_and_cert.Padding != nil {
+ bytes = append(bytes, keys_and_cert.Padding...)
+ padlen = len(keys_and_cert.Padding)
+ }
+ // bytes = append(bytes, keys_and_cert.Padding...)
+ spublen := 0
+ if keys_and_cert.SigningPublic != nil {
+ bytes = append(bytes, keys_and_cert.SigningPublic.Bytes()...)
+ spublen = len(keys_and_cert.SigningPublic.Bytes())
+ }
+ // bytes = append(bytes, keys_and_cert.SigningPublic.Bytes()...)
+ certlen := 0
+ if keys_and_cert.KeyCertificate != nil {
+ bytes = append(bytes, keys_and_cert.KeyCertificate.Bytes()...)
+ certlen = len(keys_and_cert.KeyCertificate.Bytes())
+ }
+ // bytes = append(bytes, keys_and_cert.KeyCertificate.Bytes()...)
log.WithFields(logrus.Fields{
"bytes": bytes,
"padding": keys_and_cert.Padding,
"bytes_length": len(bytes),
- "pk_bytes_length": len(keys_and_cert.publicKey.Bytes()),
- "padding_bytes_length": len(keys_and_cert.Padding),
- "spk_bytes_length": len(keys_and_cert.signingPublicKey.Bytes()),
- "cert_bytes_length": len(keys_and_cert.KeyCertificate.Bytes()),
+ "pk_bytes_length": rpublen,
+ "padding_bytes_length": padlen,
+ "spk_bytes_length": spublen,
+ "cert_bytes_length": certlen,
}).Debug("Retrieved bytes from KeysAndCert")
return bytes
}
// publicKey returns the public key as a crypto.publicKey.
-func (keys_and_cert *KeysAndCert) PublicKey() (key crypto.PublicKey) {
- return keys_and_cert.publicKey
+func (keys_and_cert *KeysAndCert) PublicKey() (key crypto.RecievingPublicKey) {
+ return keys_and_cert.ReceivingPublic
}
// signingPublicKey returns the signing public key.
func (keys_and_cert *KeysAndCert) SigningPublicKey() (signing_public_key crypto.SigningPublicKey) {
- return keys_and_cert.signingPublicKey
+ return keys_and_cert.SigningPublic
}
// Certfificate returns the certificate.
@@ -120,10 +139,13 @@ func (keys_and_cert *KeysAndCert) Certificate() (cert Certificate) {
// ReadKeysAndCert creates a new *KeysAndCert from []byte using ReadKeysAndCert.
// Returns a pointer to KeysAndCert unlike ReadKeysAndCert.
-func ReadKeysAndCert(data []byte) (keys_and_cert KeysAndCert, remainder []byte, err error) {
+func ReadKeysAndCert(data []byte) (*KeysAndCert, []byte, error) {
log.WithFields(logrus.Fields{
"input_length": len(data),
}).Debug("Reading KeysAndCert from data")
+ var err error
+ var remainder []byte
+ var keys_and_cert KeysAndCert
data_len := len(data)
if data_len < KEYS_AND_CERT_MIN_SIZE {
@@ -133,14 +155,14 @@ func ReadKeysAndCert(data []byte) (keys_and_cert KeysAndCert, remainder []byte,
"required_len": KEYS_AND_CERT_MIN_SIZE,
"reason": "not enough data",
}).Error("error parsing keys and cert")
- err = errors.New("error parsing KeysAndCert: data is smaller than minimum valid size")
- return
+ err = oops.Errorf("error parsing KeysAndCert: data is smaller than minimum valid size")
+ return &keys_and_cert, remainder, err
}
keys_and_cert.KeyCertificate, remainder, err = NewKeyCertificate(data[KEYS_AND_CERT_DATA_SIZE:])
if err != nil {
log.WithError(err).Error("Failed to create keyCertificate")
- return
+ return &keys_and_cert, remainder, err
}
// Get the actual key sizes from the certificate
@@ -148,10 +170,10 @@ func ReadKeysAndCert(data []byte) (keys_and_cert KeysAndCert, remainder []byte,
sigKeySize := keys_and_cert.KeyCertificate.SignatureSize()
// Construct public key
- keys_and_cert.publicKey, err = keys_and_cert.KeyCertificate.ConstructPublicKey(data[:pubKeySize])
+ keys_and_cert.ReceivingPublic, err = keys_and_cert.KeyCertificate.ConstructPublicKey(data[:pubKeySize])
if err != nil {
log.WithError(err).Error("Failed to construct publicKey")
- return
+ return &keys_and_cert, remainder, err
}
// Calculate padding size and extract padding
@@ -162,12 +184,12 @@ func ReadKeysAndCert(data []byte) (keys_and_cert KeysAndCert, remainder []byte,
}
// Construct signing public key
- keys_and_cert.signingPublicKey, err = keys_and_cert.KeyCertificate.ConstructSigningPublicKey(
+ keys_and_cert.SigningPublic, err = keys_and_cert.KeyCertificate.ConstructSigningPublicKey(
data[KEYS_AND_CERT_DATA_SIZE-sigKeySize : KEYS_AND_CERT_DATA_SIZE],
)
if err != nil {
log.WithError(err).Error("Failed to construct signingPublicKey")
- return
+ return &keys_and_cert, remainder, err
}
log.WithFields(logrus.Fields{
@@ -177,7 +199,7 @@ func ReadKeysAndCert(data []byte) (keys_and_cert KeysAndCert, remainder []byte,
"remainder_length": len(remainder),
}).Debug("Successfully read KeysAndCert")
- return
+ return &keys_and_cert, remainder, err
}
func ReadKeysAndCertElgAndEd25519(data []byte) (keysAndCert *KeysAndCert, remainder []byte, err error) {
@@ -196,7 +218,7 @@ func ReadKeysAndCertElgAndEd25519(data []byte) (keysAndCert *KeysAndCert, remain
dataLen := len(data)
if dataLen < minDataLength {
- err = fmt.Errorf("error parsing KeysAndCert: data is smaller than minimum valid size, got %d bytes", dataLen)
+ err = oops.Errorf("error parsing KeysAndCert: data is smaller than minimum valid size, got %d bytes", dataLen)
log.WithError(err).Error("Data is smaller than minimum valid size")
return
}
@@ -207,13 +229,13 @@ func ReadKeysAndCertElgAndEd25519(data []byte) (keysAndCert *KeysAndCert, remain
// Extract public key
publicKeyData := data[:pubKeySize]
if len(publicKeyData) != pubKeySize {
- err = errors.New("invalid ElGamal public key length")
+ err = oops.Errorf("invalid ElGamal public key length")
log.WithError(err).Error("Invalid ElGamal public key length")
return
}
var elgPublicKey crypto.ElgPublicKey
copy(elgPublicKey[:], publicKeyData)
- keysAndCert.publicKey = elgPublicKey
+ keysAndCert.ReceivingPublic = elgPublicKey
// Extract padding
paddingStart := pubKeySize
@@ -223,12 +245,12 @@ func ReadKeysAndCertElgAndEd25519(data []byte) (keysAndCert *KeysAndCert, remain
// Extract signing public key
signingPubKeyData := data[paddingEnd : paddingEnd+sigKeySize]
if len(signingPubKeyData) != sigKeySize {
- err = errors.New("invalid Ed25519 public key length")
+ err = oops.Errorf("invalid Ed25519 public key length")
log.WithError(err).Error("Invalid Ed25519 public key length")
return
}
edPublicKey := crypto.Ed25519PublicKey(signingPubKeyData)
- keysAndCert.signingPublicKey = edPublicKey
+ keysAndCert.SigningPublic = edPublicKey
// Extract the certificate
certData := data[totalKeySize:]
@@ -248,18 +270,18 @@ func ReadKeysAndCertElgAndEd25519(data []byte) (keysAndCert *KeysAndCert, remain
return
}
-func constructPublicKey(data []byte, cryptoType uint16) (crypto.PublicKey, error) {
+func constructPublicKey(data []byte, cryptoType uint16) (crypto.RecievingPublicKey, error) {
switch cryptoType {
case CRYPTO_KEY_TYPE_ELGAMAL:
if len(data) != 256 {
- return nil, errors.New("invalid ElGamal public key length")
+ return nil, oops.Errorf("invalid ElGamal public key length")
}
var elgPublicKey crypto.ElgPublicKey
copy(elgPublicKey[:], data)
return elgPublicKey, nil
// Handle other crypto types...
default:
- return nil, fmt.Errorf("unsupported crypto key type: %d", cryptoType)
+ return nil, oops.Errorf("unsupported crypto key type: %d", cryptoType)
}
}
@@ -267,12 +289,12 @@ func constructSigningPublicKey(data []byte, sigType uint16) (crypto.SigningPubli
switch sigType {
case SIGNATURE_TYPE_ED25519_SHA512:
if len(data) != 32 {
- return nil, errors.New("invalid Ed25519 public key length")
+ return nil, oops.Errorf("invalid Ed25519 public key length")
}
return crypto.Ed25519PublicKey(data), nil
// Handle other signature types...
default:
- return nil, fmt.Errorf("unsupported signature key type: %d", sigType)
+ return nil, oops.Errorf("unsupported signature key type: %d", sigType)
}
}
@@ -280,7 +302,7 @@ func constructSigningPublicKey(data []byte, sigType uint16) (crypto.SigningPubli
// It validates the sizes of the provided keys and padding before assembling the struct.
func NewKeysAndCert(
keyCertificate *KeyCertificate,
- publicKey crypto.PublicKey,
+ publicKey crypto.RecievingPublicKey,
padding []byte,
signingPublicKey crypto.SigningPublicKey,
) (*KeysAndCert, error) {
@@ -288,7 +310,7 @@ func NewKeysAndCert(
if keyCertificate == nil {
log.Error("KeyCertificate is nil")
- return nil, errors.New("KeyCertificate cannot be nil")
+ return nil, oops.Errorf("KeyCertificate cannot be nil")
}
// Get actual key sizes from certificate
@@ -296,21 +318,25 @@ func NewKeysAndCert(
sigKeySize := keyCertificate.SignatureSize()
// Validate public key size
- if publicKey.Len() != pubKeySize {
- log.WithFields(logrus.Fields{
- "expected_size": pubKeySize,
- "actual_size": publicKey.Len(),
- }).Error("Invalid publicKey size")
- return nil, fmt.Errorf("publicKey has invalid size: expected %d, got %d", pubKeySize, publicKey.Len())
+ if publicKey != nil {
+ if publicKey.Len() != pubKeySize {
+ log.WithFields(logrus.Fields{
+ "expected_size": pubKeySize,
+ "actual_size": publicKey.Len(),
+ }).Error("Invalid publicKey size")
+ return nil, oops.Errorf("publicKey has invalid size: expected %d, got %d", pubKeySize, publicKey.Len())
+ }
}
- // Validate signing key size
- if signingPublicKey.Len() != sigKeySize {
- log.WithFields(logrus.Fields{
- "expected_size": sigKeySize,
- "actual_size": signingPublicKey.Len(),
- }).Error("Invalid signingPublicKey size")
- return nil, fmt.Errorf("signingPublicKey has invalid size: expected %d, got %d", sigKeySize, signingPublicKey.Len())
+ if signingPublicKey != nil {
+ // Validate signing key size
+ if signingPublicKey.Len() != sigKeySize {
+ log.WithFields(logrus.Fields{
+ "expected_size": sigKeySize,
+ "actual_size": signingPublicKey.Len(),
+ }).Error("Invalid signingPublicKey size")
+ return nil, oops.Errorf("signingPublicKey has invalid size: expected %d, got %d", sigKeySize, signingPublicKey.Len())
+ }
}
// Calculate expected padding size
@@ -320,21 +346,21 @@ func NewKeysAndCert(
"expected_size": expectedPaddingSize,
"actual_size": len(padding),
}).Error("Invalid padding size")
- return nil, fmt.Errorf("invalid padding size")
+ return nil, oops.Errorf("invalid padding size")
}
keysAndCert := &KeysAndCert{
- KeyCertificate: keyCertificate,
- publicKey: publicKey,
- Padding: padding,
- signingPublicKey: signingPublicKey,
+ KeyCertificate: keyCertificate,
+ ReceivingPublic: publicKey,
+ Padding: padding,
+ SigningPublic: signingPublicKey,
}
- log.WithFields(logrus.Fields{
+ /*log.WithFields(logrus.Fields{
"public_key_length": publicKey.Len(),
"signing_public_key_length": signingPublicKey.Len(),
"padding_length": len(padding),
- }).Debug("Successfully created KeysAndCert")
+ }).Debug("Successfully created KeysAndCert")*/
return keysAndCert, nil
}
diff --git a/lib/common/keys_and_cert/keys_and_cert.svg b/lib/common/keys_and_cert/keys_and_cert.svg
new file mode 100644
index 0000000..732c89b
--- /dev/null
+++ b/lib/common/keys_and_cert/keys_and_cert.svg
@@ -0,0 +1,531 @@
+
+
+
+
+
diff --git a/lib/common/keys_and_cert/keys_and_cert_test.go b/lib/common/keys_and_cert/keys_and_cert_test.go
index be98ce3..59375ae 100644
--- a/lib/common/keys_and_cert/keys_and_cert_test.go
+++ b/lib/common/keys_and_cert/keys_and_cert_test.go
@@ -2,6 +2,7 @@ package keys_and_cert
import (
"bytes"
+ "crypto/ed25519"
"crypto/rand"
"testing"
@@ -32,8 +33,15 @@ func TestCertificateWithMissingData(t *testing.T) {
// createValidKeyCertificate creates a valid KeyCertificate for testing.
func createValidKeyAndCert(t *testing.T) *KeysAndCert {
// Generate signing key pair (Ed25519)
- var ed25519_privkey crypto.Ed25519PrivateKey
- _, err := (&ed25519_privkey).Generate()
+ //var ed25519_privkey crypto.Ed25519PrivateKey
+ _, priv, err := ed25519.GenerateKey(rand.Reader)
+ if err != nil {
+ t.Fatalf("Failed to generate Ed25519 private %s", err)
+ }
+ // Copy the full private key (includes public key)
+ ed25519_privkey := make(crypto.Ed25519PrivateKey, ed25519.PrivateKeySize)
+ copy(ed25519_privkey, priv)
+ //_, err = (ed25519_privkey).Generate()
if err != nil {
t.Fatalf("Failed to generate Ed25519 private key: %v\n", err)
}
@@ -103,7 +111,7 @@ func createValidKeyAndCert(t *testing.T) *KeysAndCert {
t.Fatal(err)
}
- t.Logf("pubkey bytes after NewKeysAndCert: %v\n", keysAndCert.signingPublicKey.Bytes())
+ t.Logf("pubkey bytes after NewKeysAndCert: %v\n", keysAndCert.SigningPublic.Bytes())
return keysAndCert
}
@@ -122,9 +130,9 @@ func TestCertificateWithValidDataElgAndEd25519(t *testing.T) {
// Compare individual fields
assert.Equal(keysAndCert.KeyCertificate.Bytes(), parsedKeysAndCert.KeyCertificate.Bytes(), "KeyCertificates should match")
- assert.Equal(keysAndCert.publicKey.Bytes(), parsedKeysAndCert.publicKey.Bytes(), "PublicKeys should match")
+ assert.Equal(keysAndCert.ReceivingPublic.Bytes(), parsedKeysAndCert.ReceivingPublic.Bytes(), "PublicKeys should match")
assert.Equal(keysAndCert.Padding, parsedKeysAndCert.Padding, "Padding should match")
- assert.Equal(keysAndCert.signingPublicKey.Bytes(), parsedKeysAndCert.signingPublicKey.Bytes(), "SigningPublicKeys should match")
+ assert.Equal(keysAndCert.SigningPublic.Bytes(), parsedKeysAndCert.SigningPublic.Bytes(), "SigningPublicKeys should match")
}
func TestCertificateWithValidDataManual(t *testing.T) {
diff --git a/lib/common/lease/doc.md b/lib/common/lease/README.md
similarity index 68%
rename from lib/common/lease/doc.md
rename to lib/common/lease/README.md
index ec9e6cd..2f7074f 100644
--- a/lib/common/lease/doc.md
+++ b/lib/common/lease/README.md
@@ -2,6 +2,8 @@
--
import "github.com/go-i2p/go-i2p/lib/common/lease"
+
+
Package lease implements the I2P lease common data structure
## Usage
@@ -21,17 +23,21 @@ Sizes in bytes of various components of a Lease
type Lease [LEASE_SIZE]byte
```
-Lease is the represenation of an I2P Lease.
-
-https://geti2p.net/spec/common-structures#lease
#### func NewLease
```go
-func NewLease(data []byte) (lease *Lease, remainder []byte, err error)
+func NewLease(tunnelGateway Hash, tunnelID uint32, expirationTime time.Time) (*Lease, error)
```
-NewLease creates a new *NewLease from []byte using ReadLease. Returns a pointer
-to KeysAndCert unlike ReadLease.
+NewLease creates a new Lease with the provided parameters.
+
+#### func NewLeaseFromBytes
+
+```go
+func NewLeaseFromBytes(data []byte) (lease *Lease, remainder []byte, err error)
+```
+NewLeaseFromBytes creates a new *Lease from []byte using ReadLease. Returns a
+pointer to Lease unlike ReadLease.
#### func ReadLease
@@ -61,3 +67,9 @@ TunnelGateway returns the tunnel gateway as a Hash.
func (lease Lease) TunnelID() uint32
```
TunnelID returns the tunnel id as a uint23.
+
+
+
+lease
+
+github.com/go-i2p/go-i2p/lib/common/lease
diff --git a/lib/common/lease/lease.go b/lib/common/lease/lease.go
index e5589ea..58745e3 100644
--- a/lib/common/lease/lease.go
+++ b/lib/common/lease/lease.go
@@ -3,11 +3,11 @@ package lease
import (
"encoding/binary"
- "errors"
"time"
. "github.com/go-i2p/go-i2p/lib/common/data"
- "github.com/go-i2p/go-i2p/lib/util/logger"
+ "github.com/go-i2p/logger"
+ "github.com/samber/oops"
"github.com/sirupsen/logrus"
)
@@ -87,7 +87,7 @@ func ReadLease(data []byte) (lease Lease, remainder []byte, err error) {
log.WithField("input_length", len(data)).Debug("Reading Lease from bytes")
if len(data) < LEASE_SIZE {
- err = errors.New("error parsing lease: not enough data")
+ err = oops.Errorf("error parsing lease: not enough data")
log.WithFields(logrus.Fields{
"data_length": len(data),
"required_length": LEASE_SIZE,
diff --git a/lib/common/lease/lease.svg b/lib/common/lease/lease.svg
new file mode 100644
index 0000000..ca5acb8
--- /dev/null
+++ b/lib/common/lease/lease.svg
@@ -0,0 +1,391 @@
+
+
+
+
+
diff --git a/lib/common/lease/lease_test.go b/lib/common/lease/lease_test.go
index 2485808..4e8aa4d 100644
--- a/lib/common/lease/lease_test.go
+++ b/lib/common/lease/lease_test.go
@@ -2,6 +2,7 @@ package lease
import (
"testing"
+
"github.com/stretchr/testify/assert"
. "github.com/go-i2p/go-i2p/lib/common/data"
@@ -14,7 +15,7 @@ func TestTunnelGateway(t *testing.T) {
var lease_bytes []byte
lease_bytes = append(lease_bytes, expectedTunnelGatewayBytes...)
- lease_bytes = append(lease_bytes, make([]byte, LEASE_SIZE - LEASE_TUNNEL_GW_SIZE)...)
+ lease_bytes = append(lease_bytes, make([]byte, LEASE_SIZE-LEASE_TUNNEL_GW_SIZE)...)
lease := Lease(lease_bytes)
tunnelGateway := lease.TunnelGateway()
@@ -29,7 +30,7 @@ func TestTunnelID(t *testing.T) {
var lease_bytes []byte
lease_bytes = append(lease_bytes, make([]byte, LEASE_TUNNEL_GW_SIZE)...)
lease_bytes = append(lease_bytes, expectedTunnelIDBytes...)
- lease_bytes = append(lease_bytes, make([]byte, LEASE_SIZE - LEASE_TUNNEL_ID_SIZE - LEASE_TUNNEL_GW_SIZE)...)
+ lease_bytes = append(lease_bytes, make([]byte, LEASE_SIZE-LEASE_TUNNEL_ID_SIZE-LEASE_TUNNEL_GW_SIZE)...)
lease := Lease(lease_bytes)
tunnelID := lease.TunnelID()
@@ -42,7 +43,7 @@ func TestDate(t *testing.T) {
expectedDateBytes := []byte{0x21, 0x37, 0x31, 0x33, 0x16, 0x93, 0x13, 0x28}
var lease_bytes []byte
- lease_bytes = append(lease_bytes, make([]byte, LEASE_TUNNEL_GW_SIZE + LEASE_TUNNEL_ID_SIZE)...)
+ lease_bytes = append(lease_bytes, make([]byte, LEASE_TUNNEL_GW_SIZE+LEASE_TUNNEL_ID_SIZE)...)
lease_bytes = append(lease_bytes, expectedDateBytes...)
lease := Lease(lease_bytes)
diff --git a/lib/common/lease_set/doc.md b/lib/common/lease_set/README.md
similarity index 76%
rename from lib/common/lease_set/doc.md
rename to lib/common/lease_set/README.md
index 6fa5410..f1ff622 100644
--- a/lib/common/lease_set/doc.md
+++ b/lib/common/lease_set/README.md
@@ -2,6 +2,8 @@
--
import "github.com/go-i2p/go-i2p/lib/common/lease_set"
+
+
Package lease_set implements the I2P LeastSet common data structure
## Usage
@@ -15,6 +17,12 @@ const (
```
Sizes of various structures in an I2P LeaseSet
+#### func ReadDestinationFromLeaseSet
+
+```go
+func ReadDestinationFromLeaseSet(data []byte) (destination Destination, remainder []byte, err error)
+```
+
#### type LeaseSet
```go
@@ -25,6 +33,18 @@ LeaseSet is the represenation of an I2P LeaseSet.
https://geti2p.net/spec/common-structures#leaseset
+#### func NewLeaseSet
+
+```go
+func NewLeaseSet(
+ destination Destination,
+ encryptionKey crypto.RecievingPublicKey,
+ signingKey crypto.SigningPublicKey,
+ leases []Lease,
+ signingPrivateKey crypto.SigningPrivateKey,
+) (LeaseSet, error)
+```
+
#### func (LeaseSet) Destination
```go
@@ -32,6 +52,12 @@ func (lease_set LeaseSet) Destination() (destination Destination, err error)
```
Destination returns the Destination as []byte.
+#### func (LeaseSet) DestinationDeux
+
+```go
+func (lease_set LeaseSet) DestinationDeux() (destination Destination, err error)
+```
+
#### func (LeaseSet) LeaseCount
```go
@@ -74,7 +100,7 @@ encountered during parsing.
#### func (LeaseSet) Signature
```go
-func (lease_set LeaseSet) Signature() (signature Signature, err error)
+func (lease_set LeaseSet) Signature() (signature signature.Signature, err error)
```
Signature returns the signature as Signature. returns errors encountered during
parsing.
@@ -93,3 +119,9 @@ errors encountered during parsing.
func (lease_set LeaseSet) Verify() error
```
Verify returns nil
+
+
+
+lease_set
+
+github.com/go-i2p/go-i2p/lib/common/lease_set
diff --git a/lib/common/lease_set/lease_set.go b/lib/common/lease_set/lease_set.go
index e27d4dd..6deb36f 100644
--- a/lib/common/lease_set/lease_set.go
+++ b/lib/common/lease_set/lease_set.go
@@ -2,12 +2,12 @@
package lease_set
import (
- "errors"
"fmt"
"github.com/go-i2p/go-i2p/lib/common/signature"
+ "github.com/samber/oops"
- "github.com/go-i2p/go-i2p/lib/util/logger"
+ "github.com/go-i2p/logger"
"github.com/sirupsen/logrus"
. "github.com/go-i2p/go-i2p/lib/common/certificate"
@@ -175,7 +175,7 @@ func ReadDestinationFromLeaseSet(data []byte) (destination Destination, remainde
fmt.Printf("Reading Destination from LeaseSet, input_length=%d\n", len(data))
if len(data) < 387 { // Minimum size of Destination (384 keys + 3 bytes for minimum certificate)
- err = errors.New("LeaseSet data too short to contain Destination")
+ err = oops.Errorf("LeaseSet data too short to contain Destination")
fmt.Printf("Error: %v\n", err)
return
}
@@ -199,7 +199,7 @@ func ReadDestinationFromLeaseSet(data []byte) (destination Destination, remainde
fmt.Printf(" destinationLength: %d\n", destinationLength)
if len(data) < destinationLength {
- err = errors.New("LeaseSet data too short to contain full Destination")
+ err = oops.Errorf("LeaseSet data too short to contain full Destination")
fmt.Printf("Error: %v\n", err)
return
}
@@ -208,7 +208,7 @@ func ReadDestinationFromLeaseSet(data []byte) (destination Destination, remainde
keysAndCert, _, err := ReadKeysAndCert(destinationData)
if err != nil {
- fmt.Printf("Failed to read KeysAndCert: %v\n", err) //32 / 0 error
+ fmt.Printf("Failed to read KeysAndCert: %v\n", err) // 32 / 0 error
return
}
@@ -237,7 +237,7 @@ func (lease_set LeaseSet) PublicKey() (public_key crypto.ElgPublicKey, err error
"required_len": LEASE_SET_PUBKEY_SIZE,
"reason": "not enough data",
}).Error("error parsing public key")
- err = errors.New("error parsing public key: not enough data")
+ err = oops.Errorf("error parsing public key: not enough data")
copy(public_key[:], remainder)
return
}
@@ -270,7 +270,7 @@ func (lease_set LeaseSet) SigningKey() (signing_public_key crypto.SigningPublicK
"required_len": offset + LEASE_SET_SPK_SIZE,
"reason": "not enough data",
}).Error("error parsing signing public key")
- err = errors.New("error parsing signing public key: not enough data")
+ err = oops.Errorf("error parsing signing public key: not enough data")
return
}
if cert_len == 0 {
@@ -328,7 +328,7 @@ func (lease_set LeaseSet) LeaseCount() (count int, err error) {
"required_len": LEASE_SET_PUBKEY_SIZE + LEASE_SET_SPK_SIZE + 1,
"reason": "not enough data",
}).Error("error parsing lease count")
- err = errors.New("error parsing lease count: not enough data")
+ err = oops.Errorf("error parsing lease count: not enough data")
return
}
c := Integer([]byte{remainder[LEASE_SET_PUBKEY_SIZE+LEASE_SET_SPK_SIZE]})
@@ -339,7 +339,7 @@ func (lease_set LeaseSet) LeaseCount() (count int, err error) {
"lease_count": count,
"reason": "more than 16 leases",
}).Warn("invalid lease set")
- err = errors.New("invalid lease set: more than 16 leases")
+ err = oops.Errorf("invalid lease set: more than 16 leases")
} else {
log.WithField("lease_count", count).Debug("Retrieved LeaseCount from LeaseSet")
}
@@ -372,7 +372,7 @@ func (lease_set LeaseSet) Leases() (leases []Lease, err error) {
"required_len": end,
"reason": "some leases missing",
}).Error("error parsnig lease set")
- err = errors.New("error parsing lease set: some leases missing")
+ err = oops.Errorf("error parsing lease set: some leases missing")
return
}
var lease Lease
@@ -422,7 +422,7 @@ func (lease_set LeaseSet) Signature() (signature signature.Signature, err error)
"required_len": end,
"reason": "not enough data",
}).Error("error parsing signatre")
- err = errors.New("error parsing signature: not enough data")
+ err = oops.Errorf("error parsing signature: not enough data")
return
}
signature = []byte(lease_set[start:end])
@@ -492,7 +492,7 @@ func (lease_set LeaseSet) OldestExpiration() (earliest Date, err error) {
func NewLeaseSet(
destination Destination,
- encryptionKey crypto.PublicKey,
+ encryptionKey crypto.RecievingPublicKey,
signingKey crypto.SigningPublicKey,
leases []Lease,
signingPrivateKey crypto.SigningPrivateKey,
@@ -500,15 +500,15 @@ func NewLeaseSet(
log.Debug("Creating new LeaseSet")
// Validate destination size
if len(destination.KeysAndCert.Bytes()) < 387 {
- return nil, errors.New("invalid destination: minimum size is 387 bytes")
+ return nil, oops.Errorf("invalid destination: minimum size is 387 bytes")
}
// Validate encryption key size
if len(encryptionKey.Bytes()) != LEASE_SET_PUBKEY_SIZE {
- return nil, errors.New("invalid encryption key size")
+ return nil, oops.Errorf("invalid encryption key size")
}
// Validate inputs
if len(leases) > 16 {
- return nil, errors.New("invalid lease set: more than 16 leases")
+ return nil, oops.Errorf("invalid lease set: more than 16 leases")
}
// Validate signing key size matches certificate
cert := destination.Certificate()
@@ -520,13 +520,13 @@ func NewLeaseSet(
}
expectedSize := keyCert.SignatureSize()
if len(signingKey.Bytes()) != expectedSize {
- return nil, fmt.Errorf("invalid signing key size: got %d, expected %d",
+ return nil, oops.Errorf("invalid signing key size: got %d, expected %d",
len(signingKey.Bytes()), expectedSize)
}
} else {
// Default DSA size
if len(signingKey.Bytes()) != LEASE_SET_SPK_SIZE {
- return nil, errors.New("invalid signing key size")
+ return nil, oops.Errorf("invalid signing key size")
}
}
// Build LeaseSet data
diff --git a/lib/common/lease_set/lease_set.svg b/lib/common/lease_set/lease_set.svg
new file mode 100644
index 0000000..3d3fd93
--- /dev/null
+++ b/lib/common/lease_set/lease_set.svg
@@ -0,0 +1,1256 @@
+
+
+
+
+
diff --git a/lib/common/lease_set/lease_set_test.go b/lib/common/lease_set/lease_set_test.go
index fa53ca3..669a634 100644
--- a/lib/common/lease_set/lease_set_test.go
+++ b/lib/common/lease_set/lease_set_test.go
@@ -3,14 +3,15 @@ package lease_set
import (
"bytes"
"crypto/rand"
- "fmt"
+ "testing"
+ "time"
+
"github.com/go-i2p/go-i2p/lib/common/destination"
"github.com/go-i2p/go-i2p/lib/common/key_certificate"
"github.com/go-i2p/go-i2p/lib/common/router_address"
"github.com/go-i2p/go-i2p/lib/common/router_info"
"github.com/go-i2p/go-i2p/lib/common/signature"
- "testing"
- "time"
+ "github.com/samber/oops"
"github.com/go-i2p/go-i2p/lib/common/data"
"github.com/go-i2p/go-i2p/lib/common/keys_and_cert"
@@ -23,7 +24,7 @@ import (
"github.com/stretchr/testify/assert"
)
-func generateTestRouterInfo(t *testing.T) (*router_info.RouterInfo, crypto.PublicKey, crypto.SigningPublicKey, crypto.SigningPrivateKey, crypto.SigningPrivateKey, error) {
+func generateTestRouterInfo(t *testing.T) (*router_info.RouterInfo, crypto.RecievingPublicKey, crypto.SigningPublicKey, crypto.SigningPrivateKey, crypto.SigningPrivateKey, error) {
// Generate signing key pair (Ed25519)
var ed25519_privkey crypto.Ed25519PrivateKey
_, err := (&ed25519_privkey).Generate()
@@ -63,7 +64,7 @@ func generateTestRouterInfo(t *testing.T) (*router_info.RouterInfo, crypto.Publi
copy(elg_pubkey[256-len(yBytes):], yBytes)
// Ensure that elg_pubkey implements crypto.PublicKey interface
- var _ crypto.PublicKey = elg_pubkey
+ var _ crypto.RecievingPublicKey = elg_pubkey
// Create KeyCertificate specifying key types
var payload bytes.Buffer
@@ -135,13 +136,11 @@ func generateTestRouterInfo(t *testing.T) (*router_info.RouterInfo, crypto.Publi
// Generate signing key pair for the LeaseSet (Ed25519)
var leaseSetSigningPrivKey crypto.Ed25519PrivateKey
_, err = leaseSetSigningPrivKey.Generate()
-
if err != nil {
t.Fatalf("Failed to generate lease set Ed25519 private key: %v", err)
}
leaseSetSigningPubKeyRaw, err := leaseSetSigningPrivKey.Public()
-
if err != nil {
t.Fatalf("Failed to derive lease set Ed25519 public key: %v", err)
}
@@ -176,7 +175,8 @@ func createTestLease(t *testing.T, index int, routerInfo *router_info.RouterInfo
return testLease, nil
}
-func generateTestDestination(t *testing.T) (*destination.Destination, crypto.PublicKey, crypto.SigningPublicKey, crypto.SigningPrivateKey, error) {
+
+func generateTestDestination(t *testing.T) (*destination.Destination, crypto.RecievingPublicKey, crypto.SigningPublicKey, crypto.SigningPrivateKey, error) {
// Generate client signing key pair (Ed25519)
var ed25519_privkey crypto.Ed25519PrivateKey
_, err := (&ed25519_privkey).Generate()
@@ -274,7 +274,7 @@ func createTestLeaseSet(t *testing.T, routerInfo *router_info.RouterInfo, leaseC
// Generate test Destination and client keys
dest, encryptionKey, signingKey, signingPrivKey, err := generateTestDestination(t)
if err != nil {
- return nil, fmt.Errorf("failed to generate test destination: %v", err)
+ return nil, oops.Errorf("failed to generate test destination: %v", err)
}
destBytes := dest.KeysAndCert.Bytes()
diff --git a/lib/common/router_address/doc.md b/lib/common/router_address/README.md
similarity index 82%
rename from lib/common/router_address/doc.md
rename to lib/common/router_address/README.md
index 4491417..dbab825 100644
--- a/lib/common/router_address/doc.md
+++ b/lib/common/router_address/README.md
@@ -2,6 +2,8 @@
--
import "github.com/go-i2p/go-i2p/lib/common/router_address"
+
+
Package router_address implements the I2P RouterAddress common data structure
## Usage
@@ -28,6 +30,14 @@ RouterAddress is the represenation of an I2P RouterAddress.
https://geti2p.net/spec/common-structures#routeraddress
+#### func NewRouterAddress
+
+```go
+func NewRouterAddress(cost uint8, expiration time.Time, transportType string, options map[string]string) (*RouterAddress, error)
+```
+NewRouterAddress creates a new RouterAddress with the provided parameters.
+Returns a pointer to RouterAddress.
+
#### func ReadRouterAddress
```go
@@ -44,6 +54,12 @@ func (router_address RouterAddress) Bytes() []byte
```
Bytes returns the router address as a []byte.
+#### func (RouterAddress) CapsString
+
+```go
+func (router_address RouterAddress) CapsString() I2PString
+```
+
#### func (RouterAddress) Cost
```go
@@ -77,10 +93,17 @@ func (router_address RouterAddress) Host() (net.Addr, error)
func (router_address RouterAddress) HostString() I2PString
```
+#### func (*RouterAddress) IPVersion
+
+```go
+func (router_address *RouterAddress) IPVersion() string
+```
+IPVersion returns a string "4" for IPv4 or 6 for IPv6
+
#### func (RouterAddress) InitializationVector
```go
-func (router_address RouterAddress) InitializationVector() ([32]byte, error)
+func (router_address RouterAddress) InitializationVector() ([16]byte, error)
```
#### func (RouterAddress) InitializationVectorString
@@ -112,7 +135,7 @@ func (router_address RouterAddress) IntroducerTagString(num int) I2PString
```go
func (router_address *RouterAddress) Network() string
```
-Network implements net.Addr. It returns the transport type
+Network implements net.Addr. It returns the transport type plus 4 or 6
#### func (RouterAddress) Options
@@ -177,3 +200,9 @@ I2PString.
```go
func (router_address *RouterAddress) UDP() bool
```
+
+
+
+router_address
+
+github.com/go-i2p/go-i2p/lib/common/router_address
diff --git a/lib/common/router_address/router_address.go b/lib/common/router_address/router_address.go
index 738700e..6355533 100644
--- a/lib/common/router_address/router_address.go
+++ b/lib/common/router_address/router_address.go
@@ -3,14 +3,13 @@ package router_address
import (
"encoding/binary"
- "errors"
- "fmt"
"net"
"strconv"
"strings"
"time"
- "github.com/go-i2p/go-i2p/lib/util/logger"
+ "github.com/go-i2p/logger"
+ "github.com/samber/oops"
"github.com/sirupsen/logrus"
. "github.com/go-i2p/go-i2p/lib/common/data"
@@ -180,6 +179,16 @@ func (router_address RouterAddress) GetOption(key I2PString) I2PString {
return router_address.Options().Values().Get(key)
}
+func (router_address RouterAddress) HasOption(key I2PString) bool {
+ opt := router_address.GetOption(key)
+ return opt != nil
+}
+
+func (router_address RouterAddress) CheckOption(key string) bool {
+ keyv, _ := ToI2PString(key)
+ return router_address.HasOption(keyv)
+}
+
func (router_address RouterAddress) HostString() I2PString {
host, _ := ToI2PString("host")
return router_address.GetOption(host)
@@ -251,7 +260,7 @@ func (router_address RouterAddress) Host() (net.Addr, error) {
ip := net.ParseIP(hostBytes)
if ip == nil {
log.Error("Failed to parse IP address")
- return nil, fmt.Errorf("null host error")
+ return nil, oops.Errorf("null host error")
}
// return net.ResolveIPAddr("", ip.String())
addr, err := net.ResolveIPAddr("", ip.String())
@@ -285,17 +294,17 @@ func (router_address RouterAddress) Port() (string, error) {
func (router_address RouterAddress) StaticKey() ([32]byte, error) {
sk := router_address.StaticKeyString()
if len([]byte(sk)) != 32 {
- return [32]byte{}, fmt.Errorf("error: invalid static key")
+ return [32]byte{}, oops.Errorf("error: invalid static key")
}
return [32]byte(sk), nil
}
-func (router_address RouterAddress) InitializationVector() ([32]byte, error) {
+func (router_address RouterAddress) InitializationVector() ([16]byte, error) {
iv := router_address.InitializationVectorString()
- if len([]byte(iv)) != 32 {
- return [32]byte{}, fmt.Errorf("error: invalid static key")
+ if len([]byte(iv)) != 16 {
+ return [16]byte{}, oops.Errorf("error: invalid IV")
}
- return [32]byte(iv), nil
+ return [16]byte(iv), nil
}
func (router_address RouterAddress) ProtocolVersion() (string, error) {
@@ -319,7 +328,7 @@ func ReadRouterAddress(data []byte) (router_address RouterAddress, remainder []b
log.WithField("data_length", len(data)).Debug("Reading RouterAddress from data")
if len(data) == 0 {
log.WithField("at", "(RouterAddress) ReadRouterAddress").Error("error parsing RouterAddress: no data")
- err = errors.New("error parsing RouterAddress: no data")
+ err = oops.Errorf("error parsing RouterAddress: no data")
return
}
router_address.TransportCost, remainder, err = NewInteger(data, 1)
diff --git a/lib/common/router_address/router_address.svg b/lib/common/router_address/router_address.svg
new file mode 100644
index 0000000..d4a9750
--- /dev/null
+++ b/lib/common/router_address/router_address.svg
@@ -0,0 +1,1380 @@
+
+
+
+
+
diff --git a/lib/common/router_identity/doc.md b/lib/common/router_identity/README.md
similarity index 60%
rename from lib/common/router_identity/doc.md
rename to lib/common/router_identity/README.md
index 37b2643..adfe098 100644
--- a/lib/common/router_identity/doc.md
+++ b/lib/common/router_identity/README.md
@@ -2,6 +2,8 @@
--
import "github.com/go-i2p/go-i2p/lib/common/router_identity"
+
+
Package router_identity implements the I2P RouterIdentity common data structure
## Usage
@@ -18,6 +20,12 @@ RouterIdentity is the represenation of an I2P RouterIdentity.
https://geti2p.net/spec/common-structures#routeridentity
+#### func NewRouterIdentity
+
+```go
+func NewRouterIdentity(publicKey crypto.RecievingPublicKey, signingPublicKey crypto.SigningPublicKey, cert certificate.Certificate, padding []byte) (*RouterIdentity, error)
+```
+
#### func ReadRouterIdentity
```go
@@ -26,3 +34,15 @@ func ReadRouterIdentity(data []byte) (router_identity RouterIdentity, remainder
ReadRouterIdentity returns RouterIdentity from a []byte. The remaining bytes
after the specified length are also returned. Returns a list of errors that
occurred during parsing.
+
+#### func (*RouterIdentity) AsDestination
+
+```go
+func (router_identity *RouterIdentity) AsDestination() destination.Destination
+```
+
+
+
+router_identity
+
+github.com/go-i2p/go-i2p/lib/common/router_identity
diff --git a/lib/common/router_identity/router_identity.go b/lib/common/router_identity/router_identity.go
index c170489..01b7f21 100644
--- a/lib/common/router_identity/router_identity.go
+++ b/lib/common/router_identity/router_identity.go
@@ -7,7 +7,7 @@ import (
"github.com/go-i2p/go-i2p/lib/common/key_certificate"
. "github.com/go-i2p/go-i2p/lib/common/keys_and_cert"
"github.com/go-i2p/go-i2p/lib/crypto"
- "github.com/go-i2p/go-i2p/lib/util/logger"
+ "github.com/go-i2p/logger"
"github.com/sirupsen/logrus"
)
@@ -28,13 +28,13 @@ Identical to KeysAndCert.
//
// https://geti2p.net/spec/common-structures#routeridentity
type RouterIdentity struct {
- KeysAndCert
+ *KeysAndCert
}
// ReadRouterIdentity returns RouterIdentity from a []byte.
// The remaining bytes after the specified length are also returned.
// Returns a list of errors that occurred during parsing.
-func ReadRouterIdentity(data []byte) (router_identity RouterIdentity, remainder []byte, err error) {
+func ReadRouterIdentity(data []byte) (router_identity *RouterIdentity, remainder []byte, err error) {
log.WithFields(logrus.Fields{
"input_length": len(data),
}).Debug("Reading RouterIdentity from data")
@@ -43,7 +43,7 @@ func ReadRouterIdentity(data []byte) (router_identity RouterIdentity, remainder
log.WithError(err).Error("Failed to read KeysAndCert for RouterIdentity")
return
}
- router_identity = RouterIdentity{
+ router_identity = &RouterIdentity{
keys_and_cert,
}
log.WithFields(logrus.Fields{
@@ -52,7 +52,7 @@ func ReadRouterIdentity(data []byte) (router_identity RouterIdentity, remainder
return
}
-func NewRouterIdentity(publicKey crypto.PublicKey, signingPublicKey crypto.SigningPublicKey, cert certificate.Certificate, padding []byte) (*RouterIdentity, error) {
+func NewRouterIdentity(publicKey crypto.RecievingPublicKey, signingPublicKey crypto.SigningPublicKey, cert certificate.Certificate, padding []byte) (*RouterIdentity, error) {
log.Debug("Creating new RouterIdentity")
// Step 1: Create keyCertificate from the provided certificate.
@@ -72,7 +72,7 @@ func NewRouterIdentity(publicKey crypto.PublicKey, signingPublicKey crypto.Signi
// Step 3: Initialize RouterIdentity with KeysAndCert.
routerIdentity := RouterIdentity{
- KeysAndCert: *keysAndCert,
+ KeysAndCert: keysAndCert,
}
log.WithFields(logrus.Fields{
diff --git a/lib/common/router_identity/router_identity.svg b/lib/common/router_identity/router_identity.svg
new file mode 100644
index 0000000..bdeff7d
--- /dev/null
+++ b/lib/common/router_identity/router_identity.svg
@@ -0,0 +1,295 @@
+
+
+
+
+
diff --git a/lib/common/router_info/10k_test.go b/lib/common/router_info/10k_test.go
index 055fbe7..505e701 100644
--- a/lib/common/router_info/10k_test.go
+++ b/lib/common/router_info/10k_test.go
@@ -8,18 +8,20 @@ import (
"strings"
"testing"
"time"
+
+ "github.com/samber/oops"
)
func consolidateNetDb(sourcePath string, destPath string) error {
// Create destination directory if it doesn't exist
if err := os.MkdirAll(destPath, 0o755); err != nil {
- return fmt.Errorf("failed to create destination directory: %v", err)
+ return oops.Errorf("failed to create destination directory: %v", err)
}
// Walk through all subdirectories
return filepath.Walk(sourcePath, func(path string, info os.FileInfo, err error) error {
if err != nil {
- return fmt.Errorf("error accessing path %q: %v", path, err)
+ return oops.Errorf("error accessing path %q: %v", path, err)
}
// Skip if it's a directory
@@ -37,7 +39,7 @@ func consolidateNetDb(sourcePath string, destPath string) error {
// Copy the file
if err := copyFile(srcFile, dstFile); err != nil {
- return fmt.Errorf("failed to copy %s: %v", info.Name(), err)
+ return oops.Errorf("failed to copy %s: %v", info.Name(), err)
}
}
@@ -69,7 +71,7 @@ func consolidateAllNetDbs(tempDir string) error {
// Create the temp directory
if err := os.MkdirAll(tempDir, 0o755); err != nil {
- return fmt.Errorf("failed to create temp directory: %v", err)
+ return oops.Errorf("failed to create temp directory: %v", err)
}
// Try to consolidate I2P netDb
@@ -91,7 +93,7 @@ func consolidateAllNetDbs(tempDir string) error {
func cleanupTempDir(path string) error {
if err := os.RemoveAll(path); err != nil {
- return fmt.Errorf("failed to cleanup temporary directory %s: %v", path, err)
+ return oops.Errorf("failed to cleanup temporary directory %s: %v", path, err)
}
return nil
}
@@ -110,7 +112,7 @@ func createTempNetDbDir() (string, error) {
// Create the directory with appropriate permissions
err := os.MkdirAll(tempDir, 0o755)
if err != nil {
- return "", fmt.Errorf("failed to create temporary directory: %v", err)
+ return "", oops.Errorf("failed to create temporary directory: %v", err)
}
return tempDir, nil
@@ -148,10 +150,10 @@ func Test10K(t *testing.T) {
t.Fatalf("Failed to read temp directory: %v", err)
}
- for _, file := range files {
+ for d, file := range files {
if !file.IsDir() && strings.HasPrefix(file.Name(), "routerInfo-") {
// Read the router info file
- log.Println("RI LOAD: ", file.Name())
+ log.Println("RI LOAD: ", d, file.Name())
data, err := os.ReadFile(filepath.Join(tempDir, file.Name()))
if err != nil {
t.Logf("Failed to read file %s: %v", file.Name(), err)
diff --git a/lib/common/router_info/doc.md b/lib/common/router_info/README.md
similarity index 80%
rename from lib/common/router_info/doc.md
rename to lib/common/router_info/README.md
index d9f50ad..37fce74 100644
--- a/lib/common/router_info/doc.md
+++ b/lib/common/router_info/README.md
@@ -2,6 +2,8 @@
--
import "github.com/go-i2p/go-i2p/lib/common/router_info"
+
+
Package router_info implements the I2P RouterInfo common data structure
## Usage
@@ -28,6 +30,25 @@ RouterInfo is the represenation of an I2P RouterInfo.
https://geti2p.net/spec/common-structures#routerinfo
+#### func NewRouterInfo
+
+```go
+func NewRouterInfo(
+ routerIdentity *RouterIdentity,
+ publishedTime time.Time,
+ addresses []*RouterAddress,
+ options map[string]string,
+ signingPrivateKey crypto.SigningPrivateKey,
+ sigType int,
+) (*RouterInfo, error)
+```
+
+#### func OwnedRouterInfo
+
+```go
+func OwnedRouterInfo(keyCertificate key_certificate.KeyCertificate) *RouterInfo
+```
+
#### func ReadRouterInfo
```go
@@ -37,6 +58,12 @@ ReadRouterInfo returns RouterInfo from a []byte. The remaining bytes after the
specified length are also returned. Returns a list of errors that occurred
during parsing.
+#### func (*RouterInfo) AddAddress
+
+```go
+func (router_info *RouterInfo) AddAddress(address *RouterAddress)
+```
+
#### func (RouterInfo) Bytes
```go
@@ -57,6 +84,13 @@ func (router_info *RouterInfo) IdentHash() Hash
```
IndentHash returns the identity hash (sha256 sum) for this RouterInfo.
+#### func (RouterInfo) Network
+
+```go
+func (router_info RouterInfo) Network() string
+```
+Network implements net.Addr
+
#### func (RouterInfo) Options
```go
@@ -137,3 +171,9 @@ func (router_info RouterInfo) String() string
```go
func (router_info *RouterInfo) UnCongested() bool
```
+
+
+
+router_info
+
+github.com/go-i2p/go-i2p/lib/common/router_info
diff --git a/lib/common/router_info/new.go b/lib/common/router_info/new.go
new file mode 100644
index 0000000..f2c3a08
--- /dev/null
+++ b/lib/common/router_info/new.go
@@ -0,0 +1,9 @@
+package router_info
+
+import "github.com/go-i2p/go-i2p/lib/common/key_certificate"
+
+func OwnedRouterInfo(keyCertificate key_certificate.KeyCertificate) *RouterInfo {
+ return &RouterInfo{
+ // ...
+ }
+}
diff --git a/lib/common/router_info/router_info.go b/lib/common/router_info/router_info.go
index efcc788..5a8688d 100644
--- a/lib/common/router_info/router_info.go
+++ b/lib/common/router_info/router_info.go
@@ -3,17 +3,16 @@ package router_info
import (
"encoding/binary"
- "errors"
- "fmt"
"strconv"
"strings"
"time"
"github.com/go-i2p/go-i2p/lib/common/certificate"
+ "github.com/samber/oops"
"github.com/go-i2p/go-i2p/lib/crypto"
- "github.com/go-i2p/go-i2p/lib/util/logger"
+ "github.com/go-i2p/logger"
"github.com/sirupsen/logrus"
. "github.com/go-i2p/go-i2p/lib/common/data"
@@ -115,7 +114,7 @@ signature :: Signature
//
// https://geti2p.net/spec/common-structures#routerinfo
type RouterInfo struct {
- router_identity RouterIdentity
+ router_identity *RouterIdentity
published *Date
size *Integer
addresses []*RouterAddress
@@ -170,7 +169,7 @@ func (router_info RouterInfo) String() string {
// RouterIdentity returns the router identity as *RouterIdentity.
func (router_info *RouterInfo) RouterIdentity() *RouterIdentity {
- return &router_info.router_identity
+ return router_info.router_identity
}
// IndentHash returns the identity hash (sha256 sum) for this RouterInfo.
@@ -224,6 +223,10 @@ func (router_info RouterInfo) Network() string {
return "i2p"
}
+func (router_info *RouterInfo) AddAddress(address *RouterAddress) {
+ router_info.addresses = append(router_info.addresses, address)
+}
+
// ReadRouterInfo returns RouterInfo from a []byte.
// The remaining bytes after the specified length are also returned.
// Returns a list of errors that occurred during parsing.
@@ -302,7 +305,7 @@ func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error)
sigType, err := certificate.GetSignatureTypeFromCertificate(cert)
if err != nil {
log.WithError(err).Error("Failed to get signature type from certificate")
- return RouterInfo{}, remainder, fmt.Errorf("certificate signature type error: %v", err)
+ return RouterInfo{}, remainder, oops.Errorf("certificate signature type error: %v", err)
}
// Enhanced signature type validation
@@ -311,7 +314,7 @@ func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error)
"sigType": sigType,
"cert": cert,
}).Error("Invalid signature type detected")
- return RouterInfo{}, remainder, fmt.Errorf("invalid signature type: %d", sigType)
+ return RouterInfo{}, remainder, oops.Errorf("invalid signature type: %d", sigType)
}
log.WithFields(logrus.Fields{
@@ -325,7 +328,7 @@ func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error)
//"required_len": MAPPING_SIZE,
"reason": "not enough data",
}).Error("error parsing router info")
- err = errors.New("error parsing router info: not enough data to read signature")
+ err = oops.Errorf("error parsing router info: not enough data to read signature")
}
log.WithFields(logrus.Fields{
@@ -407,7 +410,7 @@ func NewRouterInfo(
// 5. Assemble RouterInfo without signature
routerInfo := &RouterInfo{
- router_identity: *routerIdentity,
+ router_identity: routerIdentity,
published: &publishedDate,
size: sizeInt,
addresses: addresses,
diff --git a/lib/common/router_info/router_info.svg b/lib/common/router_info/router_info.svg
new file mode 100644
index 0000000..c7ad3d1
--- /dev/null
+++ b/lib/common/router_info/router_info.svg
@@ -0,0 +1,1370 @@
+
+
+
+
+
diff --git a/lib/common/router_info/router_info2_test.go b/lib/common/router_info/router_info2_test.go
index 4a93dae..ed50581 100644
--- a/lib/common/router_info/router_info2_test.go
+++ b/lib/common/router_info/router_info2_test.go
@@ -22,11 +22,12 @@ import (
func TestCreateRouterInfo(t *testing.T) {
// Generate signing key pair (Ed25519)
var ed25519_privkey crypto.Ed25519PrivateKey
- _, err := (&ed25519_privkey).Generate()
+ ed25519_signingprivkey, err := ed25519_privkey.Generate()
if err != nil {
t.Fatalf("Failed to generate Ed25519 private key: %v\n", err)
}
- ed25519_pubkey_raw, err := ed25519_privkey.Public()
+
+ ed25519_pubkey_raw, err := ed25519_signingprivkey.Public()
if err != nil {
t.Fatalf("Failed to derive Ed25519 public key: %v\n", err)
}
@@ -59,7 +60,7 @@ func TestCreateRouterInfo(t *testing.T) {
copy(elg_pubkey[256-len(yBytes):], yBytes)
// Ensure that elg_pubkey implements crypto.PublicKey interface
- var _ crypto.PublicKey = elg_pubkey
+ var _ crypto.RecievingPublicKey = elg_pubkey
// Create KeyCertificate specifying key types
var payload bytes.Buffer
diff --git a/lib/common/router_info/router_info_test.go b/lib/common/router_info/router_info_test.go
index bbd141a..0422f49 100644
--- a/lib/common/router_info/router_info_test.go
+++ b/lib/common/router_info/router_info_test.go
@@ -3,10 +3,11 @@ package router_info
import (
"bytes"
"crypto/rand"
- "github.com/go-i2p/go-i2p/lib/common/keys_and_cert"
"testing"
"time"
+ "github.com/go-i2p/go-i2p/lib/common/keys_and_cert"
+
"github.com/go-i2p/go-i2p/lib/common/certificate"
"github.com/go-i2p/go-i2p/lib/common/data"
"github.com/go-i2p/go-i2p/lib/common/key_certificate"
@@ -59,7 +60,7 @@ func generateTestRouterInfo(t *testing.T, publishedTime time.Time) (*RouterInfo,
copy(elg_pubkey[256-len(yBytes):], yBytes)
// Ensure that elg_pubkey implements crypto.PublicKey interface
- var _ crypto.PublicKey = elg_pubkey
+ var _ crypto.RecievingPublicKey = elg_pubkey
// Create KeyCertificate specifying key types
var payload bytes.Buffer
diff --git a/lib/common/session_key/doc.md b/lib/common/session_key/README.md
similarity index 89%
rename from lib/common/session_key/doc.md
rename to lib/common/session_key/README.md
index c5e92ec..6fd0d50 100644
--- a/lib/common/session_key/doc.md
+++ b/lib/common/session_key/README.md
@@ -2,6 +2,8 @@
--
import "github.com/go-i2p/go-i2p/lib/common/session_key"
+
+
Package session_key implements the I2P SessionKey common data structure
## Usage
@@ -32,3 +34,9 @@ func ReadSessionKey(bytes []byte) (info SessionKey, remainder []byte, err error)
ReadSessionKey returns SessionKey from a []byte. The remaining bytes after the
specified length are also returned. Returns a list of errors that occurred
during parsing.
+
+
+
+session_key
+
+github.com/go-i2p/go-i2p/lib/common/session_key
diff --git a/lib/common/session_key/session_key.svg b/lib/common/session_key/session_key.svg
new file mode 100644
index 0000000..103b537
--- /dev/null
+++ b/lib/common/session_key/session_key.svg
@@ -0,0 +1,167 @@
+
+
+
+
+
diff --git a/lib/common/session_tag/doc.md b/lib/common/session_tag/README.md
similarity index 89%
rename from lib/common/session_tag/doc.md
rename to lib/common/session_tag/README.md
index 03374e6..2473a1a 100644
--- a/lib/common/session_tag/doc.md
+++ b/lib/common/session_tag/README.md
@@ -2,6 +2,8 @@
--
import "github.com/go-i2p/go-i2p/lib/common/session_tag"
+
+
Package session_tag implements the I2P SessionTag common data structure
## Usage
@@ -32,3 +34,9 @@ func ReadSessionTag(bytes []byte) (info SessionTag, remainder []byte, err error)
ReadSessionTag returns SessionTag from a []byte. The remaining bytes after the
specified length are also returned. Returns a list of errors that occurred
during parsing.
+
+
+
+session_tag
+
+github.com/go-i2p/go-i2p/lib/common/session_tag
diff --git a/lib/common/session_tag/session_tag.go b/lib/common/session_tag/session_tag.go
index 6c48ae2..b4851b9 100644
--- a/lib/common/session_tag/session_tag.go
+++ b/lib/common/session_tag/session_tag.go
@@ -2,7 +2,7 @@
package session_tag
import (
- "github.com/go-i2p/go-i2p/lib/util/logger"
+ "github.com/go-i2p/logger"
"github.com/sirupsen/logrus"
)
diff --git a/lib/common/session_tag/session_tag.svg b/lib/common/session_tag/session_tag.svg
new file mode 100644
index 0000000..0396b32
--- /dev/null
+++ b/lib/common/session_tag/session_tag.svg
@@ -0,0 +1,203 @@
+
+
+
+
+
diff --git a/lib/common/signature/README.md b/lib/common/signature/README.md
new file mode 100644
index 0000000..41cf596
--- /dev/null
+++ b/lib/common/signature/README.md
@@ -0,0 +1,80 @@
+# signature
+--
+ import "github.com/go-i2p/go-i2p/lib/common/signature"
+
+
+
+Package signature implements the I2P Signature common data structure
+
+## Usage
+
+```go
+const (
+ DSA_SHA1_SIZE = 40
+ ECDSA_SHA256_P256_SIZE = 64
+ ECDSA_SHA384_P384_SIZE = 96
+ ECDSA_SHA512_P512_SIZE = 132
+ RSA_SHA256_2048_SIZE = 256
+ RSA_SHA384_3072_SIZE = 384
+ RSA_SHA512_4096_SIZE = 512
+ EdDSA_SHA512_Ed25519_SIZE = 64
+ EdDSA_SHA512_Ed25519ph_SIZE = 64
+ RedDSA_SHA512_Ed25519_SIZE = 64
+)
+```
+Lengths of signature keys
+
+```go
+const (
+ SIGNATURE_TYPE_DSA_SHA1 = 0
+ SIGNATURE_TYPE_ECDSA_SHA256_P256 = 1
+ SIGNATURE_TYPE_ECDSA_SHA384_P384 = 2
+ SIGNATURE_TYPE_ECDSA_SHA512_P521 = 3
+ SIGNATURE_TYPE_RSA_SHA256_2048 = 4
+ SIGNATURE_TYPE_RSA_SHA384_3072 = 5
+ SIGNATURE_TYPE_RSA_SHA512_4096 = 6
+ SIGNATURE_TYPE_EDDSA_SHA512_ED25519 = 7
+ SIGNATURE_TYPE_EDDSA_SHA512_ED25519PH = 8
+ SIGNATURE_TYPE_REDDSA_SHA512_ED25519 = 11
+)
+```
+
+#### type Signature
+
+```go
+type Signature []byte
+```
+
+Signature is the represenation of an I2P Signature.
+
+https://geti2p.net/spec/common-structures#signature
+
+#### func NewSignature
+
+```go
+func NewSignature(data []byte, sigType int) (signature *Signature, remainder []byte, err error)
+```
+NewSignature creates a new *Signature from []byte using ReadSignature. Returns a
+pointer to Signature unlike ReadSignature.
+
+#### func ReadSignature
+
+```go
+func ReadSignature(data []byte, sigType int) (sig Signature, remainder []byte, err error)
+```
+ReadSignature returns a Signature from a []byte. The remaining bytes after the
+specified length are also returned. Returns an error if there is insufficient
+data to read the signature.
+
+Since the signature type and length are inferred from context (the type of key
+used), and are not explicitly stated, this function assumes the default
+signature type (DSA_SHA1) with a length of 40 bytes.
+
+If a different signature type is expected based on context, this function should
+be modified accordingly to handle the correct signature length.
+
+
+
+signature
+
+github.com/go-i2p/go-i2p/lib/common/signature
diff --git a/lib/common/signature/doc.md b/lib/common/signature/doc.md
deleted file mode 100644
index c43764d..0000000
--- a/lib/common/signature/doc.md
+++ /dev/null
@@ -1,50 +0,0 @@
-# signature
---
- import "github.com/go-i2p/go-i2p/lib/common/signature"
-
-Package signature implements the I2P Signature common data structure
-
-## Usage
-
-```go
-const (
- DSA_SHA1_SIZE = 40
- ECDSA_SHA256_P256_SIZE = 64
- ECDSA_SHA384_P384_SIZE = 96
- ECDSA_SHA512_P512_SIZE = 132
- RSA_SHA256_2048_SIZE = 256
- RSA_SHA384_3072_SIZE = 384
- RSA_SHA512_4096_SIZE = 512
- EdDSA_SHA512_Ed25519_SIZE = 64
- EdDSA_SHA512_Ed25519ph_SIZE = 64
- RedDSA_SHA512_Ed25519_SIZE = 64
-)
-```
-Lengths of signature keys
-
-#### type Signature
-
-```go
-type Signature []byte
-```
-
-Signature is the represenation of an I2P Signature.
-
-https://geti2p.net/spec/common-structures#signature
-
-#### func NewSignature
-
-```go
-func NewSignature(data []byte) (session_tag *Signature, remainder []byte, err error)
-```
-NewSignature creates a new *Signature from []byte using ReadSignature. Returns a
-pointer to Signature unlike ReadSignature.
-
-#### func ReadSignature
-
-```go
-func ReadSignature(bytes []byte) (info Signature, remainder []byte, err error)
-```
-ReadSignature returns Signature from a []byte. The remaining bytes after the
-specified length are also returned. Returns a list of errors that occurred
-during parsing.
diff --git a/lib/common/signature/signature.go b/lib/common/signature/signature.go
index 7bd93dd..46839d8 100644
--- a/lib/common/signature/signature.go
+++ b/lib/common/signature/signature.go
@@ -2,9 +2,8 @@
package signature
import (
- "fmt"
-
- "github.com/go-i2p/go-i2p/lib/util/logger"
+ "github.com/go-i2p/logger"
+ "github.com/samber/oops"
"github.com/sirupsen/logrus"
)
@@ -88,12 +87,12 @@ func ReadSignature(data []byte, sigType int) (sig Signature, remainder []byte, e
case SIGNATURE_TYPE_REDDSA_SHA512_ED25519:
sigLength = RedDSA_SHA512_Ed25519_SIZE
default:
- err = fmt.Errorf("unsupported signature type: %d", sigType)
+ err = oops.Errorf("unsupported signature type: %d", sigType)
return
}
if len(data) < sigLength {
- err = fmt.Errorf("insufficient data to read signature: need %d bytes, have %d", sigLength, len(data))
+ err = oops.Errorf("insufficient data to read signature: need %d bytes, have %d", sigLength, len(data))
log.WithError(err).Error("Failed to read Signature")
return
}
diff --git a/lib/common/signature/signature.svg b/lib/common/signature/signature.svg
new file mode 100644
index 0000000..de28547
--- /dev/null
+++ b/lib/common/signature/signature.svg
@@ -0,0 +1,221 @@
+
+
+
+
+
diff --git a/lib/common/signature/signature_test.go b/lib/common/signature/signature_test.go
index 947de74..7ac6fd9 100644
--- a/lib/common/signature/signature_test.go
+++ b/lib/common/signature/signature_test.go
@@ -6,11 +6,10 @@ import (
"github.com/stretchr/testify/assert"
)
-
func TestReadSignatureErrors(t *testing.T) {
assert := assert.New(t)
- data := []byte{0xbe,0xef}
+ data := []byte{0xbe, 0xef}
unsupportedSigType := 1000
_, _, err := ReadSignature(data, unsupportedSigType)
assert.NotNil(err, "unsupported signature error should be reported")
@@ -41,7 +40,7 @@ func TestReadSignature(t *testing.T) {
dataLen := 1024
data := []byte{}
for i := 0; i < dataLen; i++ {
- data = append(data, byte(i % 10))
+ data = append(data, byte(i%10))
}
for i, sigType := range sigTypes {
@@ -55,7 +54,7 @@ func TestReadSignature(t *testing.T) {
func TestNewSignatureError(t *testing.T) {
assert := assert.New(t)
- data := []byte{0xbe,0xef}
+ data := []byte{0xbe, 0xef}
unsupportedSigType := 1000
_, _, err := NewSignature(data, unsupportedSigType)
assert.NotNil(err, "NewSignature error should be reported")
@@ -67,8 +66,8 @@ func TestNewSignature(t *testing.T) {
data := []byte{}
sigLength := EdDSA_SHA512_Ed25519_SIZE
remLength := 20
- for i := 0; i < sigLength + remLength; i++ {
- data = append(data, byte(i % 10))
+ for i := 0; i < sigLength+remLength; i++ {
+ data = append(data, byte(i%10))
}
sigType := SIGNATURE_TYPE_EDDSA_SHA512_ED25519
diff --git a/lib/config/doc.md b/lib/config/README.md
similarity index 84%
rename from lib/config/doc.md
rename to lib/config/README.md
index 5608091..7f523ab 100644
--- a/lib/config/doc.md
+++ b/lib/config/README.md
@@ -2,9 +2,22 @@
--
import "github.com/go-i2p/go-i2p/lib/config"
+
+
+
## Usage
+```go
+const GOI2P_BASE_DIR = ".go-i2p"
+```
+
+```go
+var (
+ CfgFile string
+)
+```
+
```go
var DefaultBootstrapConfig = BootstrapConfig{
LowPeerThreshold: 10,
@@ -25,6 +38,18 @@ default settings for netdb
var RouterConfigProperties = DefaultRouterConfig()
```
+#### func InitConfig
+
+```go
+func InitConfig()
+```
+
+#### func UpdateRouterConfig
+
+```go
+func UpdateRouterConfig()
+```
+
#### type BootstrapConfig
```go
@@ -83,3 +108,9 @@ router.config options
```go
func DefaultRouterConfig() *RouterConfig
```
+
+
+
+config
+
+github.com/go-i2p/go-i2p/lib/config
diff --git a/lib/config/config.go b/lib/config/config.go
index b636b21..974e9eb 100644
--- a/lib/config/config.go
+++ b/lib/config/config.go
@@ -4,9 +4,9 @@ import (
"os"
"path/filepath"
- "github.com/go-i2p/go-i2p/lib/util/logger"
+ "github.com/go-i2p/go-i2p/lib/util"
+ "github.com/go-i2p/logger"
"github.com/spf13/viper"
- "gopkg.in/yaml.v3"
)
var (
@@ -17,48 +17,13 @@ var (
const GOI2P_BASE_DIR = ".go-i2p"
func InitConfig() {
- defaultConfigDir := filepath.Join(os.Getenv("HOME"), GOI2P_BASE_DIR)
- defaultConfigFile := filepath.Join(defaultConfigDir, "config.yaml")
if CfgFile != "" {
// Use config file from the flag
viper.SetConfigFile(CfgFile)
} else {
- // Create default config if it doesn't exist
- if _, err := os.Stat(defaultConfigFile); os.IsNotExist(err) {
- // Ensure directory exists
- if err := os.MkdirAll(defaultConfigDir, 0o755); err != nil {
- log.Fatalf("Could not create config directory: %s", err)
- }
-
- // Create default configuration
- defaultConfig := struct {
- BaseDir string `yaml:"base_dir"`
- WorkingDir string `yaml:"working_dir"`
- NetDB NetDbConfig `yaml:"netdb"`
- Bootstrap BootstrapConfig `yaml:"bootstrap"`
- }{
- BaseDir: DefaultRouterConfig().BaseDir,
- WorkingDir: DefaultRouterConfig().WorkingDir,
- NetDB: *DefaultRouterConfig().NetDb,
- Bootstrap: *DefaultRouterConfig().Bootstrap,
- }
-
- yamlData, err := yaml.Marshal(defaultConfig)
- if err != nil {
- log.Fatalf("Could not marshal default config: %s", err)
- }
-
- // Write default config file
- if err := os.WriteFile(defaultConfigFile, yamlData, 0o644); err != nil {
- log.Fatalf("Could not write default config file: %s", err)
- }
-
- log.Debugf("Created default configuration at: %s", defaultConfigFile)
- }
-
- // Set up viper to use the config file
- viper.AddConfigPath(defaultConfigDir)
+ // Set up viper to use the default config path $HOME/.go-ip/
+ viper.AddConfigPath(BuildI2PDirPath())
viper.SetConfigName("config")
viper.SetConfigType("yaml")
}
@@ -66,11 +31,8 @@ func InitConfig() {
// Load defaults
setDefaults()
- if err := viper.ReadInConfig(); err != nil {
- log.Warnf("Error reading config file: %s", err)
- } else {
- log.Debugf("Using config file: %s", viper.ConfigFileUsed())
- }
+ // handle config file creating it if needed
+ handleConfigFile()
// Update RouterConfigProperties
UpdateRouterConfig()
@@ -111,3 +73,41 @@ func UpdateRouterConfig() {
ReseedServers: reseedServers,
}
}
+
+func createDefaultConfig(defaultConfigDir string) {
+
+ defaultConfigFile := filepath.Join(defaultConfigDir, "config.yaml")
+ // Ensure directory exists
+ if err := os.MkdirAll(defaultConfigDir, 0o755); err != nil {
+ log.Fatalf("Could not create config directory: %s", err)
+ }
+
+ // Write current config file
+ if err := viper.WriteConfig(); err != nil {
+ log.Fatalf("Could not write default config file: %s", err)
+ }
+
+ log.Debugf("Created default configuration at: %s", defaultConfigFile)
+
+}
+
+func handleConfigFile() {
+ if err := viper.ReadInConfig(); err != nil {
+ if _, ok := err.(viper.ConfigFileNotFoundError); ok {
+ if CfgFile != "" {
+ log.Fatalf("Config file %s is not found: %s", CfgFile, err)
+ } else {
+ createDefaultConfig(BuildI2PDirPath())
+ }
+ } else {
+ log.Fatalf("Error reading config file: %s", err)
+ }
+ } else {
+ log.Debugf("Using config file: %s", viper.ConfigFileUsed())
+ }
+
+}
+
+func BuildI2PDirPath() string {
+ return filepath.Join(util.UserHome(), GOI2P_BASE_DIR)
+}
diff --git a/lib/config/config.svg b/lib/config/config.svg
new file mode 100644
index 0000000..668bef2
--- /dev/null
+++ b/lib/config/config.svg
@@ -0,0 +1,481 @@
+
+
+
+
+
diff --git a/lib/config/router.go b/lib/config/router.go
index 4510e5a..976bb04 100644
--- a/lib/config/router.go
+++ b/lib/config/router.go
@@ -1,7 +1,6 @@
package config
import (
- "os"
"path/filepath"
)
@@ -17,20 +16,12 @@ type RouterConfig struct {
Bootstrap *BootstrapConfig
}
-func home() string {
- h, err := os.UserHomeDir()
- if err != nil {
- panic(err)
- }
- return h
-}
-
func defaultBase() string {
- return filepath.Join(home(), GOI2P_BASE_DIR, "base")
+ return filepath.Join(BuildI2PDirPath(), "base")
}
func defaultConfig() string {
- return filepath.Join(home(), GOI2P_BASE_DIR, "config")
+ return filepath.Join(BuildI2PDirPath(), "config")
}
// defaults for router
diff --git a/lib/crypto/doc.md b/lib/crypto/README.md
similarity index 62%
rename from lib/crypto/doc.md
rename to lib/crypto/README.md
index 3f7ede8..bb2916b 100644
--- a/lib/crypto/doc.md
+++ b/lib/crypto/README.md
@@ -2,7 +2,9 @@
--
import "github.com/go-i2p/go-i2p/lib/crypto"
-package for i2p specific cryptography
+
+
+package for i2p specific crpytography
## Usage
@@ -12,89 +14,31 @@ const (
OPAD = byte(0x5C)
)
```
-#### type AESSymmetricKey
-```go
-type AESSymmetricKey struct {
- Key []byte // AES key (must be 16, 24, or 32 bytes for AES-128, AES-192, AES-256)
- IV []byte // Initialization Vector (must be 16 bytes for AES)
-}
-```
-AESSymmetricKey represents a symmetric key for AES encryption/decryption
-
-#### func (AESSymmetricKey) NewEncrypter
-
-```go
-func (k *AESSymmetricKey) NewEncrypter() (Encrypter, error)
-```
-NewEncrypter creates a new AESSymmetricEncrypter
-
-#### func (AESSymmetricKey) NewDecrypter
-
-```go
-func (k *AESSymmetricKey) NewDecrypter() (Decrypter, error)
-```
-NewDecrypter creates a new AESSymmetricDecrypter
-
-#### func (AESSymmetricKey) Len
-
-```go
-func (k *AESSymmetricKey) Len() int
-```
-Len returns the length of the key
-
-#### type AESSymmetricEncrypter
-
-```go
-type AESSymmetricEncrypter struct {
- Key []byte
- IV []byte
-}
-```
-
-AESSymmetricEncrypter implements the Encrypter interface using AES
-
-#### func (*AESSymmetricEncrypter) Encrypt
-
-```go
-func (e *AESSymmetricEncrypter) Encrypt(data []byte) ([]byte, error)
-```
-Encrypt encrypts data using AES-CBC with PKCS#7 padding
-
-#### type AESSymmetricDecrypter
-
-```go
-type AESSymmetricDecrypter struct {
- Key []byte
- IV []byte
-}
-```
-
-AESSymmetricDecrypter implements the Decrypter interface using AES
-
-#### func (*AESSymmetricDecrypter) Decrypt
-
-```go
-func (d *AESSymmetricDecrypter) Decrypt(data []byte) ([]byte, error)
-```
-Decrypt decrypts data using AES-CBC with PKCS#7 padding
```go
var (
- ElgDecryptFail = errors.New("failed to decrypt elgamal encrypted data")
- ElgEncryptTooBig = errors.New("failed to encrypt data, too big for elgamal")
+ Ed25519EncryptTooBig = oops.Errorf("failed to encrypt data, too big for Ed25519")
+ ErrInvalidPublicKeySize = oops.Errorf("failed to verify: invalid ed25519 public key size")
)
```
```go
var (
- ErrBadSignatureSize = errors.New("bad signature size")
- ErrInvalidKeyFormat = errors.New("invalid key format")
- ErrInvalidSignature = errors.New("invalid signature")
+ ElgDecryptFail = oops.Errorf("failed to decrypt elgamal encrypted data")
+ ElgEncryptTooBig = oops.Errorf("failed to encrypt data, too big for elgamal")
)
```
```go
-var Ed25519EncryptTooBig = errors.New("failed to encrypt data, too big for Ed25519")
+var (
+ ErrBadSignatureSize = oops.Errorf("bad signature size")
+ ErrInvalidKeyFormat = oops.Errorf("invalid key format")
+ ErrInvalidSignature = oops.Errorf("invalid signature")
+)
+```
+
+```go
+var Curve25519EncryptTooBig = oops.Errorf("failed to encrypt data, too big for Curve25519")
```
```go
@@ -108,6 +52,180 @@ func ElgamalGenerate(priv *elgamal.PrivateKey, rand io.Reader) (err error)
```
generate an elgamal key pair
+#### type AESSymmetricDecrypter
+
+```go
+type AESSymmetricDecrypter struct {
+ Key []byte
+ IV []byte
+}
+```
+
+AESSymmetricDecrypter implements the Decrypter interface using AES
+
+#### func (*AESSymmetricDecrypter) Decrypt
+
+```go
+func (d *AESSymmetricDecrypter) Decrypt(data []byte) ([]byte, error)
+```
+Decrypt decrypts data using AES-CBC with PKCS#7 padding
+
+#### func (*AESSymmetricDecrypter) DecryptNoPadding
+
+```go
+func (d *AESSymmetricDecrypter) DecryptNoPadding(data []byte) ([]byte, error)
+```
+DecryptNoPadding decrypts data using AES-CBC without padding
+
+#### type AESSymmetricEncrypter
+
+```go
+type AESSymmetricEncrypter struct {
+ Key []byte
+ IV []byte
+}
+```
+
+AESSymmetricEncrypter implements the Encrypter interface using AES
+
+#### func (*AESSymmetricEncrypter) Encrypt
+
+```go
+func (e *AESSymmetricEncrypter) Encrypt(data []byte) ([]byte, error)
+```
+Encrypt encrypts data using AES-CBC with PKCS#7 padding
+
+#### func (*AESSymmetricEncrypter) EncryptNoPadding
+
+```go
+func (e *AESSymmetricEncrypter) EncryptNoPadding(data []byte) ([]byte, error)
+```
+EncryptNoPadding encrypts data using AES-CBC without padding
+
+#### type AESSymmetricKey
+
+```go
+type AESSymmetricKey struct {
+ Key []byte // AES key (must be 16, 24, or 32 bytes for AES-128, AES-192, AES-256)
+ IV []byte // Initialization Vector (must be 16 bytes for AES)
+}
+```
+
+AESSymmetricKey represents a symmetric key for AES encryption/decryption
+
+#### func (*AESSymmetricKey) Len
+
+```go
+func (k *AESSymmetricKey) Len() int
+```
+Len returns the length of the key
+
+#### func (*AESSymmetricKey) NewDecrypter
+
+```go
+func (k *AESSymmetricKey) NewDecrypter() (Decrypter, error)
+```
+NewDecrypter creates a new AESSymmetricDecrypter
+
+#### func (*AESSymmetricKey) NewEncrypter
+
+```go
+func (k *AESSymmetricKey) NewEncrypter() (Encrypter, error)
+```
+NewEncrypter creates a new AESSymmetricEncrypter
+
+#### type Curve25519Encryption
+
+```go
+type Curve25519Encryption struct {
+}
+```
+
+
+#### func (*Curve25519Encryption) Encrypt
+
+```go
+func (curve25519 *Curve25519Encryption) Encrypt(data []byte) (enc []byte, err error)
+```
+
+#### func (*Curve25519Encryption) EncryptPadding
+
+```go
+func (curve25519 *Curve25519Encryption) EncryptPadding(data []byte, zeroPadding bool) (encrypted []byte, err error)
+```
+
+#### type Curve25519PrivateKey
+
+```go
+type Curve25519PrivateKey curve25519.PrivateKey
+```
+
+
+#### type Curve25519PublicKey
+
+```go
+type Curve25519PublicKey []byte
+```
+
+
+#### func (Curve25519PublicKey) Len
+
+```go
+func (k Curve25519PublicKey) Len() int
+```
+
+#### func (Curve25519PublicKey) NewEncrypter
+
+```go
+func (elg Curve25519PublicKey) NewEncrypter() (enc Encrypter, err error)
+```
+
+#### func (Curve25519PublicKey) NewVerifier
+
+```go
+func (k Curve25519PublicKey) NewVerifier() (v Verifier, err error)
+```
+
+#### type Curve25519Signer
+
+```go
+type Curve25519Signer struct {
+}
+```
+
+
+#### func (*Curve25519Signer) Sign
+
+```go
+func (s *Curve25519Signer) Sign(data []byte) (sig []byte, err error)
+```
+
+#### func (*Curve25519Signer) SignHash
+
+```go
+func (s *Curve25519Signer) SignHash(h []byte) (sig []byte, err error)
+```
+
+#### type Curve25519Verifier
+
+```go
+type Curve25519Verifier struct {
+}
+```
+
+
+#### func (*Curve25519Verifier) Verify
+
+```go
+func (v *Curve25519Verifier) Verify(data, sig []byte) (err error)
+```
+
+#### func (*Curve25519Verifier) VerifyHash
+
+```go
+func (v *Curve25519Verifier) VerifyHash(h, sig []byte) (err error)
+```
+
#### type DSAPrivateKey
```go
@@ -147,6 +265,12 @@ type DSAPublicKey [128]byte
```
+#### func (DSAPublicKey) Bytes
+
+```go
+func (k DSAPublicKey) Bytes() []byte
+```
+
#### func (DSAPublicKey) Len
```go
@@ -251,6 +375,12 @@ type ECP256PublicKey [64]byte
```
+#### func (ECP256PublicKey) Bytes
+
+```go
+func (k ECP256PublicKey) Bytes() []byte
+```
+
#### func (ECP256PublicKey) Len
```go
@@ -277,6 +407,12 @@ type ECP384PublicKey [96]byte
```
+#### func (ECP384PublicKey) Bytes
+
+```go
+func (k ECP384PublicKey) Bytes() []byte
+```
+
#### func (ECP384PublicKey) Len
```go
@@ -303,6 +439,12 @@ type ECP521PublicKey [132]byte
```
+#### func (ECP521PublicKey) Bytes
+
+```go
+func (k ECP521PublicKey) Bytes() []byte
+```
+
#### func (ECP521PublicKey) Len
```go
@@ -315,6 +457,26 @@ func (k ECP521PublicKey) Len() int
func (k ECP521PublicKey) NewVerifier() (Verifier, error)
```
+#### type Ed25519Decrypter
+
+```go
+type Ed25519Decrypter struct {
+}
+```
+
+
+#### func (*Ed25519Decrypter) Decrypt
+
+```go
+func (d *Ed25519Decrypter) Decrypt(data []byte) ([]byte, error)
+```
+
+#### func (*Ed25519Decrypter) DecryptPadding
+
+```go
+func (d *Ed25519Decrypter) DecryptPadding(data []byte, zeroPadding bool) ([]byte, error)
+```
+
#### type Ed25519Encryption
```go
@@ -342,6 +504,48 @@ type Ed25519PrivateKey ed25519.PrivateKey
```
+#### func (Ed25519PrivateKey) Bytes
+
+```go
+func (k Ed25519PrivateKey) Bytes() []byte
+```
+
+#### func (Ed25519PrivateKey) Generate
+
+```go
+func (k Ed25519PrivateKey) Generate() (SigningPrivateKey, error)
+```
+
+#### func (Ed25519PrivateKey) Len
+
+```go
+func (k Ed25519PrivateKey) Len() int
+```
+
+#### func (Ed25519PrivateKey) NewDecrypter
+
+```go
+func (k Ed25519PrivateKey) NewDecrypter() (Decrypter, error)
+```
+
+#### func (Ed25519PrivateKey) NewSigner
+
+```go
+func (k Ed25519PrivateKey) NewSigner() (Signer, error)
+```
+
+#### func (Ed25519PrivateKey) Public
+
+```go
+func (k Ed25519PrivateKey) Public() (SigningPublicKey, error)
+```
+
+#### func (Ed25519PrivateKey) Zero
+
+```go
+func (k Ed25519PrivateKey) Zero()
+```
+
#### type Ed25519PublicKey
```go
@@ -349,6 +553,18 @@ type Ed25519PublicKey []byte
```
+#### func CreateEd25519PublicKeyFromBytes
+
+```go
+func CreateEd25519PublicKeyFromBytes(data []byte) (Ed25519PublicKey, error)
+```
+
+#### func (Ed25519PublicKey) Bytes
+
+```go
+func (k Ed25519PublicKey) Bytes() []byte
+```
+
#### func (Ed25519PublicKey) Len
```go
@@ -433,6 +649,12 @@ type ElgPublicKey [256]byte
```
+#### func (ElgPublicKey) Bytes
+
+```go
+func (elg ElgPublicKey) Bytes() []byte
+```
+
#### func (ElgPublicKey) Len
```go
@@ -509,6 +731,21 @@ type PrivateEncryptionKey interface {
```
+#### type PrivateKey
+
+```go
+type PrivateKey interface {
+ // Public returns the public key corresponding to this private key
+ Public() (SigningPublicKey, error)
+ // Bytes returns the raw bytes of this private key
+ Bytes() []byte
+ // Zero clears all sensitive data from the private key
+ Zero()
+}
+```
+
+PrivateKey is an interface for private keys
+
#### type PublicEncryptionKey
```go
@@ -527,7 +764,7 @@ type PublicEncryptionKey interface {
```go
type PublicKey interface {
Len() int
- NewEncrypter() (Encrypter, error)
+ Bytes() []byte
}
```
@@ -546,6 +783,27 @@ type RSA2048PublicKey [256]byte
```
+#### func (RSA2048PublicKey) Bytes
+
+```go
+func (r RSA2048PublicKey) Bytes() []byte
+```
+Bytes implements SigningPublicKey.
+
+#### func (RSA2048PublicKey) Len
+
+```go
+func (r RSA2048PublicKey) Len() int
+```
+Len implements SigningPublicKey.
+
+#### func (RSA2048PublicKey) NewVerifier
+
+```go
+func (r RSA2048PublicKey) NewVerifier() (Verifier, error)
+```
+NewVerifier implements SigningPublicKey.
+
#### type RSA3072PrivateKey
```go
@@ -560,6 +818,27 @@ type RSA3072PublicKey [384]byte
```
+#### func (RSA3072PublicKey) Bytes
+
+```go
+func (r RSA3072PublicKey) Bytes() []byte
+```
+Bytes implements SigningPublicKey.
+
+#### func (RSA3072PublicKey) Len
+
+```go
+func (r RSA3072PublicKey) Len() int
+```
+Len implements SigningPublicKey.
+
+#### func (RSA3072PublicKey) NewVerifier
+
+```go
+func (r RSA3072PublicKey) NewVerifier() (Verifier, error)
+```
+NewVerifier implements SigningPublicKey.
+
#### type RSA4096PrivateKey
```go
@@ -574,6 +853,38 @@ type RSA4096PublicKey [512]byte
```
+#### func (RSA4096PublicKey) Bytes
+
+```go
+func (r RSA4096PublicKey) Bytes() []byte
+```
+Bytes implements SigningPublicKey.
+
+#### func (RSA4096PublicKey) Len
+
+```go
+func (r RSA4096PublicKey) Len() int
+```
+Len implements SigningPublicKey.
+
+#### func (RSA4096PublicKey) NewVerifier
+
+```go
+func (r RSA4096PublicKey) NewVerifier() (Verifier, error)
+```
+NewVerifier implements SigningPublicKey.
+
+#### type RecievingPublicKey
+
+```go
+type RecievingPublicKey interface {
+ Len() int
+ Bytes() []byte
+ NewEncrypter() (Encrypter, error)
+}
+```
+
+
#### type Signer
```go
@@ -618,6 +929,7 @@ type SigningPublicKey interface {
NewVerifier() (Verifier, error)
// get the size of this public key
Len() int
+ Bytes() []byte
}
```
@@ -686,3 +998,9 @@ type Verifier interface {
```
type for verifying signatures
+
+
+
+crypto
+
+github.com/go-i2p/go-i2p/lib/crypto
diff --git a/lib/crypto/aes.go b/lib/crypto/aes.go
index 1da3c82..584e5cc 100644
--- a/lib/crypto/aes.go
+++ b/lib/crypto/aes.go
@@ -4,9 +4,9 @@ import (
"bytes"
"crypto/aes"
"crypto/cipher"
- "fmt"
- "github.com/go-i2p/go-i2p/lib/util/logger"
+ "github.com/go-i2p/logger"
+ "github.com/samber/oops"
"github.com/sirupsen/logrus"
)
@@ -61,7 +61,7 @@ func (d *AESSymmetricDecrypter) Decrypt(data []byte) ([]byte, error) {
if len(data)%aes.BlockSize != 0 {
log.Error("Ciphertext is not a multiple of the block size")
- return nil, fmt.Errorf("ciphertext is not a multiple of the block size")
+ return nil, oops.Errorf("ciphertext is not a multiple of the block size")
}
plaintext := make([]byte, len(data))
@@ -120,18 +120,18 @@ func pkcs7Unpad(data []byte) ([]byte, error) {
length := len(data)
if length == 0 {
log.Error("Data is empty")
- return nil, fmt.Errorf("data is empty")
+ return nil, oops.Errorf("data is empty")
}
padding := int(data[length-1])
if padding == 0 || padding > aes.BlockSize {
log.WithField("padding", padding).Error("Invalid padding")
- return nil, fmt.Errorf("invalid padding")
+ return nil, oops.Errorf("invalid padding")
}
paddingStart := length - padding
for i := paddingStart; i < length; i++ {
if data[i] != byte(padding) {
log.Error("Invalid padding")
- return nil, fmt.Errorf("invalid padding")
+ return nil, oops.Errorf("invalid padding")
}
}
@@ -143,7 +143,7 @@ func pkcs7Unpad(data []byte) ([]byte, error) {
// EncryptNoPadding encrypts data using AES-CBC without padding
func (e *AESSymmetricEncrypter) EncryptNoPadding(data []byte) ([]byte, error) {
if len(data)%aes.BlockSize != 0 {
- return nil, fmt.Errorf("data length must be a multiple of block size")
+ return nil, oops.Errorf("data length must be a multiple of block size")
}
block, err := aes.NewCipher(e.Key)
@@ -161,7 +161,7 @@ func (e *AESSymmetricEncrypter) EncryptNoPadding(data []byte) ([]byte, error) {
// DecryptNoPadding decrypts data using AES-CBC without padding
func (d *AESSymmetricDecrypter) DecryptNoPadding(data []byte) ([]byte, error) {
if len(data)%aes.BlockSize != 0 {
- return nil, fmt.Errorf("data length must be a multiple of block size")
+ return nil, oops.Errorf("data length must be a multiple of block size")
}
block, err := aes.NewCipher(d.Key)
diff --git a/lib/crypto/crypto.svg b/lib/crypto/crypto.svg
new file mode 100644
index 0000000..947c327
--- /dev/null
+++ b/lib/crypto/crypto.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
diff --git a/lib/crypto/curve25519.go b/lib/crypto/curve25519.go
index 41f7c71..66066ec 100644
--- a/lib/crypto/curve25519.go
+++ b/lib/crypto/curve25519.go
@@ -4,16 +4,16 @@ import (
"crypto/rand"
"crypto/sha256"
"crypto/sha512"
- "errors"
"io"
"math/big"
+ "github.com/samber/oops"
"github.com/sirupsen/logrus"
curve25519 "go.step.sm/crypto/x25519"
)
-var Curve25519EncryptTooBig = errors.New("failed to encrypt data, too big for Curve25519")
+var Curve25519EncryptTooBig = oops.Errorf("failed to encrypt data, too big for Curve25519")
type Curve25519PublicKey []byte
@@ -132,14 +132,14 @@ func (v *Curve25519Verifier) VerifyHash(h, sig []byte) (err error) {
}
if len(v.k) != curve25519.PublicKeySize {
log.Error("Invalid Curve25519 public key size")
- err = errors.New("failed to verify: invalid curve25519 public key size")
+ err = oops.Errorf("failed to verify: invalid curve25519 public key size")
return
}
ok := curve25519.Verify(v.k, h, sig)
if !ok {
log.Error("Invalid signature")
- err = errors.New("failed to verify: invalid signature")
+ err = oops.Errorf("failed to verify: invalid signature")
} else {
log.Debug("Hash verified successfully")
}
@@ -168,7 +168,7 @@ func (s *Curve25519Signer) Sign(data []byte) (sig []byte, err error) {
if len(s.k) != curve25519.PrivateKeySize {
log.Error("Invalid Curve25519 private key size")
- err = errors.New("failed to sign: invalid curve25519 private key size")
+ err = oops.Errorf("failed to sign: invalid curve25519 private key size")
return
}
h := sha512.Sum512(data)
diff --git a/lib/crypto/ed25519.go b/lib/crypto/ed25519.go
index 75891b5..cee54fc 100644
--- a/lib/crypto/ed25519.go
+++ b/lib/crypto/ed25519.go
@@ -1,21 +1,22 @@
package crypto
import (
+ "bytes"
"crypto/ed25519"
"crypto/rand"
"crypto/sha256"
"crypto/sha512"
- "errors"
"fmt"
"io"
"math/big"
+ "github.com/samber/oops"
"github.com/sirupsen/logrus"
)
var (
- Ed25519EncryptTooBig = errors.New("failed to encrypt data, too big for Ed25519")
- ErrInvalidPublicKeySize = errors.New("failed to verify: invalid ed25519 public key size")
+ Ed25519EncryptTooBig = oops.Errorf("failed to encrypt data, too big for Ed25519")
+ ErrInvalidPublicKeySize = oops.Errorf("failed to verify: invalid ed25519 public key size")
)
type Ed25519PublicKey []byte
@@ -132,7 +133,7 @@ func (elg Ed25519PublicKey) NewEncrypter() (enc Encrypter, err error) {
log.Debug("Creating new Ed25519 encrypter")
k := createEd25519PublicKey(elg[:])
if k == nil {
- return nil, errors.New("invalid public key format")
+ return nil, oops.Errorf("invalid public key format")
}
enc, err = createEd25519Encryption(k, rand.Reader)
@@ -158,14 +159,14 @@ func (v *Ed25519Verifier) VerifyHash(h, sig []byte) (err error) {
}
if len(v.k) != ed25519.PublicKeySize {
log.Error("Invalid Ed25519 public key size")
- err = errors.New("failed to verify: invalid ed25519 public key size")
+ err = oops.Errorf("failed to verify: invalid ed25519 public key size")
return
}
ok := ed25519.Verify(v.k, h, sig)
if !ok {
log.Warn("Invalid Ed25519 signature")
- err = errors.New("failed to verify: invalid signature")
+ err = oops.Errorf("failed to verify: invalid signature")
} else {
log.Debug("Ed25519 signature verified successfully")
}
@@ -185,14 +186,84 @@ func (v *Ed25519Verifier) Verify(data, sig []byte) (err error) {
type Ed25519PrivateKey ed25519.PrivateKey
+func (k Ed25519PrivateKey) Bytes() []byte {
+ return k
+}
+
+func (k Ed25519PrivateKey) Zero() {
+ for i := range k {
+ k[i] = 0
+ }
+}
+
func (k Ed25519PrivateKey) NewDecrypter() (Decrypter, error) {
- // TODO implement me
- panic("implement me")
+ if len(k) != ed25519.PrivateKeySize {
+ return nil, oops.Errorf("invalid ed25519 private key size")
+ }
+ d := &Ed25519Decrypter{
+ privateKey: k,
+ }
+ return d, nil
+}
+
+type Ed25519Decrypter struct {
+ privateKey Ed25519PrivateKey
+}
+
+func (d *Ed25519Decrypter) Decrypt(data []byte) ([]byte, error) {
+ return d.DecryptPadding(data, true)
+}
+
+func (d *Ed25519Decrypter) DecryptPadding(data []byte, zeroPadding bool) ([]byte, error) {
+ if len(data) != 514 && len(data) != 512 {
+ return nil, oops.Errorf("invalid ciphertext length")
+ }
+
+ // Extract components based on padding
+ var aBytes, bBytes []byte
+ if zeroPadding {
+ aBytes = data[1:258]
+ bBytes = data[258:]
+ } else {
+ aBytes = data[0:256]
+ bBytes = data[256:]
+ }
+
+ // Convert to big integers
+ a := new(big.Int).SetBytes(aBytes)
+ b := new(big.Int).SetBytes(bBytes)
+
+ // Compute p = 2^255 - 19
+ p := new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 255), big.NewInt(19))
+
+ // Use private key to decrypt
+ m := new(big.Int).ModInverse(a, p)
+ if m == nil {
+ return nil, oops.Errorf("decryption failed: modular inverse does not exist")
+ }
+
+ decrypted := new(big.Int).Mod(new(big.Int).Mul(b, m), p).Bytes()
+
+ // Remove padding and validate hash
+ if len(decrypted) < 33 {
+ return nil, oops.Errorf("decryption failed: result too short")
+ }
+
+ hashBytes := decrypted[1:33]
+ message := decrypted[33:]
+
+ // Verify hash
+ actualHash := sha256.Sum256(message)
+ if !bytes.Equal(hashBytes, actualHash[:]) {
+ return nil, oops.Errorf("decryption failed: hash verification failed")
+ }
+
+ return message, nil
}
func (k Ed25519PrivateKey) NewSigner() (Signer, error) {
if len(k) != ed25519.PrivateKeySize {
- return nil, errors.New("invalid ed25519 private key size")
+ return nil, oops.Errorf("invalid ed25519 private key size")
}
return &Ed25519Signer{k: k}, nil
}
@@ -201,27 +272,39 @@ func (k Ed25519PrivateKey) Len() int {
return len(k)
}
-func (k *Ed25519PrivateKey) Generate() (SigningPrivateKey, error) {
- // Generate a new Ed25519 key pair
+func (k Ed25519PrivateKey) Generate() (SigningPrivateKey, error) {
_, priv, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
- return nil, err
+ return nil, oops.Errorf("failed to generate ed25519 key: %v", err)
}
- // Assign the generated private key to the receiver
- *k = Ed25519PrivateKey(priv)
- return k, nil
+ // Copy the full private key (includes public key)
+ newKey := make(Ed25519PrivateKey, ed25519.PrivateKeySize)
+ copy(newKey, priv)
+ return newKey, nil
}
func (k Ed25519PrivateKey) Public() (SigningPublicKey, error) {
fmt.Printf("Ed25519PrivateKey.Public(): len(k) = %d\n", len(k))
if len(k) != ed25519.PrivateKeySize {
- return nil, fmt.Errorf("invalid ed25519 private key size: expected %d, got %d", ed25519.PrivateKeySize, len(k))
+ return nil, oops.Errorf("invalid ed25519 private key size: expected %d, got %d",
+ ed25519.PrivateKeySize, len(k))
}
- pubKey := k[32:]
+ // Extract public key portion (last 32 bytes)
+ pubKey := ed25519.PrivateKey(k).Public().(ed25519.PublicKey)
fmt.Printf("Ed25519PrivateKey.Public(): extracted pubKey length: %d\n", len(pubKey))
return Ed25519PublicKey(pubKey), nil
}
+func CreateEd25519PrivateKeyFromBytes(data []byte) (Ed25519PrivateKey, error) {
+ if len(data) != ed25519.PrivateKeySize {
+ return nil, oops.Errorf("invalid ed25519 private key size: expected %d, got %d",
+ ed25519.PrivateKeySize, len(data))
+ }
+ privKey := make(Ed25519PrivateKey, ed25519.PrivateKeySize)
+ copy(privKey, data)
+ return privKey, nil
+}
+
type Ed25519Signer struct {
k []byte
}
@@ -231,7 +314,7 @@ func (s *Ed25519Signer) Sign(data []byte) (sig []byte, err error) {
if len(s.k) != ed25519.PrivateKeySize {
log.Error("Invalid Ed25519 private key size")
- err = errors.New("failed to sign: invalid ed25519 private key size")
+ err = oops.Errorf("failed to sign: invalid ed25519 private key size")
return
}
h := sha512.Sum512(data)
diff --git a/lib/crypto/elg.go b/lib/crypto/elg.go
index 4ad11cc..dbf3fb2 100644
--- a/lib/crypto/elg.go
+++ b/lib/crypto/elg.go
@@ -4,10 +4,10 @@ import (
"crypto/rand"
"crypto/sha256"
"crypto/subtle"
- "errors"
"io"
"math/big"
+ "github.com/samber/oops"
"github.com/sirupsen/logrus"
"golang.org/x/crypto/openpgp/elgamal"
@@ -38,8 +38,8 @@ var (
)
var (
- ElgDecryptFail = errors.New("failed to decrypt elgamal encrypted data")
- ElgEncryptTooBig = errors.New("failed to encrypt data, too big for elgamal")
+ ElgDecryptFail = oops.Errorf("failed to decrypt elgamal encrypted data")
+ ElgEncryptTooBig = oops.Errorf("failed to encrypt data, too big for elgamal")
)
// generate an elgamal key pair
diff --git a/lib/crypto/privatekey.go b/lib/crypto/privatekey.go
new file mode 100644
index 0000000..d2a0ab0
--- /dev/null
+++ b/lib/crypto/privatekey.go
@@ -0,0 +1,11 @@
+package crypto
+
+// PrivateKey is an interface for private keys
+type PrivateKey interface {
+ // Public returns the public key corresponding to this private key
+ Public() (SigningPublicKey, error)
+ // Bytes returns the raw bytes of this private key
+ Bytes() []byte
+ // Zero clears all sensitive data from the private key
+ Zero()
+}
diff --git a/lib/crypto/public.go b/lib/crypto/public.go
new file mode 100644
index 0000000..833aa8c
--- /dev/null
+++ b/lib/crypto/public.go
@@ -0,0 +1,6 @@
+package crypto
+
+type PublicKey interface {
+ Len() int
+ Bytes() []byte
+}
diff --git a/lib/crypto/sign.go b/lib/crypto/sign.go
index e770ced..92b4cdf 100644
--- a/lib/crypto/sign.go
+++ b/lib/crypto/sign.go
@@ -1,13 +1,11 @@
package crypto
-import (
- "errors"
-)
+import "github.com/samber/oops"
var (
- ErrBadSignatureSize = errors.New("bad signature size")
- ErrInvalidKeyFormat = errors.New("invalid key format")
- ErrInvalidSignature = errors.New("invalid signature")
+ ErrBadSignatureSize = oops.Errorf("bad signature size")
+ ErrInvalidKeyFormat = oops.Errorf("invalid key format")
+ ErrInvalidSignature = oops.Errorf("invalid signature")
)
// type for verifying signatures
@@ -28,7 +26,7 @@ type SigningPublicKey interface {
Len() int
Bytes() []byte
}
-type PublicKey interface {
+type RecievingPublicKey interface {
Len() int
Bytes() []byte
NewEncrypter() (Encrypter, error)
diff --git a/lib/i2np/doc.md b/lib/i2np/README.md
similarity index 95%
rename from lib/i2np/doc.md
rename to lib/i2np/README.md
index e63adff..7f732ed 100644
--- a/lib/i2np/doc.md
+++ b/lib/i2np/README.md
@@ -2,6 +2,9 @@
--
import "github.com/go-i2p/go-i2p/lib/i2np"
+
+
+
## Usage
@@ -23,11 +26,11 @@ const (
```
```go
-var ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA = errors.New("not enough i2np build request record data")
+var ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA = oops.Errorf("not enough i2np build request record data")
```
```go
-var ERR_I2NP_NOT_ENOUGH_DATA = errors.New("not enough i2np header data")
+var ERR_I2NP_NOT_ENOUGH_DATA = oops.Errorf("not enough i2np header data")
```
#### func ReadI2NPNTCPData
@@ -341,3 +344,9 @@ type VariableTunnelBuildReply struct {
BuildResponseRecords []BuildResponseRecord
}
```
+
+
+
+i2np
+
+github.com/go-i2p/go-i2p/lib/i2np
diff --git a/lib/i2np/build_request_record.go b/lib/i2np/build_request_record.go
index b9c7e2c..4e611d2 100644
--- a/lib/i2np/build_request_record.go
+++ b/lib/i2np/build_request_record.go
@@ -1,15 +1,15 @@
package i2np
import (
- "errors"
"time"
+ "github.com/samber/oops"
"github.com/sirupsen/logrus"
common "github.com/go-i2p/go-i2p/lib/common/data"
"github.com/go-i2p/go-i2p/lib/common/session_key"
"github.com/go-i2p/go-i2p/lib/tunnel"
- "github.com/go-i2p/go-i2p/lib/util/logger"
+ "github.com/go-i2p/logger"
)
var log = logger.GetGoI2PLogger()
@@ -173,7 +173,7 @@ type BuildRequestRecord struct {
Padding [29]byte
}
-var ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA = errors.New("not enough i2np build request record data")
+var ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA = oops.Errorf("not enough i2np build request record data")
func ReadBuildRequestRecord(data []byte) (BuildRequestRecord, error) {
log.Debug("Reading BuildRequestRecord")
diff --git a/lib/i2np/fuzz/header/doc.md b/lib/i2np/fuzz/header/README.md
similarity index 59%
rename from lib/i2np/fuzz/header/doc.md
rename to lib/i2np/fuzz/header/README.md
index 5d85fcc..fb5f188 100644
--- a/lib/i2np/fuzz/header/doc.md
+++ b/lib/i2np/fuzz/header/README.md
@@ -2,6 +2,9 @@
--
import "github.com/go-i2p/go-i2p/lib/i2np/fuzz/header"
+
+
+
## Usage
@@ -10,3 +13,9 @@
```go
func Fuzz(data []byte) int
```
+
+
+
+exportable
+
+github.com/go-i2p/go-i2p/lib/i2np/fuzz/header
diff --git a/lib/i2np/fuzz/header/exportable.svg b/lib/i2np/fuzz/header/exportable.svg
new file mode 100644
index 0000000..5126871
--- /dev/null
+++ b/lib/i2np/fuzz/header/exportable.svg
@@ -0,0 +1,46 @@
+
+
+
+
+
diff --git a/lib/i2np/header.go b/lib/i2np/header.go
index 5ed92f6..e430b2a 100644
--- a/lib/i2np/header.go
+++ b/lib/i2np/header.go
@@ -1,9 +1,9 @@
package i2np
import (
- "errors"
"time"
+ "github.com/samber/oops"
"github.com/sirupsen/logrus"
datalib "github.com/go-i2p/go-i2p/lib/common/data"
@@ -90,7 +90,7 @@ type I2NPSSUHeader struct {
Expiration time.Time
}
-var ERR_I2NP_NOT_ENOUGH_DATA = errors.New("not enough i2np header data")
+var ERR_I2NP_NOT_ENOUGH_DATA = oops.Errorf("not enough i2np header data")
// Read an entire I2NP message and return the parsed header
// with embedded encrypted data
diff --git a/lib/i2np/i2np.svg b/lib/i2np/i2np.svg
new file mode 100644
index 0000000..a15ea96
--- /dev/null
+++ b/lib/i2np/i2np.svg
@@ -0,0 +1,1104 @@
+
+
+
+
+
diff --git a/lib/keys/README.md b/lib/keys/README.md
new file mode 100644
index 0000000..4e003a4
--- /dev/null
+++ b/lib/keys/README.md
@@ -0,0 +1,105 @@
+# keys
+--
+ import "github.com/go-i2p/go-i2p/lib/keys"
+
+
+
+
+
+## Usage
+
+#### type KeyStore
+
+```go
+type KeyStore interface {
+ KeyID() string
+ // GetKeys returns the public and private keys
+ GetKeys() (publicKey crypto.PublicKey, privateKey crypto.PrivateKey, err error)
+ // StoreKeys stores the keys
+ StoreKeys() error
+}
+```
+
+KeyStore is an interface for storing and retrieving keys
+
+#### type KeyStoreImpl
+
+```go
+type KeyStoreImpl struct {
+}
+```
+
+
+#### func NewKeyStoreImpl
+
+```go
+func NewKeyStoreImpl(dir, name string, privateKey crypto.PrivateKey) *KeyStoreImpl
+```
+
+#### func (*KeyStoreImpl) GetKeys
+
+```go
+func (ks *KeyStoreImpl) GetKeys() (crypto.PublicKey, crypto.PrivateKey, error)
+```
+
+#### func (*KeyStoreImpl) KeyID
+
+```go
+func (ks *KeyStoreImpl) KeyID() string
+```
+
+#### func (*KeyStoreImpl) StoreKeys
+
+```go
+func (ks *KeyStoreImpl) StoreKeys() error
+```
+
+#### type RouterInfoKeystore
+
+```go
+type RouterInfoKeystore struct {
+ *sntp.RouterTimestamper
+}
+```
+
+RouterInfoKeystore is an implementation of KeyStore for storing and retrieving
+RouterInfo private keys and exporting RouterInfos
+
+#### func NewRouterInfoKeystore
+
+```go
+func NewRouterInfoKeystore(dir, name string) (*RouterInfoKeystore, error)
+```
+NewRouterInfoKeystore creates a new RouterInfoKeystore with fresh and new
+private keys it accepts a directory to store the keys in and a name for the keys
+then it generates new private keys for the routerInfo if none exist
+
+#### func (*RouterInfoKeystore) ConstructRouterInfo
+
+```go
+func (ks *RouterInfoKeystore) ConstructRouterInfo(addresses []*router_address.RouterAddress) (*router_info.RouterInfo, error)
+```
+
+#### func (*RouterInfoKeystore) GetKeys
+
+```go
+func (ks *RouterInfoKeystore) GetKeys() (crypto.PublicKey, crypto.PrivateKey, error)
+```
+
+#### func (*RouterInfoKeystore) KeyID
+
+```go
+func (ks *RouterInfoKeystore) KeyID() string
+```
+
+#### func (*RouterInfoKeystore) StoreKeys
+
+```go
+func (ks *RouterInfoKeystore) StoreKeys() error
+```
+
+
+
+keys
+
+github.com/go-i2p/go-i2p/lib/keys
diff --git a/lib/keys/keys.svg b/lib/keys/keys.svg
new file mode 100644
index 0000000..44a97ba
--- /dev/null
+++ b/lib/keys/keys.svg
@@ -0,0 +1,375 @@
+
+
+
+
+
diff --git a/lib/keys/routerinfo_keystore.go b/lib/keys/routerinfo_keystore.go
new file mode 100644
index 0000000..a48e61e
--- /dev/null
+++ b/lib/keys/routerinfo_keystore.go
@@ -0,0 +1,198 @@
+package keys
+
+import (
+ "bytes"
+ "crypto/ed25519"
+ "crypto/rand"
+ "os"
+ "path/filepath"
+
+ "github.com/go-i2p/go-i2p/lib/common/certificate"
+ "github.com/go-i2p/go-i2p/lib/common/data"
+ "github.com/go-i2p/go-i2p/lib/common/key_certificate"
+ "github.com/go-i2p/go-i2p/lib/common/keys_and_cert"
+ "github.com/go-i2p/go-i2p/lib/common/router_address"
+ "github.com/go-i2p/go-i2p/lib/common/router_identity"
+ "github.com/go-i2p/go-i2p/lib/common/router_info"
+ "github.com/go-i2p/go-i2p/lib/common/signature"
+ "github.com/go-i2p/go-i2p/lib/crypto"
+ "github.com/go-i2p/go-i2p/lib/util/time/sntp"
+ "github.com/samber/oops"
+)
+
+// RouterInfoKeystore is an implementation of KeyStore for storing and retrieving RouterInfo private keys and exporting RouterInfos
+type RouterInfoKeystore struct {
+ *sntp.RouterTimestamper
+ dir string
+ name string
+ privateKey crypto.PrivateKey
+}
+
+var riks KeyStore = &RouterInfoKeystore{}
+
+// NewRouterInfoKeystore creates a new RouterInfoKeystore with fresh and new private keys
+// it accepts a directory to store the keys in and a name for the keys
+// then it generates new private keys for the routerInfo if none exist
+func NewRouterInfoKeystore(dir, name string) (*RouterInfoKeystore, error) {
+ if _, err := os.Stat(dir); os.IsNotExist(err) {
+ err := os.MkdirAll(dir, 0o755)
+ if err != nil {
+ return nil, err
+ }
+ }
+ var privateKey crypto.PrivateKey
+ fullPath := filepath.Join(dir, name)
+ if _, err := os.Stat(fullPath); os.IsNotExist(err) {
+ privateKey, err = generateNewKey()
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ keyData, err := os.ReadFile(fullPath)
+ if err != nil {
+ return nil, err
+ }
+ privateKey, err = loadExistingKey(keyData)
+ if err != nil {
+ return nil, err
+ }
+ }
+ defaultClient := &sntp.DefaultNTPClient{}
+ timestamper := sntp.NewRouterTimestamper(defaultClient)
+ return &RouterInfoKeystore{
+ dir: dir,
+ name: name,
+ privateKey: privateKey,
+ RouterTimestamper: timestamper,
+ }, nil
+}
+
+func generateNewKey() (crypto.Ed25519PrivateKey, error) {
+ // Generate a new key pair
+ _, priv, err := ed25519.GenerateKey(rand.Reader)
+ if err != nil {
+ return nil, err
+ }
+
+ // Convert to our type
+ return crypto.Ed25519PrivateKey(priv), nil
+}
+
+func loadExistingKey(keyData []byte) (crypto.Ed25519PrivateKey, error) {
+ // Validate key length
+ if len(keyData) != ed25519.PrivateKeySize {
+ return nil, oops.Errorf("invalid key length")
+ }
+
+ // Convert to our type
+ return crypto.Ed25519PrivateKey(keyData), nil
+}
+
+func (ks *RouterInfoKeystore) GetKeys() (crypto.PublicKey, crypto.PrivateKey, error) {
+ public, err := ks.privateKey.Public()
+ if err != nil {
+ return nil, nil, err
+ }
+ return public, ks.privateKey, nil
+}
+
+func (ks *RouterInfoKeystore) StoreKeys() error {
+ if _, err := os.Stat(ks.dir); os.IsNotExist(err) {
+ err := os.MkdirAll(ks.dir, 0o755)
+ if err != nil {
+ return err
+ }
+ }
+ // on the disk somewhere
+ filename := filepath.Join(ks.dir, ks.KeyID()+".key")
+ return os.WriteFile(filename, ks.privateKey.Bytes(), 0o644)
+}
+
+func (ks *RouterInfoKeystore) KeyID() string {
+ if ks.name == "" {
+ public, err := ks.privateKey.Public()
+ if err != nil {
+ return "error"
+ }
+ if len(public.Bytes()) > 10 {
+ return string(public.Bytes()[:10])
+ }
+ return string(public.Bytes())
+ }
+ return ks.name
+}
+
+func (ks *RouterInfoKeystore) ConstructRouterInfo(addresses []*router_address.RouterAddress) (*router_info.RouterInfo, error) {
+ // Get signing keys
+ publicKey, privateKey, err := ks.GetKeys()
+ if err != nil {
+ return nil, oops.Errorf("failed to get keys: %w", err)
+ }
+
+ // Create certificate with Ed25519 key type
+ payload := new(bytes.Buffer)
+ cryptoKeyType, err := data.NewIntegerFromInt(7, 2) // Ed25519
+ if err != nil {
+ return nil, oops.Errorf("failed to create crypto key type: %w", err)
+ }
+ signingKeyType, err := data.NewIntegerFromInt(7, 2) // Ed25519
+ if err != nil {
+ return nil, oops.Errorf("failed to create signing key type: %w", err)
+ }
+ payload.Write(*cryptoKeyType)
+ payload.Write(*signingKeyType)
+
+ cert, err := certificate.NewCertificateWithType(certificate.CERT_KEY, payload.Bytes())
+ if err != nil {
+ return nil, oops.Errorf("failed to create certificate: %w", err)
+ }
+
+ // Create padding
+ keyCert, err := key_certificate.KeyCertificateFromCertificate(*cert)
+ if err != nil {
+ return nil, oops.Errorf("failed to create key certificate: %w", err)
+ }
+
+ pubKeySize := keyCert.CryptoSize()
+ sigKeySize := keyCert.SignatureSize()
+ paddingSize := keys_and_cert.KEYS_AND_CERT_DATA_SIZE - (pubKeySize + sigKeySize)
+ padding := make([]byte, paddingSize)
+ _, err = rand.Read(padding)
+ if err != nil {
+ return nil, oops.Errorf("failed to generate padding: %w", err)
+ }
+
+ // Create RouterIdentity
+ routerIdentity, err := router_identity.NewRouterIdentity(
+ crypto.RecievingPublicKey(nil),
+ publicKey.(crypto.SigningPublicKey),
+ *cert,
+ padding,
+ )
+ if err != nil {
+ return nil, oops.Errorf("failed to create router identity: %w", err)
+ }
+
+ // Get timestamp
+ publishedTime := ks.RouterTimestamper.GetCurrentTime()
+
+ // Standard router options
+ options := map[string]string{
+ "caps": "NU", // Standard capabilities - Not floodfill, Not Reachable
+ "netId": "2", // Production network
+ }
+
+ ri, err := router_info.NewRouterInfo(
+ routerIdentity,
+ publishedTime,
+ addresses,
+ options,
+ privateKey.(crypto.SigningPrivateKey),
+ signature.SIGNATURE_TYPE_EDDSA_SHA512_ED25519,
+ )
+ if err != nil {
+ return nil, oops.Errorf("failed to create router info: %w", err)
+ }
+
+ return ri, nil
+}
diff --git a/lib/keys/types.go b/lib/keys/types.go
new file mode 100644
index 0000000..6ea0449
--- /dev/null
+++ b/lib/keys/types.go
@@ -0,0 +1,67 @@
+package keys
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/go-i2p/go-i2p/lib/crypto"
+)
+
+// KeyStore is an interface for storing and retrieving keys
+type KeyStore interface {
+ KeyID() string
+ // GetKeys returns the public and private keys
+ GetKeys() (publicKey crypto.PublicKey, privateKey crypto.PrivateKey, err error)
+ // StoreKeys stores the keys
+ StoreKeys() error
+}
+
+type KeyStoreImpl struct {
+ dir string
+ name string
+ privateKey crypto.PrivateKey
+}
+
+func NewKeyStoreImpl(dir, name string, privateKey crypto.PrivateKey) *KeyStoreImpl {
+ return &KeyStoreImpl{
+ dir: dir,
+ name: name,
+ privateKey: privateKey,
+ }
+}
+
+func (ks *KeyStoreImpl) KeyID() string {
+ if ks.name == "" {
+ public, err := ks.privateKey.Public()
+ if err != nil {
+ return "error"
+ }
+ if len(public.Bytes()) > 10 {
+ return string(public.Bytes()[:10])
+ } else {
+ return string(public.Bytes())
+ }
+ }
+ return ks.name
+}
+
+func (ks *KeyStoreImpl) GetKeys() (crypto.PublicKey, crypto.PrivateKey, error) {
+ public, err := ks.privateKey.Public()
+ if err != nil {
+ return nil, nil, err
+ }
+ return public, ks.privateKey, nil
+}
+
+func (ks *KeyStoreImpl) StoreKeys() error {
+ // make sure the directory exists
+ if _, err := os.Stat(ks.dir); os.IsNotExist(err) {
+ err := os.MkdirAll(ks.dir, 0o755)
+ if err != nil {
+ return err
+ }
+ }
+ // on the disk somewhere
+ filename := fmt.Sprintf("private-%s.key", ks.KeyID())
+ return os.WriteFile(filename, ks.privateKey.Bytes(), 0o644)
+}
diff --git a/lib/netdb/doc.md b/lib/netdb/README.md
similarity index 98%
rename from lib/netdb/doc.md
rename to lib/netdb/README.md
index 1a6c205..d82a2ef 100644
--- a/lib/netdb/doc.md
+++ b/lib/netdb/README.md
@@ -2,6 +2,9 @@
--
import "github.com/go-i2p/go-i2p/lib/netdb"
+
+
+
## Usage
@@ -180,3 +183,9 @@ return how many routers we know about in our network database
func (db *StdNetDB) SkiplistFile(hash common.Hash) (fpath string)
```
get the skiplist file that a RouterInfo with this hash would go in
+
+
+
+netdb
+
+github.com/go-i2p/go-i2p/lib/netdb
diff --git a/lib/netdb/netdb.svg b/lib/netdb/netdb.svg
new file mode 100644
index 0000000..2a54c5c
--- /dev/null
+++ b/lib/netdb/netdb.svg
@@ -0,0 +1,818 @@
+
+
+
+
+
diff --git a/lib/netdb/reseed/doc.md b/lib/netdb/reseed/README.md
similarity index 79%
rename from lib/netdb/reseed/doc.md
rename to lib/netdb/reseed/README.md
index 61bae77..2db8fbc 100644
--- a/lib/netdb/reseed/doc.md
+++ b/lib/netdb/reseed/README.md
@@ -2,6 +2,9 @@
--
import "github.com/go-i2p/go-i2p/lib/netdb/reseed"
+
+
+
## Usage
@@ -25,3 +28,9 @@ type Reseed struct {
```go
func (r Reseed) SingleReseed(uri string) ([]router_info.RouterInfo, error)
```
+
+
+
+reseed
+
+github.com/go-i2p/go-i2p/lib/netdb/reseed
diff --git a/lib/netdb/reseed/reseed.go b/lib/netdb/reseed/reseed.go
index 21088cc..7dc159d 100644
--- a/lib/netdb/reseed/reseed.go
+++ b/lib/netdb/reseed/reseed.go
@@ -1,7 +1,6 @@
package reseed
import (
- "fmt"
"io"
"net"
"net/http"
@@ -9,7 +8,8 @@ import (
"os"
"path/filepath"
- "github.com/go-i2p/go-i2p/lib/util/logger"
+ "github.com/go-i2p/logger"
+ "github.com/samber/oops"
"github.com/sirupsen/logrus"
"github.com/eyedeekay/go-unzip/pkg/unzip"
@@ -93,7 +93,7 @@ func (r Reseed) SingleReseed(uri string) ([]router_info.RouterInfo, error) {
}
if len(files) <= 0 {
log.Error("Reseed appears to have no content")
- return nil, fmt.Errorf("error: reseed appears to have no content")
+ return nil, oops.Errorf("error: reseed appears to have no content")
}
log.WithField("file_count", len(files)).Debug("Successfully extracted reseed files")
@@ -121,5 +121,5 @@ func (r Reseed) SingleReseed(uri string) ([]router_info.RouterInfo, error) {
}
}
log.Error("Undefined reseed error")
- return nil, fmt.Errorf("error: undefined reseed error")
+ return nil, oops.Errorf("error: undefined reseed error")
}
diff --git a/lib/netdb/reseed/reseed.svg b/lib/netdb/reseed/reseed.svg
new file mode 100644
index 0000000..5b45396
--- /dev/null
+++ b/lib/netdb/reseed/reseed.svg
@@ -0,0 +1,361 @@
+
+
+
+
+
diff --git a/lib/netdb/std.go b/lib/netdb/std.go
index 75681f5..f0531dd 100644
--- a/lib/netdb/std.go
+++ b/lib/netdb/std.go
@@ -9,7 +9,7 @@ import (
"strconv"
"strings"
- "github.com/go-i2p/go-i2p/lib/util/logger"
+ "github.com/go-i2p/logger"
"github.com/sirupsen/logrus"
"github.com/go-i2p/go-i2p/lib/bootstrap"
diff --git a/lib/router/doc.md b/lib/router/README.md
similarity index 71%
rename from lib/router/doc.md
rename to lib/router/README.md
index 7cada2d..71c6240 100644
--- a/lib/router/doc.md
+++ b/lib/router/README.md
@@ -2,6 +2,9 @@
--
import "github.com/go-i2p/go-i2p/lib/router"
+
+
+
## Usage
@@ -9,6 +12,10 @@
```go
type Router struct {
+ // keystore for router info
+ *keys.RouterInfoKeystore
+ // multi-transport manager
+ *transport.TransportMuxer
}
```
@@ -17,9 +24,9 @@ i2p router type
#### func CreateRouter
```go
-func CreateRouter() (r *Router, err error)
+func CreateRouter(cfg *config.RouterConfig) (*Router, error)
```
-create router with default configuration
+CreateRouter creates a router with the provided configuration
#### func FromConfig
@@ -56,3 +63,9 @@ Stop starts stopping internal state of router
func (r *Router) Wait()
```
Wait blocks until router is fully stopped
+
+
+
+router
+
+github.com/go-i2p/go-i2p/lib/router
diff --git a/lib/router/router.go b/lib/router/router.go
index c4c0a30..954e51d 100644
--- a/lib/router/router.go
+++ b/lib/router/router.go
@@ -1,23 +1,38 @@
package router
import (
+ "crypto/sha256"
+ "strconv"
"time"
- "github.com/go-i2p/go-i2p/lib/util/logger"
+ "github.com/go-i2p/go-i2p/lib/common/base32"
+ "github.com/go-i2p/go-i2p/lib/transport/ntcp"
+
+ "github.com/go-i2p/logger"
"github.com/sirupsen/logrus"
"github.com/go-i2p/go-i2p/lib/config"
+ "github.com/go-i2p/go-i2p/lib/keys"
"github.com/go-i2p/go-i2p/lib/netdb"
+ "github.com/go-i2p/go-i2p/lib/transport"
)
var log = logger.GetGoI2PLogger()
// i2p router type
type Router struct {
- cfg *config.RouterConfig
- ndb netdb.StdNetDB
+ // keystore for router info
+ *keys.RouterInfoKeystore
+ // multi-transport manager
+ *transport.TransportMuxer
+ // router configuration
+ cfg *config.RouterConfig
+ // netdb
+ ndb netdb.StdNetDB
+ // close channel
closeChnl chan bool
- running bool
+ // running flag
+ running bool
}
// CreateRouter creates a router with the provided configuration
@@ -26,9 +41,65 @@ func CreateRouter(cfg *config.RouterConfig) (*Router, error) {
r, err := FromConfig(cfg)
if err != nil {
log.WithError(err).Error("Failed to create router from configuration")
+ return nil, err
} else {
log.Debug("Router created successfully with provided configuration")
}
+ r.RouterInfoKeystore, err = keys.NewRouterInfoKeystore(cfg.WorkingDir, "localRouter")
+ log.Debug("Working directory is:", cfg.WorkingDir)
+ if err != nil {
+ log.WithError(err).Error("Failed to create RouterInfoKeystore")
+ return nil, err
+ } else {
+ log.Debug("RouterInfoKeystore created successfully")
+ if err = r.RouterInfoKeystore.StoreKeys(); err != nil {
+ log.WithError(err).Error("Failed to store RouterInfoKeystore")
+ return nil, err
+ } else {
+ log.Debug("RouterInfoKeystore stored successfully")
+ }
+ }
+ pub, _, err := r.RouterInfoKeystore.GetKeys()
+ if err != nil {
+ log.WithError(err).Error("Failed to get keys from RouterInfoKeystore")
+ return nil, err
+ } else {
+ // sha256 hash of public key
+ pubHash := sha256.Sum256(pub.Bytes())
+ b32PubHash := base32.EncodeToString(pubHash[:])
+ log.Debug("Router public key hash:", b32PubHash)
+ }
+
+ ri, err := r.RouterInfoKeystore.ConstructRouterInfo(nil)
+ if err != nil {
+ log.WithError(err).Error("Failed to construct RouterInfo")
+ return nil, err
+ } else {
+ log.Debug("RouterInfo constructed successfully")
+ log.Debug("RouterInfo:", ri)
+ }
+
+ // we have our keystore and our routerInfo,, so now let's set up transports
+ // add NTCP2 transport
+ ntcp2, err := ntcp.NewNTCP2Transport(ri)
+ if err != nil {
+ log.WithError(err).Error("Failed to create NTCP2 transport")
+ return nil, err
+ } else {
+ log.Debug("NTCP2 transport created successfully")
+ }
+ r.TransportMuxer = transport.Mux(ntcp2)
+ ntcpaddr, err := ntcp2.Address()
+ if err != nil {
+ log.WithError(err).Error("Failed to get NTCP2 address")
+ return nil, err
+ } else {
+ log.Debug("NTCP2 address:", ntcpaddr)
+ }
+ ri.AddAddress(ntcpaddr)
+
+ // create a transport address
+
return r, err
}
@@ -89,7 +160,7 @@ func (r *Router) mainloop() {
log.WithError(err).Error("Failed to ensure NetDB")
}
if sz := r.ndb.Size(); sz >= 0 {
- log.WithField("size", sz).Debug("NetDB Size")
+ log.WithField("size", sz).Debug("NetDB Size: " + strconv.Itoa(sz))
} else {
log.Warn("Unable to determine NetDB size")
}
diff --git a/lib/router/router.svg b/lib/router/router.svg
new file mode 100644
index 0000000..f6de68b
--- /dev/null
+++ b/lib/router/router.svg
@@ -0,0 +1,635 @@
+
+
+
+
+
diff --git a/lib/su3/doc.md b/lib/su3/README.md
similarity index 72%
rename from lib/su3/doc.md
rename to lib/su3/README.md
index 7d315f4..0ba1f07 100644
--- a/lib/su3/doc.md
+++ b/lib/su3/README.md
@@ -2,6 +2,8 @@
--
import "github.com/go-i2p/go-i2p/lib/su3"
+
+
Package su3 implements reading the SU3 file format.
SU3 files provide content that is signed by a known identity. They are used to
@@ -72,29 +74,29 @@ an error. For clarification, see TestReadSignatureFirst.
```go
var (
- ErrMissingMagicBytes = errors.New("missing magic bytes")
- ErrMissingUnusedByte6 = errors.New("missing unused byte 6")
- ErrMissingFileFormatVersion = errors.New("missing or incorrect file format version")
- ErrMissingSignatureType = errors.New("missing or invalid signature type")
- ErrUnsupportedSignatureType = errors.New("unsupported signature type")
- ErrMissingSignatureLength = errors.New("missing signature length")
- ErrMissingUnusedByte12 = errors.New("missing unused byte 12")
- ErrMissingVersionLength = errors.New("missing version length")
- ErrVersionTooShort = errors.New("version length too short")
- ErrMissingUnusedByte14 = errors.New("missing unused byte 14")
- ErrMissingSignerIDLength = errors.New("missing signer ID length")
- ErrMissingContentLength = errors.New("missing content length")
- ErrMissingUnusedByte24 = errors.New("missing unused byte 24")
- ErrMissingFileType = errors.New("missing or invalid file type")
- ErrMissingUnusedByte26 = errors.New("missing unused byte 26")
- ErrMissingContentType = errors.New("missing or invalid content type")
- ErrMissingUnusedBytes28To39 = errors.New("missing unused bytes 28-39")
- ErrMissingVersion = errors.New("missing version")
- ErrMissingSignerID = errors.New("missing signer ID")
- ErrMissingContent = errors.New("missing content")
- ErrMissingSignature = errors.New("missing signature")
- ErrInvalidPublicKey = errors.New("invalid public key")
- ErrInvalidSignature = errors.New("invalid signature")
+ ErrMissingMagicBytes = oops.Errorf("missing magic bytes")
+ ErrMissingUnusedByte6 = oops.Errorf("missing unused byte 6")
+ ErrMissingFileFormatVersion = oops.Errorf("missing or incorrect file format version")
+ ErrMissingSignatureType = oops.Errorf("missing or invalid signature type")
+ ErrUnsupportedSignatureType = oops.Errorf("unsupported signature type")
+ ErrMissingSignatureLength = oops.Errorf("missing signature length")
+ ErrMissingUnusedByte12 = oops.Errorf("missing unused byte 12")
+ ErrMissingVersionLength = oops.Errorf("missing version length")
+ ErrVersionTooShort = oops.Errorf("version length too short")
+ ErrMissingUnusedByte14 = oops.Errorf("missing unused byte 14")
+ ErrMissingSignerIDLength = oops.Errorf("missing signer ID length")
+ ErrMissingContentLength = oops.Errorf("missing content length")
+ ErrMissingUnusedByte24 = oops.Errorf("missing unused byte 24")
+ ErrMissingFileType = oops.Errorf("missing or invalid file type")
+ ErrMissingUnusedByte26 = oops.Errorf("missing unused byte 26")
+ ErrMissingContentType = oops.Errorf("missing or invalid content type")
+ ErrMissingUnusedBytes28To39 = oops.Errorf("missing unused bytes 28-39")
+ ErrMissingVersion = oops.Errorf("missing version")
+ ErrMissingSignerID = oops.Errorf("missing signer ID")
+ ErrMissingContent = oops.Errorf("missing content")
+ ErrMissingSignature = oops.Errorf("missing signature")
+ ErrInvalidPublicKey = oops.Errorf("invalid public key")
+ ErrInvalidSignature = oops.Errorf("invalid signature")
)
```
@@ -187,3 +189,9 @@ const (
EdDSA_SHA512_Ed25519ph SignatureType = "EdDSA-SHA512-Ed25519ph"
)
```
+
+
+
+su3
+
+github.com/go-i2p/go-i2p/lib/su3
diff --git a/lib/su3/su3.go b/lib/su3/su3.go
index cd59751..11b82eb 100644
--- a/lib/su3/su3.go
+++ b/lib/su3/su3.go
@@ -72,14 +72,14 @@ import (
"crypto/sha512"
"encoding/binary"
"errors"
- "fmt"
"hash"
"io"
"io/ioutil"
"strings"
"sync"
- "github.com/go-i2p/go-i2p/lib/util/logger"
+ "github.com/go-i2p/logger"
+ "github.com/samber/oops"
"github.com/sirupsen/logrus"
)
@@ -152,29 +152,29 @@ var contentTypes = map[byte]ContentType{
}
var (
- ErrMissingMagicBytes = errors.New("missing magic bytes")
- ErrMissingUnusedByte6 = errors.New("missing unused byte 6")
- ErrMissingFileFormatVersion = errors.New("missing or incorrect file format version")
- ErrMissingSignatureType = errors.New("missing or invalid signature type")
- ErrUnsupportedSignatureType = errors.New("unsupported signature type")
- ErrMissingSignatureLength = errors.New("missing signature length")
- ErrMissingUnusedByte12 = errors.New("missing unused byte 12")
- ErrMissingVersionLength = errors.New("missing version length")
- ErrVersionTooShort = errors.New("version length too short")
- ErrMissingUnusedByte14 = errors.New("missing unused byte 14")
- ErrMissingSignerIDLength = errors.New("missing signer ID length")
- ErrMissingContentLength = errors.New("missing content length")
- ErrMissingUnusedByte24 = errors.New("missing unused byte 24")
- ErrMissingFileType = errors.New("missing or invalid file type")
- ErrMissingUnusedByte26 = errors.New("missing unused byte 26")
- ErrMissingContentType = errors.New("missing or invalid content type")
- ErrMissingUnusedBytes28To39 = errors.New("missing unused bytes 28-39")
- ErrMissingVersion = errors.New("missing version")
- ErrMissingSignerID = errors.New("missing signer ID")
- ErrMissingContent = errors.New("missing content")
- ErrMissingSignature = errors.New("missing signature")
- ErrInvalidPublicKey = errors.New("invalid public key")
- ErrInvalidSignature = errors.New("invalid signature")
+ ErrMissingMagicBytes = oops.Errorf("missing magic bytes")
+ ErrMissingUnusedByte6 = oops.Errorf("missing unused byte 6")
+ ErrMissingFileFormatVersion = oops.Errorf("missing or incorrect file format version")
+ ErrMissingSignatureType = oops.Errorf("missing or invalid signature type")
+ ErrUnsupportedSignatureType = oops.Errorf("unsupported signature type")
+ ErrMissingSignatureLength = oops.Errorf("missing signature length")
+ ErrMissingUnusedByte12 = oops.Errorf("missing unused byte 12")
+ ErrMissingVersionLength = oops.Errorf("missing version length")
+ ErrVersionTooShort = oops.Errorf("version length too short")
+ ErrMissingUnusedByte14 = oops.Errorf("missing unused byte 14")
+ ErrMissingSignerIDLength = oops.Errorf("missing signer ID length")
+ ErrMissingContentLength = oops.Errorf("missing content length")
+ ErrMissingUnusedByte24 = oops.Errorf("missing unused byte 24")
+ ErrMissingFileType = oops.Errorf("missing or invalid file type")
+ ErrMissingUnusedByte26 = oops.Errorf("missing unused byte 26")
+ ErrMissingContentType = oops.Errorf("missing or invalid content type")
+ ErrMissingUnusedBytes28To39 = oops.Errorf("missing unused bytes 28-39")
+ ErrMissingVersion = oops.Errorf("missing version")
+ ErrMissingSignerID = oops.Errorf("missing signer ID")
+ ErrMissingContent = oops.Errorf("missing content")
+ ErrMissingSignature = oops.Errorf("missing signature")
+ ErrInvalidPublicKey = oops.Errorf("invalid public key")
+ ErrInvalidSignature = oops.Errorf("invalid signature")
)
const magicBytes = "I2Psu3"
@@ -217,7 +217,7 @@ func Read(reader io.Reader) (su3 *SU3, err error) {
l, err := reader.Read(mbytes)
if err != nil && !errors.Is(err, io.EOF) {
log.WithError(err).Error("Failed to read magic bytes")
- return nil, fmt.Errorf("reading magic bytes: %w", err)
+ return nil, oops.Errorf("reading magic bytes: %w", err)
}
if l != len(mbytes) {
log.Error("Missing magic bytes")
@@ -235,7 +235,7 @@ func Read(reader io.Reader) (su3 *SU3, err error) {
l, err = reader.Read(unused[:])
if err != nil && !errors.Is(err, io.EOF) {
log.WithError(err).Error("Failed to read unused byte 6")
- return nil, fmt.Errorf("reading unused byte 6: %w", err)
+ return nil, oops.Errorf("reading unused byte 6: %w", err)
}
if l != 1 {
log.Error("Missing unused byte 6")
@@ -248,7 +248,7 @@ func Read(reader io.Reader) (su3 *SU3, err error) {
l, err = reader.Read(unused[:])
if err != nil && !errors.Is(err, io.EOF) {
log.WithError(err).Error("Failed to read SU3 file format version")
- return nil, fmt.Errorf("reading SU3 file format version: %w", err)
+ return nil, oops.Errorf("reading SU3 file format version: %w", err)
}
if l != 1 {
log.Error("Missing SU3 file format version")
@@ -271,7 +271,7 @@ func Read(reader io.Reader) (su3 *SU3, err error) {
l, err = reader.Read(sigTypeBytes[:])
if err != nil && !errors.Is(err, io.EOF) {
log.WithError(err).Error("Failed to read signature type")
- return nil, fmt.Errorf("reading signature type: %w", err)
+ return nil, oops.Errorf("reading signature type: %w", err)
}
if l != 2 {
log.Error("Missing signature type")
@@ -291,7 +291,7 @@ func Read(reader io.Reader) (su3 *SU3, err error) {
l, err = reader.Read(sigLengthBytes[:])
if err != nil && !errors.Is(err, io.EOF) {
log.WithError(err).Error("Failed to read signature length")
- return nil, fmt.Errorf("reading signature length: %w", err)
+ return nil, oops.Errorf("reading signature length: %w", err)
}
if l != 2 {
log.Error("Missing signature length")
@@ -307,7 +307,7 @@ func Read(reader io.Reader) (su3 *SU3, err error) {
l, err = reader.Read(unused[:])
if err != nil && !errors.Is(err, io.EOF) {
log.WithError(err).Error("Failed to read unused byte 12")
- return nil, fmt.Errorf("reading unused byte 12: %w", err)
+ return nil, oops.Errorf("reading unused byte 12: %w", err)
}
if l != 1 {
log.Error("Missing unused byte 12")
@@ -321,7 +321,7 @@ func Read(reader io.Reader) (su3 *SU3, err error) {
l, err = reader.Read(verLengthBytes[:])
if err != nil && !errors.Is(err, io.EOF) {
log.WithError(err).Error("Failed to read version length")
- return nil, fmt.Errorf("reading version length: %w", err)
+ return nil, oops.Errorf("reading version length: %w", err)
}
if l != 1 {
log.Error("Missing version length")
@@ -339,7 +339,7 @@ func Read(reader io.Reader) (su3 *SU3, err error) {
l, err = reader.Read(unused[:])
if err != nil && !errors.Is(err, io.EOF) {
log.WithError(err).Error("Failed to read unused byte 14")
- return nil, fmt.Errorf("reading unused byte 14: %w", err)
+ return nil, oops.Errorf("reading unused byte 14: %w", err)
}
if l != 1 {
log.Error("Missing unused byte 14")
@@ -353,7 +353,7 @@ func Read(reader io.Reader) (su3 *SU3, err error) {
l, err = reader.Read(sigIDLengthBytes[:])
if err != nil && !errors.Is(err, io.EOF) {
log.WithError(err).Error("Failed to read signer ID length")
- return nil, fmt.Errorf("reading signer id length: %w", err)
+ return nil, oops.Errorf("reading signer id length: %w", err)
}
if l != 1 {
log.Error("Missing signer ID length")
@@ -368,7 +368,7 @@ func Read(reader io.Reader) (su3 *SU3, err error) {
l, err = reader.Read(contentLengthBytes[:])
if err != nil && !errors.Is(err, io.EOF) {
log.WithError(err).Error("Failed to read content length")
- return nil, fmt.Errorf("reading content length: %w", err)
+ return nil, oops.Errorf("reading content length: %w", err)
}
if l != 8 {
log.Error("Missing content length")
@@ -383,7 +383,7 @@ func Read(reader io.Reader) (su3 *SU3, err error) {
l, err = reader.Read(unused[:])
if err != nil && !errors.Is(err, io.EOF) {
log.WithError(err).Error("Failed to read unused byte 24")
- return nil, fmt.Errorf("reading unused byte 24: %w", err)
+ return nil, oops.Errorf("reading unused byte 24: %w", err)
}
if l != 1 {
log.Error("Missing unused byte 24")
@@ -397,7 +397,7 @@ func Read(reader io.Reader) (su3 *SU3, err error) {
l, err = reader.Read(fileTypeBytes[:])
if err != nil && !errors.Is(err, io.EOF) {
log.WithError(err).Error("Failed to read file type")
- return nil, fmt.Errorf("reading file type: %w", err)
+ return nil, oops.Errorf("reading file type: %w", err)
}
if l != 1 {
log.Error("Missing file type")
@@ -416,7 +416,7 @@ func Read(reader io.Reader) (su3 *SU3, err error) {
l, err = reader.Read(unused[:])
if err != nil && !errors.Is(err, io.EOF) {
log.WithError(err).Error("Failed to read unused byte 26")
- return nil, fmt.Errorf("reading unused byte 26: %w", err)
+ return nil, oops.Errorf("reading unused byte 26: %w", err)
}
if l != 1 {
log.Error("Missing unused byte 26")
@@ -430,7 +430,7 @@ func Read(reader io.Reader) (su3 *SU3, err error) {
l, err = reader.Read(contentTypeBytes[:])
if err != nil && !errors.Is(err, io.EOF) {
log.WithError(err).Error("Failed to read content type")
- return nil, fmt.Errorf("reading content type: %w", err)
+ return nil, oops.Errorf("reading content type: %w", err)
}
if l != 1 {
log.Error("Missing content type")
@@ -450,7 +450,7 @@ func Read(reader io.Reader) (su3 *SU3, err error) {
l, err = reader.Read(unused[:])
if err != nil && !errors.Is(err, io.EOF) {
log.WithError(err).Error("Failed to read unused bytes 28-39")
- return nil, fmt.Errorf("reading unused bytes 28-39: %w", err)
+ return nil, oops.Errorf("reading unused bytes 28-39: %w", err)
}
if l != 1 {
log.WithField("byte_number", 28+i).Error("Missing unused byte")
@@ -465,7 +465,7 @@ func Read(reader io.Reader) (su3 *SU3, err error) {
l, err = reader.Read(versionBytes[:])
if err != nil && !errors.Is(err, io.EOF) {
log.Debug("Read unused bytes 28-39")
- return nil, fmt.Errorf("reading version: %w", err)
+ return nil, oops.Errorf("reading version: %w", err)
}
if l != int(verLen) {
log.Error("Missing version")
@@ -481,7 +481,7 @@ func Read(reader io.Reader) (su3 *SU3, err error) {
l, err = reader.Read(signerIDBytes[:])
if err != nil && !errors.Is(err, io.EOF) {
log.WithError(err).Error("Failed to read signer ID")
- return nil, fmt.Errorf("reading signer id: %w", err)
+ return nil, oops.Errorf("reading signer id: %w", err)
}
if l != int(signIDLen) {
log.Error("Missing signer ID")
@@ -562,7 +562,7 @@ func (r *contentReader) Read(p []byte) (n int, err error) {
if r.finished {
log.Warn("Attempt to read content after finishing")
- return 0, errors.New("out of bytes, maybe you read the signature before you read the content")
+ return 0, oops.Errorf("out of bytes, maybe you read the signature before you read the content")
}
if r.reader == nil {
@@ -578,7 +578,7 @@ func (r *contentReader) Read(p []byte) (n int, err error) {
if err != nil && !errors.Is(err, io.EOF) {
log.WithError(err).Error("Error reading content")
- return l, fmt.Errorf("reading content: %w", err)
+ return l, oops.Errorf("reading content: %w", err)
} else if errors.Is(err, io.EOF) && r.reader.readSoFar != r.su3.ContentLength {
log.Error("Content shorter than expected")
return l, ErrMissingContent
@@ -656,7 +656,7 @@ func (r *signatureReader) getBytes() {
_, err := ioutil.ReadAll(r.su3.contentReader)
if err != nil {
log.WithError(err).Error("Failed to read remaining content")
- r.err = fmt.Errorf("reading content: %w", err)
+ r.err = oops.Errorf("reading content: %w", err)
return
}
}
@@ -671,7 +671,7 @@ func (r *signatureReader) getBytes() {
if err != nil {
log.WithError(err).Error("Failed to read signature")
- r.err = fmt.Errorf("reading signature: %w", err)
+ r.err = oops.Errorf("reading signature: %w", err)
} else if reader.readSoFar != uint64(r.su3.SignatureLength) {
log.Error("Signature shorter than expected")
r.err = ErrMissingSignature
diff --git a/lib/su3/su3.svg b/lib/su3/su3.svg
new file mode 100644
index 0000000..1586f8b
--- /dev/null
+++ b/lib/su3/su3.svg
@@ -0,0 +1,506 @@
+
+
+
+
+
diff --git a/lib/transport/doc.md b/lib/transport/README.md
similarity index 89%
rename from lib/transport/doc.md
rename to lib/transport/README.md
index c3269c1..d73eae4 100644
--- a/lib/transport/doc.md
+++ b/lib/transport/README.md
@@ -2,6 +2,8 @@
--
import "github.com/go-i2p/go-i2p/lib/transport"
+
+
*
i2np messages transports
@@ -9,7 +11,7 @@
## Usage
```go
-var ErrNoTransportAvailable = errors.New("no transports available")
+var ErrNoTransportAvailable = oops.Errorf("no transports available")
```
error for when we have no transports available to use
@@ -27,7 +29,7 @@ type Transport interface {
// will bind if the underlying socket is not already
// if the underlying socket is already bound update the RouterIdentity
// returns any errors that happen if they do
- SetIdentity(ident router_identity.RouterIdentity) error
+ SetIdentity(ident router_info.RouterInfo) error
// Obtain a transport session with a router given its RouterInfo.
// If a session with this router is NOT already made attempt to create one and block until made or until an error happens
@@ -77,7 +79,7 @@ close every transport that this transport muxer has
```go
func (tmux *TransportMuxer) Compatible(routerInfo router_info.RouterInfo) (compat bool)
```
-is there a transport that we mux that is compatible with this router info?
+is there a transport that we mux that is compatable with this router info?
#### func (*TransportMuxer) GetSession
@@ -97,7 +99,7 @@ the name of this transport with the names of all the ones that we mux
#### func (*TransportMuxer) SetIdentity
```go
-func (tmux *TransportMuxer) SetIdentity(ident router_identity.RouterIdentity) (err error)
+func (tmux *TransportMuxer) SetIdentity(ident router_info.RouterInfo) (err error)
```
set the identity for every transport
@@ -120,3 +122,9 @@ type TransportSession interface {
```
a session between 2 routers for tranmitting i2np messages securly
+
+
+
+transport
+
+github.com/go-i2p/go-i2p/lib/transport
diff --git a/lib/transport/errors.go b/lib/transport/errors.go
index 6b5d577..dd4dbaf 100644
--- a/lib/transport/errors.go
+++ b/lib/transport/errors.go
@@ -1,8 +1,6 @@
package transport
-import (
- "errors"
-)
+import "github.com/samber/oops"
// error for when we have no transports available to use
-var ErrNoTransportAvailable = errors.New("no transports available")
+var ErrNoTransportAvailable = oops.Errorf("no transports available")
diff --git a/lib/transport/handshake/hanshake.go b/lib/transport/handshake/hanshake.go
new file mode 100644
index 0000000..080a6a5
--- /dev/null
+++ b/lib/transport/handshake/hanshake.go
@@ -0,0 +1,18 @@
+package handshake
+
+import "github.com/flynn/noise"
+
+// HandshakeState manages the Noise handshake state
+type HandshakeState interface {
+ // GenerateEphemeral creates ephemeral keypair
+ GenerateEphemeral() (*noise.DHKey, error)
+
+ // WriteMessage creates Noise message
+ WriteMessage([]byte) ([]byte, *noise.CipherState, *noise.CipherState, error)
+
+ // HandshakeComplete returns true if handshake is complete
+ HandshakeComplete() bool
+
+ // CompleteHandshake completes the handshake
+ CompleteHandshake() error
+}
diff --git a/lib/transport/messages/doc.md b/lib/transport/messages/README.md
similarity index 93%
rename from lib/transport/messages/doc.md
rename to lib/transport/messages/README.md
index f83c2d7..1e7bbed 100644
--- a/lib/transport/messages/doc.md
+++ b/lib/transport/messages/README.md
@@ -2,6 +2,9 @@
--
import "github.com/go-i2p/go-i2p/lib/transport/messages"
+
+
+
## Usage
@@ -66,3 +69,9 @@ PayloadSize returns the message payload size
func (sr *SessionRequest) Type() MessageType
```
Type returns the message type
+
+
+
+ntcp
+
+github.com/go-i2p/go-i2p/lib/transport/messages
diff --git a/lib/transport/messages/ntcp.svg b/lib/transport/messages/ntcp.svg
new file mode 100644
index 0000000..947c327
--- /dev/null
+++ b/lib/transport/messages/ntcp.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
diff --git a/lib/transport/multi.go b/lib/transport/multi.go
index 383a293..461a404 100644
--- a/lib/transport/multi.go
+++ b/lib/transport/multi.go
@@ -1,9 +1,8 @@
package transport
import (
- "github.com/go-i2p/go-i2p/lib/common/router_identity"
"github.com/go-i2p/go-i2p/lib/common/router_info"
- "github.com/go-i2p/go-i2p/lib/util/logger"
+ "github.com/go-i2p/logger"
)
var log = logger.GetGoI2PLogger()
@@ -25,7 +24,7 @@ func Mux(t ...Transport) (tmux *TransportMuxer) {
}
// set the identity for every transport
-func (tmux *TransportMuxer) SetIdentity(ident router_identity.RouterIdentity) (err error) {
+func (tmux *TransportMuxer) SetIdentity(ident router_info.RouterInfo) (err error) {
log.WithField("identity", ident).Debug("TransportMuxer: Setting identity for all transports")
for i, t := range tmux.trans {
err = t.SetIdentity(ident)
diff --git a/lib/transport/noise/README.md b/lib/transport/noise/README.md
new file mode 100644
index 0000000..5660e56
--- /dev/null
+++ b/lib/transport/noise/README.md
@@ -0,0 +1,327 @@
+# noise
+--
+ import "github.com/go-i2p/go-i2p/lib/transport/noise"
+
+
+
+
+
+## Usage
+
+```go
+const (
+ NOISE_DH_CURVE25519 = 1
+
+ NOISE_CIPHER_CHACHAPOLY = 1
+ NOISE_CIPHER_AESGCM = 2
+
+ NOISE_HASH_SHA256 = 3
+
+ NOISE_PATTERN_XK = 11
+
+ MaxPayloadSize = 65537
+)
+```
+
+```go
+const NOISE_PROTOCOL_NAME = "NOISE"
+```
+
+```go
+var ExampleNoiseListener net.Listener = exampleNoiseTransport
+```
+ExampleNoiseListener is not a real Noise Listener, do not use it. It is exported
+so that it can be confirmed that the transport implements net.Listener
+
+```go
+var (
+ ExampleNoiseSession net.Conn = exampleNoiseSession.(*NoiseSession)
+)
+```
+
+#### func NewNoiseTransportSession
+
+```go
+func NewNoiseTransportSession(ri router_info.RouterInfo) (transport.TransportSession, error)
+```
+
+#### type HandshakeState
+
+```go
+type HandshakeState struct {
+ *noise.HandshakeState
+}
+```
+
+
+#### func NewHandshakeState
+
+```go
+func NewHandshakeState(staticKey noise.DHKey, isInitiator bool) (*HandshakeState, error)
+```
+
+#### func (*HandshakeState) GenerateEphemeral
+
+```go
+func (h *HandshakeState) GenerateEphemeral() (*noise.DHKey, error)
+```
+GenerateEphemeral creates the ephemeral keypair that will be used in handshake
+This needs to be separate so NTCP2 can obfuscate it
+
+#### func (*HandshakeState) ReadMessage
+
+```go
+func (h *HandshakeState) ReadMessage(message []byte) ([]byte, *noise.CipherState, *noise.CipherState, error)
+```
+
+#### func (*HandshakeState) SetEphemeral
+
+```go
+func (h *HandshakeState) SetEphemeral(key *noise.DHKey) error
+```
+SetEphemeral allows setting a potentially modified ephemeral key This is needed
+for NTCP2's obfuscation layer
+
+#### func (*HandshakeState) WriteMessage
+
+```go
+func (h *HandshakeState) WriteMessage(payload []byte) ([]byte, *noise.CipherState, *noise.CipherState, error)
+```
+
+#### type NoiseSession
+
+```go
+type NoiseSession struct {
+ router_info.RouterInfo
+ *noise.CipherState
+ *sync.Cond
+ *NoiseTransport // The parent transport, which "Dialed" the connection to the peer with whom we established the session
+ *HandshakeState
+ RecvQueue *cb.Queue
+ SendQueue *cb.Queue
+ VerifyCallback VerifyCallbackFunc
+
+ Conn net.Conn
+}
+```
+
+
+#### func NewNoiseSession
+
+```go
+func NewNoiseSession(ri router_info.RouterInfo) (*NoiseSession, error)
+```
+
+#### func (*NoiseSession) Close
+
+```go
+func (s *NoiseSession) Close() error
+```
+
+#### func (*NoiseSession) ComposeInitiatorHandshakeMessage
+
+```go
+func (c *NoiseSession) ComposeInitiatorHandshakeMessage(
+ payload []byte,
+ ephemeralPrivate []byte,
+) (
+ negotiationData,
+ handshakeMessage []byte,
+ handshakeState *noise.HandshakeState,
+ err error,
+)
+```
+
+#### func (*NoiseSession) ComposeReceiverHandshakeMessage
+
+```go
+func (c *NoiseSession) ComposeReceiverHandshakeMessage(localStatic noise.DHKey, remoteStatic []byte, payload []byte, ephemeralPrivate []byte) (negData, msg []byte, state *noise.HandshakeState, err error)
+```
+
+#### func (*NoiseSession) LocalAddr
+
+```go
+func (s *NoiseSession) LocalAddr() net.Addr
+```
+
+#### func (*NoiseSession) QueueSendI2NP
+
+```go
+func (s *NoiseSession) QueueSendI2NP(msg i2np.I2NPMessage)
+```
+
+#### func (*NoiseSession) Read
+
+```go
+func (c *NoiseSession) Read(b []byte) (int, error)
+```
+
+#### func (*NoiseSession) ReadNextI2NP
+
+```go
+func (s *NoiseSession) ReadNextI2NP() (i2np.I2NPMessage, error)
+```
+
+#### func (*NoiseSession) RemoteAddr
+
+```go
+func (noise_session *NoiseSession) RemoteAddr() net.Addr
+```
+RemoteAddr implements net.Conn
+
+#### func (*NoiseSession) RunIncomingHandshake
+
+```go
+func (c *NoiseSession) RunIncomingHandshake() error
+```
+
+#### func (*NoiseSession) RunOutgoingHandshake
+
+```go
+func (c *NoiseSession) RunOutgoingHandshake() error
+```
+
+#### func (*NoiseSession) SendQueueSize
+
+```go
+func (s *NoiseSession) SendQueueSize() int
+```
+
+#### func (*NoiseSession) SetDeadline
+
+```go
+func (noise_session *NoiseSession) SetDeadline(t time.Time) error
+```
+SetDeadline implements net.Conn
+
+#### func (*NoiseSession) SetReadDeadline
+
+```go
+func (noise_session *NoiseSession) SetReadDeadline(t time.Time) error
+```
+SetReadDeadline implements net.Conn
+
+#### func (*NoiseSession) SetWriteDeadline
+
+```go
+func (noise_session *NoiseSession) SetWriteDeadline(t time.Time) error
+```
+SetWriteDeadline implements net.Conn
+
+#### func (*NoiseSession) Write
+
+```go
+func (c *NoiseSession) Write(b []byte) (int, error)
+```
+
+#### type NoiseTransport
+
+```go
+type NoiseTransport struct {
+ sync.Mutex
+ router_info.RouterInfo
+
+ Listener net.Listener
+}
+```
+
+
+#### func NewNoiseTransport
+
+```go
+func NewNoiseTransport(netSocket net.Listener) *NoiseTransport
+```
+NewNoiseTransport create a NoiseTransport using a supplied net.Listener
+
+#### func NewNoiseTransportSocket
+
+```go
+func NewNoiseTransportSocket() (*NoiseTransport, error)
+```
+NewNoiseTransportSocket creates a Noise transport socket with a random host and
+port.
+
+#### func (*NoiseTransport) Accept
+
+```go
+func (noopt *NoiseTransport) Accept() (net.Conn, error)
+```
+Accept a connection on a listening socket.
+
+#### func (*NoiseTransport) Addr
+
+```go
+func (noopt *NoiseTransport) Addr() net.Addr
+```
+Addr of the transport, for now this is returning the IP:Port the transport is
+listening on, but this might actually be the router identity
+
+#### func (*NoiseTransport) Close
+
+```go
+func (noopt *NoiseTransport) Close() error
+```
+close the transport cleanly blocks until done returns an error if one happens
+
+#### func (*NoiseTransport) Compatable
+
+```go
+func (noopt *NoiseTransport) Compatable(routerInfo router_info.RouterInfo) bool
+```
+Compatable return true if a routerInfo is compatable with this transport
+
+#### func (*NoiseTransport) Compatible
+
+```go
+func (noopt *NoiseTransport) Compatible(routerInfo router_info.RouterInfo) bool
+```
+
+#### func (*NoiseTransport) GetSession
+
+```go
+func (noopt *NoiseTransport) GetSession(routerInfo router_info.RouterInfo) (transport.TransportSession, error)
+```
+Obtain a transport session with a router given its RouterInfo. If a session with
+this router is NOT already made attempt to create one and block until made or
+until an error happens returns an established TransportSession and nil on
+success returns nil and an error on error
+
+#### func (*NoiseTransport) Handshake
+
+```go
+func (c *NoiseTransport) Handshake(routerInfo router_info.RouterInfo) error
+```
+
+#### func (*NoiseTransport) HandshakeKey
+
+```go
+func (h *NoiseTransport) HandshakeKey() *noise.DHKey
+```
+
+#### func (*NoiseTransport) Name
+
+```go
+func (noopt *NoiseTransport) Name() string
+```
+Name of the transport TYPE, in this case `noise`
+
+#### func (*NoiseTransport) SetIdentity
+
+```go
+func (noopt *NoiseTransport) SetIdentity(ident router_info.RouterInfo) (err error)
+```
+SetIdentity will set the router identity for this transport. will bind if the
+underlying socket is not already if the underlying socket is already bound
+update the RouterIdentity returns any errors that happen if they do
+
+#### type VerifyCallbackFunc
+
+```go
+type VerifyCallbackFunc func(publicKey []byte, data []byte) error
+```
+
+
+
+noise
+
+github.com/go-i2p/go-i2p/lib/transport/noise
diff --git a/lib/transport/noise/doc.md b/lib/transport/noise/doc.md
deleted file mode 100644
index 348df1a..0000000
--- a/lib/transport/noise/doc.md
+++ /dev/null
@@ -1,300 +0,0 @@
-
-# noise
-
-## Overview
-
-The `noise` package implements the Noise Protocol to establish secure, authenticated sessions over TCP. This package includes functions for session management, handshake initiation, packet encryption, decryption, and transport abstraction.
-
-
-- [handshake.go](#handshakego)
-- [i2np.go](#i2npgo)
-- [incoming_handshake.go](#incoming_handshakego)
-- [outgoing_handshake.go](#outgoing_handshakego)
-- [noise_constants.go](#noise_constantsgo)
-- [read_session.go](#read_sessiongo)
-- [session.go](#sessiongo)
-- [transport.go](#transportgo)
-- [write_session.go](#write_sessiongo)
-
----
-
-## handshake.go
-
-Defines the `Handshake` function, which initiates the Noise handshake process for secure, authenticated sessions.
-
-### Package
-
-```go
-package noise
-```
-
-### Imports
-
-```go
-import (
- "sync"
- "github.com/go-i2p/go-i2p/lib/util/logger"
- "github.com/go-i2p/go-i2p/lib/common/router_info"
-)
-```
-
-### Variables
-
-- **`log`**: Logger instance for capturing debug and error messages related to the handshake process.
-
-### Function: `Handshake`
-
-#### Definition
-
-```go
-func (c *NoiseTransport) Handshake(routerInfo router_info.RouterInfo) error
-```
-
-#### Parameters
-- `routerInfo`: Information about the router with which the handshake is established.
-
-#### Returns
-- `error`: Returns `nil` on success, or an error if the handshake fails.
-
-#### Description
-The `Handshake` function initiates an authenticated handshake with a router, establishing a secure session.
-
-#### Workflow
-1. **Logging Start**: Logs initiation of the handshake.
-2. **Lock Mutex**: Locks `c.Mutex` to prevent concurrent access.
-3. **Session Retrieval**: Calls `c.getSession(routerInfo)`.
-4. **Condition Variable Setup**: Sets a `Cond` for the session.
-5. **Outgoing Handshake**: Executes `RunOutgoingHandshake`.
-6. **Completion Broadcast**: Broadcasts to waiting goroutines.
-7. **Finalize and Unlock**: Logs success.
-
----
-
-## i2np.go
-
-Provides functions to queue and send I2NP messages using a `NoiseSession`.
-
-### Package
-
-```go
-package noise
-```
-
-### Imports
-
-```go
-import "github.com/go-i2p/go-i2p/lib/i2np"
-```
-
-### Functions
-
-#### `QueueSendI2NP`
-
-Queues an I2NP message for sending.
-
-```go
-func (s *NoiseSession) QueueSendI2NP(msg i2np.I2NPMessage)
-```
-
-#### Parameters
-- `msg`: The I2NP message.
-
----
-
-#### `SendQueueSize`
-
-Returns the size of the send queue.
-
-```go
-func (s *NoiseSession) SendQueueSize() int
-```
-
----
-
-#### `ReadNextI2NP`
-
-Attempts to read the next I2NP message from the queue.
-
-```go
-func (s *NoiseSession) ReadNextI2NP() (i2np.I2NPMessage, error)
-```
-
----
-
-## incoming_handshake.go
-
-Defines functions for the incoming (receiver) side of the handshake.
-
-### Functions
-
-#### `ComposeReceiverHandshakeMessage`
-
-Creates a receiver handshake message using Noise patterns.
-
-```go
-func ComposeReceiverHandshakeMessage(s noise.DHKey, rs []byte, payload []byte, ePrivate []byte) (negData, msg []byte, state *noise.HandshakeState, err error)
-```
-
-- **`s`**: Static Diffie-Hellman key.
-- **`rs`**: Remote static key.
-- **`payload`**: Optional payload data.
-- **`ePrivate`**: Private ephemeral key.
-
----
-
-#### `RunIncomingHandshake`
-
-Executes an incoming handshake process.
-
-```go
-func (c *NoiseSession) RunIncomingHandshake() error
-```
-
-- Initializes and sends the negotiation data and handshake message.
-
----
-
-## outgoing_handshake.go
-
-Defines functions for the outgoing (initiator) side of the handshake.
-
-### Functions
-
-#### `ComposeInitiatorHandshakeMessage`
-
-Creates an initiator handshake message.
-
-```go
-func ComposeInitiatorHandshakeMessage(s noise.DHKey, rs []byte, payload []byte, ePrivate []byte) (negData, msg []byte, state *noise.HandshakeState, err error)
-```
-
----
-
-#### `RunOutgoingHandshake`
-
-Executes the outgoing handshake process.
-
-```go
-func (c *NoiseSession) RunOutgoingHandshake() error
-```
-
-- Sends negotiation data and handshake message.
-
----
-
-## noise_constants.go
-
-Defines constants and utility functions for configuring Noise protocol parameters.
-
-### Constants
-
-```go
-const (
- NOISE_DH_CURVE25519 = 1
- NOISE_CIPHER_CHACHAPOLY = 1
- NOISE_HASH_SHA256 = 3
- NOISE_PATTERN_XK = 11
- uint16Size = 2
- MaxPayloadSize = 65537
-)
-```
-
-### Functions
-
-#### `initNegotiationData`
-
-Initializes negotiation data with default values.
-
-```go
-func initNegotiationData(negotiationData []byte) []byte
-```
-
----
-
-## read_session.go
-
-Functions related to reading encrypted data in a Noise session.
-
-### Functions
-
-#### `Read`
-
-Reads from the Noise session.
-
-```go
-func (c *NoiseSession) Read(b []byte) (int, error)
-```
-
-#### `decryptPacket`
-
-Decrypts a packet.
-
-```go
-func (c *NoiseSession) decryptPacket(data []byte) (int, []byte, error)
-```
-
----
-
-## session.go
-
-Defines the `NoiseSession` struct and associated methods for session management.
-
-### Struct: `NoiseSession`
-
-Defines session properties.
-
-```go
-type NoiseSession struct {
- // Session properties here
-}
-```
-
----
-
-## transport.go
-
-Defines the `NoiseTransport` struct and its methods for session compatibility, accepting connections, etc.
-
-### Struct: `NoiseTransport`
-
-```go
-type NoiseTransport struct {
- sync.Mutex
- router_identity.RouterIdentity
- *noise.CipherState
- Listener net.Listener
- peerConnections map[data.Hash]transport.TransportSession
-}
-```
-
-#### Methods
-
-- `Compatible`: Checks compatibility.
-- `Accept`: Accepts a connection.
-- `Addr`: Returns the address.
-- `SetIdentity`: Sets the router identity.
-- `GetSession`: Obtains a session.
-
----
-
-## write_session.go
-
-Functions for writing encrypted data in a Noise session.
-
-### Functions
-
-#### `Write`
-
-Writes data in a Noise session.
-
-```go
-func (c *NoiseSession) Write(b []byte) (int, error)
-```
-
-#### `encryptPacket`
-
-Encrypts a packet.
-
-```go
-func (c *NoiseSession) encryptPacket(data []byte) (int, []byte, error)
-```
\ No newline at end of file
diff --git a/lib/transport/noise/encrdecr_packet_test.go b/lib/transport/noise/encrdecr_packet_test.go
index 250a65b..4e7d02e 100644
--- a/lib/transport/noise/encrdecr_packet_test.go
+++ b/lib/transport/noise/encrdecr_packet_test.go
@@ -5,19 +5,19 @@ import (
"crypto/cipher"
"crypto/rand"
"encoding/binary"
- "fmt"
"testing"
"github.com/go-i2p/go-i2p/lib/crypto"
"github.com/go-i2p/go-i2p/lib/transport/obfs"
"github.com/flynn/noise"
+ "github.com/samber/oops"
"github.com/stretchr/testify/assert"
)
func (ns *NoiseSession) testEncryptPacket(plaintext []byte) (int, []byte, error) {
if ns.CipherState == nil {
- return 0, nil, fmt.Errorf("CipherState is nil")
+ return 0, nil, oops.Errorf("CipherState is nil")
}
// Encrypt the data
@@ -37,18 +37,18 @@ func (ns *NoiseSession) testEncryptPacket(plaintext []byte) (int, []byte, error)
func (ns *NoiseSession) testPacketDeux(packet []byte) (int, []byte, error) {
if ns.CipherState == nil {
- return 0, nil, fmt.Errorf("CipherState is nil")
+ return 0, nil, oops.Errorf("CipherState is nil")
}
if len(packet) < 2 {
- return 0, nil, fmt.Errorf("Packet too short to contain length prefix")
+ return 0, nil, oops.Errorf("Packet too short to contain length prefix")
}
// Extract the length prefix
packetLength := binary.BigEndian.Uint16(packet[:2])
if len(packet[2:]) < int(packetLength) {
- return 0, nil, fmt.Errorf("Packet data is shorter than indicated length")
+ return 0, nil, oops.Errorf("Packet data is shorter than indicated length")
}
ciphertext := packet[2 : 2+packetLength]
diff --git a/lib/transport/noise/handshake.go b/lib/transport/noise/handshake.go
index 8dee4d7..c36839d 100644
--- a/lib/transport/noise/handshake.go
+++ b/lib/transport/noise/handshake.go
@@ -4,27 +4,26 @@ import (
"sync"
"github.com/go-i2p/go-i2p/lib/common/router_info"
- "github.com/go-i2p/go-i2p/lib/util/logger"
+ "github.com/go-i2p/logger"
"github.com/flynn/noise"
)
-type HandshakeState struct {
+type NoiseHandshakeState struct {
mutex sync.Mutex
ephemeral *noise.DHKey
pattern noise.HandshakePattern
handshakeComplete bool
- HandKey noise.DHKey
*noise.HandshakeState
}
-func NewHandshakeState(staticKey noise.DHKey, isInitiator bool) (*HandshakeState, error) {
- hs := &HandshakeState{
+func NewHandshakeState(staticKey noise.DHKey, isInitiator bool) (*NoiseHandshakeState, error) {
+ hs := &NoiseHandshakeState{
pattern: noise.HandshakeXK,
}
config := noise.Config{
- CipherSuite: noise.NewCipherSuite(noise.DH25519, noise.CipherAESGCM, noise.HashSHA256),
+ CipherSuite: noise.NewCipherSuite(noise.DH25519, noise.CipherChaChaPoly, noise.HashSHA256),
Pattern: hs.pattern,
Initiator: isInitiator,
StaticKeypair: staticKey,
@@ -39,9 +38,20 @@ func NewHandshakeState(staticKey noise.DHKey, isInitiator bool) (*HandshakeState
return hs, nil
}
+func (h *NoiseHandshakeState) HandshakeComplete() bool {
+ return h.handshakeComplete
+}
+
+func (h *NoiseHandshakeState) CompleteHandshake() error {
+ h.mutex.Lock()
+ defer h.mutex.Unlock()
+ h.handshakeComplete = true
+ return nil
+}
+
// GenerateEphemeral creates the ephemeral keypair that will be used in handshake
// This needs to be separate so NTCP2 can obfuscate it
-func (h *HandshakeState) GenerateEphemeral() (*noise.DHKey, error) {
+func (h *NoiseHandshakeState) GenerateEphemeral() (*noise.DHKey, error) {
h.mutex.Lock()
defer h.mutex.Unlock()
@@ -55,21 +65,21 @@ func (h *HandshakeState) GenerateEphemeral() (*noise.DHKey, error) {
// SetEphemeral allows setting a potentially modified ephemeral key
// This is needed for NTCP2's obfuscation layer
-func (h *HandshakeState) SetEphemeral(key *noise.DHKey) error {
+func (h *NoiseHandshakeState) SetEphemeral(key *noise.DHKey) error {
h.mutex.Lock()
defer h.mutex.Unlock()
h.ephemeral = key
return nil
}
-func (h *HandshakeState) WriteMessage(payload []byte) ([]byte, *noise.CipherState, *noise.CipherState, error) {
+func (h *NoiseHandshakeState) WriteMessage(payload []byte) ([]byte, *noise.CipherState, *noise.CipherState, error) {
h.mutex.Lock()
defer h.mutex.Unlock()
return h.HandshakeState.WriteMessage(nil, payload)
}
-func (h *HandshakeState) ReadMessage(message []byte) ([]byte, *noise.CipherState, *noise.CipherState, error) {
+func (h *NoiseHandshakeState) ReadMessage(message []byte) ([]byte, *noise.CipherState, *noise.CipherState, error) {
h.mutex.Lock()
defer h.mutex.Unlock()
diff --git a/lib/transport/noise/incoming_handshake.go b/lib/transport/noise/incoming_handshake.go
index 9867944..da76431 100644
--- a/lib/transport/noise/incoming_handshake.go
+++ b/lib/transport/noise/incoming_handshake.go
@@ -3,22 +3,22 @@ package noise
import (
"bytes"
"crypto/rand"
- "errors"
"io"
"github.com/flynn/noise"
+ "github.com/samber/oops"
"github.com/sirupsen/logrus"
)
func (c *NoiseSession) RunIncomingHandshake() error {
log.Debug("Starting incoming handshake")
- negData, msg, state, err := ComposeReceiverHandshakeMessage(c.HandKey, nil, nil, nil)
+ negData, msg, state, err := c.ComposeReceiverHandshakeMessage(*c.HandshakeKey(), nil, nil, nil)
if err != nil {
log.WithError(err).Error("Failed to compose receiver handshake message")
return err
}
- c.HandshakeState = &HandshakeState{
+ c.HandshakeState = &NoiseHandshakeState{
HandshakeState: state,
}
log.WithFields(logrus.Fields{
@@ -37,17 +37,17 @@ func (c *NoiseSession) RunIncomingHandshake() error {
log.Debug("Handshake message written successfully")
log.WithField("state", state).Debug("Handshake state after message write")
log.Println(state)
- c.handshakeComplete = true
+ c.CompleteHandshake()
log.Debug("Incoming handshake completed successfully")
return nil
}
-func ComposeReceiverHandshakeMessage(s noise.DHKey, rs []byte, payload []byte, ePrivate []byte) (negData, msg []byte, state *noise.HandshakeState, err error) {
+func (c *NoiseSession) ComposeReceiverHandshakeMessage(localStatic noise.DHKey, remoteStatic []byte, payload []byte, ephemeralPrivate []byte) (negData, msg []byte, state *noise.HandshakeState, err error) {
log.Debug("Starting ComposeReceiverHandshakeMessage")
- if len(rs) != 0 && len(rs) != noise.DH25519.DHLen() {
- log.WithField("rs_length", len(rs)).Error("Invalid remote static key length")
- return nil, nil, nil, errors.New("only 32 byte curve25519 public keys are supported")
+ if len(remoteStatic) != 0 && len(remoteStatic) != noise.DH25519.DHLen() {
+ log.WithField("rs_length", len(remoteStatic)).Error("Invalid remote static key length")
+ return nil, nil, nil, oops.Errorf("only 32 byte curve25519 public keys are supported")
}
negData = make([]byte, 6)
@@ -56,18 +56,18 @@ func ComposeReceiverHandshakeMessage(s noise.DHKey, rs []byte, payload []byte, e
negData[5] = NOISE_PATTERN_XK
var random io.Reader
- if len(ePrivate) == 0 {
+ if len(ephemeralPrivate) == 0 {
random = rand.Reader
log.Debug("Using crypto/rand as random source")
} else {
- random = bytes.NewBuffer(ePrivate)
+ random = bytes.NewBuffer(ephemeralPrivate)
}
config := noise.Config{
- CipherSuite: noise.NewCipherSuite(noise.DH25519, noise.CipherAESGCM, noise.HashSHA256),
+ CipherSuite: noise.NewCipherSuite(noise.DH25519, noise.CipherChaChaPoly, noise.HashSHA256),
Pattern: pattern,
Initiator: false,
- StaticKeypair: s,
+ StaticKeypair: localStatic,
Random: random,
}
@@ -84,7 +84,7 @@ func ComposeReceiverHandshakeMessage(s noise.DHKey, rs []byte, payload []byte, e
// Verify no CipherStates are returned yet
if cs0 != nil || cs1 != nil {
- return nil, nil, nil, errors.New("unexpected cipher states in message 2")
+ return nil, nil, nil, oops.Errorf("unexpected cipher states in message 2")
}
return negData, msg, state, nil
diff --git a/lib/transport/noise/noise.svg b/lib/transport/noise/noise.svg
new file mode 100644
index 0000000..012a94d
--- /dev/null
+++ b/lib/transport/noise/noise.svg
@@ -0,0 +1,2337 @@
+
+
+
+
+
diff --git a/lib/transport/noise/outgoing_handshake.go b/lib/transport/noise/outgoing_handshake.go
index 60b1e10..aea59b3 100644
--- a/lib/transport/noise/outgoing_handshake.go
+++ b/lib/transport/noise/outgoing_handshake.go
@@ -3,18 +3,18 @@ package noise
import (
"bytes"
"crypto/rand"
- "errors"
"io"
"github.com/sirupsen/logrus"
"github.com/flynn/noise"
+ "github.com/samber/oops"
)
func (c *NoiseSession) RunOutgoingHandshake() error {
log.Debug("Starting outgoing handshake")
- negData, msg, state, err := ComposeInitiatorHandshakeMessage(c.HandKey, nil, nil, nil)
+ negData, msg, state, err := c.ComposeInitiatorHandshakeMessage(nil, nil)
if err != nil {
log.WithError(err).Error("Failed to compose initiator handshake message")
return err
@@ -23,7 +23,7 @@ func (c *NoiseSession) RunOutgoingHandshake() error {
"negData_length": len(negData),
"msg_length": len(msg),
}).Debug("Initiator handshake message composed")
- c.HandshakeState = &HandshakeState{
+ c.HandshakeState = &NoiseHandshakeState{
HandshakeState: state,
}
@@ -40,53 +40,76 @@ func (c *NoiseSession) RunOutgoingHandshake() error {
log.Debug("Handshake message written successfully")
log.WithField("state", state).Debug("Handshake state after message write")
log.Println(state)
- c.handshakeComplete = true
+ c.CompleteHandshake()
log.Debug("Outgoing handshake completed successfully")
return nil
}
-func ComposeInitiatorHandshakeMessage(s noise.DHKey, rs []byte, payload []byte, ePrivate []byte) (negData, msg []byte, state *noise.HandshakeState, err error) {
+func (c *NoiseSession) ComposeInitiatorHandshakeMessage(
+ payload []byte,
+ ephemeralPrivate []byte,
+) (
+ negotiationData,
+ handshakeMessage []byte,
+ handshakeState *noise.HandshakeState,
+ err error,
+) {
log.Debug("Starting ComposeInitiatorHandshakeMessage")
- if len(rs) != 0 && len(rs) != noise.DH25519.DHLen() {
- return nil, nil, nil, errors.New("only 32 byte curve25519 public keys are supported")
+ remoteStatic, err := c.peerStaticKey()
+ if err != nil {
+ return nil, nil, nil, oops.Errorf("Peer static key retrieval error: %s", err)
}
- negData = make([]byte, 6)
- copy(negData, initNegotiationData(nil))
+ /*localStatic, err := c.localStaticKey()
+ if err != nil {
+ return nil, nil, nil, oops.Errorf("Local static key retrieval error: %s", err)
+ }
+ localStaticDH := noise.DHKey{
+ Public: localStatic[:],
+ Private: localStatic[:],
+ }*/
+ localStaticDH := *c.HandshakeKey()
+
+ if len(remoteStatic) != 0 && len(remoteStatic) != noise.DH25519.DHLen() {
+ return nil, nil, nil, oops.Errorf("only 32 byte curve25519 public keys are supported")
+ }
+
+ negotiationData = make([]byte, 6)
+ copy(negotiationData, initNegotiationData(nil))
pattern := noise.HandshakeXK
- negData[5] = NOISE_PATTERN_XK
+ negotiationData[5] = NOISE_PATTERN_XK
var random io.Reader
- if len(ePrivate) == 0 {
+ if len(ephemeralPrivate) == 0 {
random = rand.Reader
} else {
- random = bytes.NewBuffer(ePrivate)
+ random = bytes.NewBuffer(ephemeralPrivate)
}
config := noise.Config{
- CipherSuite: noise.NewCipherSuite(noise.DH25519, noise.CipherAESGCM, noise.HashSHA256),
+ CipherSuite: noise.NewCipherSuite(noise.DH25519, noise.CipherChaChaPoly, noise.HashSHA256),
Pattern: pattern,
Initiator: true,
- StaticKeypair: s,
+ StaticKeypair: localStaticDH,
Random: random,
}
- state, err = noise.NewHandshakeState(config)
+ handshakeState, err = noise.NewHandshakeState(config)
if err != nil {
return nil, nil, nil, err
}
// Write message, expecting no CipherStates yet since this is message 1
- msg, cs0, cs1, err := state.WriteMessage(nil, payload)
+ handshakeMessage, cs0, cs1, err := handshakeState.WriteMessage(nil, payload)
if err != nil {
return nil, nil, nil, err
}
// Verify no CipherStates are returned yet
if cs0 != nil || cs1 != nil {
- return nil, nil, nil, errors.New("unexpected cipher states in message 1")
+ return nil, nil, nil, oops.Errorf("unexpected cipher states in message 1")
}
- return negData, msg, state, nil
+ return negotiationData, handshakeMessage, handshakeState, nil
}
diff --git a/lib/transport/noise/read_session.go b/lib/transport/noise/read_session.go
index b8f8833..0626970 100644
--- a/lib/transport/noise/read_session.go
+++ b/lib/transport/noise/read_session.go
@@ -1,9 +1,10 @@
package noise
import (
- "errors"
+ "encoding/binary"
"sync/atomic"
+ "github.com/samber/oops"
"github.com/sirupsen/logrus"
)
@@ -17,7 +18,7 @@ func (c *NoiseSession) Read(b []byte) (int, error) {
"at": "(NoiseSession) Read",
"reason": "session is closed",
}).Error("session is closed")
- return 0, errors.New("session is closed")
+ return 0, oops.Errorf("session is closed")
}
if atomic.CompareAndSwapInt32(&c.activeCall, x, x+2) {
defer atomic.AddInt32(&c.activeCall, -2)
@@ -25,7 +26,7 @@ func (c *NoiseSession) Read(b []byte) (int, error) {
}
log.Debug("NoiseSession Read: retrying atomic operation")
}
- if !c.handshakeComplete {
+ if !c.HandshakeComplete() {
log.Debug("NoiseSession Read: handshake not complete, running incoming handshake")
if err := c.RunIncomingHandshake(); err != nil {
log.WithError(err).Error("NoiseSession Read: failed to run incoming handshake")
@@ -34,9 +35,9 @@ func (c *NoiseSession) Read(b []byte) (int, error) {
}
c.Mutex.Lock()
defer c.Mutex.Unlock()
- if !c.handshakeComplete {
+ if !c.HandshakeComplete() {
log.Error("NoiseSession Read: internal error - handshake still not complete after running")
- return 0, errors.New("internal error")
+ return 0, oops.Errorf("internal error")
}
n, err := c.readPacketLocked(b)
if err != nil {
@@ -48,47 +49,46 @@ func (c *NoiseSession) Read(b []byte) (int, error) {
}
func (c *NoiseSession) decryptPacket(data []byte) (int, []byte, error) {
- log.WithField("data_length", len(data)).Debug("Starting packet decryption")
+ log.WithField("data_length", len(data)).Debug("NoiseSession: Starting packet decryption")
if c.CipherState == nil {
- log.Error("Packet decryption: CipherState is nil")
- return 0, nil, errors.New("CipherState is nil")
+ log.Error("NoiseSession: decryptPacket - readState is nil")
+ return 0, nil, oops.Errorf("readState is nil")
}
- // Decrypt
- decryptedData, err := c.CipherState.Decrypt(nil, nil, data)
+
+ if len(data) < 2 {
+ log.Error("NoiseSession: decryptPacket - packet too short")
+ return 0, nil, oops.Errorf("packet too short")
+ }
+
+ // Extract payload length from prefix
+ payloadLen := binary.BigEndian.Uint16(data[:2])
+ if len(data[2:]) < int(payloadLen) {
+ log.Error("NoiseSession: decryptPacket - incomplete packet")
+ return 0, nil, oops.Errorf("incomplete packet")
+ }
+
+ // Decrypt payload
+ decryptedData, err := c.CipherState.Decrypt(nil, nil, data[2:2+payloadLen])
if err != nil {
- log.WithError(err).Error("Packet decryption: failed to decrypt data")
- return 0, nil, err
+ log.WithError(err).Error("NoiseSession: decryptPacket - failed to decrypt data")
+ return 0, nil, oops.Errorf("failed to decrypt: %w", err)
}
+
m := len(decryptedData)
- log.WithField("decrypted_length", m).Debug("Packet decryption: successfully decrypted data")
+ log.WithFields(logrus.Fields{
+ "encrypted_length": payloadLen,
+ "decrypted_length": m,
+ }).Debug("NoiseSession: decryptPacket - packet decrypted successfully")
+
return m, decryptedData, nil
- /*packet := c.InitializePacket()
- maxPayloadSize := c.maxPayloadSizeForRead(packet)
- if m > int(maxPayloadSize) {
- m = int(maxPayloadSize)
- }
- if c.CipherState != nil {
- ////fmt.Println("writing encrypted packet:", m)
- packet.reserve(uint16Size + uint16Size + m + macSize)
- packet.resize(uint16Size + uint16Size + m)
- copy(packet.data[uint16Size+uint16Size:], data[:m])
- binary.BigEndian.PutUint16(packet.data[uint16Size:], uint16(m))
- //fmt.Println("encrypt size", uint16(m))
- } else {
- packet.resize(len(packet.data) + len(data))
- copy(packet.data[uint16Size:len(packet.data)], data[:m])
- binary.BigEndian.PutUint16(packet.data, uint16(len(data)))
- }
- b := c.encryptIfNeeded(packet)*/
- //c.freeBlock(packet)
}
func (c *NoiseSession) readPacketLocked(data []byte) (int, error) {
log.WithField("data_length", len(data)).Debug("Starting readPacketLocked")
var n int
- if len(data) == 0 { // special case to answer when everything is ok during handshake
+ if len(data) == 0 { // Handle special case where data length is zero during handshake
log.Debug("readPacketLocked: special case - reading 2 bytes during handshake")
if _, err := c.Conn.Read(make([]byte, 2)); err != nil {
log.WithError(err).Error("readPacketLocked: failed to read 2 bytes during handshake")
@@ -96,26 +96,18 @@ func (c *NoiseSession) readPacketLocked(data []byte) (int, error) {
}
}
for len(data) > 0 {
- m, b, err := c.encryptPacket(data)
+ _, b, err := c.decryptPacket(data)
if err != nil {
log.WithError(err).Error("readPacketLocked: failed to encrypt packet")
return 0, err
}
- /*
- if n, err := c.Conn.Read(b); err != nil {
- return n, err
- } else {
- n += m
- data = data[m:]
- }
- */
- n, err := c.Conn.Read(b)
+ bytesRead, err := c.Conn.Read(b)
if err != nil {
- log.WithError(err).WithField("bytes_read (aka n)", n).Error("readPacketLocked: failed to read from connection")
- return n, err
+ log.WithError(err).WithField("bytes_read", bytesRead).Error("readPacketLocked: failed to read from connection")
+ return bytesRead, err
}
- n += m
- data = data[m:]
+ n += bytesRead
+ data = data[bytesRead:]
log.WithFields(logrus.Fields{
"bytes_read": n,
"remaining_data": len(data),
diff --git a/lib/transport/noise/session.go b/lib/transport/noise/session.go
index 990a70d..d7aac44 100644
--- a/lib/transport/noise/session.go
+++ b/lib/transport/noise/session.go
@@ -1,7 +1,6 @@
package noise
import (
- "fmt"
"net"
"sync"
"time"
@@ -10,17 +9,19 @@ import (
cb "github.com/emirpasic/gods/queues/circularbuffer"
"github.com/flynn/noise"
+ "github.com/samber/oops"
"github.com/go-i2p/go-i2p/lib/common/router_info"
"github.com/go-i2p/go-i2p/lib/transport"
+ "github.com/go-i2p/go-i2p/lib/transport/handshake"
)
type NoiseSession struct {
router_info.RouterInfo
*noise.CipherState
*sync.Cond
- *NoiseTransport // The parent transport, which "Dialed" the connection to the peer whith whom we established the session
- *HandshakeState
+ *NoiseTransport // The parent transport, which "Dialed" the connection to the peer with whom we established the session
+ handshake.HandshakeState
RecvQueue *cb.Queue
SendQueue *cb.Queue
VerifyCallback VerifyCallbackFunc
@@ -90,6 +91,33 @@ func (c *NoiseSession) processCallback(publicKey []byte, payload []byte) error {
return err
}
+// PeerStaticKey is equal to the NTCP2 peer's static public key, found in their router info
+func (s *NoiseSession) peerStaticKey() ([32]byte, error) {
+ for _, addr := range s.RouterInfo.RouterAddresses() {
+ transportStyle, err := addr.TransportStyle().Data()
+ if err != nil {
+ continue
+ }
+ if transportStyle == NOISE_PROTOCOL_NAME {
+ return addr.StaticKey()
+ }
+ }
+ return [32]byte{}, oops.Errorf("Remote static key error")
+}
+
+func (s *NoiseSession) peerStaticIV() ([16]byte, error) {
+ for _, addr := range s.RouterInfo.RouterAddresses() {
+ transportStyle, err := addr.TransportStyle().Data()
+ if err != nil {
+ continue
+ }
+ if transportStyle == NOISE_PROTOCOL_NAME {
+ return addr.InitializationVector()
+ }
+ }
+ return [16]byte{}, oops.Errorf("Remote static IV error")
+}
+
// newBlock allocates a new packet, from hc's free list if possible.
func newBlock() []byte {
// return make([]byte, MaxPayloadSize)
@@ -120,5 +148,13 @@ func NewNoiseTransportSession(ri router_info.RouterInfo) (transport.TransportSes
return session, nil
}
log.Error("Failed to create NoiseTransportSession, all addresses failed")
- return nil, fmt.Errorf("Transport constructor error")
+ return nil, oops.Errorf("Transport constructor error")
+}
+
+func NewNoiseSession(ri router_info.RouterInfo) (*NoiseSession, error) {
+ ns, err := NewNoiseTransportSession(ri)
+ if err != nil {
+ return nil, err
+ }
+ return ns.(*NoiseSession), err
}
diff --git a/lib/transport/noise/transport.go b/lib/transport/noise/transport.go
index cd07e88..7a9f1a5 100644
--- a/lib/transport/noise/transport.go
+++ b/lib/transport/noise/transport.go
@@ -7,30 +7,52 @@ package noise
**/
import (
- "errors"
"net"
"sync"
+ "github.com/flynn/noise"
+ "github.com/samber/oops"
"github.com/sirupsen/logrus"
"github.com/go-i2p/go-i2p/lib/common/data"
- "github.com/go-i2p/go-i2p/lib/common/router_identity"
"github.com/go-i2p/go-i2p/lib/common/router_info"
"github.com/go-i2p/go-i2p/lib/transport"
)
+const NOISE_PROTOCOL_NAME = "NOISE"
+
type NoiseTransport struct {
sync.Mutex
- router_identity.RouterIdentity
- Listener net.Listener
- peerConnections map[data.Hash]transport.TransportSession
+ router_info.RouterInfo
+ transportStyle string
+ Listener net.Listener
+ // peerConnections map[data.Hash]transport.TransportSession
+ peerConnections map[data.Hash]*NoiseSession
}
func (noopt *NoiseTransport) Compatible(routerInfo router_info.RouterInfo) bool {
- // TODO implement
- // panic("implement me")
- log.Warn("func (noopt *NoiseTransport) Compatible(routerInfo router_info.RouterInfo) is not implemented!")
- return true
+ // Check if we have an existing session with this router
+ _, ok := noopt.peerConnections[routerInfo.IdentHash()]
+ if ok {
+ return true
+ }
+
+ // Check router addresses for Noise protocol support
+ for _, addr := range routerInfo.RouterAddresses() {
+ transportStyle, err := addr.TransportStyle().Data()
+ if err != nil {
+ continue
+ }
+
+ // Check for Noise protocol support
+ if transportStyle == NOISE_PROTOCOL_NAME {
+ // A router is compatible if it has a static key
+ if addr.CheckOption("s") {
+ return true
+ }
+ }
+ }
+ return false
}
var exampleNoiseTransport transport.Transport = &NoiseTransport{}
@@ -71,15 +93,15 @@ func (noopt *NoiseTransport) Name() string {
// will bind if the underlying socket is not already
// if the underlying socket is already bound update the RouterIdentity
// returns any errors that happen if they do
-func (noopt *NoiseTransport) SetIdentity(ident router_identity.RouterIdentity) (err error) {
+func (noopt *NoiseTransport) SetIdentity(ident router_info.RouterInfo) (err error) {
log.WithField("identity", ident).Debug("NoiseTransport: Setting identity")
- noopt.RouterIdentity = ident
+ noopt.RouterInfo = ident
if noopt.Listener == nil {
log.WithFields(logrus.Fields{
"at": "(NoiseTransport) SetIdentity",
"reason": "network socket is null",
}).Error("network socket is null")
- err = errors.New("network socket is null")
+ err = oops.Errorf("network socket is null")
return
}
log.Debug("NoiseTransport: Identity set successfully")
@@ -95,7 +117,7 @@ func (noopt *NoiseTransport) GetSession(routerInfo router_info.RouterInfo) (tran
log.WithField("hash", hash).Debug("NoiseTransport: Getting session")
if len(hash) == 0 {
log.Error("NoiseTransport: RouterInfo has no IdentityHash")
- return nil, errors.New("NoiseTransport: GetSession: RouterInfo has no IdentityHash")
+ return nil, oops.Errorf("NoiseTransport: GetSession: RouterInfo has no IdentityHash")
}
if t, ok := noopt.peerConnections[hash]; ok {
log.Debug("NoiseTransport: Existing session found")
@@ -103,7 +125,7 @@ func (noopt *NoiseTransport) GetSession(routerInfo router_info.RouterInfo) (tran
}
log.Debug("NoiseTransport: Creating new session")
var err error
- if noopt.peerConnections[hash], err = NewNoiseTransportSession(routerInfo); err != nil {
+ if noopt.peerConnections[hash], err = NewNoiseSession(routerInfo); err != nil {
log.WithError(err).Error("NoiseTransport: Failed to create new session")
return noopt.peerConnections[hash], err
}
@@ -119,7 +141,7 @@ func (c *NoiseTransport) getSession(routerInfo router_info.RouterInfo) (transpor
return nil, err
}
for {
- if session.(*NoiseSession).handshakeComplete {
+ if session.(*NoiseSession).HandshakeComplete() {
log.Debug("NoiseTransport: Handshake complete")
return nil, nil
}
@@ -156,8 +178,9 @@ func (noopt *NoiseTransport) Close() error {
func NewNoiseTransport(netSocket net.Listener) *NoiseTransport {
log.WithField("listener_addr", netSocket.Addr().String()).Debug("Creating new NoiseTransport")
return &NoiseTransport{
- peerConnections: make(map[data.Hash]transport.TransportSession),
+ peerConnections: make(map[data.Hash]*NoiseSession),
Listener: netSocket,
+ transportStyle: NOISE_PROTOCOL_NAME,
}
}
@@ -175,3 +198,35 @@ func NewNoiseTransportSocket() (*NoiseTransport, error) {
log.WithField("addr", netSocket.Addr().String()).Debug("Created new NoiseTransportSocket")
return _transport, nil
}
+
+// LocalStaticKey is equal to the NTCP2 static public key, found in our router info
+func (s *NoiseTransport) localStaticKey() ([32]byte, error) {
+ // s.RouterIdentity
+ for _, addr := range s.RouterInfo.RouterAddresses() {
+ transportStyle, err := addr.TransportStyle().Data()
+ if err != nil {
+ continue
+ }
+ if transportStyle == s.transportStyle {
+ return addr.StaticKey()
+ }
+ }
+ return [32]byte{}, oops.Errorf("Remote static key error")
+}
+
+func (s *NoiseTransport) localStaticIV() ([16]byte, error) {
+ for _, addr := range s.RouterInfo.RouterAddresses() {
+ transportStyle, err := addr.TransportStyle().Data()
+ if err != nil {
+ continue
+ }
+ if transportStyle == s.transportStyle {
+ return addr.InitializationVector()
+ }
+ }
+ return [16]byte{}, oops.Errorf("Remote static IV error")
+}
+
+func (h *NoiseTransport) HandshakeKey() *noise.DHKey {
+ return nil
+}
diff --git a/lib/transport/noise/write_session.go b/lib/transport/noise/write_session.go
index 19c098a..0b4b6bf 100644
--- a/lib/transport/noise/write_session.go
+++ b/lib/transport/noise/write_session.go
@@ -2,10 +2,9 @@ package noise
import (
"encoding/binary"
- "errors"
- "fmt"
"sync/atomic"
+ "github.com/samber/oops"
"github.com/sirupsen/logrus"
)
@@ -19,7 +18,7 @@ func (c *NoiseSession) Write(b []byte) (int, error) {
"at": "(NoiseSession) Write",
"reason": "session is closed",
}).Error("session is closed")
- return 0, errors.New("session is closed")
+ return 0, oops.Errorf("session is closed")
}
if atomic.CompareAndSwapInt32(&c.activeCall, x, x+2) {
defer atomic.AddInt32(&c.activeCall, -2)
@@ -27,7 +26,7 @@ func (c *NoiseSession) Write(b []byte) (int, error) {
}
log.Debug("NoiseSession: Write - retrying atomic operation")
}
- if !c.handshakeComplete {
+ if !c.HandshakeComplete() {
log.Debug("NoiseSession: Write - handshake not complete, running outgoing handshake")
if err := c.RunOutgoingHandshake(); err != nil {
log.WithError(err).Error("NoiseSession: Write - failed to run outgoing handshake")
@@ -36,9 +35,9 @@ func (c *NoiseSession) Write(b []byte) (int, error) {
}
c.Mutex.Lock()
defer c.Mutex.Unlock()
- if !c.handshakeComplete {
+ if !c.HandshakeComplete() {
log.Error("NoiseSession: Write - internal error, handshake still not complete")
- return 0, errors.New("internal error")
+ return 0, oops.Errorf("internal error")
}
n, err := c.writePacketLocked(b)
if err != nil {
@@ -54,48 +53,33 @@ func (c *NoiseSession) encryptPacket(data []byte) (int, []byte, error) {
m := len(data)
if c.CipherState == nil {
- log.Error("NoiseSession: encryptPacket - CipherState is nil")
- return 0, nil, errors.New("CipherState is nil")
+ log.Error("NoiseSession: encryptPacket - writeState is nil")
+ return 0, nil, oops.Errorf("writeState is nil")
}
+ // Create length prefix first
+ lengthPrefix := make([]byte, 2)
+ binary.BigEndian.PutUint16(lengthPrefix, uint16(m))
+
// Encrypt the data
encryptedData, err := c.CipherState.Encrypt(nil, nil, data)
if err != nil {
log.WithError(err).Error("NoiseSession: encryptPacket - failed to encrypt data")
- return 0, nil, fmt.Errorf("failed to encrypt: '%w'", err)
+ return 0, nil, oops.Errorf("failed to encrypt: %w", err)
}
- // m := len(encryptedData)
- lengthPrefix := make([]byte, 2)
- binary.BigEndian.PutUint16(lengthPrefix, uint16(len(encryptedData)))
+ // Combine length prefix and encrypted data
+ packet := make([]byte, 0, len(lengthPrefix)+len(encryptedData))
+ packet = append(packet, lengthPrefix...)
+ packet = append(packet, encryptedData...)
- // Append encr data to prefix
- packet := append(lengthPrefix, encryptedData...)
log.WithFields(logrus.Fields{
"original_length": m,
"encrypted_length": len(encryptedData),
"packet_length": len(packet),
}).Debug("NoiseSession: encryptPacket - packet encrypted successfully")
+
return m, packet, nil
- /*packet := c.InitializePacket()
- maxPayloadSize := c.maxPayloadSizeForWrite(packet)
- if m > int(maxPayloadSize) {
- m = int(maxPayloadSize)
- }
- if c.CipherState != nil {
- ////fmt.Println("writing encrypted packet:", m)
- packet.reserve(uint16Size + uint16Size + m + macSize)
- packet.resize(uint16Size + uint16Size + m)
- copy(packet.data[uint16Size+uint16Size:], data[:m])
- binary.BigEndian.PutUint16(packet.data[uint16Size:], uint16(m))
- //fmt.Println("encrypt size", uint16(m))
- } else {
- packet.resize(len(packet.data) + len(data))
- copy(packet.data[uint16Size:len(packet.data)], data[:m])
- binary.BigEndian.PutUint16(packet.data, uint16(len(data)))
- }
- b := c.encryptIfNeeded(packet)*/
- //c.freeBlock(packet)
}
func (c *NoiseSession) writePacketLocked(data []byte) (int, error) {
diff --git a/lib/transport/ntcp/README.md b/lib/transport/ntcp/README.md
new file mode 100644
index 0000000..506b290
--- /dev/null
+++ b/lib/transport/ntcp/README.md
@@ -0,0 +1,170 @@
+# ntcp
+--
+ import "github.com/go-i2p/go-i2p/lib/transport/ntcp"
+
+
+
+
+
+## Usage
+
+```go
+const (
+ NOISE_DH_CURVE25519 = 1
+
+ NOISE_CIPHER_CHACHAPOLY = 1
+ NOISE_CIPHER_AESGCM = 2
+
+ NOISE_HASH_SHA256 = 3
+
+ NOISE_PATTERN_XK = 11
+
+ MaxPayloadSize = math.MaxUint16 - 16 - uint16Size /*data len*/
+)
+```
+
+```go
+const (
+ NTCP_PROTOCOL_VERSION = 2
+ NTCP_PROTOCOL_NAME = "NTCP2"
+ NTCP_MESSAGE_MAX_SIZE = 65537
+)
+```
+
+#### type NTCP2Session
+
+```go
+type NTCP2Session struct {
+ *noise.NoiseSession
+ *NTCP2Transport
+}
+```
+
+NTCP2Session extends the base noise.NoiseSession with NTCP2-specific
+functionality
+
+#### func NewNTCP2Session
+
+```go
+func NewNTCP2Session(noiseConfig router_info.RouterInfo) (*NTCP2Session, error)
+```
+NewNTCP2Session creates a new NTCP2 session using the existing noise
+implementation
+
+#### func (*NTCP2Session) ComposeInitiatorHandshakeMessage
+
+```go
+func (c *NTCP2Session) ComposeInitiatorHandshakeMessage(
+ localStatic noise.DHKey,
+ remoteStatic []byte,
+ payload []byte,
+ ephemeralPrivate []byte,
+) (
+ negotiationData,
+ handshakeMessage []byte,
+ handshakeState *noise.HandshakeState,
+ err error,
+)
+```
+Modify ComposeInitiatorHandshakeMessage in outgoing_handshake.go At the moment,
+remoteStatic is stored in the NTCP2Session() and doesn't need to be passed as an
+argument. You actually get it directly out of the remote RouterInfo, which the
+NoiseSession also has access to. So maybe, the interface should change so that
+we:
+
+ - A: get the localStatic out of the parent NTCP2Transport's routerInfo, which is the "local" routerInfo
+ - B: get the remoteStatic out of the NTCP2Session router, which is the "remote" routerInfo
+
+#### func (*NTCP2Session) CreateSessionRequest
+
+```go
+func (s *NTCP2Session) CreateSessionRequest() (*SessionRequest, error)
+```
+
+#### func (*NTCP2Session) DeobfuscateEphemeral
+
+```go
+func (s *NTCP2Session) DeobfuscateEphemeral(obfuscatedEphemeralKey []byte) ([]byte, error)
+```
+DeobfuscateEphemeral reverses the key obfuscation
+
+#### func (*NTCP2Session) ObfuscateEphemeral
+
+```go
+func (s *NTCP2Session) ObfuscateEphemeral(ephemeralKey []byte) ([]byte, error)
+```
+ObfuscateEphemeral implements NTCP2's key obfuscation using AES-256-CBC
+
+#### type NTCP2Transport
+
+```go
+type NTCP2Transport struct {
+ *noise.NoiseTransport
+ *sntp.RouterTimestamper
+}
+```
+
+NTCP2Transport is an ntcp2 transport implementing transport.NTCP2Transport
+interface
+
+#### func NewNTCP2Transport
+
+```go
+func NewNTCP2Transport(routerInfo *router_info.RouterInfo) (*NTCP2Transport, error)
+```
+
+#### func (*NTCP2Transport) Accept
+
+```go
+func (t *NTCP2Transport) Accept() (net.Conn, error)
+```
+
+#### func (*NTCP2Transport) Address
+
+```go
+func (t *NTCP2Transport) Address() (*router_address.RouterAddress, error)
+```
+
+#### func (*NTCP2Transport) Compatible
+
+```go
+func (t *NTCP2Transport) Compatible(routerInfo router_info.RouterInfo) bool
+```
+
+#### func (*NTCP2Transport) GetSession
+
+```go
+func (t *NTCP2Transport) GetSession(routerInfo router_info.RouterInfo) (transport.TransportSession, error)
+```
+
+#### func (*NTCP2Transport) Name
+
+```go
+func (t *NTCP2Transport) Name() string
+```
+
+#### type PaddingStrategy
+
+```go
+type PaddingStrategy interface {
+ AddPadding(message []byte) []byte
+ RemovePadding(message []byte) []byte
+}
+```
+
+
+#### type SessionRequest
+
+```go
+type SessionRequest struct {
+ ObfuscatedKey []byte // 32 bytes
+ Timestamp uint32 // 4 bytes
+ Padding []byte // Random padding
+}
+```
+
+
+
+ntcp
+
+github.com/go-i2p/go-i2p/lib/transport/ntcp
diff --git a/lib/transport/ntcp/address.go b/lib/transport/ntcp/address.go
new file mode 100644
index 0000000..d3f56db
--- /dev/null
+++ b/lib/transport/ntcp/address.go
@@ -0,0 +1,23 @@
+package ntcp
+
+import (
+ "time"
+
+ "github.com/go-i2p/go-i2p/lib/common/router_address"
+
+ "github.com/samber/oops"
+)
+
+func (t *NTCP2Transport) Address() (*router_address.RouterAddress, error) {
+ // Construct a complete NTCP2 address for the transport:
+ timeStamp := t.GetCurrentTime().Add(10 * time.Minute)
+ // 2. Initialize an empty options map.
+ options := make(map[string]string)
+ // 3. Create a new RouterAddress with the provided parameters.
+ addr, err := router_address.NewRouterAddress(8, timeStamp, t.Name(), options)
+ if err != nil {
+ return nil, oops.Errorf("failed to create RouterAddress: %w", err)
+ }
+ // 4. Return the created address or an error if the creation fails.
+ return addr, nil
+}
diff --git a/lib/transport/ntcp/constants.go b/lib/transport/ntcp/constants.go
index 2086a8a..ae050c3 100644
--- a/lib/transport/ntcp/constants.go
+++ b/lib/transport/ntcp/constants.go
@@ -1,6 +1,7 @@
package ntcp
import (
+ "encoding/binary"
"math"
"github.com/flynn/noise"
@@ -32,3 +33,15 @@ var hashes = map[byte]noise.HashFunc{
var patterns = map[byte]noise.HandshakePattern{
NOISE_PATTERN_XK: noise.HandshakeXK,
}
+
+func initNegotiationData(negotiationData []byte) []byte {
+ if negotiationData != nil {
+ return negotiationData
+ }
+ negotiationData = make([]byte, 6)
+ binary.BigEndian.PutUint16(negotiationData, 1) // version
+ negotiationData[2] = NOISE_DH_CURVE25519
+ negotiationData[3] = NOISE_CIPHER_CHACHAPOLY
+ negotiationData[4] = NOISE_HASH_SHA256
+ return negotiationData
+}
diff --git a/lib/transport/ntcp/doc.md b/lib/transport/ntcp/doc.md
deleted file mode 100644
index 0d6fcc3..0000000
--- a/lib/transport/ntcp/doc.md
+++ /dev/null
@@ -1,30 +0,0 @@
-# ntcp
---
- import "github.com/go-i2p/go-i2p/lib/transport/ntcp"
-
-
-## Usage
-
-```go
-const (
- NTCP_PROTOCOL_VERSION = 2
- NTCP_PROTOCOL_NAME = "NTCP2"
- NTCP_MESSAGE_MAX_SIZE = 65537
-)
-```
-
-#### type Session
-
-```go
-type Session struct{}
-```
-
-Session implements TransportSession An established transport session
-
-#### type Transport
-
-```go
-type Transport struct{}
-```
-
-Transport is an ntcp transport implementing transport.Transport interface
diff --git a/lib/transport/ntcp/new.go b/lib/transport/ntcp/new.go
new file mode 100644
index 0000000..199a635
--- /dev/null
+++ b/lib/transport/ntcp/new.go
@@ -0,0 +1,20 @@
+package ntcp
+
+import (
+ "github.com/go-i2p/go-i2p/lib/common/router_info"
+ "github.com/go-i2p/go-i2p/lib/transport/noise"
+ "github.com/go-i2p/go-i2p/lib/util/time/sntp"
+)
+
+func NewNTCP2Transport(routerInfo *router_info.RouterInfo) (*NTCP2Transport, error) {
+ defaultClient := &sntp.DefaultNTPClient{}
+ timestamper := sntp.NewRouterTimestamper(defaultClient)
+ n := &NTCP2Transport{
+ NoiseTransport: &noise.NoiseTransport{
+ RouterInfo: *routerInfo,
+ },
+ RouterTimestamper: timestamper,
+ transportStyle: NTCP_PROTOCOL_NAME,
+ }
+ return n, nil
+}
diff --git a/lib/transport/ntcp/ntcp.svg b/lib/transport/ntcp/ntcp.svg
new file mode 100644
index 0000000..5777fb8
--- /dev/null
+++ b/lib/transport/ntcp/ntcp.svg
@@ -0,0 +1,857 @@
+
+
+
+
+
diff --git a/lib/transport/ntcp/outgoing_handshake.go b/lib/transport/ntcp/outgoing_handshake.go
new file mode 100644
index 0000000..a22aaaf
--- /dev/null
+++ b/lib/transport/ntcp/outgoing_handshake.go
@@ -0,0 +1,71 @@
+package ntcp
+
+import (
+ "bytes"
+ "crypto/rand"
+ "encoding/binary"
+
+ "github.com/flynn/noise"
+ "github.com/go-i2p/logger"
+)
+
+var log = logger.GetGoI2PLogger()
+
+// Modify ComposeInitiatorHandshakeMessage in outgoing_handshake.go
+// At the moment, remoteStatic is stored in the NTCP2Session() and doesn't need to be passed as an argument.
+// You actually get it directly out of the remote RouterInfo, which the NoiseSession also has access to.
+// So maybe, the interface should change so that we:
+// - A: get the localStatic out of the parent NTCP2Transport's routerInfo, which is the "local" routerInfo
+// - B: get the remoteStatic out of the NTCP2Session router, which is the "remote" routerInfo
+func (c *NTCP2Session) ComposeInitiatorHandshakeMessage(
+ localStatic noise.DHKey,
+ remoteStatic []byte,
+ payload []byte,
+ ephemeralPrivate []byte,
+) (
+ negotiationData,
+ handshakeMessage []byte,
+ handshakeState *noise.HandshakeState,
+ err error,
+) {
+ // Create session request
+ request, err := c.CreateSessionRequest()
+ if err != nil {
+ return nil, nil, nil, err
+ }
+
+ // Buffer for the complete message
+ buf := new(bytes.Buffer)
+
+ // Write obfuscated key
+ buf.Write(request.ObfuscatedKey)
+
+ // Write timestamp
+ binary.BigEndian.PutUint32(buf.Next(4), request.Timestamp)
+
+ // Initialize Noise
+ config := noise.Config{
+ CipherSuite: noise.NewCipherSuite(noise.DH25519, noise.CipherChaChaPoly, noise.HashSHA256),
+ Pattern: noise.HandshakeXK,
+ Initiator: true,
+ StaticKeypair: localStatic,
+ Random: rand.Reader,
+ }
+
+ handshakeState, err = noise.NewHandshakeState(config)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+
+ // Create Noise message
+ handshakeMessage, _, _, err = handshakeState.WriteMessage(nil, buf.Bytes())
+ if err != nil {
+ return nil, nil, nil, err
+ }
+
+ // Add padding
+ handshakeMessage = append(handshakeMessage, request.Padding...)
+
+ // Ensure entire message is written at once
+ return nil, handshakeMessage, handshakeState, nil
+}
diff --git a/lib/transport/ntcp/session.go b/lib/transport/ntcp/session.go
index 13e3437..49841d8 100644
--- a/lib/transport/ntcp/session.go
+++ b/lib/transport/ntcp/session.go
@@ -1,12 +1,17 @@
package ntcp
import (
- "crypto/aes"
- "crypto/cipher"
- "fmt"
+ "crypto/rand"
+ "math/big"
+ "time"
"github.com/go-i2p/go-i2p/lib/common/router_info"
+ "github.com/go-i2p/go-i2p/lib/crypto"
"github.com/go-i2p/go-i2p/lib/transport/noise"
+ "github.com/go-i2p/go-i2p/lib/transport/obfs"
+ "github.com/go-i2p/go-i2p/lib/transport/padding"
+
+ "github.com/samber/oops"
)
/*
@@ -28,7 +33,47 @@ import (
// NTCP2Session extends the base noise.NoiseSession with NTCP2-specific functionality
type NTCP2Session struct {
*noise.NoiseSession
- paddingStrategy PaddingStrategy
+ *NTCP2Transport
+ paddingStrategy padding.PaddingStrategy
+}
+
+type SessionRequest struct {
+ ObfuscatedKey []byte // 32 bytes
+ Timestamp uint32 // 4 bytes
+ Padding []byte // Random padding
+}
+
+func (s *NTCP2Session) CreateSessionRequest() (*SessionRequest, error) {
+ // Get our ephemeral key pair
+ ephemeralKey := make([]byte, 32)
+ if _, err := rand.Read(ephemeralKey); err != nil {
+ return nil, err
+ }
+
+ // Obfuscate the ephemeral key using Bob's static key
+ obfuscatedKey, err := s.ObfuscateEphemeral(ephemeralKey)
+ if err != nil {
+ return nil, err
+ }
+
+ // Create timestamp (current time in seconds)
+ timestamp := uint32(time.Now().Unix())
+
+ // Add random padding (implementation specific)
+ randomInt, err := rand.Int(rand.Reader, big.NewInt(16))
+ if err != nil {
+ return nil, err
+ }
+ padding := make([]byte, randomInt.Int64()) // Up to 16 bytes of padding
+ if _, err := rand.Read(padding); err != nil {
+ return nil, err
+ }
+
+ return &SessionRequest{
+ ObfuscatedKey: obfuscatedKey,
+ Timestamp: timestamp,
+ Padding: padding,
+ }, nil
}
// NewNTCP2Session creates a new NTCP2 session using the existing noise implementation
@@ -39,15 +84,11 @@ func NewNTCP2Session(noiseConfig router_info.RouterInfo) (*NTCP2Session, error)
}
return &NTCP2Session{
- NoiseSession: baseNoiseSession.(*noise.NoiseSession),
+ NoiseSession: baseNoiseSession.(*noise.NoiseSession),
+ paddingStrategy: &padding.NullPaddingStrategy{},
}, nil
}
-type PaddingStrategy interface {
- AddPadding(message []byte) []byte
- RemovePadding(message []byte) []byte
-}
-
// PeerStaticKey is equal to the NTCP2 peer's static public key, found in their router info
func (s *NTCP2Session) peerStaticKey() ([32]byte, error) {
for _, addr := range s.RouterInfo.RouterAddresses() {
@@ -59,43 +100,53 @@ func (s *NTCP2Session) peerStaticKey() ([32]byte, error) {
return addr.StaticKey()
}
}
- return [32]byte{}, fmt.Errorf("Remote static key error")
+ return [32]byte{}, oops.Errorf("Remote static key error")
+}
+
+func (s *NTCP2Session) peerStaticIV() ([16]byte, error) {
+ for _, addr := range s.RouterInfo.RouterAddresses() {
+ transportStyle, err := addr.TransportStyle().Data()
+ if err != nil {
+ continue
+ }
+ if transportStyle == NTCP_PROTOCOL_NAME {
+ return addr.InitializationVector()
+ }
+ }
+ return [16]byte{}, oops.Errorf("Remote static IV error")
}
// ObfuscateEphemeral implements NTCP2's key obfuscation using AES-256-CBC
-func (s *NTCP2Session) ObfuscateEphemeral(key []byte) ([]byte, error) {
- static, err := s.peerStaticKey()
- if err != nil {
- return nil, err
- }
- block, err := aes.NewCipher(static[:])
+func (s *NTCP2Session) ObfuscateEphemeral(ephemeralKey []byte) ([]byte, error) {
+ AESStaticKey, err := s.buildAesStaticKey()
if err != nil {
return nil, err
}
- obfuscated := make([]byte, len(key))
- iv := make([]byte, aes.BlockSize)
- mode := cipher.NewCBCEncrypter(block, iv)
- mode.CryptBlocks(obfuscated, key)
-
- return obfuscated, nil
+ return obfs.ObfuscateEphemeralKey(ephemeralKey, AESStaticKey)
}
// DeobfuscateEphemeral reverses the key obfuscation
-func (s *NTCP2Session) DeobfuscateEphemeral(obfuscated []byte) ([]byte, error) {
- static, err := s.peerStaticKey()
- if err != nil {
- return nil, err
- }
- block, err := aes.NewCipher(static[:])
+func (s *NTCP2Session) DeobfuscateEphemeral(obfuscatedEphemeralKey []byte) ([]byte, error) {
+ AESStaticKey, err := s.buildAesStaticKey()
if err != nil {
return nil, err
}
- key := make([]byte, len(obfuscated))
- iv := make([]byte, aes.BlockSize)
- mode := cipher.NewCBCDecrypter(block, iv)
- mode.CryptBlocks(key, obfuscated)
-
- return key, nil
+ return obfs.DeobfuscateEphemeralKey(obfuscatedEphemeralKey, AESStaticKey)
+}
+
+func (s *NTCP2Session) buildAesStaticKey() (*crypto.AESSymmetricKey, error) {
+ staticKey, err := s.peerStaticKey()
+ if err != nil {
+ return nil, err
+ }
+ staticIV, err := s.peerStaticIV()
+ if err != nil {
+ return nil, err
+ }
+ var AESStaticKey crypto.AESSymmetricKey
+ AESStaticKey.Key = staticKey[:]
+ AESStaticKey.IV = staticIV[:]
+ return &AESStaticKey, nil
}
diff --git a/lib/transport/ntcp/session_request.go b/lib/transport/ntcp/session_request.go
new file mode 100644
index 0000000..7f4098a
--- /dev/null
+++ b/lib/transport/ntcp/session_request.go
@@ -0,0 +1,18 @@
+package ntcp
+
+// SessionRequestMessage represents Message 1 of the NTCP2 handshake
+type SessionRequestMessage struct {
+ ObfuscatedKey []byte // 32 bytes ephemeral key X
+ Timestamp uint32 // Current time
+ Options [16]byte // Options block
+ Padding []byte // Random padding
+}
+
+// SessionRequestBuilder handles creation of NTCP2 Message 1
+type SessionRequestBuilder interface {
+ // CreateSessionRequest builds Message 1 of handshake
+ CreateSessionRequest() (*SessionRequestMessage, error)
+
+ // ObfuscateEphemeral obfuscates ephemeral key using AES
+ ObfuscateEphemeral(key []byte) ([]byte, error)
+}
diff --git a/lib/transport/ntcp/transport.go b/lib/transport/ntcp/transport.go
index e4641f3..5fae2b4 100644
--- a/lib/transport/ntcp/transport.go
+++ b/lib/transport/ntcp/transport.go
@@ -5,12 +5,14 @@ package ntcp
**/
import (
- "fmt"
"net"
"github.com/go-i2p/go-i2p/lib/common/router_info"
"github.com/go-i2p/go-i2p/lib/transport"
"github.com/go-i2p/go-i2p/lib/transport/noise"
+ "github.com/go-i2p/go-i2p/lib/util/time/sntp"
+
+ "github.com/samber/oops"
)
const (
@@ -19,18 +21,20 @@ const (
NTCP_MESSAGE_MAX_SIZE = 65537
)
-var exampleNTCPTransport transport.Transport = &Transport{}
+var exampleNTCPTransport transport.Transport = &NTCP2Transport{}
-// Transport is an ntcp2 transport implementing transport.Transport interface
-type Transport struct {
+// NTCP2Transport is an ntcp2 transport implementing transport.NTCP2Transport interface
+type NTCP2Transport struct {
*noise.NoiseTransport
+ *sntp.RouterTimestamper
+ transportStyle string
}
-func (t *Transport) Name() string {
+func (t *NTCP2Transport) Name() string {
return NTCP_PROTOCOL_NAME
}
-func (t *Transport) Compatible(routerInfo router_info.RouterInfo) bool {
+func (t *NTCP2Transport) Compatible(routerInfo router_info.RouterInfo) bool {
// Check if the router info contains NTCP2 address and capabilities
addresses := routerInfo.RouterAddresses()
for _, addr := range addresses {
@@ -39,13 +43,16 @@ func (t *Transport) Compatible(routerInfo router_info.RouterInfo) bool {
continue
}
if transportStyle == NTCP_PROTOCOL_NAME {
- return true
+ // Verify required NTCP2 options exist
+ if addr.CheckOption("s") && addr.CheckOption("i") && addr.CheckOption("v") {
+ return true
+ }
}
}
return false
}
-func (t *Transport) GetSession(routerInfo router_info.RouterInfo) (transport.TransportSession, error) {
+func (t *NTCP2Transport) GetSession(routerInfo router_info.RouterInfo) (transport.TransportSession, error) {
// Create new NTCP2 session
session, err := NewNTCP2Session(routerInfo)
if err != nil {
@@ -53,14 +60,14 @@ func (t *Transport) GetSession(routerInfo router_info.RouterInfo) (transport.Tra
}
// Perform handshake
- if err := session.Handshake(routerInfo); err != nil {
+ if err := session.NTCP2Transport.Handshake(routerInfo); err != nil {
return nil, err
}
return session, nil
}
-func (t *Transport) Accept() (net.Conn, error) {
+func (t *NTCP2Transport) Accept() (net.Conn, error) {
conn, err := t.NoiseTransport.Accept()
if err != nil {
return nil, err
@@ -71,11 +78,11 @@ func (t *Transport) Accept() (net.Conn, error) {
// then check if it's a router address
routerAddr, ok := remoteAddr.(*router_info.RouterInfo)
if !ok {
- return nil, fmt.Errorf("remote address is not a router address")
+ return nil, oops.Errorf("remote address is not a router address")
}
// then check if it's compatible
if !t.Compatible(*routerAddr) {
- return nil, fmt.Errorf("remote router address is not compatible with NTCP2")
+ return nil, oops.Errorf("remote router address is not compatible with NTCP2")
}
// Wrap connection with NTCP2 session
session, err := NewNTCP2Session(remoteAddr.(router_info.RouterInfo)) // nil for incoming connections
@@ -86,3 +93,31 @@ func (t *Transport) Accept() (net.Conn, error) {
return session, nil
}
+
+// LocalStaticKey is equal to the NTCP2 static public key, found in our router info
+func (s *NTCP2Transport) localStaticKey() ([32]byte, error) {
+ // s.RouterIdentity
+ for _, addr := range s.RouterInfo.RouterAddresses() {
+ transportStyle, err := addr.TransportStyle().Data()
+ if err != nil {
+ continue
+ }
+ if transportStyle == NTCP_PROTOCOL_NAME {
+ return addr.StaticKey()
+ }
+ }
+ return [32]byte{}, oops.Errorf("Remote static key error")
+}
+
+func (s *NTCP2Transport) localStaticIV() ([16]byte, error) {
+ for _, addr := range s.RouterInfo.RouterAddresses() {
+ transportStyle, err := addr.TransportStyle().Data()
+ if err != nil {
+ continue
+ }
+ if transportStyle == NTCP_PROTOCOL_NAME {
+ return addr.InitializationVector()
+ }
+ }
+ return [16]byte{}, oops.Errorf("Remote static IV error")
+}
diff --git a/lib/transport/obfs/README.md b/lib/transport/obfs/README.md
new file mode 100644
index 0000000..79cf342
--- /dev/null
+++ b/lib/transport/obfs/README.md
@@ -0,0 +1,31 @@
+# obfs
+--
+ import "github.com/go-i2p/go-i2p/lib/transport/obfs"
+
+
+
+
+
+## Usage
+
+#### func DeobfuscateEphemeralKey
+
+```go
+func DeobfuscateEphemeralKey(message []byte, aesKey *crypto.AESSymmetricKey) ([]byte, error)
+```
+DeobfuscateEphemeralKey decrypts the ephemeral public key in the message using
+AES-256-CBC without padding
+
+#### func ObfuscateEphemeralKey
+
+```go
+func ObfuscateEphemeralKey(message []byte, aesKey *crypto.AESSymmetricKey) ([]byte, error)
+```
+ObfuscateEphemeralKey encrypts the ephemeral public key in the message using
+AES-256-CBC without padding
+
+
+
+obfs
+
+github.com/go-i2p/go-i2p/lib/transport/obfs
diff --git a/lib/transport/obfs/obfs.go b/lib/transport/obfs/obfs.go
index acf3b98..892dd92 100644
--- a/lib/transport/obfs/obfs.go
+++ b/lib/transport/obfs/obfs.go
@@ -1,15 +1,14 @@
package obfs
import (
- "fmt"
-
"github.com/go-i2p/go-i2p/lib/crypto"
+ "github.com/samber/oops"
)
// ObfuscateEphemeralKey encrypts the ephemeral public key in the message using AES-256-CBC without padding
func ObfuscateEphemeralKey(message []byte, aesKey *crypto.AESSymmetricKey) ([]byte, error) {
if len(message) < 32 {
- return nil, fmt.Errorf("message is too short to contain ephemeral public key")
+ return nil, oops.Errorf("message is too short to contain ephemeral public key")
}
// Extract the ephemeral public key (first 32 bytes)
@@ -36,7 +35,7 @@ func ObfuscateEphemeralKey(message []byte, aesKey *crypto.AESSymmetricKey) ([]by
// DeobfuscateEphemeralKey decrypts the ephemeral public key in the message using AES-256-CBC without padding
func DeobfuscateEphemeralKey(message []byte, aesKey *crypto.AESSymmetricKey) ([]byte, error) {
if len(message) < 32 {
- return nil, fmt.Errorf("message is too short to contain ephemeral public key")
+ return nil, oops.Errorf("message is too short to contain ephemeral public key")
}
// Extract the encrypted ephemeral public key (first 32 bytes)
diff --git a/lib/transport/obfs/obfs.svg b/lib/transport/obfs/obfs.svg
new file mode 100644
index 0000000..002d4c8
--- /dev/null
+++ b/lib/transport/obfs/obfs.svg
@@ -0,0 +1,118 @@
+
+
+
+
+
diff --git a/lib/transport/padding/padding.go b/lib/transport/padding/padding.go
new file mode 100644
index 0000000..80a1e95
--- /dev/null
+++ b/lib/transport/padding/padding.go
@@ -0,0 +1,16 @@
+package padding
+
+type PaddingStrategy interface {
+ AddPadding(message []byte) []byte
+ RemovePadding(message []byte) []byte
+}
+
+type NullPaddingStrategy struct{}
+
+func (p *NullPaddingStrategy) AddPadding(message []byte) []byte {
+ return message
+}
+
+func (p *NullPaddingStrategy) RemovePadding(message []byte) []byte {
+ return message
+}
diff --git a/lib/transport/ssu/doc.md b/lib/transport/ssu/README.md
similarity index 60%
rename from lib/transport/ssu/doc.md
rename to lib/transport/ssu/README.md
index 0200ebb..924eec9 100644
--- a/lib/transport/ssu/doc.md
+++ b/lib/transport/ssu/README.md
@@ -2,6 +2,14 @@
--
import "github.com/go-i2p/go-i2p/lib/transport/ssu"
+
+
i2p ssu transport implementation
## Usage
+
+
+
+ssu
+
+github.com/go-i2p/go-i2p/lib/transport/ssu
diff --git a/lib/transport/ssu/ssu.svg b/lib/transport/ssu/ssu.svg
new file mode 100644
index 0000000..947c327
--- /dev/null
+++ b/lib/transport/ssu/ssu.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
diff --git a/lib/transport/transport.go b/lib/transport/transport.go
index e84762d..f3f7002 100644
--- a/lib/transport/transport.go
+++ b/lib/transport/transport.go
@@ -3,7 +3,6 @@ package transport
import (
"net"
- "github.com/go-i2p/go-i2p/lib/common/router_identity"
"github.com/go-i2p/go-i2p/lib/common/router_info"
"github.com/go-i2p/go-i2p/lib/i2np"
@@ -37,7 +36,7 @@ type Transport interface {
// will bind if the underlying socket is not already
// if the underlying socket is already bound update the RouterIdentity
// returns any errors that happen if they do
- SetIdentity(ident router_identity.RouterIdentity) error
+ SetIdentity(ident router_info.RouterInfo) error
// Obtain a transport session with a router given its RouterInfo.
// If a session with this router is NOT already made attempt to create one and block until made or until an error happens
diff --git a/lib/transport/transport.svg b/lib/transport/transport.svg
new file mode 100644
index 0000000..057b0f6
--- /dev/null
+++ b/lib/transport/transport.svg
@@ -0,0 +1,400 @@
+
+
+
+
+
diff --git a/lib/tunnel/doc.md b/lib/tunnel/README.md
similarity index 98%
rename from lib/tunnel/doc.md
rename to lib/tunnel/README.md
index a993ddc..4df6569 100644
--- a/lib/tunnel/doc.md
+++ b/lib/tunnel/README.md
@@ -2,6 +2,8 @@
--
import "github.com/go-i2p/go-i2p/lib/tunnel"
+
+
i2p garlic tunnel implementation
## Usage
@@ -257,3 +259,9 @@ a pool of tunnels which we have created
```go
type TunnelID uint32
```
+
+
+
+tunnel
+
+github.com/go-i2p/go-i2p/lib/tunnel
diff --git a/lib/tunnel/delivery.go b/lib/tunnel/delivery.go
index 498c39e..8334850 100644
--- a/lib/tunnel/delivery.go
+++ b/lib/tunnel/delivery.go
@@ -2,10 +2,10 @@ package tunnel
import (
"encoding/binary"
- "errors"
common "github.com/go-i2p/go-i2p/lib/common/data"
- "github.com/go-i2p/go-i2p/lib/util/logger"
+ "github.com/go-i2p/logger"
+ "github.com/samber/oops"
"github.com/sirupsen/logrus"
)
@@ -180,7 +180,7 @@ func (delivery_instructions DeliveryInstructions) Type() (int, error) {
return FIRST_FRAGMENT, nil
}
log.Error("DeliveryInstructions contains no data")
- return 0, errors.New("DeliveryInstructions contains no data")
+ return 0, oops.Errorf("DeliveryInstructions contains no data")
}
// Read the integer stored in the 6-1 bits of a FOLLOW_ON_FRAGMENT's flag, indicating
@@ -212,7 +212,7 @@ func (delivery_instructions DeliveryInstructions) FragmentNumber() (int, error)
return fragNum, nil
}
log.Error("Fragment Number only exists on FOLLOW_ON_FRAGMENT Delivery Instructions")
- return 0, errors.New("Fragment Number only exists on FOLLOW_ON_FRAGMENT Delivery Instructions")
+ return 0, oops.Errorf("Fragment Number only exists on FOLLOW_ON_FRAGMENT Delivery Instructions")
}
// Read the value of the 0 bit of a FOLLOW_ON_FRAGMENT, which is set to 1 to indicate the
@@ -246,7 +246,7 @@ func (delivery_instructions DeliveryInstructions) LastFollowOnFragment() (bool,
return isLast, nil
}
log.Error("Last Fragment only exists for FOLLOW_ON_FRAGMENT Delivery Instructions")
- return false, errors.New("Last Fragment only exists for FOLLOW_ON_FRAGMENT Delivery Instructions")
+ return false, oops.Errorf("Last Fragment only exists for FOLLOW_ON_FRAGMENT Delivery Instructions")
}
// Return the delivery type for these DeliveryInstructions, can be of type
@@ -270,7 +270,7 @@ func (delivery_instructions DeliveryInstructions) DeliveryType() (byte, error) {
return deliveryType, nil
}
log.Error("DeliveryInstructions contains no data")
- return 0, errors.New("DeliveryInstructions contains no data")
+ return 0, oops.Errorf("DeliveryInstructions contains no data")
}
// Check if the delay bit is set. This feature in unimplemented in the Java router.
@@ -304,7 +304,7 @@ func (delivery_instructions DeliveryInstructions) HasDelay() (bool, error) {
return delay, nil
}
log.Error("DeliveryInstructions contains no data")
- return false, errors.New("DeliveryInstructions contains no data")
+ return false, oops.Errorf("DeliveryInstructions contains no data")
}
// Returns true if the Delivery Instructions are fragmented or false
@@ -333,7 +333,7 @@ func (delivery_instructions DeliveryInstructions) Fragmented() (bool, error) {
// return ((delivery_instructions[0] & 0x08) == 0x08), nil
}
log.Error("DeliveryInstructions contains no data")
- return false, errors.New("DeliveryInstructions contains no data")
+ return false, oops.Errorf("DeliveryInstructions contains no data")
}
// Check if the extended options bit is set. This feature in unimplemented in the Java router.
@@ -368,7 +368,7 @@ func (delivery_instructions DeliveryInstructions) HasExtendedOptions() (bool, er
return extended_options, nil
}
log.Error("DeliveryInstructions contains no data")
- return false, errors.New("DeliveryInstructions contains no data")
+ return false, oops.Errorf("DeliveryInstructions contains no data")
}
// Check if the DeliveryInstructions is of type DT_TUNNEL.
@@ -399,7 +399,7 @@ func (delivery_instructions DeliveryInstructions) HasHash() (bool, error) {
}
if len(delivery_instructions) < min_size {
log.Error("Delivery Instructions indicates hash present but has too little data")
- return false, errors.New("Delivery Instructions indicates hash present but has too little data")
+ return false, oops.Errorf("Delivery Instructions indicates hash present but has too little data")
}
log.Debug("DeliveryInstructions has Hash")
} else {
@@ -425,11 +425,11 @@ func (delivery_instructions DeliveryInstructions) TunnelID() (tunnel_id uint32,
log.WithField("tunnel_id", tunnel_id).Debug("TunnelID retrieved")
} else {
log.Error("DeliveryInstructions are invalid, too little data for Tunnel ID")
- err = errors.New("DeliveryInstructions are invalid, too little data for Tunnel ID")
+ err = oops.Errorf("DeliveryInstructions are invalid, too little data for Tunnel ID")
}
} else {
log.Error("DeliveryInstructions are not of type DT_TUNNEL")
- err = errors.New("DeliveryInstructions are not of type DT_TUNNEL")
+ err = oops.Errorf("DeliveryInstructions are not of type DT_TUNNEL")
}
return
}
@@ -455,7 +455,7 @@ func (delivery_instructions DeliveryInstructions) Hash() (hash common.Hash, err
log.WithField("hash", hash).Debug("Hash retrieved for DT_TUNNEL")
} else {
log.Error("DeliveryInstructions is invalid, not contain enough data for hash given type DT_TUNNEL")
- err = errors.New("DeliveryInstructions is invalid, not contain enough data for hash given type DT_TUNNEL")
+ err = oops.Errorf("DeliveryInstructions is invalid, not contain enough data for hash given type DT_TUNNEL")
}
} else if delivery_type == DT_ROUTER {
if len(delivery_instructions) >= hash_end {
@@ -463,11 +463,11 @@ func (delivery_instructions DeliveryInstructions) Hash() (hash common.Hash, err
log.WithField("hash", hash).Debug("Hash retrieved for DT_ROUTER")
} else {
log.Error("DeliveryInstructions is invalid, not contain enough data for hash given type DT_ROUTER")
- err = errors.New("DeliveryInstructions is invalid, not contain enough data for hash given type DT_ROUTER")
+ err = oops.Errorf("DeliveryInstructions is invalid, not contain enough data for hash given type DT_ROUTER")
}
} else {
log.Error("No Hash on DeliveryInstructions not of type DT_TUNNEL or DT_ROUTER")
- err = errors.New("No Hash on DeliveryInstructions not of type DT_TUNNEL or DT_ROUTER")
+ err = oops.Errorf("No Hash on DeliveryInstructions not of type DT_TUNNEL or DT_ROUTER")
}
return
}
@@ -493,7 +493,7 @@ func (delivery_instructions DeliveryInstructions) Delay() (delay_factor DelayFac
log.WithField("delay_factor", delay_factor).Debug("Delay factor retrieved for DT_TUNNEL")
} else {
log.Error("DeliveryInstructions is invalid, does not contain enough data for DelayFactor")
- err = errors.New("DeliveryInstructions is invalid, does not contain enough data for DelayFactor")
+ err = oops.Errorf("DeliveryInstructions is invalid, does not contain enough data for DelayFactor")
return
}
} else if di_type == DT_ROUTER {
@@ -502,7 +502,7 @@ func (delivery_instructions DeliveryInstructions) Delay() (delay_factor DelayFac
log.WithField("delay_factor", delay_factor).Debug("Delay factor retrieved for DT_ROUTER")
} else {
log.Error("DeliveryInstructions is invalid, does not contain enough data for DelayFactor")
- err = errors.New("DeliveryInstructions is invalid, does not contain enough data for DelayFactor")
+ err = oops.Errorf("DeliveryInstructions is invalid, does not contain enough data for DelayFactor")
return
}
} else {
@@ -529,7 +529,7 @@ func (delivery_instructions DeliveryInstructions) MessageID() (msgid uint32, err
log.WithField("message_id", msgid).Debug("MessageID retrieved for FOLLOW_ON_FRAGMENT")
} else {
log.Error("DeliveryInstructions are invalid, not enough data for Message ID")
- err = errors.New("DeliveryInstructions are invalid, not enough data for Message ID")
+ err = oops.Errorf("DeliveryInstructions are invalid, not enough data for Message ID")
}
} else if di_type == FIRST_FRAGMENT {
var message_id_index int
@@ -543,11 +543,11 @@ func (delivery_instructions DeliveryInstructions) MessageID() (msgid uint32, err
log.WithField("message_id", msgid).Debug("MessageID retrieved for FIRST_FRAGMENT")
} else {
log.Error("DeliveryInstructions are invalid, not enough data for Message ID")
- err = errors.New("DeliveryInstructions are invalid, not enough data for Message ID")
+ err = oops.Errorf("DeliveryInstructions are invalid, not enough data for Message ID")
}
} else {
log.Error("No Message ID for DeliveryInstructions not of type FIRST_FRAGMENT or FOLLOW_ON_FRAGMENT")
- err = errors.New("No Message ID for DeliveryInstructions not of type FIRST_FRAGMENT or FOLLOW_ON_FRAGMENT")
+ err = oops.Errorf("No Message ID for DeliveryInstructions not of type FIRST_FRAGMENT or FOLLOW_ON_FRAGMENT")
}
return
}
@@ -570,13 +570,13 @@ func (delivery_instructions DeliveryInstructions) ExtendedOptions() (data []byte
}
if len(delivery_instructions) < extended_options_index+2 {
log.Error("DeliveryInstructions are invalid, length is shorter than required for Extended Options")
- err = errors.New("DeliveryInstructions are invalid, length is shorter than required for Extended Options")
+ err = oops.Errorf("DeliveryInstructions are invalid, length is shorter than required for Extended Options")
return
} else {
extended_options_size := common.Integer([]byte{delivery_instructions[extended_options_index]})
if len(delivery_instructions) < extended_options_index+1+extended_options_size.Int() {
log.Error("DeliveryInstructions are invalid, length is shorter than specified in Extended Options")
- err = errors.New("DeliveryInstructions are invalid, length is shorter than specified in Extended Options")
+ err = oops.Errorf("DeliveryInstructions are invalid, length is shorter than specified in Extended Options")
return
} else {
data = delivery_instructions[extended_options_index+1 : extended_options_size.Int()]
@@ -587,7 +587,7 @@ func (delivery_instructions DeliveryInstructions) ExtendedOptions() (data []byte
}
} else {
log.Error("DeliveryInstruction does not have the ExtendedOptions flag set")
- err = errors.New("DeliveryInstruction does not have the ExtendedOptions flag set")
+ err = oops.Errorf("DeliveryInstruction does not have the ExtendedOptions flag set")
}
return
}
@@ -606,7 +606,7 @@ func (delivery_instructions DeliveryInstructions) FragmentSize() (frag_size uint
log.WithField("fragment_size", frag_size).Debug("FragmentSize retrieved for FOLLOW_ON_FRAGMENT")
} else {
log.Error("DeliveryInstructions are invalid, not enough data for Fragment Size")
- err = errors.New("DeliveryInstructions are invalid, not enough data for Fragment Size")
+ err = oops.Errorf("DeliveryInstructions are invalid, not enough data for Fragment Size")
}
} else if di_type == FIRST_FRAGMENT {
var fragment_size_index int
@@ -620,11 +620,11 @@ func (delivery_instructions DeliveryInstructions) FragmentSize() (frag_size uint
log.WithField("fragment_size", frag_size).Debug("FragmentSize retrieved for FIRST_FRAGMENT")
} else {
log.Error("DeliveryInstructions are invalid, not enough data for Fragment Size")
- err = errors.New("DeliveryInstructions are invalid, not enough data for Fragment Size")
+ err = oops.Errorf("DeliveryInstructions are invalid, not enough data for Fragment Size")
}
} else {
log.Error("No Fragment Size for DeliveryInstructions not of type FIRST_FRAGMENT or FOLLOW_ON_FRAGMENT")
- err = errors.New("No Fragment Size for DeliveryInstructions not of type FIRST_FRAGMENT or FOLLOW_ON_FRAGMENT")
+ err = oops.Errorf("No Fragment Size for DeliveryInstructions not of type FIRST_FRAGMENT or FOLLOW_ON_FRAGMENT")
}
return
}
@@ -668,7 +668,7 @@ func (delivery_instructions DeliveryInstructions) message_id_index() (message_id
return message_id, nil
} else {
log.Error("DeliveryInstruction must be fragmented to have a Message ID")
- return 0, errors.New("DeliveryInstruction must be fragmented to have a Message ID")
+ return 0, oops.Errorf("DeliveryInstruction must be fragmented to have a Message ID")
}
}
@@ -719,7 +719,7 @@ func (delivery_instructions DeliveryInstructions) extended_options_index() (exte
} else {
log.Error("DeliveryInstruction does not have the ExtendedOptions flag set")
- err = errors.New("DeliveryInstruction does not have the ExtendedOptions flag set")
+ err = oops.Errorf("DeliveryInstruction does not have the ExtendedOptions flag set")
}
return
}
@@ -845,7 +845,7 @@ func maybeAppendMessageID(di_flag DeliveryInstructions, di_type int, data, curre
}
if len(data) < message_id_index+4 {
log.Error("Data is too short to contain message ID in FIRST_FRAGMENT")
- err = errors.New("data is too short to contain message ID in FIRST_FRAGMENT")
+ err = oops.Errorf("data is too short to contain message ID in FIRST_FRAGMENT")
} else {
now = append(current, data[message_id_index:message_id_index+4]...)
log.Debug("MessageID appended for FIRST_FRAGMENT")
@@ -854,7 +854,7 @@ func maybeAppendMessageID(di_flag DeliveryInstructions, di_type int, data, curre
} else if di_type == FOLLOW_ON_FRAGMENT {
if len(data) < 5 {
log.Error("Data is too short to contain message ID in FOLLOW_ON_FRAGMENT")
- err = errors.New("data is too short to contain message ID in FOLLOW_ON_FRAGMENT")
+ err = oops.Errorf("data is too short to contain message ID in FOLLOW_ON_FRAGMENT")
} else {
now = append(current, data[1:5]...)
log.Debug("MessageID appended for FOLLOW_ON_FRAGMENT")
@@ -886,7 +886,7 @@ func maybeAppendSize(di_flag DeliveryInstructions, di_type int, data, current []
} else if di_type == FOLLOW_ON_FRAGMENT {
if len(data) < 7 {
log.Error("Data is too short to contain size data")
- err = errors.New("data is too short to contain size data")
+ err = oops.Errorf("data is too short to contain size data")
} else {
now = append(now, data[5:7]...)
log.Debug("Size appended for FOLLOW_ON_FRAGMENT")
@@ -899,7 +899,7 @@ func readDeliveryInstructions(data []byte) (instructions DeliveryInstructions, r
log.Debug("Reading DeliveryInstructions")
if len(data) < 1 {
log.Error("No data provided")
- err = errors.New("no data provided")
+ err = oops.Errorf("no data provided")
return
}
diff --git a/lib/tunnel/tunnel.svg b/lib/tunnel/tunnel.svg
new file mode 100644
index 0000000..ca1425d
--- /dev/null
+++ b/lib/tunnel/tunnel.svg
@@ -0,0 +1,1867 @@
+
+
+
+
+
diff --git a/lib/util/doc.md b/lib/util/README.md
similarity index 90%
rename from lib/util/doc.md
rename to lib/util/README.md
index 1380e22..92098bd 100644
--- a/lib/util/doc.md
+++ b/lib/util/README.md
@@ -2,6 +2,9 @@
--
import "github.com/go-i2p/go-i2p/lib/util"
+
+
+
## Usage
@@ -37,3 +40,9 @@ Panicf allows passing formated string to panic()
```go
func RegisterCloser(c io.Closer)
```
+
+
+
+util
+
+github.com/go-i2p/go-i2p/lib/util
diff --git a/lib/util/home.go b/lib/util/home.go
new file mode 100644
index 0000000..fdee95a
--- /dev/null
+++ b/lib/util/home.go
@@ -0,0 +1,15 @@
+package util
+
+import (
+ "log"
+ "os"
+)
+
+func UserHome() string {
+ homeDir, err := os.UserHomeDir()
+ if err != nil {
+ log.Fatalf("Unable to get current user's home directory. $HOME environment variable issue? %s", err)
+ }
+
+ return homeDir
+}
diff --git a/lib/util/logger/log.go b/lib/util/logger/log.go
deleted file mode 100644
index 329f966..0000000
--- a/lib/util/logger/log.go
+++ /dev/null
@@ -1,129 +0,0 @@
-package logger
-
-import (
- "io"
- "os"
- "strings"
- "sync"
-
- "github.com/sirupsen/logrus"
-)
-
-var (
- log *Logger
- once sync.Once
- failFast string
-)
-
-// Logger wraps logrus.Logger and adds the ability to make all warnings fatal
-type Logger struct {
- *logrus.Logger
-}
-
-// Entry wraps logrus.Entry and enables it to use our Logger
-type Entry struct {
- Logger
- entry *logrus.Entry
-}
-
-// Warn wraps logrus.Warn and logs a fatal error if failFast is set
-func (l *Logger) Warn(args ...interface{}) {
- warnFatal(args)
- l.Logger.Warn(args...)
-}
-
-// Warnf wraps logrus.Warnf and logs a fatal error if failFast is set
-func (l *Logger) Warnf(format string, args ...interface{}) {
- warnFatalf(format, args...)
- l.Logger.Warnf(format, args...)
-}
-
-// Error wraps logrus.Error and logs a fatal error if failFast is set
-func (l *Logger) Error(args ...interface{}) {
- warnFatal(args)
- l.Logger.Error(args...)
-}
-
-// Errorf wraps logrus.Errorf and logs a fatal error if failFast is set
-func (l *Logger) Errorf(format string, args ...interface{}) {
- warnFatalf(format, args...)
- l.Logger.Errorf(format, args...)
-}
-
-// WithField wraps logrus.WithField and returns an Entry
-func (l *Logger) WithField(key string, value interface{}) *Entry {
- entry := l.Logger.WithField(key, value)
- return &Entry{*l, entry}
-}
-
-// WithFields wraps logrus.WithFields and returns an Entry
-func (l *Logger) WithFields(fields logrus.Fields) *Entry {
- entry := l.Logger.WithFields(fields)
- return &Entry{*l, entry}
-}
-
-// WithError wraps logrus.WithError and returns an Entry
-func (l *Logger) WithError(err error) *Entry {
- entry := l.Logger.WithError(err)
- return &Entry{*l, entry}
-}
-
-func warnFatal(args ...interface{}) {
- if failFast != "" {
- log.Fatal(args)
- }
-}
-
-func warnFatalf(format string, args ...interface{}) {
- if failFast != "" {
- log.Fatalf(format, args...)
- }
-}
-
-func warnFail() {
- if failFast != "" {
- log.Error("FATAL ERROR")
- }
-}
-
-// InitializeGoI2PLogger sets up all the necessary logging
-func InitializeGoI2PLogger() {
- once.Do(func() {
- log = &Logger{}
- log.Logger = logrus.New()
- // We do not want to log by default
- log.SetOutput(io.Discard)
- log.SetLevel(logrus.PanicLevel)
- // Check if DEBUG_I2P is set
- if logLevel := os.Getenv("DEBUG_I2P"); logLevel != "" {
- failFast = os.Getenv("WARNFAIL_I2P")
- if failFast != "" && logLevel == "" {
- logLevel = "debug"
- }
- log.SetOutput(os.Stdout)
- switch strings.ToLower(logLevel) {
- case "debug":
- log.SetLevel(logrus.DebugLevel)
- case "warn":
- log.SetLevel(logrus.WarnLevel)
- case "error":
- log.SetLevel(logrus.ErrorLevel)
- default:
- log.SetLevel(logrus.DebugLevel)
- }
- log.WithField("level", log.GetLevel()).Debug("Logging enabled.")
- }
- })
-}
-
-// GetGoI2PLogger returns the initialized Logger
-func GetGoI2PLogger() *Logger {
- if log == nil {
- InitializeGoI2PLogger()
- }
- return log
-}
-
-func init() {
- InitializeGoI2PLogger()
-}
diff --git a/lib/util/signals/doc.md b/lib/util/signals/README.md
similarity index 80%
rename from lib/util/signals/doc.md
rename to lib/util/signals/README.md
index 643aa0d..38d7673 100644
--- a/lib/util/signals/doc.md
+++ b/lib/util/signals/README.md
@@ -2,6 +2,9 @@
--
import "github.com/go-i2p/go-i2p/lib/util/signals"
+
+
+
## Usage
@@ -28,3 +31,9 @@ func RegisterReloadHandler(f Handler)
```go
type Handler func()
```
+
+
+
+signals
+
+github.com/go-i2p/go-i2p/lib/util/signals
diff --git a/lib/util/signals/signals.svg b/lib/util/signals/signals.svg
new file mode 100644
index 0000000..17712a1
--- /dev/null
+++ b/lib/util/signals/signals.svg
@@ -0,0 +1,90 @@
+
+
+
+
+
diff --git a/lib/util/time/sntp/README.md b/lib/util/time/sntp/README.md
new file mode 100644
index 0000000..8d4f08b
--- /dev/null
+++ b/lib/util/time/sntp/README.md
@@ -0,0 +1,124 @@
+# sntp
+--
+ import "github.com/go-i2p/go-i2p/lib/util/time/sntp"
+
+
+
+
+
+## Usage
+
+#### type DefaultNTPClient
+
+```go
+type DefaultNTPClient struct{}
+```
+
+
+#### func (*DefaultNTPClient) QueryWithOptions
+
+```go
+func (c *DefaultNTPClient) QueryWithOptions(host string, options ntp.QueryOptions) (*ntp.Response, error)
+```
+
+#### type NTPClient
+
+```go
+type NTPClient interface {
+ QueryWithOptions(host string, options ntp.QueryOptions) (*ntp.Response, error)
+}
+```
+
+
+#### type RouterTimestamper
+
+```go
+type RouterTimestamper struct {
+}
+```
+
+
+#### func NewRouterTimestamper
+
+```go
+func NewRouterTimestamper(client NTPClient) *RouterTimestamper
+```
+
+#### func (*RouterTimestamper) AddListener
+
+```go
+func (rt *RouterTimestamper) AddListener(listener UpdateListener)
+```
+
+#### func (*RouterTimestamper) GetCurrentTime
+
+```go
+func (rt *RouterTimestamper) GetCurrentTime() time.Time
+```
+
+#### func (*RouterTimestamper) RemoveListener
+
+```go
+func (rt *RouterTimestamper) RemoveListener(listener UpdateListener)
+```
+
+#### func (*RouterTimestamper) Start
+
+```go
+func (rt *RouterTimestamper) Start()
+```
+
+#### func (*RouterTimestamper) Stop
+
+```go
+func (rt *RouterTimestamper) Stop()
+```
+
+#### func (*RouterTimestamper) TimestampNow
+
+```go
+func (rt *RouterTimestamper) TimestampNow()
+```
+
+#### func (*RouterTimestamper) WaitForInitialization
+
+```go
+func (rt *RouterTimestamper) WaitForInitialization()
+```
+
+#### type UpdateListener
+
+```go
+type UpdateListener interface {
+ SetNow(now time.Time, stratum uint8)
+}
+```
+
+UpdateListener is an interface that listeners must implement to receive time
+updates.
+
+#### type Zones
+
+```go
+type Zones struct {
+}
+```
+
+
+#### func NewZones
+
+```go
+func NewZones() *Zones
+```
+
+#### func (*Zones) GetZone
+
+```go
+func (z *Zones) GetZone(countryCode string) string
+```
+
+
+
+sntp
+
+github.com/go-i2p/go-i2p/lib/util/time/sntp
diff --git a/lib/util/time/sntp/doc.md b/lib/util/time/sntp/doc.md
deleted file mode 100644
index 6b8224f..0000000
--- a/lib/util/time/sntp/doc.md
+++ /dev/null
@@ -1,128 +0,0 @@
-# sntp
---
- import "github.com/go-i2p/go-i2p/lib/util/sntp"
-
-## Usage
-
-```go
-import "github.com/go-i2p/go-i2p/lib/util/sntp"
-```
-
-## Types
-
-### type RouterTimestamper
-
-```go
-type RouterTimestamper struct {
- servers []string
- priorityServers [][]string
- listeners []UpdateListener
- queryFrequency time.Duration
- concurringServers int
- consecutiveFails int
- disabled bool
- initialized bool
- wellSynced bool
- isRunning bool
- mutex sync.Mutex
- zones *Zones
- stopChan chan struct{}
- waitGroup sync.WaitGroup
- ntpClient NTPClient
-}
-```
-
-RouterTimestamper is responsible for querying NTP servers and managing time synchronization.
-
-#### func NewRouterTimestamper
-
-```go
-func NewRouterTimestamper(client NTPClient) *RouterTimestamper
-```
-
-NewRouterTimestamper creates a new RouterTimestamper instance.
-
-#### func (*RouterTimestamper) Start
-
-```go
-func (rt *RouterTimestamper) Start()
-```
-
-Start begins the time synchronization process.
-
-#### func (*RouterTimestamper) Stop
-
-```go
-func (rt *RouterTimestamper) Stop()
-```
-
-Stop halts the time synchronization process.
-
-#### func (*RouterTimestamper) AddListener
-
-```go
-func (rt *RouterTimestamper) AddListener(listener UpdateListener)
-```
-
-AddListener adds a new listener for time updates.
-
-#### func (*RouterTimestamper) RemoveListener
-
-```go
-func (rt *RouterTimestamper) RemoveListener(listener UpdateListener)
-```
-
-RemoveListener removes a listener from receiving time updates.
-
-#### func (*RouterTimestamper) WaitForInitialization
-
-```go
-func (rt *RouterTimestamper) WaitForInitialization()
-```
-
-WaitForInitialization blocks until the RouterTimestamper is initialized or a timeout occurs.
-
-#### func (*RouterTimestamper) TimestampNow
-
-```go
-func (rt *RouterTimestamper) TimestampNow()
-```
-
-TimestampNow triggers an immediate time synchronization.
-
-### type UpdateListener
-
-```go
-type UpdateListener interface {
- SetNow(now time.Time, stratum uint8)
-}
-```
-
-UpdateListener is an interface that listeners must implement to receive time updates.
-
-### type Zones
-
-```go
-type Zones struct {
- countryToZone map[string]string
- continentToZone map[string]string
-}
-```
-
-Zones manages mappings between country codes, continent codes, and NTP zones.
-
-#### func NewZones
-
-```go
-func NewZones() *Zones
-```
-
-NewZones creates a new Zones instance and initializes it with data.
-
-#### func (*Zones) GetZone
-
-```go
-func (z *Zones) GetZone(countryCode string) string
-```
-
-GetZone returns the NTP zone for a given country code.
\ No newline at end of file
diff --git a/lib/util/time/sntp/router_timestamper.go b/lib/util/time/sntp/router_timestamper.go
index 8c897b3..2d4219c 100644
--- a/lib/util/time/sntp/router_timestamper.go
+++ b/lib/util/time/sntp/router_timestamper.go
@@ -393,3 +393,23 @@ func absDuration(d time.Duration) time.Duration {
func getLocalCountryCode() string {
return ""
}
+
+func (rt *RouterTimestamper) GetCurrentTime() time.Time {
+ if rt.initialized && rt.isRunning && !rt.disabled {
+ // Request immediate timestamp update
+ rt.TimestampNow()
+ // Wait briefly for update to complete
+ time.Sleep(100 * time.Millisecond)
+ }
+
+ // Return current time based on latest offset
+ rt.mutex.Lock()
+ defer rt.mutex.Unlock()
+ if len(rt.listeners) > 0 {
+ // Use first listener's time if available
+ var t time.Time
+ rt.listeners[0].SetNow(t, 0) // Get current time from listener
+ return t
+ }
+ return time.Now() // Fallback to system time
+}
diff --git a/lib/util/time/sntp/sntp.svg b/lib/util/time/sntp/sntp.svg
new file mode 100644
index 0000000..bed86f2
--- /dev/null
+++ b/lib/util/time/sntp/sntp.svg
@@ -0,0 +1,407 @@
+
+
+
+
+
diff --git a/lib/util/util.svg b/lib/util/util.svg
new file mode 100644
index 0000000..947c327
--- /dev/null
+++ b/lib/util/util.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
diff --git a/main.go b/main.go
index 7fc5aae..7cee785 100644
--- a/main.go
+++ b/main.go
@@ -6,8 +6,8 @@ import (
"github.com/go-i2p/go-i2p/lib/config"
"github.com/go-i2p/go-i2p/lib/router"
- "github.com/go-i2p/go-i2p/lib/util/logger"
"github.com/go-i2p/go-i2p/lib/util/signals"
+ "github.com/go-i2p/logger"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"gopkg.in/yaml.v3"
diff --git a/template.md b/template.md
new file mode 100644
index 0000000..7dcc429
--- /dev/null
+++ b/template.md
@@ -0,0 +1,13 @@
+{{ .EmitHeader }}
+
+
+
+{{ .EmitSynopsis }}
+
+{{ .EmitUsage }}
+
+{{ if .IsCommand }} ... {{ end }}
+
+{{ .Name }}
+
+{{ .ImportPath }}