seekia/internal/encoding/encoding.go

333 lines
7.5 KiB
Go

// 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
}
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
}
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
}