2024-04-11 15:51:56 +02:00
|
|
|
|
|
|
|
// encoding provides functions to encode and decode data in hex, base32, base64, and MessagePack
|
|
|
|
|
|
|
|
package encoding
|
|
|
|
|
|
|
|
// See what encodings are used for which types of data in Specification.md
|
|
|
|
|
|
|
|
import "bytes"
|
|
|
|
import "encoding/hex"
|
|
|
|
import "encoding/base64"
|
|
|
|
import "encoding/base32"
|
|
|
|
import "strings"
|
|
|
|
import "errors"
|
|
|
|
|
|
|
|
import messagepack "github.com/vmihailenco/msgpack/v5"
|
|
|
|
|
|
|
|
|
|
|
|
func DecodeHexStringToBytes(hexInput string)([]byte, error){
|
|
|
|
|
|
|
|
decodedBytes, err := hex.DecodeString(hexInput)
|
|
|
|
if (err != nil) { return nil, err }
|
|
|
|
|
|
|
|
return decodedBytes, nil
|
|
|
|
}
|
|
|
|
|
2024-06-02 10:43:39 +02:00
|
|
|
func DecodeHexStringTo3ByteArray(hexInput string)([3]byte, error){
|
|
|
|
|
|
|
|
decodedBytes, err := hex.DecodeString(hexInput)
|
|
|
|
if (err != nil) { return [3]byte{}, err }
|
|
|
|
|
|
|
|
if (len(decodedBytes) != 3){
|
|
|
|
return [3]byte{}, errors.New("DecodeHexStringTo3ByteArray called with invalid length hex string: " + hexInput)
|
|
|
|
}
|
|
|
|
|
|
|
|
result := [3]byte(decodedBytes)
|
|
|
|
|
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func DecodeHexStringTo16ByteArray(hexInput string)([16]byte, error){
|
|
|
|
|
|
|
|
decodedBytes, err := hex.DecodeString(hexInput)
|
|
|
|
if (err != nil) { return [16]byte{}, err }
|
|
|
|
|
|
|
|
if (len(decodedBytes) != 16){
|
|
|
|
return [16]byte{}, errors.New("DecodeHexStringTo16ByteArray called with invalid length hex string: " + hexInput)
|
|
|
|
}
|
|
|
|
|
|
|
|
result := [16]byte(decodedBytes)
|
|
|
|
|
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
2024-04-11 15:51:56 +02:00
|
|
|
func EncodeBytesToHexString(input []byte)string{
|
|
|
|
|
|
|
|
result := hex.EncodeToString(input)
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
const base32Charset = "abcdefghijklmnopqrstuvwxyz234567"
|
|
|
|
|
|
|
|
func EncodeBytesToBase32String(input []byte)string{
|
|
|
|
|
|
|
|
newEncodingObject := base32.NewEncoding(base32Charset)
|
|
|
|
|
|
|
|
result := newEncodingObject.EncodeToString(input)
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
func DecodeBase32StringToBytes(input string)([]byte, error){
|
|
|
|
|
|
|
|
// We have to check for newlines because golang's base32 allows them
|
|
|
|
|
|
|
|
for _, element := range input{
|
|
|
|
|
|
|
|
if (element == '\r' || element == '\n') {
|
|
|
|
return nil, errors.New("Invalid base32 input: contains newline.")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
newEncodingObject := base32.NewEncoding(base32Charset)
|
|
|
|
|
|
|
|
decodedBytes, err := newEncodingObject.DecodeString(input)
|
|
|
|
if (err != nil) { return nil, err }
|
|
|
|
|
|
|
|
return decodedBytes, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verifies string is a base32 string
|
|
|
|
// Outputs:
|
|
|
|
// -bool: String is base32 charset only
|
|
|
|
// -string: Character that is not base32
|
|
|
|
func VerifyStringContainsOnlyBase32Charset(input string)(bool, string){
|
|
|
|
|
|
|
|
// This iterates through the string's runes
|
|
|
|
for _, element := range input {
|
|
|
|
|
|
|
|
characterString := string(element)
|
|
|
|
|
|
|
|
isBase32Character := strings.ContainsAny(characterString, base32Charset)
|
|
|
|
if (isBase32Character == false) {
|
|
|
|
return false, characterString
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true, ""
|
|
|
|
}
|
|
|
|
|
|
|
|
func EncodeBytesToBase64String(input []byte) string {
|
|
|
|
|
|
|
|
result := base64.URLEncoding.EncodeToString(input)
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
func DecodeBase64StringToBytes(base64Input string) ([]byte, error) {
|
|
|
|
|
|
|
|
decodedBytes, err := base64.URLEncoding.DecodeString(base64Input)
|
|
|
|
if (err != nil) { return nil, err }
|
|
|
|
|
|
|
|
return decodedBytes, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func DecodeBase64StringToUnicodeString(base64Input string)(string, error){
|
|
|
|
|
|
|
|
decodedBytes, err := DecodeBase64StringToBytes(base64Input)
|
|
|
|
if (err != nil) { return "", err }
|
|
|
|
|
|
|
|
decodedString := string(decodedBytes)
|
|
|
|
|
|
|
|
return decodedString, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// This will omit empty values
|
|
|
|
func EncodeMessagePackBytes(input interface{}) ([]byte, error) {
|
|
|
|
|
|
|
|
encoder := messagepack.GetEncoder()
|
|
|
|
encoder.SetOmitEmpty(true)
|
|
|
|
encoder.UseCompactInts(true)
|
|
|
|
|
|
|
|
var buffer bytes.Buffer
|
|
|
|
encoder.Reset(&buffer)
|
|
|
|
|
|
|
|
err := encoder.Encode(input)
|
|
|
|
bytes := buffer.Bytes()
|
|
|
|
|
|
|
|
messagepack.PutEncoder(encoder)
|
|
|
|
|
|
|
|
if (err != nil) {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return bytes, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func DecodeRawMessagePackToString(data messagepack.RawMessage)(string, error){
|
|
|
|
|
|
|
|
var outputString string
|
|
|
|
|
|
|
|
err := DecodeMessagePackBytes(false, data, &outputString)
|
|
|
|
if (err != nil) { return "", err }
|
|
|
|
|
|
|
|
return outputString, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func DecodeRawMessagePackToByte(data messagepack.RawMessage)(byte, error){
|
|
|
|
|
|
|
|
var outputByte byte
|
|
|
|
|
|
|
|
err := DecodeMessagePackBytes(false, data, &outputByte)
|
|
|
|
if (err != nil) { return 0, err }
|
|
|
|
|
|
|
|
return outputByte, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func DecodeRawMessagePackToBytes(data messagepack.RawMessage)([]byte, error){
|
|
|
|
|
|
|
|
var outputBytes []byte
|
|
|
|
|
|
|
|
err := DecodeMessagePackBytes(false, data, &outputBytes)
|
|
|
|
if (err != nil) { return nil, err }
|
|
|
|
|
|
|
|
return outputBytes, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is used to decode inboxes
|
|
|
|
func DecodeRawMessagePackTo10ByteArray(data messagepack.RawMessage)([10]byte, error){
|
|
|
|
|
|
|
|
var outputArray [10]byte
|
|
|
|
|
|
|
|
err := DecodeMessagePackBytes(false, data, &outputArray)
|
|
|
|
if (err != nil) { return [10]byte{}, err }
|
|
|
|
|
|
|
|
return outputArray, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is used to decode device identifiers
|
|
|
|
func DecodeRawMessagePackTo11ByteArray(data messagepack.RawMessage)([11]byte, error){
|
|
|
|
|
|
|
|
var outputArray [11]byte
|
|
|
|
|
|
|
|
err := DecodeMessagePackBytes(false, data, &outputArray)
|
|
|
|
if (err != nil) { return [11]byte{}, err }
|
|
|
|
|
|
|
|
return outputArray, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is used to decode identity hashes
|
|
|
|
func DecodeRawMessagePackTo16ByteArray(data messagepack.RawMessage)([16]byte, error){
|
|
|
|
|
|
|
|
var outputArray [16]byte
|
|
|
|
|
|
|
|
err := DecodeMessagePackBytes(false, data, &outputArray)
|
|
|
|
if (err != nil) { return [16]byte{}, err }
|
|
|
|
|
|
|
|
return outputArray, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func DecodeRawMessagePackTo22ByteArray(data messagepack.RawMessage)([22]byte, error){
|
|
|
|
|
|
|
|
var outputArray [22]byte
|
|
|
|
|
|
|
|
err := DecodeMessagePackBytes(false, data, &outputArray)
|
|
|
|
if (err != nil) { return [22]byte{}, err }
|
|
|
|
|
|
|
|
return outputArray, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func DecodeRawMessagePackTo24ByteArray(data messagepack.RawMessage)([24]byte, error){
|
|
|
|
|
|
|
|
var outputArray [24]byte
|
|
|
|
|
|
|
|
err := DecodeMessagePackBytes(false, data, &outputArray)
|
|
|
|
if (err != nil) { return [24]byte{}, err }
|
|
|
|
|
|
|
|
return outputArray, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is used to decode message cipher key hashes
|
|
|
|
func DecodeRawMessagePackTo25ByteArray(data messagepack.RawMessage)([25]byte, error){
|
|
|
|
|
|
|
|
var outputArray [25]byte
|
|
|
|
|
|
|
|
err := DecodeMessagePackBytes(false, data, &outputArray)
|
|
|
|
if (err != nil) { return [25]byte{}, err }
|
|
|
|
|
|
|
|
return outputArray, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func DecodeRawMessagePackTo32ByteArray(data messagepack.RawMessage)([32]byte, error){
|
|
|
|
|
|
|
|
var outputArray [32]byte
|
|
|
|
|
|
|
|
err := DecodeMessagePackBytes(false, data, &outputArray)
|
|
|
|
if (err != nil) { return [32]byte{}, err }
|
|
|
|
|
|
|
|
return outputArray, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func DecodeRawMessagePackTo64ByteArray(data messagepack.RawMessage)([64]byte, error){
|
|
|
|
|
|
|
|
var outputArray [64]byte
|
|
|
|
|
|
|
|
err := DecodeMessagePackBytes(false, data, &outputArray)
|
|
|
|
if (err != nil) { return [64]byte{}, err }
|
|
|
|
|
|
|
|
return outputArray, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func DecodeRawMessagePackToBool(data messagepack.RawMessage)(bool, error){
|
|
|
|
|
|
|
|
var outputBool bool
|
|
|
|
|
|
|
|
err := DecodeMessagePackBytes(false, data, &outputBool)
|
|
|
|
if (err != nil) { return false, err }
|
|
|
|
|
|
|
|
return outputBool, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func DecodeRawMessagePackToInt(data messagepack.RawMessage)(int, error){
|
|
|
|
|
|
|
|
var outputInt int
|
|
|
|
|
|
|
|
err := DecodeMessagePackBytes(false, data, &outputInt)
|
|
|
|
if (err != nil) { return 0, err }
|
|
|
|
|
|
|
|
return outputInt, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func DecodeRawMessagePackToInt64(data messagepack.RawMessage)(int64, error){
|
|
|
|
|
|
|
|
var outputInt int64
|
|
|
|
|
|
|
|
err := DecodeMessagePackBytes(false, data, &outputInt)
|
|
|
|
if (err != nil) { return 0, err }
|
|
|
|
|
|
|
|
return outputInt, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func DecodeRawMessagePackToFloat64(data messagepack.RawMessage)(float64, error){
|
|
|
|
|
|
|
|
var outputFloat float64
|
|
|
|
|
|
|
|
err := DecodeMessagePackBytes(false, data, &outputFloat)
|
|
|
|
if (err != nil) { return 0, err }
|
|
|
|
|
|
|
|
return outputFloat, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func DecodeMessagePackBytes(allowUnknownFields bool, data []byte, output interface{}) error {
|
|
|
|
|
|
|
|
decoder := messagepack.GetDecoder()
|
|
|
|
|
|
|
|
//TODO: Make allowUnknownFields also reject ignored fields
|
|
|
|
|
|
|
|
decoder.DisallowUnknownFields(!allowUnknownFields)
|
|
|
|
|
|
|
|
newReader := bytes.NewReader(data)
|
|
|
|
|
|
|
|
decoder.Reset(newReader)
|
|
|
|
|
|
|
|
err := decoder.Decode(output)
|
|
|
|
|
|
|
|
messagepack.PutDecoder(decoder)
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|