@@ -25,7 +25,7 @@ const (
25
25
typeRemotePublicKey tlv.Type = 11
26
26
typeMacaroonRecipe tlv.Type = 12
27
27
typeCreatedAt tlv.Type = 13
28
- typeReservedNum1 tlv.Type = 14
28
+ typeFeaturesConfig tlv.Type = 14
29
29
typeReservedNum2 tlv.Type = 15
30
30
typeRevokedAt tlv.Type = 16
31
31
@@ -42,6 +42,9 @@ const (
42
42
43
43
typePermEntity tlv.Type = 1
44
44
typePermAction tlv.Type = 2
45
+
46
+ typeFeatureName tlv.Type = 1
47
+ typeFeatureConfig tlv.Type = 2
45
48
)
46
49
47
50
// SerializeSession binary serializes the given session to the writer using the
@@ -111,7 +114,23 @@ func SerializeSession(w io.Writer, session *Session) error {
111
114
112
115
tlvRecords = append (
113
116
tlvRecords , tlv .MakePrimitiveRecord (typeCreatedAt , & createdAt ),
114
- tlv .MakePrimitiveRecord (typeRevokedAt , & revokedAt ),
117
+ )
118
+
119
+ if session .FeatureConfig != nil && len (* session .FeatureConfig ) != 0 {
120
+ tlvRecords = append (tlvRecords , tlv .MakeDynamicRecord (
121
+ typeFeaturesConfig , session .FeatureConfig ,
122
+ func () uint64 {
123
+ return recordSize (
124
+ featureConfigEncoder ,
125
+ session .FeatureConfig ,
126
+ )
127
+ },
128
+ featureConfigEncoder , featureConfigDecoder ,
129
+ ))
130
+ }
131
+
132
+ tlvRecords = append (
133
+ tlvRecords , tlv .MakePrimitiveRecord (typeRevokedAt , & revokedAt ),
115
134
)
116
135
117
136
tlvStream , err := tlv .NewStream (tlvRecords ... )
@@ -132,6 +151,7 @@ func DeserializeSession(r io.Reader) (*Session, error) {
132
151
state , typ , devServer uint8
133
152
expiry , createdAt , revokedAt uint64
134
153
macRecipe MacaroonRecipe
154
+ featureConfig FeaturesConfig
135
155
)
136
156
tlvStream , err := tlv .NewStream (
137
157
tlv .MakePrimitiveRecord (typeLabel , & label ),
@@ -153,6 +173,10 @@ func DeserializeSession(r io.Reader) (*Session, error) {
153
173
macaroonRecipeEncoder , macaroonRecipeDecoder ,
154
174
),
155
175
tlv .MakePrimitiveRecord (typeCreatedAt , & createdAt ),
176
+ tlv .MakeDynamicRecord (
177
+ typeFeaturesConfig , & featureConfig , nil ,
178
+ featureConfigEncoder , featureConfigDecoder ,
179
+ ),
156
180
tlv .MakePrimitiveRecord (typeRevokedAt , & revokedAt ),
157
181
)
158
182
if err != nil {
@@ -191,9 +215,115 @@ func DeserializeSession(r io.Reader) (*Session, error) {
191
215
)
192
216
}
193
217
218
+ if t , ok := parsedTypes [typeFeaturesConfig ]; ok && t == nil {
219
+ session .FeatureConfig = & featureConfig
220
+ }
221
+
194
222
return session , nil
195
223
}
196
224
225
+ func featureConfigEncoder (w io.Writer , val interface {}, buf * [8 ]byte ) error {
226
+ if v , ok := val .(* FeaturesConfig ); ok {
227
+ for n , config := range * v {
228
+ name := []byte (n )
229
+ config := config
230
+
231
+ var permsTLVBytes bytes.Buffer
232
+ tlvStream , err := tlv .NewStream (
233
+ tlv .MakePrimitiveRecord (typeFeatureName , & name ),
234
+ tlv .MakePrimitiveRecord (
235
+ typeFeatureConfig , & config ,
236
+ ),
237
+ )
238
+ if err != nil {
239
+ return err
240
+ }
241
+
242
+ err = tlvStream .Encode (& permsTLVBytes )
243
+ if err != nil {
244
+ return err
245
+ }
246
+
247
+ // We encode the record with a varint length followed by
248
+ // the _raw_ TLV bytes.
249
+ tlvLen := uint64 (len (permsTLVBytes .Bytes ()))
250
+ if err := tlv .WriteVarInt (w , tlvLen , buf ); err != nil {
251
+ return err
252
+ }
253
+
254
+ _ , err = w .Write (permsTLVBytes .Bytes ())
255
+ if err != nil {
256
+ return err
257
+ }
258
+ }
259
+
260
+ return nil
261
+ }
262
+
263
+ return tlv .NewTypeForEncodingErr (val , "FeaturesConfig" )
264
+ }
265
+
266
+ func featureConfigDecoder (r io.Reader , val interface {}, buf * [8 ]byte ,
267
+ l uint64 ) error {
268
+
269
+ if v , ok := val .(* FeaturesConfig ); ok {
270
+ featureConfig := make (map [string ][]byte )
271
+
272
+ // Using this information, we'll create a new limited
273
+ // reader that'll return an EOF once the end has been
274
+ // reached so the stream stops consuming bytes.
275
+ innerTlvReader := io.LimitedReader {
276
+ R : r ,
277
+ N : int64 (l ),
278
+ }
279
+
280
+ for {
281
+ // Read out the varint that encodes the size of this
282
+ // inner TLV record.
283
+ blobSize , err := tlv .ReadVarInt (& innerTlvReader , buf )
284
+ if err == io .EOF {
285
+ break
286
+ } else if err != nil {
287
+ return err
288
+ }
289
+
290
+ innerInnerTlvReader := io.LimitedReader {
291
+ R : & innerTlvReader ,
292
+ N : int64 (blobSize ),
293
+ }
294
+
295
+ var (
296
+ name []byte
297
+ config []byte
298
+ )
299
+ tlvStream , err := tlv .NewStream (
300
+ tlv .MakePrimitiveRecord (
301
+ typeFeatureName , & name ,
302
+ ),
303
+ tlv .MakePrimitiveRecord (
304
+ typeFeatureConfig , & config ,
305
+ ),
306
+ )
307
+ if err != nil {
308
+ return err
309
+ }
310
+
311
+ err = tlvStream .Decode (& innerInnerTlvReader )
312
+ if err != nil {
313
+ return err
314
+ }
315
+
316
+ featureConfig [string (name )] = config
317
+ }
318
+
319
+ * v = featureConfig
320
+
321
+ return nil
322
+ }
323
+
324
+ return tlv .NewTypeForEncodingErr (val , "FeaturesConfig" )
325
+ }
326
+
197
327
// macaroonRecipeEncoder is a custom TLV encoder for a MacaroonRecipe record.
198
328
func macaroonRecipeEncoder (w io.Writer , val interface {}, buf * [8 ]byte ) error {
199
329
if v , ok := val .(* MacaroonRecipe ); ok {
0 commit comments