Skip to content

Commit 4639e7e

Browse files
committed
session+rpcserver: add feature config to session type
1 parent 160977d commit 4639e7e

File tree

4 files changed

+159
-11
lines changed

4 files changed

+159
-11
lines changed

session/interface.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ type MacaroonRecipe struct {
4040
Caveats []macaroon.Caveat
4141
}
4242

43+
// FeaturesConfig is a map from feature name to a raw byte array which stores
44+
// any config feature config options.
45+
type FeaturesConfig map[string][]byte
46+
4347
// Session is a struct representing a long-term Terminal Connect session.
4448
type Session struct {
4549
ID ID
@@ -57,6 +61,7 @@ type Session struct {
5761
LocalPrivateKey *btcec.PrivateKey
5862
LocalPublicKey *btcec.PublicKey
5963
RemotePublicKey *btcec.PublicKey
64+
FeatureConfig *FeaturesConfig
6065
}
6166

6267
// MacaroonBaker is a function type for baking a super macaroon.
@@ -65,8 +70,8 @@ type MacaroonBaker func(ctx context.Context, rootKeyID uint64,
6570

6671
// NewSession creates a new session with the given user-defined parameters.
6772
func NewSession(label string, typ Type, expiry time.Time, serverAddr string,
68-
devServer bool, perms []bakery.Op, caveats []macaroon.Caveat) (*Session,
69-
error) {
73+
devServer bool, perms []bakery.Op, caveats []macaroon.Caveat,
74+
featureConfig FeaturesConfig) (*Session, error) {
7075

7176
_, pairingSecret, err := mailbox.NewPassphraseEntropy()
7277
if err != nil {
@@ -106,6 +111,10 @@ func NewSession(label string, typ Type, expiry time.Time, serverAddr string,
106111
}
107112
}
108113

114+
if len(featureConfig) != 0 {
115+
sess.FeatureConfig = &featureConfig
116+
}
117+
109118
return sess, nil
110119
}
111120

session/tlv.go

Lines changed: 132 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ const (
2525
typeRemotePublicKey tlv.Type = 11
2626
typeMacaroonRecipe tlv.Type = 12
2727
typeCreatedAt tlv.Type = 13
28-
typeReservedNum1 tlv.Type = 14
28+
typeFeaturesConfig tlv.Type = 14
2929
typeReservedNum2 tlv.Type = 15
3030
typeRevokedAt tlv.Type = 16
3131

@@ -42,6 +42,9 @@ const (
4242

4343
typePermEntity tlv.Type = 1
4444
typePermAction tlv.Type = 2
45+
46+
typeFeatureName tlv.Type = 1
47+
typeFeatureConfig tlv.Type = 2
4548
)
4649

4750
// SerializeSession binary serializes the given session to the writer using the
@@ -111,7 +114,23 @@ func SerializeSession(w io.Writer, session *Session) error {
111114

112115
tlvRecords = append(
113116
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),
115134
)
116135

117136
tlvStream, err := tlv.NewStream(tlvRecords...)
@@ -132,6 +151,7 @@ func DeserializeSession(r io.Reader) (*Session, error) {
132151
state, typ, devServer uint8
133152
expiry, createdAt, revokedAt uint64
134153
macRecipe MacaroonRecipe
154+
featureConfig FeaturesConfig
135155
)
136156
tlvStream, err := tlv.NewStream(
137157
tlv.MakePrimitiveRecord(typeLabel, &label),
@@ -153,6 +173,10 @@ func DeserializeSession(r io.Reader) (*Session, error) {
153173
macaroonRecipeEncoder, macaroonRecipeDecoder,
154174
),
155175
tlv.MakePrimitiveRecord(typeCreatedAt, &createdAt),
176+
tlv.MakeDynamicRecord(
177+
typeFeaturesConfig, &featureConfig, nil,
178+
featureConfigEncoder, featureConfigDecoder,
179+
),
156180
tlv.MakePrimitiveRecord(typeRevokedAt, &revokedAt),
157181
)
158182
if err != nil {
@@ -191,9 +215,115 @@ func DeserializeSession(r io.Reader) (*Session, error) {
191215
)
192216
}
193217

218+
if t, ok := parsedTypes[typeFeaturesConfig]; ok && t == nil {
219+
session.FeatureConfig = &featureConfig
220+
}
221+
194222
return session, nil
195223
}
196224

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+
197327
// macaroonRecipeEncoder is a custom TLV encoder for a MacaroonRecipe record.
198328
func macaroonRecipeEncoder(w io.Writer, val interface{}, buf *[8]byte) error {
199329
if v, ok := val.(*MacaroonRecipe); ok {

session/tlv_test.go

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,12 @@ var (
5151
// and deserialized from and to the tlv binary format successfully.
5252
func TestSerializeDeserializeSession(t *testing.T) {
5353
tests := []struct {
54-
name string
55-
sessType Type
56-
revokedAt time.Time
57-
perms []bakery.Op
58-
caveats []macaroon.Caveat
54+
name string
55+
sessType Type
56+
revokedAt time.Time
57+
perms []bakery.Op
58+
caveats []macaroon.Caveat
59+
featureConfig map[string][]byte
5960
}{
6061
{
6162
name: "session 1",
@@ -70,6 +71,14 @@ func TestSerializeDeserializeSession(t *testing.T) {
7071
perms: perms,
7172
caveats: caveats,
7273
},
74+
{
75+
name: "session 3",
76+
sessType: TypeMacaroonCustom,
77+
featureConfig: map[string][]byte{
78+
"AutoFees": {1, 2, 3, 4},
79+
"AutoSomething": {4, 3, 4, 5, 6, 6},
80+
},
81+
},
7382
}
7483

7584
for _, test := range tests {
@@ -78,7 +87,7 @@ func TestSerializeDeserializeSession(t *testing.T) {
7887
test.name, test.sessType,
7988
time.Date(99999, 1, 1, 0, 0, 0, 0, time.UTC),
8089
"foo.bar.baz:1234", true, test.perms,
81-
test.caveats,
90+
test.caveats, test.featureConfig,
8291
)
8392
require.NoError(t, err)
8493

session_rpcserver.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ func (s *sessionRpcServer) AddSession(_ context.Context,
249249

250250
sess, err := session.NewSession(
251251
req.Label, typ, expiry, req.MailboxServerAddr, req.DevServer,
252-
uniquePermissions, caveats,
252+
uniquePermissions, caveats, nil,
253253
)
254254
if err != nil {
255255
return nil, fmt.Errorf("error creating new session: %v", err)

0 commit comments

Comments
 (0)