github.com/wfusion/gofusion@v1.1.14/internal/util/payload/unseal.go (about)

     1  package pd
     2  
     3  import (
     4  	"context"
     5  	"encoding/binary"
     6  	"reflect"
     7  
     8  	"github.com/mitchellh/mapstructure"
     9  	"github.com/pkg/errors"
    10  
    11  	"github.com/wfusion/gofusion/common/utils"
    12  	"github.com/wfusion/gofusion/common/utils/compress"
    13  	"github.com/wfusion/gofusion/common/utils/encode"
    14  	"github.com/wfusion/gofusion/common/utils/inspect"
    15  	"github.com/wfusion/gofusion/common/utils/serialize"
    16  
    17  	fusCtx "github.com/wfusion/gofusion/context"
    18  )
    19  
    20  func Unseal(src []byte, opts ...utils.OptionExtender) (ctx context.Context, dst any, ok bool, err error) {
    21  	if len(src) <= sealPrefixLength {
    22  		return defaultUnseal(src, opts...)
    23  	}
    24  
    25  	// unseal magic number
    26  	magicNumber, next := src[:4], src[4:]
    27  	if binary.LittleEndian.Uint32(magicNumber) != sealMagicNumber {
    28  		return defaultUnseal(src, opts...)
    29  	}
    30  
    31  	// unseal info
    32  	inf, next := next[:len(sealTypeNumber)], next[len(sealTypeNumber):]
    33  	switch inf[0] {
    34  	case 1:
    35  		return unsealV1(inf, next, opts...)
    36  	default:
    37  		panic(errors.Errorf("unsupported message version for unseal: %v", inf[0]))
    38  	}
    39  }
    40  
    41  func unsealV1(inf, src []byte, opts ...utils.OptionExtender) (ctx context.Context, dst any, ok bool, err error) {
    42  	opt := utils.ApplyOptions[option](opts...)
    43  	serializeType := serialize.ParseAlgorithm(serialize.Algorithm(inf[1]))
    44  	if opt.serializeType.IsValid() {
    45  		serializeType = opt.serializeType
    46  	}
    47  	compressType := compress.ParseAlgorithm(compress.Algorithm(inf[2]))
    48  	if opt.compressType.IsValid() {
    49  		compressType = opt.compressType
    50  	}
    51  
    52  	isRaw := false
    53  	if inf[3] == 1 {
    54  		isRaw = true
    55  	}
    56  
    57  	// unseal encrypted inf
    58  	encryptedInfLength := binary.LittleEndian.Uint32(inf[4:])
    59  	_, src = src[:encryptedInfLength], src[encryptedInfLength:]
    60  
    61  	// unseal context
    62  	contextLengthBytes, src := src[:8], src[8:]
    63  	contextLength := binary.LittleEndian.Uint64(contextLengthBytes)
    64  	if contextLength > 0 {
    65  		var contextBytes []byte
    66  		contextBytes, src = src[:contextLength], src[contextLength:]
    67  		ctx = fusCtx.New(fusCtx.Context(contextBytes))
    68  	}
    69  
    70  	// unseal data type
    71  	inf, src = src[:8], src[8:]
    72  	structNameLength := binary.LittleEndian.Uint64(inf)
    73  	structName, src := src[:structNameLength], src[structNameLength:]
    74  	if !isRaw && opt.dataType == nil {
    75  		if opt.dataType = inspect.TypeOf(string(structName)); opt.dataType == nil {
    76  			opt.dataType = reflect.TypeOf((*any)(nil)).Elem()
    77  		}
    78  	}
    79  
    80  	// unseal data
    81  	// unseal data length
    82  	_, src = src[:8], src[8:]
    83  	// binary.LittleEndian.Uint64(src[:8])
    84  
    85  	// unseal data
    86  	var decoded []byte
    87  	if compressType.IsValid() {
    88  		decoded, err = encode.From(src).Decode(encode.Compress(compressType)).ToBytes()
    89  	} else {
    90  		decoded = src
    91  	}
    92  	if err != nil {
    93  		return
    94  	}
    95  
    96  	if !serializeType.IsValid() {
    97  		dst = decoded
    98  	} else {
    99  		dstBuffer, cb := utils.BytesBufferPool.Get(nil)
   100  		defer cb()
   101  		dstBuffer.Write(decoded)
   102  
   103  		unmarshalFunc := serialize.UnmarshalStreamFuncByType(serializeType, opt.dataType)
   104  		if dst, err = unmarshalFunc(dstBuffer); err != nil {
   105  			return
   106  		}
   107  	}
   108  
   109  	ok = true
   110  	return
   111  }
   112  
   113  func UnsealT[T any](src []byte, opts ...utils.OptionExtender) (ctx context.Context, dst T, ok bool, err error) {
   114  	if len(src) <= sealPrefixLength {
   115  		return
   116  	}
   117  
   118  	// unseal magic number
   119  	magicNumber, src := src[:4], src[4:]
   120  	if binary.LittleEndian.Uint32(magicNumber) != sealMagicNumber {
   121  		return
   122  	}
   123  
   124  	// unseal info
   125  	inf, src := src[:len(sealTypeNumber)], src[len(sealTypeNumber):]
   126  	switch inf[0] {
   127  	case 1:
   128  		return unsealV1T[T](inf, src, opts...)
   129  	default:
   130  		panic(errors.Errorf("unsupported message version for unseal: %v", inf[0]))
   131  	}
   132  }
   133  
   134  func unsealV1T[T any](inf, src []byte, opts ...utils.OptionExtender) (ctx context.Context, dst T, ok bool, err error) {
   135  	opt := utils.ApplyOptions[option](opts...)
   136  	serializeType := serialize.ParseAlgorithm(serialize.Algorithm(inf[1]))
   137  	if opt.serializeType.IsValid() {
   138  		serializeType = opt.serializeType
   139  	}
   140  	compressType := compress.ParseAlgorithm(compress.Algorithm(inf[2]))
   141  	if opt.compressType.IsValid() {
   142  		compressType = opt.compressType
   143  	}
   144  
   145  	isRaw := false
   146  	if inf[3] == 1 {
   147  		isRaw = true
   148  	}
   149  
   150  	// unseal encrypted inf
   151  	encryptedInfLength := binary.LittleEndian.Uint32(inf[4:])
   152  	_, src = src[:encryptedInfLength], src[encryptedInfLength:]
   153  
   154  	// unseal context
   155  	contextLengthBytes, src := src[:8], src[8:]
   156  	contextLength := binary.LittleEndian.Uint64(contextLengthBytes)
   157  	if contextLength > 0 {
   158  		var contextBytes []byte
   159  		contextBytes, src = src[:contextLength], src[contextLength:]
   160  		ctx = fusCtx.New(fusCtx.Context(contextBytes))
   161  	}
   162  
   163  	// unseal data type
   164  	inf, src = src[:8], src[8:]
   165  	structNameLength := binary.LittleEndian.Uint64(inf)
   166  	structName, src := src[:structNameLength], src[structNameLength:]
   167  	if !isRaw && opt.dataType == nil {
   168  		if opt.dataType = inspect.TypeOf(string(structName)); opt.dataType == nil {
   169  			opt.dataType = reflect.TypeOf((*any)(nil)).Elem()
   170  		}
   171  	}
   172  
   173  	// unseal data
   174  	// unseal data length
   175  	_, src = src[:8], src[8:]
   176  	// binary.LittleEndian.Uint64(src[:8])
   177  
   178  	// unseal data
   179  	var decoded []byte
   180  	if compressType.IsValid() {
   181  		decoded, err = encode.From(src).Decode(encode.Compress(compressType)).ToBytes()
   182  	} else {
   183  		decoded = src
   184  	}
   185  	if err != nil {
   186  		return
   187  	}
   188  
   189  	if !serializeType.IsValid() {
   190  		dst = reflect.ValueOf(decoded).Convert(reflect.TypeOf(new(T)).Elem()).Interface().(T)
   191  	} else {
   192  		dstBuffer, cb := utils.BytesBufferPool.Get(nil)
   193  		defer cb()
   194  		dstBuffer.Write(decoded)
   195  
   196  		unmarshalFunc := serialize.UnmarshalStreamFunc[T](serializeType)
   197  		if dst, err = unmarshalFunc(dstBuffer); err != nil {
   198  			return
   199  		}
   200  	}
   201  
   202  	ok = true
   203  	return
   204  }
   205  
   206  func UnsealRaw(src []byte, opts ...utils.OptionExtender) (ctx context.Context, dst []byte, isRaw bool, err error) {
   207  	if len(src) <= sealPrefixLength {
   208  		return nil, src, true, nil
   209  	}
   210  
   211  	// unseal magic number
   212  	magicNumber, next := src[:4], src[4:]
   213  	if binary.LittleEndian.Uint32(magicNumber) != sealMagicNumber {
   214  		return nil, src, true, nil
   215  	}
   216  
   217  	// unseal info
   218  	inf, src := next[:len(sealTypeNumber)], next[len(sealTypeNumber):]
   219  	switch inf[0] {
   220  	case 1:
   221  		return unsealRawV1(inf, src, opts...)
   222  	default:
   223  		panic(errors.Errorf("unsupported message version for unseal raw: %v", inf[0]))
   224  	}
   225  	return
   226  }
   227  
   228  func unsealRawV1(inf, src []byte, opts ...utils.OptionExtender) (
   229  	ctx context.Context, dst []byte, isRaw bool, err error) {
   230  	opt := utils.ApplyOptions[option](opts...)
   231  	compressType := compress.ParseAlgorithm(compress.Algorithm(inf[2]))
   232  	if opt.compressType.IsValid() {
   233  		compressType = opt.compressType
   234  	}
   235  	if src[3] == 1 {
   236  		isRaw = true
   237  	}
   238  
   239  	// unseal encrypted inf
   240  	encryptedInfLength := binary.LittleEndian.Uint32(inf[4:])
   241  	_, src = src[:encryptedInfLength], src[encryptedInfLength:]
   242  
   243  	// unseal context
   244  	contextLengthBytes, src := src[:8], src[8:]
   245  	contextLength := binary.LittleEndian.Uint64(contextLengthBytes)
   246  	if contextLength > 0 {
   247  		var contextBytes []byte
   248  		contextBytes, src = src[:contextLength], src[contextLength:]
   249  		ctx = fusCtx.New(fusCtx.Context(contextBytes))
   250  	}
   251  
   252  	// unseal data type
   253  	inf, src = src[:8], src[8:]
   254  	structNameLength := binary.LittleEndian.Uint64(inf)
   255  	_, src = src[:structNameLength], src[structNameLength:]
   256  
   257  	// unseal data
   258  	// unseal data length
   259  	_, src = src[:8], src[8:]
   260  	// binary.LittleEndian.Uint64(src[:8])
   261  
   262  	// unseal data
   263  	if compressType.IsValid() {
   264  		dst, err = encode.From(src).Decode(encode.Compress(compressType)).ToBytes()
   265  	} else {
   266  		dst = src
   267  	}
   268  	return
   269  }
   270  
   271  func defaultUnseal(src []byte, opts ...utils.OptionExtender) (ctx context.Context, dst any, ok bool, err error) {
   272  	opt := utils.ApplyOptions[option](opts...)
   273  	if opt.compressType.IsValid() {
   274  		if src, err = encode.From(src).Decode(encode.Compress(opt.compressType)).ToBytes(); err != nil {
   275  			return
   276  		}
   277  	}
   278  	if !opt.serializeType.IsValid() {
   279  		// try to convert directly
   280  		srcVal := reflect.ValueOf(src)
   281  		if srcVal.CanConvert(opt.dataType) {
   282  			return nil, srcVal.Convert(opt.dataType).Interface(), false, nil
   283  		}
   284  
   285  		// try to map the structure
   286  		out := reflect.New(opt.dataType).Interface()
   287  		if err = mapstructure.Decode(src, out); err != nil {
   288  			return
   289  		}
   290  		dst = reflect.ValueOf(out).Elem()
   291  		return
   292  	}
   293  	unmarshalFunc := serialize.UnmarshalFuncByType(opt.serializeType, opt.dataType, serialize.JsonEscapeHTML(false))
   294  	dst, err = unmarshalFunc(src)
   295  	return
   296  }