Compare commits
25 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
b4e9da89e9 | ||
![]() |
afae8e6f14 | ||
![]() |
6c95fc6ac7 | ||
![]() |
ada0d39af4 | ||
![]() |
59bffea3f3 | ||
![]() |
316dc840d6 | ||
![]() |
90da121025 | ||
![]() |
d362997650 | ||
![]() |
4004d3050d | ||
![]() |
0d58ebfa78 | ||
![]() |
acbf68bc58 | ||
![]() |
dc8ef52d46 | ||
![]() |
aae46b4dec | ||
![]() |
597e1da68d | ||
![]() |
4cf76aeec2 | ||
![]() |
80bfc77145 | ||
![]() |
5ae94bc639 | ||
![]() |
c86c07c1df | ||
![]() |
fde718e1d8 | ||
![]() |
3a99966c42 | ||
![]() |
d23cb52f2c | ||
![]() |
81f9b8a8cc | ||
![]() |
28d6bf4d97 | ||
![]() |
9307ae9cf4 | ||
![]() |
e6cb984e8f |
36
I2PAddr.go
36
I2PAddr.go
@@ -21,6 +21,9 @@ var (
|
||||
i2pB32enc *base32.Encoding = base32.NewEncoding("abcdefghijklmnopqrstuvwxyz234567")
|
||||
)
|
||||
|
||||
// If you set this to true, Addr will return a base64 String()
|
||||
var StringIsBase64 bool
|
||||
|
||||
// The public and private keys associated with an I2P destination. I2P hides the
|
||||
// details of exactly what this is, so treat them as blobs, but generally: One
|
||||
// pair of DSA keys, one pair of ElGamal keys, and sometimes (almost never) also
|
||||
@@ -44,7 +47,7 @@ func fileExists(filename string) (bool, error) {
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
} else if err != nil {
|
||||
return false, err
|
||||
return false, fmt.Errorf("error checking file existence: %w", err)
|
||||
}
|
||||
return !info.IsDir(), nil
|
||||
}
|
||||
@@ -68,23 +71,25 @@ func LoadKeys(r string) (I2PKeys, error) {
|
||||
if err != nil {
|
||||
return I2PKeys{}, err
|
||||
}
|
||||
if exists {
|
||||
if !exists {
|
||||
return I2PKeys{}, fmt.Errorf("file does not exist: %s", r)
|
||||
}
|
||||
fi, err := os.Open(r)
|
||||
if err != nil {
|
||||
return I2PKeys{}, err
|
||||
return I2PKeys{}, fmt.Errorf("error opening file: %w", err)
|
||||
}
|
||||
defer fi.Close()
|
||||
return LoadKeysIncompat(fi)
|
||||
}
|
||||
return I2PKeys{}, err
|
||||
}
|
||||
|
||||
// store keys in non standard format
|
||||
func StoreKeysIncompat(k I2PKeys, w io.Writer) (err error) {
|
||||
_, err = io.WriteString(w, k.Address.Base64()+"\n"+k.Both)
|
||||
return
|
||||
func StoreKeysIncompat(k I2PKeys, w io.Writer) error {
|
||||
_, err := io.WriteString(w, k.Address.Base64()+"\n"+k.Both)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error writing keys: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func StoreKeys(k I2PKeys, r string) error {
|
||||
if _, err := os.Stat(r); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
@@ -170,7 +175,7 @@ func (k I2PKeys) String() string {
|
||||
func (k I2PKeys) HostnameEntry(hostname string, opts crypto.SignerOpts) (string, error) {
|
||||
sig, err := k.Sign(rand.Reader, []byte(hostname), opts)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", fmt.Errorf("error signing hostname: %w", err)
|
||||
}
|
||||
return string(sig), nil
|
||||
}
|
||||
@@ -238,6 +243,9 @@ func (a I2PAddr) Base64() string {
|
||||
|
||||
// Returns the I2P destination (base32-encoded)
|
||||
func (a I2PAddr) String() string {
|
||||
if StringIsBase64 {
|
||||
return a.Base64()
|
||||
}
|
||||
return string(a.Base32())
|
||||
}
|
||||
|
||||
@@ -261,7 +269,7 @@ func NewI2PAddrFromString(addr string) (I2PAddr, error) {
|
||||
addr = strings.Trim(addr, "\t\n\r\f ")
|
||||
// very basic check
|
||||
if len(addr) > 4096 || len(addr) < 516 {
|
||||
return I2PAddr(""), errors.New("Not an I2P address")
|
||||
return I2PAddr(""), errors.New(addr + " is not an I2P address")
|
||||
}
|
||||
buf := make([]byte, i2pB64enc.DecodedLen(len(addr)))
|
||||
if _, err := i2pB64enc.Decode(buf, []byte(addr)); err != nil {
|
||||
@@ -329,6 +337,10 @@ HELLO VERSION MIN=3.1 MAX=3.1
|
||||
DEST GENERATE SIGNATURE_TYPE=7
|
||||
*/
|
||||
func NewDestination() (*I2PKeys, error) {
|
||||
removeNewlines := func(s string) string {
|
||||
return strings.ReplaceAll(strings.ReplaceAll(s, "\r\n", ""), "\n", "")
|
||||
}
|
||||
//
|
||||
conn, err := net.Dial("tcp", "127.0.0.1:7656")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -361,6 +373,8 @@ func NewDestination() (*I2PKeys, error) {
|
||||
pub := strings.Split(strings.Split(string(buf[:n]), "PRIV=")[0], "PUB=")[1]
|
||||
priv := strings.Split(string(buf[:n]), "PRIV=")[1]
|
||||
|
||||
priv = removeNewlines(priv) //There is an extraneous newline in the private key, so we'll remove it.
|
||||
|
||||
return &I2PKeys{
|
||||
Address: I2PAddr(pub),
|
||||
Both: pub + priv,
|
||||
|
225
I2PAddr_test.go
225
I2PAddr_test.go
@@ -1,21 +1,28 @@
|
||||
package i2pkeys
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
// "time"
|
||||
)
|
||||
|
||||
const yoursam = "127.0.0.1:7656"
|
||||
const (
|
||||
yoursam = "127.0.0.1:7656"
|
||||
validShortenedI2PAddr = "idk.i2p"
|
||||
validI2PAddrB32 = "b2o47zwxqjbn7jj37yqkmvbmci7kqubwgxu3umqid7cexmc7xudq.b32.i2p"
|
||||
validI2PAddrB64 = "spHxea2xhPjKH9yyEeFJ96aqtvKidH-GiWxs8dH6RWS2FrDoWFhuEkfw77pF~Hv57lLhMaMB3qqWjCtYXOjL48Q1zYbr3MAcTO44wwVPjOU1hU77vbJcUuwBeRvaSr2dZx-FiTSOdQuhPD1EozYNRIMFwZ0fZwKf~3Gj4dEWccOLKs~NbiPsj-~tc5tmhAs8yBeoZEqEBe40X75SfSHY-EnstcZevVAwIXYk3zX3KF0mji3bo2QXuTFcMZHHLiLd2AHLRANzWyvQ9DC1rnCsHJM4xxV4dVp0pHkP1hwBo7E0NJvN4nFkQcj-FI2RJ~cFUCk7qc86PRHwvKCjzSlrgjtDsMUwd83Dz1PfpzCqHNLUFWI7uPKbKcJZhasFm4kEhUyupd85q75Ch2IZE9J2JXodSxmseO5ZKcHK6pFtfR-HbzKjIe92TWHsNkmvtoHiUaOVrWnk-cmo2I1W1VxfL08teDxQ13P80uFaMcameRzuFM2F8pSOpoyEJUDRGLEeBQAEAAcAAA=="
|
||||
)
|
||||
|
||||
func Test_Basic(t *testing.T) {
|
||||
fmt.Println("Test_Basic")
|
||||
fmt.Println("\tAttaching to SAM at " + yoursam)
|
||||
keys, err := NewDestination()
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
t.Fail()
|
||||
return
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
fmt.Println(keys.String())
|
||||
}
|
||||
@@ -23,11 +30,211 @@ func Test_Basic(t *testing.T) {
|
||||
func Test_Basic_Lookup(t *testing.T) {
|
||||
fmt.Println("Test_Basic")
|
||||
fmt.Println("\tAttaching to SAM at " + yoursam)
|
||||
keys, err := Lookup("idk.i2p")
|
||||
keys, err := Lookup(validShortenedI2PAddr)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
t.Fail()
|
||||
return
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
fmt.Println(keys.String())
|
||||
}
|
||||
|
||||
func Test_NewI2PAddrFromString(t *testing.T) {
|
||||
t.Run("Valid base64 address", func(t *testing.T) {
|
||||
addr, err := NewI2PAddrFromString(validI2PAddrB64)
|
||||
if err != nil {
|
||||
t.Fatalf("NewI2PAddrFromString failed for valid address: '%v'", err)
|
||||
}
|
||||
if addr.Base64() != validI2PAddrB64 {
|
||||
t.Errorf("NewI2PAddrFromString returned incorrect address. Got '%s', want '%s'", addr.Base64(), validI2PAddrB64)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Invalid address", func(t *testing.T) {
|
||||
invalidAddr := "not-a-valid-address"
|
||||
_, err := NewI2PAddrFromString(invalidAddr)
|
||||
if err == nil {
|
||||
t.Error("NewI2PAddrFromString should have failed for invalid address")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Base32 address", func(t *testing.T) {
|
||||
_, err := NewI2PAddrFromString(validI2PAddrB32)
|
||||
if err == nil {
|
||||
t.Error("NewI2PAddrFromString should have failed for base32 address")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Empty address", func(t *testing.T) {
|
||||
_, err := NewI2PAddrFromString("")
|
||||
if err == nil {
|
||||
t.Error("NewI2PAddrFromString should have failed for empty address")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Address with .i2p suffix", func(t *testing.T) { //CHECK
|
||||
addr, err := NewI2PAddrFromString(validI2PAddrB64 + ".i2p")
|
||||
if err != nil {
|
||||
t.Fatalf("NewI2PAddrFromString failed for address with .i2p suffix: '%v'", err)
|
||||
}
|
||||
if addr.Base64() != validI2PAddrB64 {
|
||||
t.Errorf("NewI2PAddrFromString returned incorrect address. Got '%s', want '%s'", addr.Base64(), validI2PAddrB64)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func Test_I2PAddr(t *testing.T) {
|
||||
addr := I2PAddr(validI2PAddrB64)
|
||||
base32 := addr.Base32()
|
||||
|
||||
t.Run("Base32 suffix", func(t *testing.T) {
|
||||
if !strings.HasSuffix(base32, ".b32.i2p") {
|
||||
t.Errorf("Base32 address should end with .b32.i2p, got %s", base32)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Base32 length", func(t *testing.T) {
|
||||
if len(base32) != 60 {
|
||||
t.Errorf("Base32 address should be 60 characters long, got %d", len(base32))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func Test_DestHashFromString(t *testing.T) {
|
||||
t.Run("Valid hash", func(t *testing.T) {
|
||||
hash, err := DestHashFromString(validI2PAddrB32)
|
||||
if err != nil {
|
||||
t.Fatalf("DestHashFromString failed for valid hash: '%v'", err)
|
||||
}
|
||||
if hash.String() != validI2PAddrB32 {
|
||||
t.Errorf("DestHashFromString returned incorrect hash. Got '%s', want '%s'", hash.String(), validI2PAddrB32)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Invalid hash", func(t *testing.T) {
|
||||
invalidHash := "not-a-valid-hash"
|
||||
_, err := DestHashFromString(invalidHash)
|
||||
if err == nil {
|
||||
t.Error("DestHashFromString should have failed for invalid hash")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Empty hash", func(t *testing.T) {
|
||||
_, err := DestHashFromString("")
|
||||
if err == nil {
|
||||
t.Error("DestHashFromString should have failed for empty hash")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func Test_I2PAddrToBytes(t *testing.T) {
|
||||
addr := I2PAddr(validI2PAddrB64)
|
||||
|
||||
t.Run("ToBytes and back", func(t *testing.T) {
|
||||
decodedBytes, err := addr.ToBytes()
|
||||
if err != nil {
|
||||
t.Fatalf("ToBytes failed: '%v'", err)
|
||||
}
|
||||
|
||||
encodedString := i2pB64enc.EncodeToString(decodedBytes)
|
||||
if encodedString != validI2PAddrB64 {
|
||||
t.Errorf("Round-trip encoding/decoding failed. Got '%s', want '%s'", encodedString, validI2PAddrB64)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Direct decoding comparison", func(t *testing.T) {
|
||||
decodedBytes, err := addr.ToBytes()
|
||||
if err != nil {
|
||||
t.Fatalf("ToBytes failed: '%v'", err)
|
||||
}
|
||||
|
||||
directlyDecoded, err := i2pB64enc.DecodeString(validI2PAddrB64)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to decode test string using i2pB64enc: '%v'", err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(decodedBytes, directlyDecoded) {
|
||||
t.Errorf("Mismatch between ToBytes result and direct decoding. ToBytes len: '%d', Direct decoding len: '%d'", len(decodedBytes), len(directlyDecoded))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
func removeNewlines(s string) string {
|
||||
return strings.ReplaceAll(strings.ReplaceAll(s, "\r\n", ""), "\n", "")
|
||||
}
|
||||
*/
|
||||
func Test_KeyGenerationAndHandling(t *testing.T) {
|
||||
// Generate new keys
|
||||
keys, err := NewDestination()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to generate new I2P keys: %v", err)
|
||||
}
|
||||
t.Run("LoadKeysIncompat", func(t *testing.T) {
|
||||
//extract keys
|
||||
addr := keys.Address
|
||||
fmt.Println(addr)
|
||||
|
||||
//both := removeNewlines(keys.Both)
|
||||
both := keys.Both
|
||||
fmt.Println(both)
|
||||
|
||||
//FORMAT TO LOAD: (Address, Both)
|
||||
addrload := addr.Base64() + "\n" + both
|
||||
|
||||
r := strings.NewReader(addrload)
|
||||
loadedKeys, err := LoadKeysIncompat(r)
|
||||
if err != nil {
|
||||
t.Fatalf("LoadKeysIncompat failed: %v", err)
|
||||
}
|
||||
|
||||
if loadedKeys.Address != keys.Address {
|
||||
//fmt.Printf("loadedKeys.Address md5hash: '%s'\n keys.Address md5hash: '%s'\n", getMD5Hash(string(loadedKeys.Address)), getMD5Hash(string(keys.Address)))
|
||||
t.Errorf("LoadKeysIncompat returned incorrect address. Got '%s', want '%s'", loadedKeys.Address, keys.Address)
|
||||
|
||||
}
|
||||
if loadedKeys.Both != keys.Both {
|
||||
t.Errorf("LoadKeysIncompat returned incorrect pair. Got '%s'\nwant '%s'\n", loadedKeys.Both, keys.Both)
|
||||
/*
|
||||
if loadedKeys.Both == removeNewlines(keys.Both) {
|
||||
fmt.Println("However, both pairs are correct if newline is removed in generated keys.")
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
expected := keys.Address.Base64() + "\n" + keys.Both
|
||||
|
||||
t.Run("StoreKeysIncompat", func(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
err := StoreKeysIncompat(*keys, &buf)
|
||||
if err != nil {
|
||||
t.Fatalf("StoreKeysIncompat failed: '%v'", err)
|
||||
}
|
||||
if buf.String() != expected {
|
||||
t.Errorf("StoreKeysIncompat wrote incorrect data. Got '%s', want '%s'", buf.String(), expected)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("StoreKeys", func(t *testing.T) {
|
||||
tmpDir, err := ioutil.TempDir("", "test_keys_")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp directory: '%v'", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
tmpFilePath := filepath.Join(tmpDir, "test_keys.txt")
|
||||
|
||||
err = StoreKeys(*keys, tmpFilePath)
|
||||
if err != nil {
|
||||
t.Fatalf("StoreKeys failed: '%v'", err)
|
||||
}
|
||||
|
||||
content, err := ioutil.ReadFile(tmpFilePath)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to read temp file: '%v'", err)
|
||||
}
|
||||
|
||||
if string(content) != expected {
|
||||
t.Errorf("StoreKeys wrote incorrect data. Got '%s', want '%s'", string(content), expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
28
Makefile
28
Makefile
@@ -1,13 +1,31 @@
|
||||
|
||||
build:
|
||||
go build -a -tags netgo -ldflags '-w -extldflags "-static"'
|
||||
USER_GH=eyedeekay
|
||||
VERSION=0.33.7
|
||||
packagename=i2pkeys
|
||||
|
||||
echo:
|
||||
@echo "$(GOPATH)"
|
||||
@echo "type make version to do release $(VERSION)"
|
||||
|
||||
version:
|
||||
github-release release -s $(GITHUB_TOKEN) -u $(USER_GH) -r $(packagename) -t v$(VERSION) -d "version $(VERSION)"
|
||||
|
||||
del:
|
||||
github-release delete -s $(GITHUB_TOKEN) -u $(USER_GH) -r $(packagename) -t v$(VERSION)
|
||||
|
||||
tar:
|
||||
tar --exclude .git \
|
||||
--exclude .go \
|
||||
--exclude bin \
|
||||
-cJvf ../$(packagename)_$(VERSION).orig.tar.xz .
|
||||
|
||||
copier:
|
||||
echo '#! /usr/bin/env sh' > deb/copy.sh
|
||||
echo 'for f in $$(ls); do scp $$f/*.deb user@192.168.99.106:~/DEBIAN_PKGS/$$f/main/; done' >> deb/copy.sh
|
||||
|
||||
fmt:
|
||||
find . -path ./.go -prune -o -name "*.go" -exec gofmt -w {} \;
|
||||
find . -path ./.go -prune -o -name "*.i2pkeys" -exec rm {} \;
|
||||
|
||||
install:
|
||||
install -m755 i2pkeys /usr/local/bin/i2pkeys
|
||||
upload-linux:
|
||||
github-release upload -R -u $(USER_GH) -r "$(packagename)" -t $(VERSION) -l `sha256sum ` -n "$(packagename)" -f "$(packagename)"
|
||||
|
||||
|
Reference in New Issue
Block a user