From 47477e8fd69ca8ecdf5e708055b6280dab94d5fe Mon Sep 17 00:00:00 2001 From: irenarindos Date: Fri, 21 Apr 2023 14:41:28 -0400 Subject: [PATCH] feat(bsr): add BSR playback/conversion interfaces --- internal/bsr/bsr.go | 9 ++++++++ internal/bsr/convert/convert.go | 20 +++++++++++++++++ internal/bsr/convert/options.go | 32 ++++++++++++++++++++++++++++ internal/bsr/convert/options_test.go | 23 ++++++++++++++++++++ internal/bsr/kms/keys.go | 15 +++++++++++++ 5 files changed, 99 insertions(+) create mode 100644 internal/bsr/convert/convert.go create mode 100644 internal/bsr/convert/options.go create mode 100644 internal/bsr/convert/options_test.go diff --git a/internal/bsr/bsr.go b/internal/bsr/bsr.go index f6ebbdb559..176388f53d 100644 --- a/internal/bsr/bsr.go +++ b/internal/bsr/bsr.go @@ -138,6 +138,15 @@ func persistBsrSessionKeys(ctx context.Context, keys *kms.Keys, c *container) er return nil } +// OpenSession retrieves a BSR from storage using the sessionRecordingId and initializes it for reading. +// Encryption keys necessary for checking signed files will be unwrapped using the keyUnwrapFn +// Signature and checksum files will then be verified. +// Fields on the underlying container will be populated so that the returned Session can be used for BSR +// playback and conversion to formats such as asciinema +func OpenSession(ctx context.Context, sessionRecordingId string, f storage.FS, keyUnwrapFn kms.KeyUnwrapCallbackFunc) (*Session, error) { + panic("not implemented") +} + // NewConnection creates a Connection container for a given connection id. func (s *Session) NewConnection(ctx context.Context, meta *ConnectionMeta) (*Connection, error) { const op = "bsr.(Session).NewConnection" diff --git a/internal/bsr/convert/convert.go b/internal/bsr/convert/convert.go new file mode 100644 index 0000000000..3b11ee3e2e --- /dev/null +++ b/internal/bsr/convert/convert.go @@ -0,0 +1,20 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package convert + +import ( + "context" + "io" + + "github.com/hashicorp/boundary/internal/bsr" + "github.com/hashicorp/boundary/internal/storage" +) + +// ToAsciinema accepts a bsr.Session and will convert the underlying BSR connection or channel file to an asciinema file. +// The tempFs will be used to write the asciinema file to disk +// It returns an io.Reader to the converted asciinema file +// Supports WithChannelId() to indicate this conversion should occur on a chanel on a multiplexed session +func ToAsciinema(ctx context.Context, session bsr.Session, tempFs storage.FS, connectionId string, options ...Option) (io.Reader, error) { + panic("not implemented") +} diff --git a/internal/bsr/convert/options.go b/internal/bsr/convert/options.go new file mode 100644 index 0000000000..49bb293610 --- /dev/null +++ b/internal/bsr/convert/options.go @@ -0,0 +1,32 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package convert + +// getOpts - iterate the inbound Options and return a struct +func getOpts(opt ...Option) options { + opts := getDefaultOptions() + for _, o := range opt { + o(&opts) + } + return opts +} + +// Option - how Options are passed as arguments +type Option func(*options) + +// options = how options are represented +type options struct { + withChannelId string +} + +func getDefaultOptions() options { + return options{} +} + +// WithChannelId provides and option to specify the channelId +func WithChannelId(id string) Option { + return func(o *options) { + o.withChannelId = id + } +} diff --git a/internal/bsr/convert/options_test.go b/internal/bsr/convert/options_test.go new file mode 100644 index 0000000000..a30fec5267 --- /dev/null +++ b/internal/bsr/convert/options_test.go @@ -0,0 +1,23 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package convert + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +// Test_GetOpts provides unit tests for GetOpts and all the options +func Test_GetOpts(t *testing.T) { + t.Parallel() + t.Run("WithChannelId", func(t *testing.T) { + assert := assert.New(t) + channelId := "channel-id" + opts := getOpts(WithChannelId(channelId)) + testOpts := getDefaultOptions() + testOpts.withChannelId = channelId + assert.Equal(opts, testOpts) + }) +} diff --git a/internal/bsr/kms/keys.go b/internal/bsr/kms/keys.go index 5b483250ed..b07b6bf616 100644 --- a/internal/bsr/kms/keys.go +++ b/internal/bsr/kms/keys.go @@ -51,6 +51,21 @@ type Keys struct { l sync.RWMutex } +// WrappedKeys contains the wrapped BSR and priv keys +type WrappedKeys struct { + WrappedBsrKey *wrapping.KeyInfo + WrappedPrivKey *wrapping.KeyInfo +} + +// Unwrapped keys contains the unwrapped BSR and priv keys +type UnwrappedKeys struct { + BsrKey *wrapping.KeyInfo + PrivKey *wrapping.KeyInfo +} + +// KeyUnwrapCallbackFunc is used by OpenSession to unwrap BSR and private keys +type KeyUnwrapCallbackFunc func(WrappedKeys) (UnwrappedKeys, error) + // CreateKeys creates new bsr keys, wrapping and signing keys as required // using the provided bsrWrapper. Supported options: WithRandomReader func CreateKeys(ctx context.Context, bsrWrapper wrapping.Wrapper, sessionId string, opt ...Option) (*Keys, error) {