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 }