mirror of
https://github.com/go-i2p/go-i2p.git
synced 2025-07-05 14:13:30 -04:00
completed string
This commit is contained in:
@ -33,6 +33,12 @@ func (destination Destination) Certificate() (Certificate, error) {
|
|||||||
return KeysAndCert(destination).Certificate()
|
return KeysAndCert(destination).Certificate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ReadDestination(data []byte) (destination Destination, remainder []byte, err error) {
|
||||||
|
keys_and_cert, remainder, err := ReadKeysAndCert(data)
|
||||||
|
destination = Destination(keys_and_cert)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Generate the I2P base32 address for this Destination.
|
// Generate the I2P base32 address for this Destination.
|
||||||
//
|
//
|
||||||
|
@ -1,14 +1,54 @@
|
|||||||
package common
|
package common
|
||||||
|
|
||||||
|
/*
|
||||||
|
I2P RouterAddress
|
||||||
|
https://geti2p.net/en/docs/spec/common-structures#struct_RouterAddress
|
||||||
|
Accurate for version 0.9.24
|
||||||
|
|
||||||
|
+----+----+----+----+----+----+----+----+
|
||||||
|
|cost| expiration
|
||||||
|
+----+----+----+----+----+----+----+----+
|
||||||
|
| transport_style |
|
||||||
|
+----+----+----+----+-//-+----+----+----+
|
||||||
|
| |
|
||||||
|
+ +
|
||||||
|
| options |
|
||||||
|
~ ~
|
||||||
|
~ ~
|
||||||
|
| |
|
||||||
|
+----+----+----+----+----+----+----+----+
|
||||||
|
|
||||||
|
cost :: Integer
|
||||||
|
length -> 1 byte
|
||||||
|
|
||||||
|
case 0 -> free
|
||||||
|
case 255 -> expensive
|
||||||
|
|
||||||
|
expiration :: Date (must be all zeros, see notes below)
|
||||||
|
length -> 8 bytes
|
||||||
|
|
||||||
|
case null -> never expires
|
||||||
|
|
||||||
|
transport_style :: String
|
||||||
|
length -> 1-256 bytes
|
||||||
|
|
||||||
|
options :: Mapping
|
||||||
|
*/
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ROUTER_ADDRESS_MIN_LENGTH = 9
|
||||||
)
|
)
|
||||||
|
|
||||||
type RouterAddress []byte
|
type RouterAddress []byte
|
||||||
|
|
||||||
//
|
//
|
||||||
// Return the cost integer for this RouterAddress and any errors
|
// Return the cost integer for this RouterAddress and any errors encountered
|
||||||
// encountered parsing the RouterAddress.
|
// parsing the RouterAddress.
|
||||||
//
|
//
|
||||||
func (router_address RouterAddress) Cost() (cost int, err error) {
|
func (router_address RouterAddress) Cost() (cost int, err error) {
|
||||||
verr, exit := router_address.checkValid()
|
verr, exit := router_address.checkValid()
|
||||||
@ -21,8 +61,8 @@ func (router_address RouterAddress) Cost() (cost int, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Return the Date this RouterAddress expires and any errors
|
// Return the Date this RouterAddress expires and any errors encountered
|
||||||
// encountered parsing the RouterAddress.
|
// parsing the RouterAddress.
|
||||||
//
|
//
|
||||||
func (router_address RouterAddress) Expiration() (date Date, err error) {
|
func (router_address RouterAddress) Expiration() (date Date, err error) {
|
||||||
verr, exit := router_address.checkValid()
|
verr, exit := router_address.checkValid()
|
||||||
@ -30,14 +70,13 @@ func (router_address RouterAddress) Expiration() (date Date, err error) {
|
|||||||
if exit {
|
if exit {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
copy(date[:], router_address[1:9])
|
copy(date[:], router_address[1:ROUTER_ADDRESS_MIN_LENGTH])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Return the Transport type for this RouterAddress expire
|
// Return the Transport type for this RouterAddress and any errors encountered
|
||||||
// and any errors encountered parsing the RouterAddress.
|
// parsing the RouterAddress.
|
||||||
//
|
|
||||||
//
|
//
|
||||||
func (router_address RouterAddress) TransportStyle() (str String, err error) {
|
func (router_address RouterAddress) TransportStyle() (str String, err error) {
|
||||||
verr, exit := router_address.checkValid()
|
verr, exit := router_address.checkValid()
|
||||||
@ -45,13 +84,13 @@ func (router_address RouterAddress) TransportStyle() (str String, err error) {
|
|||||||
if exit {
|
if exit {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
str, _, err = ReadString(router_address[9:])
|
str, _, err = ReadString(router_address[ROUTER_ADDRESS_MIN_LENGTH:])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Return the Mapping containing the options for this
|
// Return the Mapping containing the options for this RouterAddress and any
|
||||||
// RouterAddress and any parsing errors.
|
// errors encountered parsing the RouterAddress.
|
||||||
//
|
//
|
||||||
func (router_address RouterAddress) Options() (mapping Mapping, err error) {
|
func (router_address RouterAddress) Options() (mapping Mapping, err error) {
|
||||||
verr, exit := router_address.checkValid()
|
verr, exit := router_address.checkValid()
|
||||||
@ -59,7 +98,7 @@ func (router_address RouterAddress) Options() (mapping Mapping, err error) {
|
|||||||
if exit {
|
if exit {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, remainder, _ := ReadString(router_address[9:])
|
_, remainder, err := ReadString(router_address[ROUTER_ADDRESS_MIN_LENGTH:])
|
||||||
if len(remainder) == 0 {
|
if len(remainder) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -68,24 +107,29 @@ func (router_address RouterAddress) Options() (mapping Mapping, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Check if the RouterAddress is empty or if it is too small
|
// Check if the RouterAddress is empty or if it is too small to contain valid data.
|
||||||
// to contain valid data
|
|
||||||
//
|
//
|
||||||
func (router_address RouterAddress) checkValid() (err error, exit bool) {
|
func (router_address RouterAddress) checkValid() (err error, exit bool) {
|
||||||
addr_len := len(router_address)
|
addr_len := len(router_address)
|
||||||
exit = false
|
exit = false
|
||||||
if addr_len == 0 {
|
if addr_len == 0 {
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"reason": "no data",
|
||||||
|
}).Error("invalid router address")
|
||||||
err = errors.New("error parsing RouterAddress: no data")
|
err = errors.New("error parsing RouterAddress: no data")
|
||||||
exit = true
|
exit = true
|
||||||
} else if addr_len < 9 {
|
} else if addr_len < ROUTER_ADDRESS_MIN_LENGTH {
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"reason": "data too small (len < ROUTER_ADDRESS_MIN_LENGTH)",
|
||||||
|
}).Warn("router address format warning")
|
||||||
err = errors.New("warning parsing RouterAddress: data too small")
|
err = errors.New("warning parsing RouterAddress: data too small")
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Given a slice of bytes, read a RouterAddress, returning the remaining
|
// Given a slice of bytes, read a RouterAddress, returning the remaining bytes and any
|
||||||
// bytes and any errors encountered parsing the RouterAddress
|
// errors encountered parsing the RouterAddress.
|
||||||
//
|
//
|
||||||
func ReadRouterAddress(data []byte) (router_address RouterAddress, remainder []byte, err error) {
|
func ReadRouterAddress(data []byte) (router_address RouterAddress, remainder []byte, err error) {
|
||||||
test_address := RouterAddress(data)
|
test_address := RouterAddress(data)
|
||||||
@ -93,8 +137,8 @@ func ReadRouterAddress(data []byte) (router_address RouterAddress, remainder []b
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
router_address = append(router_address, data[:9]...)
|
router_address = append(router_address, data[:ROUTER_ADDRESS_MIN_LENGTH]...)
|
||||||
str, remainder, err := ReadString(data[9:])
|
str, remainder, err := ReadString(data[ROUTER_ADDRESS_MIN_LENGTH:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -106,6 +150,6 @@ func ReadRouterAddress(data []byte) (router_address RouterAddress, remainder []b
|
|||||||
mapping = remainder[:map_size+2]
|
mapping = remainder[:map_size+2]
|
||||||
router_address = append(router_address, mapping...)
|
router_address = append(router_address, mapping...)
|
||||||
}
|
}
|
||||||
remainder = data[9+len(str)+len(mapping):]
|
remainder = data[ROUTER_ADDRESS_MIN_LENGTH+len(str)+len(mapping):]
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,20 @@
|
|||||||
package common
|
package common
|
||||||
|
|
||||||
|
/*
|
||||||
|
I2P RouterIdentity
|
||||||
|
https://geti2p.net/en/docs/spec/common-structures#struct_RouterIdentity
|
||||||
|
Accurate for version 0.9.24
|
||||||
|
|
||||||
|
Identical to KeysAndCert
|
||||||
|
*/
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/bounce-chat/go-i2p/lib/crypto"
|
"github.com/bounce-chat/go-i2p/lib/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//
|
||||||
|
// A RouterIdentity is identical to KeysAndCert.
|
||||||
|
//
|
||||||
type RouterIdentity []byte
|
type RouterIdentity []byte
|
||||||
|
|
||||||
func (router_identity RouterIdentity) PublicKey() (crypto.PublicKey, error) {
|
func (router_identity RouterIdentity) PublicKey() (crypto.PublicKey, error) {
|
||||||
@ -18,7 +29,8 @@ func (router_identity RouterIdentity) Certificate() (Certificate, error) {
|
|||||||
return KeysAndCert(router_identity).Certificate()
|
return KeysAndCert(router_identity).Certificate()
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadRouterIdentity(data []byte) (RouterIdentity, []byte, error) {
|
func ReadRouterIdentity(data []byte) (router_identity RouterIdentity, remainder []byte, err error) {
|
||||||
keys_and_certs, remainder, err := ReadKeysAndCert(data)
|
keys_and_cert, remainder, err := ReadKeysAndCert(data)
|
||||||
return RouterIdentity(keys_and_certs), remainder, err
|
router_identity = RouterIdentity(keys_and_cert)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
@ -1,84 +1,110 @@
|
|||||||
package common
|
package common
|
||||||
|
|
||||||
|
/*
|
||||||
|
I2P String
|
||||||
|
https://geti2p.net/en/docs/spec/common-structures#type_String
|
||||||
|
Accurate for version 0.9.24
|
||||||
|
*/
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
STRING_MAX_LENGTH = 256
|
||||||
)
|
)
|
||||||
|
|
||||||
type String []byte
|
type String []byte
|
||||||
|
|
||||||
//
|
//
|
||||||
// Look up the length of the string, reporting
|
// Look up the length of the string, reporting errors if the string is
|
||||||
// errors if the string is invalid or the specified
|
// invalid or the specified length does not match the provided data.
|
||||||
// length does not match the provided data.
|
|
||||||
//
|
//
|
||||||
func (str String) Length() (int, error) {
|
func (str String) Length() (length int, err error) {
|
||||||
if len(str) == 0 {
|
if len(str) == 0 {
|
||||||
// log
|
log.WithFields(log.Fields{
|
||||||
return 0, errors.New("error parsing string: zero length")
|
"reason": "no data",
|
||||||
|
}).Error("error parsing string")
|
||||||
|
err = errors.New("error parsing string: zero length")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
length := Integer([]byte{byte(str[0])})
|
length = Integer([]byte{byte(str[0])})
|
||||||
inferred_len := length + 1
|
inferred_len := length + 1
|
||||||
str_len := len(str)
|
str_len := len(str)
|
||||||
if inferred_len > str_len {
|
if inferred_len > str_len {
|
||||||
// log
|
log.WithFields(log.Fields{
|
||||||
return length, errors.New("string parsing warning: string data is shorter than specified by length")
|
"string_bytes_length": str_len,
|
||||||
|
"string_length_field": length,
|
||||||
|
"expected_bytes_length": inferred_len,
|
||||||
|
"reason": "data shorter than specified",
|
||||||
|
}).Warn("string format warning")
|
||||||
|
err = errors.New("string parsing warning: string data is shorter than specified by length")
|
||||||
} else if str_len > inferred_len {
|
} else if str_len > inferred_len {
|
||||||
//log
|
log.WithFields(log.Fields{
|
||||||
return length, errors.New("string parsing warning: string contains data beyond length")
|
"string_bytes_length": str_len,
|
||||||
|
"string_length_field": length,
|
||||||
|
"expected_bytes_length": inferred_len,
|
||||||
|
"reason": "data longer than specified",
|
||||||
|
}).Warn("string format warning")
|
||||||
|
err = errors.New("string parsing warning: string contains data beyond length")
|
||||||
}
|
}
|
||||||
return length, nil
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Return the string data and any errors
|
// Return the string data and any errors encountered by Length.
|
||||||
// encountered by Length.
|
|
||||||
//
|
//
|
||||||
func (str String) Data() (string, error) {
|
func (str String) Data() (data string, err error) {
|
||||||
length, err := str.Length()
|
length, err := str.Length()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch err.Error() {
|
switch err.Error() {
|
||||||
case "error parsing string: zero length":
|
case "error parsing string: zero length":
|
||||||
return "", err
|
return
|
||||||
case "string parsing warning: string data is shorter than specified by length":
|
case "string parsing warning: string data is shorter than specified by length":
|
||||||
return string(str[1:]), err
|
data = string(str[1:])
|
||||||
|
return
|
||||||
case "string parsing warning: string contains data beyond length":
|
case "string parsing warning: string contains data beyond length":
|
||||||
return string(str[1 : length+1]), err
|
data = string(str[1 : length+1])
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return string(str[1:]), nil
|
data = string(str[1:])
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// This function takes an unformatted go string
|
// This function takes an unformatted Go string and returns a String
|
||||||
// and returns a String and any errors encountered
|
// and any errors encountered during the encoding.
|
||||||
// during the encoding.
|
|
||||||
//
|
//
|
||||||
func ToI2PString(data string) (String, error) {
|
func ToI2PString(data string) (str String, err error) {
|
||||||
data_len := len(data)
|
data_len := len(data)
|
||||||
if data_len >= 256 {
|
if data_len >= STRING_MAX_LENGTH {
|
||||||
return make([]byte, 0), errors.New("cannot store that much data in I2P string")
|
log.WithFields(log.Fields{
|
||||||
|
"string_len": data_len,
|
||||||
|
"max_len": STRING_MAX_LENGTH,
|
||||||
|
"reason": "too much data",
|
||||||
|
}).Error("cannot create I2P string")
|
||||||
|
err = errors.New("cannot store that much data in I2P string")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
i2p_string := []byte{byte(data_len)}
|
i2p_string := []byte{byte(data_len)}
|
||||||
i2p_string = append(i2p_string, []byte(data)...)
|
i2p_string = append(i2p_string, []byte(data)...)
|
||||||
return String(i2p_string), nil
|
str = String(i2p_string)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Read a string from a slice of bytes, returning
|
// Read a string from a slice of bytes, returning any extra data on the end
|
||||||
// any extra data on the end of the slice.
|
// of the slice and any errors encountered parsing the String.
|
||||||
//
|
//
|
||||||
func ReadString(data []byte) (String, []byte, error) {
|
func ReadString(data []byte) (str String, remainder []byte, err error) {
|
||||||
str := String(data)
|
str = String(data)
|
||||||
length, err := String(data).Length()
|
length, err := String(data).Length()
|
||||||
if err != nil {
|
if err != nil && err.Error() == "string parsing warning: string contains data beyond length" {
|
||||||
switch err.Error() {
|
str = String(data[:length+1])
|
||||||
case "error parsing string: zero length":
|
remainder = data[length+1:]
|
||||||
return String{}, make([]byte, 0), err
|
err = nil
|
||||||
case "string parsing warning: string data is shorter than specified by length":
|
|
||||||
return str, make([]byte, 0), err
|
|
||||||
case "string parsing warning: string contains data beyond length":
|
|
||||||
return String(str[:length+1]), str[length+1:], nil //err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return str, make([]byte, 0), nil
|
return
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user