refact(bsr): Use JSON for session meta and summary data
The session metadata is provided all at once when a new bsr is opened. While the session recording metadata records metadata about a recording while the recording is happening, notably it records each time a new connection occurs. The nested structure of the session metadata does not lend itself to the append-only syntax of the recording meta file. In addition we do not want to mix different kinds of metadata together. Thus the session metadata is now written to a separate file in the BSR, and is written as JSON which better handles the nested structure and allows for simpler encoding/decoding. Similarly the summary files are intended to be written to as containers close and have been switched to JSON.
This commit is contained in:
50 files changed
+738
-1718
No files matched your search
+53
-570
@@ -4,13 +4,11 @@
|
||||
package bsr
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/bsr/internal/checksum"
|
||||
"github.com/hashicorp/boundary/internal/bsr/internal/is"
|
||||
@@ -21,11 +19,12 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
bsrFile = "%s.bsr"
|
||||
connectionFile = "%s.connection"
|
||||
channelFile = "%s.channel"
|
||||
messagesFile = "messages-%s.data"
|
||||
requestsFile = "requests-%s.data"
|
||||
bsrFile = "%s.bsr"
|
||||
connectionFile = "%s.connection"
|
||||
channelFile = "%s.channel"
|
||||
messagesFile = "messages-%s.data"
|
||||
requestsFile = "requests-%s.data"
|
||||
sessionMetaFile = "session-meta.json"
|
||||
|
||||
bsrPubKeyFile = "bsrKey.pub"
|
||||
wrappedBsrKeyFile = "wrappedBsrKey"
|
||||
@@ -34,479 +33,38 @@ const (
|
||||
pubKeySelfSignatureFile = "pubKeySelfSignature.sign"
|
||||
)
|
||||
|
||||
// decodeSessionMeta will populate a SessionMeta for an opened BSR Session
|
||||
// TODO Unmarshal without brute force
|
||||
func decodeSessionMeta(ctx context.Context, r io.Reader) (*SessionMeta, error) {
|
||||
const op = "bsr.decodeSessionMeta"
|
||||
|
||||
switch {
|
||||
case r == nil:
|
||||
return nil, fmt.Errorf("%s: missing session meta file: %w", op, ErrInvalidParameter)
|
||||
}
|
||||
|
||||
connections := make(map[string]bool)
|
||||
s := &SessionMeta{}
|
||||
user := &User{Scope: Scope{}}
|
||||
target := &Target{Scope: Scope{}}
|
||||
worker := &Worker{}
|
||||
sHost := &StaticHost{Catalog: StaticHostCatalog{}}
|
||||
dHost := &DynamicHost{Catalog: DynamicHostCatalog{}}
|
||||
staticCredStore := make(map[string]StaticCredentialStore)
|
||||
scStoreToJsonCreds := make(map[string]StaticJsonCredential)
|
||||
scStoreToUPCreds := make(map[string]StaticUsernamePasswordCredential)
|
||||
scStoreToSshCreds := make(map[string]StaticSshPrivateKeyCredential)
|
||||
vaultCredStore := make(map[string]VaultCredentialStore)
|
||||
vsStoreToVaultLib := make(map[string]VaultLibrary)
|
||||
vsStoreToVaultSshCertLib := make(map[string]VaultSshCertLibrary)
|
||||
|
||||
scanner := bufio.NewScanner(r)
|
||||
for scanner.Scan() {
|
||||
l := scanner.Text()
|
||||
if len(l) == 0 {
|
||||
continue
|
||||
}
|
||||
k, v, ok := strings.Cut(l, ":")
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%s: session meta file contains invalid entry; expecting k: v pair:%s", op, l)
|
||||
}
|
||||
v = strings.TrimSpace(v)
|
||||
switch {
|
||||
case k == "id":
|
||||
s.Id = v
|
||||
case k == "protocol":
|
||||
s.Protocol = Protocol(v)
|
||||
|
||||
// User
|
||||
case k == "user_publicId":
|
||||
user.PublicId = v
|
||||
case k == "user_name":
|
||||
user.Name = v
|
||||
case k == "user_description":
|
||||
user.Description = v
|
||||
case k == "user_scope_publicId":
|
||||
user.Scope.PublicId = v
|
||||
case k == "user_scope_name":
|
||||
user.Scope.Name = v
|
||||
case k == "user_scope_description":
|
||||
user.Scope.Description = v
|
||||
case k == "user_scope_type":
|
||||
user.Scope.Type = v
|
||||
case k == "user_scope_parentId":
|
||||
user.Scope.ParentId = v
|
||||
case k == "user_scope_primaryAuthMethod":
|
||||
user.Scope.PrimaryAuthMethodId = v
|
||||
|
||||
// Target
|
||||
case k == "target_publicId":
|
||||
target.PublicId = v
|
||||
case k == "target_name":
|
||||
target.Name = v
|
||||
case k == "target_description":
|
||||
target.Description = v
|
||||
case k == "target_defaultPort":
|
||||
dp, err := strconv.Atoi(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
target.DefaultPort = uint32(dp)
|
||||
case k == "target_sessionMaxSeconds":
|
||||
sms, err := strconv.Atoi(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
target.SessionMaxSeconds = uint32(sms)
|
||||
case k == "target_sessionConnectionLimit":
|
||||
scl, err := strconv.Atoi(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
target.SessionConnectionLimit = int32(scl)
|
||||
case k == "target_workerFilter":
|
||||
target.WorkerFilter = v
|
||||
case k == "target_egressWorkerFilter":
|
||||
target.EgressWorkerFilter = v
|
||||
case k == "target_ingressWorkerFilter":
|
||||
target.IngressWorkerFilter = v
|
||||
case k == "target_scope_publicId":
|
||||
target.Scope.PublicId = v
|
||||
case k == "target_scope_name":
|
||||
target.Scope.Name = v
|
||||
case k == "target_scope_description":
|
||||
target.Scope.Description = v
|
||||
case k == "target_scope_type":
|
||||
target.Scope.Type = v
|
||||
case k == "target_scope_parentId":
|
||||
target.Scope.ParentId = v
|
||||
case k == "target_scope_primaryAuthMethod":
|
||||
target.Scope.PrimaryAuthMethodId = v
|
||||
|
||||
// Worker
|
||||
case k == "worker_publicId":
|
||||
worker.PublicId = v
|
||||
case k == "worker_version":
|
||||
worker.Version = v
|
||||
case k == "worker_sha":
|
||||
worker.Sha = v
|
||||
|
||||
// Static Host
|
||||
case k == "staticHost_publicId":
|
||||
sHost.PublicId = v
|
||||
case k == "staticHost_name":
|
||||
sHost.Name = v
|
||||
case k == "staticHost_description":
|
||||
sHost.Description = v
|
||||
case k == "staticHost_address":
|
||||
sHost.Address = v
|
||||
case k == "staticHostCatalog_publicId":
|
||||
sHost.Catalog.PublicId = v
|
||||
case k == "staticHostCatalog_projectId":
|
||||
sHost.Catalog.ProjectId = v
|
||||
case k == "staticHostCatalog_name":
|
||||
sHost.Catalog.Name = v
|
||||
case k == "staticHostCatalog_description":
|
||||
sHost.Catalog.Description = v
|
||||
|
||||
// Dynamic Host
|
||||
case k == "dynamicHost_publicId":
|
||||
dHost.PublicId = v
|
||||
case k == "dynamicHost_name":
|
||||
dHost.Name = v
|
||||
case k == "dynamicHost_description":
|
||||
dHost.Description = v
|
||||
case k == "dynamicHost_externalId":
|
||||
dHost.ExternalId = v
|
||||
case k == "dynamicHostCatalog_publicId":
|
||||
dHost.Catalog.PublicId = v
|
||||
case k == "dynamicHostCatalog_projectId":
|
||||
dHost.Catalog.ProjectId = v
|
||||
case k == "dynamicHostCatalog_name":
|
||||
dHost.Catalog.Name = v
|
||||
case k == "dynamicHostCatalog_description":
|
||||
dHost.Catalog.Description = v
|
||||
case k == "dynamicHostCatalog_pluginId":
|
||||
dHost.Catalog.PluginId = v
|
||||
case k == "dynamicHostCatalog_attributes":
|
||||
dHost.Catalog.Attributes = v
|
||||
|
||||
// Static Credential Store
|
||||
case strings.Contains(k, "staticCredentialStore_"):
|
||||
idx := strings.Index(k, "_staticCredentialStore")
|
||||
if idx == -1 {
|
||||
break
|
||||
}
|
||||
sId := k[:idx]
|
||||
scs, ok := staticCredStore[sId]
|
||||
if !ok {
|
||||
scs = StaticCredentialStore{
|
||||
PublicId: sId,
|
||||
}
|
||||
}
|
||||
switch {
|
||||
case strings.Contains(k, "staticJsonCredential"):
|
||||
idxEnd := strings.Index(k, "_staticJsonCredential")
|
||||
idxStart := strings.Index(k, "_credential_") + len("_credential_")
|
||||
if idxStart == -1 || idxEnd == -1 {
|
||||
break
|
||||
}
|
||||
credId := k[idxStart:idxEnd]
|
||||
// credstoreid - staticJsonCredentialid in the map
|
||||
mapId := fmt.Sprintf("%s-%s", sId, credId)
|
||||
c, ok := scStoreToJsonCreds[mapId]
|
||||
if !ok {
|
||||
c = StaticJsonCredential{
|
||||
PublicId: credId,
|
||||
}
|
||||
}
|
||||
switch {
|
||||
case strings.Contains(k, "_projectId"):
|
||||
c.ProjectId = v
|
||||
case strings.Contains(k, "_name"):
|
||||
c.Name = v
|
||||
case strings.Contains(k, "_description"):
|
||||
c.Description = v
|
||||
case strings.Contains(k, "_objectHmac"):
|
||||
c.ObjectHmac = []byte(v)
|
||||
}
|
||||
scStoreToJsonCreds[mapId] = c
|
||||
case strings.Contains(k, "staticUsernamePasswordCredential"):
|
||||
idxEnd := strings.Index(k, "_staticJUsernamePasswordCredential")
|
||||
idxStart := strings.Index(k, "_credential_") + len("_credential_")
|
||||
if idxStart == -1 || idxEnd == -1 {
|
||||
break
|
||||
}
|
||||
credId := k[idxStart:idxEnd]
|
||||
// credstoreid - UsernamePasswordCredentialid in the map
|
||||
mapId := fmt.Sprintf("%s-%s", sId, credId)
|
||||
c, ok := scStoreToUPCreds[mapId]
|
||||
if !ok {
|
||||
c = StaticUsernamePasswordCredential{
|
||||
PublicId: credId,
|
||||
}
|
||||
}
|
||||
switch {
|
||||
case strings.Contains(k, "_projectId"):
|
||||
c.ProjectId = v
|
||||
case strings.Contains(k, "_name"):
|
||||
c.Name = v
|
||||
case strings.Contains(k, "_description"):
|
||||
c.Description = v
|
||||
case strings.Contains(k, "_passwordHmac"):
|
||||
c.PasswordHmac = []byte(v)
|
||||
}
|
||||
scStoreToUPCreds[mapId] = c
|
||||
case strings.Contains(k, "staticSshPrivateKeyCredential"):
|
||||
idxEnd := strings.Index(k, "_staticSshPrivateKeyCredential")
|
||||
idxStart := strings.Index(k, "_credential_") + len("_credential_")
|
||||
if idxStart == -1 || idxEnd == -1 {
|
||||
break
|
||||
}
|
||||
credId := k[idxStart:idxEnd]
|
||||
// credstoreid - staticSshPrivateKeyid in the map
|
||||
mapId := fmt.Sprintf("%s-%s", sId, credId)
|
||||
c, ok := scStoreToSshCreds[mapId]
|
||||
if !ok {
|
||||
c = StaticSshPrivateKeyCredential{
|
||||
PublicId: credId,
|
||||
}
|
||||
}
|
||||
switch {
|
||||
case strings.Contains(k, "_projectId"):
|
||||
c.ProjectId = v
|
||||
case strings.Contains(k, "_name"):
|
||||
c.Name = v
|
||||
case strings.Contains(k, "_description"):
|
||||
c.Description = v
|
||||
case strings.Contains(k, "_privateKeyHmac"):
|
||||
c.PrivateKeyHmac = []byte(v)
|
||||
case strings.Contains(k, "_privateKeyPassphraseHmac"):
|
||||
c.PrivateKeyPassphraseHmac = []byte(v)
|
||||
}
|
||||
scStoreToSshCreds[mapId] = c
|
||||
case strings.Contains(k, "_projectId"):
|
||||
scs.ProjectId = v
|
||||
case strings.Contains(k, "_name"):
|
||||
scs.Name = v
|
||||
case strings.Contains(k, "_description"):
|
||||
scs.Description = v
|
||||
}
|
||||
staticCredStore[sId] = scs
|
||||
|
||||
// Vault Credential Store
|
||||
case strings.Contains(k, "vaultCredentialStore_"):
|
||||
idx := strings.Index(k, "_vaultCredentialStore")
|
||||
if idx == -1 {
|
||||
break
|
||||
}
|
||||
vId := k[:idx]
|
||||
vcs, ok := vaultCredStore[vId]
|
||||
if !ok {
|
||||
vcs = VaultCredentialStore{
|
||||
PublicId: vId,
|
||||
}
|
||||
}
|
||||
switch {
|
||||
case strings.Contains(k, "vaultLibrary"):
|
||||
idxEnd := strings.Index(k, "_vaultLibrary")
|
||||
idxStart := strings.Index(k, "_credential_") + len("_credential_")
|
||||
if idxStart == -1 || idxEnd == -1 {
|
||||
break
|
||||
}
|
||||
credId := k[idxStart:idxEnd]
|
||||
// credstoreid - vaultLibraryid in the map
|
||||
mapId := fmt.Sprintf("%s-%s", vId, credId)
|
||||
c, ok := vsStoreToVaultLib[mapId]
|
||||
if !ok {
|
||||
c = VaultLibrary{
|
||||
PublicId: credId,
|
||||
}
|
||||
}
|
||||
switch {
|
||||
case strings.Contains(k, "_projectId"):
|
||||
c.ProjectId = v
|
||||
case strings.Contains(k, "_name"):
|
||||
c.Name = v
|
||||
case strings.Contains(k, "_description"):
|
||||
c.Description = v
|
||||
case strings.Contains(k, "_vaultPath"):
|
||||
c.VaultPath = v
|
||||
case strings.Contains(k, "_httpMethod"):
|
||||
c.HttpMethod = v
|
||||
case strings.Contains(k, "_httpRequestBody"):
|
||||
c.HttpRequestBody = []byte(v)
|
||||
case strings.Contains(k, "_credentialType"):
|
||||
c.CredentialType = v
|
||||
}
|
||||
vsStoreToVaultLib[mapId] = c
|
||||
case strings.Contains(k, "vaultSshCertLibrary"):
|
||||
idxEnd := strings.Index(k, "_vaultSshCertLibrary")
|
||||
idxStart := strings.Index(k, "_credential_") + len("_credential_")
|
||||
if idxStart == -1 || idxEnd == -1 {
|
||||
break
|
||||
}
|
||||
credId := k[idxStart:idxEnd]
|
||||
// credstoreid - vaultSshCertLibraryid in the map
|
||||
mapId := fmt.Sprintf("%s-%s", vId, credId)
|
||||
c, ok := vsStoreToVaultSshCertLib[mapId]
|
||||
if !ok {
|
||||
c = VaultSshCertLibrary{
|
||||
PublicId: credId,
|
||||
}
|
||||
}
|
||||
switch {
|
||||
case strings.Contains(k, "_projectId"):
|
||||
c.ProjectId = v
|
||||
case strings.Contains(k, "_username"):
|
||||
c.Username = v
|
||||
case strings.Contains(k, "_name"):
|
||||
c.Name = v
|
||||
case strings.Contains(k, "_description"):
|
||||
c.Description = v
|
||||
case strings.Contains(k, "_vaultPath"):
|
||||
c.VaultPath = v
|
||||
case strings.Contains(k, "_keyType"):
|
||||
c.KeyType = v
|
||||
case strings.Contains(k, "_keyBits"):
|
||||
var err error
|
||||
c.KeyBits, err = strconv.Atoi(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case strings.Contains(k, "_ttl"):
|
||||
c.Ttl = v
|
||||
case strings.Contains(k, "_criticalOptions"):
|
||||
c.CriticalOptions = []byte(v)
|
||||
case strings.Contains(k, "_extensions"):
|
||||
c.Extensions = []byte(v)
|
||||
case strings.Contains(k, "_credentialType"):
|
||||
c.CredentialType = v
|
||||
}
|
||||
vsStoreToVaultSshCertLib[mapId] = c
|
||||
case strings.Contains(k, "_projectId"):
|
||||
vcs.ProjectId = v
|
||||
case strings.Contains(k, "_namespace"):
|
||||
vcs.Namespace = v
|
||||
case strings.Contains(k, "_name"):
|
||||
vcs.Name = v
|
||||
case strings.Contains(k, "_description"):
|
||||
vcs.Description = v
|
||||
case strings.Contains(k, "_vaultAddress"):
|
||||
vcs.VaultAddress = v
|
||||
|
||||
case strings.Contains(k, "_tlsServerName"):
|
||||
vcs.TlsServerName = v
|
||||
case strings.Contains(k, "_tlsSkipVerify"):
|
||||
var err error
|
||||
vcs.TlsSkipVerify, err = strconv.ParseBool(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case strings.Contains(k, "_workerFilter"):
|
||||
vcs.WorkerFilter = v
|
||||
}
|
||||
vaultCredStore[vId] = vcs
|
||||
|
||||
// connections
|
||||
case k == "connection":
|
||||
connections[v] = true
|
||||
}
|
||||
}
|
||||
|
||||
s.Target = target
|
||||
s.Worker = worker
|
||||
s.User = user
|
||||
if sHost.PublicId != "" {
|
||||
s.StaticHost = sHost
|
||||
}
|
||||
if dHost.PublicId != "" {
|
||||
s.DynamicHost = dHost
|
||||
}
|
||||
|
||||
for k, v := range scStoreToJsonCreds {
|
||||
scId, _, ok := strings.Cut(k, "-")
|
||||
if ok {
|
||||
staticCred := staticCredStore[scId]
|
||||
staticCred.Credentials = append(staticCred.Credentials, v)
|
||||
staticCredStore[scId] = staticCred
|
||||
}
|
||||
}
|
||||
for k, v := range scStoreToUPCreds {
|
||||
scId, _, ok := strings.Cut(k, "-")
|
||||
if ok {
|
||||
staticCred := staticCredStore[scId]
|
||||
staticCred.Credentials = append(staticCred.Credentials, v)
|
||||
staticCredStore[scId] = staticCred
|
||||
}
|
||||
}
|
||||
for k, v := range scStoreToSshCreds {
|
||||
scId, _, ok := strings.Cut(k, "-")
|
||||
if ok {
|
||||
staticCred := staticCredStore[scId]
|
||||
staticCred.Credentials = append(staticCred.Credentials, v)
|
||||
staticCredStore[scId] = staticCred
|
||||
}
|
||||
}
|
||||
scStores := make([]StaticCredentialStore, 0)
|
||||
for _, v := range staticCredStore {
|
||||
scStores = append(scStores, v)
|
||||
}
|
||||
|
||||
for k, v := range vsStoreToVaultSshCertLib {
|
||||
vlId, _, ok := strings.Cut(k, "-")
|
||||
if ok {
|
||||
vaultLib := vaultCredStore[vlId]
|
||||
vaultLib.CredentialLibraries = append(vaultLib.CredentialLibraries, v)
|
||||
vaultCredStore[vlId] = vaultLib
|
||||
}
|
||||
}
|
||||
for k, v := range vsStoreToVaultLib {
|
||||
vlId, _, ok := strings.Cut(k, "-")
|
||||
if ok {
|
||||
vaultLib := vaultCredStore[vlId]
|
||||
vaultLib.CredentialLibraries = append(vaultLib.CredentialLibraries, v)
|
||||
vaultCredStore[vlId] = vaultLib
|
||||
}
|
||||
}
|
||||
vcStores := make([]VaultCredentialStore, 0)
|
||||
for _, v := range vaultCredStore {
|
||||
vcStores = append(vcStores, v)
|
||||
}
|
||||
|
||||
s.StaticCredentialStore = scStores
|
||||
s.VaultCredentialStore = vcStores
|
||||
s.connections = connections
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// Session is the top level container in a bsr that contains the files for
|
||||
// a recorded session.
|
||||
type Session struct {
|
||||
*container
|
||||
multiplexed bool
|
||||
|
||||
Meta *SessionMeta
|
||||
Meta *SessionRecordingMeta
|
||||
SessionMeta *SessionMeta
|
||||
}
|
||||
|
||||
// NewSession creates a Session container for a given session id.
|
||||
func NewSession(ctx context.Context, meta *SessionMeta, f storage.FS, keys *kms.Keys, options ...Option) (*Session, error) {
|
||||
func NewSession(ctx context.Context, meta *SessionRecordingMeta, sessionMeta *SessionMeta, f storage.FS, keys *kms.Keys, options ...Option) (*Session, error) {
|
||||
const op = "bsr.NewSession"
|
||||
|
||||
switch {
|
||||
case is.Nil(meta):
|
||||
return nil, fmt.Errorf("%s: missing meta: %w", op, ErrInvalidParameter)
|
||||
case is.Nil(sessionMeta):
|
||||
return nil, fmt.Errorf("%s: missing session meta: %w", op, ErrInvalidParameter)
|
||||
case meta.Id == "":
|
||||
return nil, fmt.Errorf("%s: missing session id: %w", op, ErrInvalidParameter)
|
||||
case is.Nil(meta.StaticHost) && is.Nil(meta.DynamicHost):
|
||||
case is.Nil(sessionMeta.StaticHost) && is.Nil(sessionMeta.DynamicHost):
|
||||
return nil, fmt.Errorf("%s: missing session host information: %w", op, ErrInvalidParameter)
|
||||
case !is.Nil(meta.StaticHost) && !is.Nil(meta.DynamicHost):
|
||||
return nil, fmt.Errorf("%s: meta cannot contain both static and dynamic host information: %w", op, ErrInvalidParameter)
|
||||
case len(meta.StaticCredentialStore) == 0 && len(meta.VaultCredentialStore) == 0:
|
||||
case !is.Nil(sessionMeta.StaticHost) && !is.Nil(sessionMeta.DynamicHost):
|
||||
return nil, fmt.Errorf("%s: sessionMeta cannot contain both static and dynamic host information: %w", op, ErrInvalidParameter)
|
||||
case len(sessionMeta.StaticCredentialStore) == 0 && len(sessionMeta.VaultCredentialStore) == 0:
|
||||
return nil, fmt.Errorf("%s: missing credential information: %w", op, ErrInvalidParameter)
|
||||
case is.Nil(meta.User):
|
||||
case is.Nil(sessionMeta.User):
|
||||
return nil, fmt.Errorf("%s: missing session user: %w", op, ErrInvalidParameter)
|
||||
case is.Nil(meta.Target):
|
||||
case is.Nil(sessionMeta.Target):
|
||||
return nil, fmt.Errorf("%s: missing session target: %w", op, ErrInvalidParameter)
|
||||
case is.Nil(meta.Worker):
|
||||
case is.Nil(sessionMeta.Worker):
|
||||
return nil, fmt.Errorf("%s: missing session worker: %w", op, ErrInvalidParameter)
|
||||
case is.Nil(f):
|
||||
return nil, fmt.Errorf("%s: missing storage fs: %w", op, ErrInvalidParameter)
|
||||
@@ -532,6 +90,23 @@ func NewSession(ctx context.Context, meta *SessionMeta, f storage.FS, keys *kms.
|
||||
return nil, errors.Join(err, fmt.Errorf("%s: %w", op, ErrBsrKeyPersistenceFailure))
|
||||
}
|
||||
|
||||
sm, err := nc.create(ctx, sessionMetaFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
smw, err := checksum.NewFile(ctx, sm, nc.checksums)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
enc := json.NewEncoder(smw)
|
||||
if err := enc.Encode(sessionMeta); err != nil {
|
||||
smw.Close()
|
||||
return nil, err
|
||||
}
|
||||
if err := smw.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = meta.writeMeta(ctx, nc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -541,6 +116,7 @@ func NewSession(ctx context.Context, meta *SessionMeta, f storage.FS, keys *kms.
|
||||
container: nc,
|
||||
multiplexed: opts.withSupportsMultiplex,
|
||||
Meta: meta,
|
||||
SessionMeta: sessionMeta,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -618,12 +194,12 @@ func OpenSession(ctx context.Context, sessionRecordingId string, f storage.FS, k
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Load and verify session metadata
|
||||
// Load and verify recording metadata
|
||||
sha256Reader, err := crypto.NewSha256SumReader(ctx, cc.metaFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: %w", op, err)
|
||||
}
|
||||
sm, err := decodeSessionMeta(ctx, sha256Reader)
|
||||
meta, err := decodeSessionRecordingMeta(ctx, sha256Reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -632,9 +208,15 @@ func OpenSession(ctx context.Context, sessionRecordingId string, f storage.FS, k
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sessionMeta := &SessionMeta{}
|
||||
if err := cc.decodeJsonFile(ctx, sessionMetaFile, sessionMeta); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
session := &Session{
|
||||
container: cc,
|
||||
Meta: sm,
|
||||
container: cc,
|
||||
Meta: meta,
|
||||
SessionMeta: sessionMeta,
|
||||
}
|
||||
|
||||
return session, nil
|
||||
@@ -645,66 +227,17 @@ func (s *Session) Close(ctx context.Context) error {
|
||||
return s.container.close(ctx)
|
||||
}
|
||||
|
||||
// ConnectionMeta contains metadata about a connection in a BSR.
|
||||
type ConnectionMeta struct {
|
||||
Id string
|
||||
channels map[string]bool
|
||||
}
|
||||
|
||||
func (c ConnectionMeta) isValid() bool {
|
||||
switch {
|
||||
case c.Id == "":
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Connection is a container in a bsr for a specific connection in a session
|
||||
// container. It contains the files for the recorded connection.
|
||||
type Connection struct {
|
||||
*container
|
||||
multiplexed bool
|
||||
|
||||
Meta *ConnectionMeta
|
||||
}
|
||||
|
||||
// decodeConnectionMeta will populate the ConnectionMeta for a BSR Connection
|
||||
// TODO Unmarshal without brute force
|
||||
func decodeConnectionMeta(ctx context.Context, r io.Reader) (*ConnectionMeta, error) {
|
||||
const op = "bsr.decodeConnectionMeta"
|
||||
|
||||
switch {
|
||||
case r == nil:
|
||||
return nil, fmt.Errorf("%s: missing connection meta file: %w", op, ErrInvalidParameter)
|
||||
}
|
||||
c := &ConnectionMeta{}
|
||||
channels := make(map[string]bool)
|
||||
scanner := bufio.NewScanner(r)
|
||||
for scanner.Scan() {
|
||||
l := scanner.Text()
|
||||
if len(l) == 0 {
|
||||
continue
|
||||
}
|
||||
k, v, ok := strings.Cut(l, ":")
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%s: connection meta file contains invalid entry; expecting k: v pair:%s", op, l)
|
||||
}
|
||||
v = strings.TrimSpace(v)
|
||||
switch {
|
||||
case k == "id":
|
||||
c.Id = v
|
||||
case k == "channel":
|
||||
channels[v] = true
|
||||
}
|
||||
}
|
||||
c.channels = channels
|
||||
|
||||
return c, nil
|
||||
Meta *ConnectionRecordingMeta
|
||||
}
|
||||
|
||||
// NewConnection creates a Connection container for a given connection id.
|
||||
func (s *Session) NewConnection(ctx context.Context, meta *ConnectionMeta) (*Connection, error) {
|
||||
func (s *Session) NewConnection(ctx context.Context, meta *ConnectionRecordingMeta) (*Connection, error) {
|
||||
const op = "bsr.(Session).NewConnection"
|
||||
|
||||
switch {
|
||||
@@ -770,7 +303,7 @@ func (s *Session) OpenConnection(ctx context.Context, connId string) (*Connectio
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: %w", op, err)
|
||||
}
|
||||
sm, err := decodeConnectionMeta(ctx, sha256Reader)
|
||||
sm, err := decodeConnectionRecordingMeta(ctx, sha256Reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -787,58 +320,8 @@ func (s *Session) OpenConnection(ctx context.Context, connId string) (*Connectio
|
||||
return connection, nil
|
||||
}
|
||||
|
||||
// ChannelMeta contains metadata about a channel in a BSR.
|
||||
type ChannelMeta struct {
|
||||
Id string
|
||||
Type string
|
||||
}
|
||||
|
||||
func (c ChannelMeta) isValid() bool {
|
||||
switch {
|
||||
case c.Id == "":
|
||||
return false
|
||||
case c.Type == "":
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// decodeChannelMeta will populate the ChannelMeta for a BSR Channel
|
||||
// TODO Unmarshal without brute force
|
||||
func decodeChannelMeta(ctx context.Context, r io.Reader) (*ChannelMeta, error) {
|
||||
const op = "bsr.decodeChannelMeta"
|
||||
|
||||
switch {
|
||||
case r == nil:
|
||||
return nil, fmt.Errorf("%s: missing channel meta file: %w", op, ErrInvalidParameter)
|
||||
}
|
||||
|
||||
c := &ChannelMeta{}
|
||||
scanner := bufio.NewScanner(r)
|
||||
for scanner.Scan() {
|
||||
l := scanner.Text()
|
||||
if len(l) == 0 {
|
||||
continue
|
||||
}
|
||||
k, v, ok := strings.Cut(l, ":")
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%s: channel meta file contains invalid entry; expecting k: v pair:%s", op, l)
|
||||
}
|
||||
v = strings.TrimSpace(v)
|
||||
switch {
|
||||
case k == "id":
|
||||
c.Id = v
|
||||
case k == "channelType":
|
||||
c.Type = v
|
||||
}
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// NewChannel creates a Channel container for a given channel id.
|
||||
func (c *Connection) NewChannel(ctx context.Context, meta *ChannelMeta) (*Channel, error) {
|
||||
func (c *Connection) NewChannel(ctx context.Context, meta *ChannelRecordingMeta) (*Channel, error) {
|
||||
const op = "bsr.(Connection).NewChannel"
|
||||
|
||||
if !c.multiplexed {
|
||||
@@ -908,7 +391,7 @@ func (c *Connection) OpenChannel(ctx context.Context, chanId string) (*Channel,
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: %w", op, err)
|
||||
}
|
||||
sm, err := decodeChannelMeta(ctx, sha256Reader)
|
||||
sm, err := decodeChannelRecordingMeta(ctx, sha256Reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -979,7 +462,7 @@ func (c *Connection) Close(ctx context.Context) error {
|
||||
type Channel struct {
|
||||
*container
|
||||
|
||||
Meta *ChannelMeta
|
||||
Meta *ChannelRecordingMeta
|
||||
}
|
||||
|
||||
// Close closes the Channel container.
|
||||
|
||||
@@ -10,7 +10,9 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/bsr/internal/fstest"
|
||||
"github.com/hashicorp/boundary/internal/bsr/kms"
|
||||
"github.com/hashicorp/boundary/internal/storage"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gopkg.in/square/go-jose.v2/json"
|
||||
)
|
||||
|
||||
func TestPopulateMeta(t *testing.T) {
|
||||
@@ -19,34 +21,42 @@ func TestPopulateMeta(t *testing.T) {
|
||||
keys, err := kms.CreateKeys(ctx, kms.TestWrapper(t), "session")
|
||||
require.NoError(t, err)
|
||||
|
||||
sessionId := "session"
|
||||
sessionProtocol := Protocol("TEST")
|
||||
sessionId := "s_01234567890"
|
||||
srm := &SessionRecordingMeta{
|
||||
Id: "sr_012344567890",
|
||||
Protocol: Protocol("TEST"),
|
||||
}
|
||||
|
||||
// Populate session meta
|
||||
sessionMeta := TestSessionMeta(sessionId, sessionProtocol)
|
||||
s, err := NewSession(ctx, sessionMeta, &fstest.MemFS{}, keys, WithSupportsMultiplex(true))
|
||||
sessionMeta := TestSessionMeta(sessionId)
|
||||
s, err := NewSession(ctx, srm, sessionMeta, &fstest.MemFS{}, keys, WithSupportsMultiplex(true))
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, s)
|
||||
|
||||
// Reset meta and populate it from the meta file
|
||||
s.Meta = &SessionMeta{}
|
||||
sm, err := decodeSessionMeta(ctx, s.container.meta)
|
||||
s.Meta = &SessionRecordingMeta{}
|
||||
sm, err := decodeSessionRecordingMeta(ctx, s.container.meta)
|
||||
require.NoError(t, err)
|
||||
s.Meta = sm
|
||||
require.Equal(t, s.Meta.Id, sessionId)
|
||||
require.Equal(t, s.Meta.Protocol, sessionProtocol)
|
||||
require.Equal(t, s.Meta.Target, sessionMeta.Target)
|
||||
require.Equal(t, s.Meta.User, sessionMeta.User)
|
||||
require.Equal(t, s.Meta.StaticHost, sessionMeta.StaticHost)
|
||||
require.Equal(t, s.Meta.Id, srm.Id)
|
||||
require.Equal(t, s.Meta.Protocol, srm.Protocol)
|
||||
|
||||
gotSessionMeta := &SessionMeta{}
|
||||
r, err := s.container.container.OpenFile(ctx, sessionMetaFile)
|
||||
require.NoError(t, err)
|
||||
dec := json.NewDecoder(r)
|
||||
err = dec.Decode(gotSessionMeta)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, sessionMeta, gotSessionMeta)
|
||||
|
||||
// Populate connection meta
|
||||
connectionId := "connection"
|
||||
c, err := s.NewConnection(ctx, &ConnectionMeta{Id: connectionId})
|
||||
c, err := s.NewConnection(ctx, &ConnectionRecordingMeta{Id: connectionId})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, c)
|
||||
|
||||
c.Meta = &ConnectionMeta{}
|
||||
cm, err := decodeConnectionMeta(ctx, c.container.meta)
|
||||
c.Meta = &ConnectionRecordingMeta{}
|
||||
cm, err := decodeConnectionRecordingMeta(ctx, c.container.meta)
|
||||
require.NoError(t, err)
|
||||
c.Meta = cm
|
||||
require.Equal(t, c.Meta.Id, connectionId)
|
||||
@@ -54,12 +64,12 @@ func TestPopulateMeta(t *testing.T) {
|
||||
// Populate channel meta
|
||||
channelId := "channel"
|
||||
channelType := "mythical"
|
||||
ch, err := c.NewChannel(ctx, &ChannelMeta{Id: channelId, Type: channelType})
|
||||
ch, err := c.NewChannel(ctx, &ChannelRecordingMeta{Id: channelId, Type: channelType})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, ch)
|
||||
|
||||
ch.Meta = &ChannelMeta{}
|
||||
chM, err := decodeChannelMeta(ctx, ch.container.meta)
|
||||
ch.Meta = &ChannelRecordingMeta{}
|
||||
chM, err := decodeChannelRecordingMeta(ctx, ch.container.meta)
|
||||
require.NoError(t, err)
|
||||
ch.Meta = chM
|
||||
require.Equal(t, ch.Meta.Id, channelId)
|
||||
@@ -73,21 +83,25 @@ func TestOpenBSRMethods(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
f := &fstest.MemFS{}
|
||||
sessionId := "session"
|
||||
sessionMeta := TestSessionMeta(sessionId, Protocol("test"))
|
||||
sessionId := "s_01234567890"
|
||||
srm := &SessionRecordingMeta{
|
||||
Id: "sr_012344567890",
|
||||
Protocol: Protocol("TEST"),
|
||||
}
|
||||
sessionMeta := TestSessionMeta(sessionId)
|
||||
|
||||
sesh, err := NewSession(ctx, sessionMeta, f, keys, WithSupportsMultiplex(true))
|
||||
sesh, err := NewSession(ctx, srm, sessionMeta, f, keys, WithSupportsMultiplex(true))
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, sesh)
|
||||
|
||||
connectionId := "connection"
|
||||
connMeta := &ConnectionMeta{Id: connectionId}
|
||||
connMeta := &ConnectionRecordingMeta{Id: connectionId}
|
||||
conn, err := sesh.NewConnection(ctx, connMeta)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, conn)
|
||||
|
||||
channelId := "channel"
|
||||
chanMeta := &ChannelMeta{
|
||||
chanMeta := &ChannelRecordingMeta{
|
||||
Id: channelId,
|
||||
Type: "chan",
|
||||
}
|
||||
@@ -107,7 +121,7 @@ func TestOpenBSRMethods(t *testing.T) {
|
||||
return u, nil
|
||||
}
|
||||
|
||||
opSesh, err := OpenSession(ctx, sessionId, f, keyFn)
|
||||
opSesh, err := OpenSession(ctx, srm.Id, f, keyFn)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, opSesh)
|
||||
sesh.Meta.connections = opSesh.Meta.connections
|
||||
@@ -191,8 +205,13 @@ func TestOpenConnection(t *testing.T) {
|
||||
|
||||
connMap := make(map[string]bool)
|
||||
connMap["connection"] = true
|
||||
meta := TestSessionMeta("sessionId", Protocol("test"))
|
||||
meta.connections = connMap
|
||||
sessionId := "s_01234567890"
|
||||
srm := &SessionRecordingMeta{
|
||||
Id: "sr_012344567890",
|
||||
Protocol: Protocol("TEST"),
|
||||
connections: connMap,
|
||||
}
|
||||
meta := TestSessionMeta(sessionId)
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
@@ -216,7 +235,8 @@ func TestOpenConnection(t *testing.T) {
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
sesh := Session{
|
||||
Meta: meta,
|
||||
Meta: srm,
|
||||
SessionMeta: meta,
|
||||
}
|
||||
got, err := sesh.OpenConnection(ctx, tc.id)
|
||||
if tc.wantErr {
|
||||
@@ -258,7 +278,7 @@ func TestOpenChannel(t *testing.T) {
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
conn := Connection{
|
||||
Meta: &ConnectionMeta{
|
||||
Meta: &ConnectionRecordingMeta{
|
||||
channels: chanMap,
|
||||
},
|
||||
}
|
||||
|
||||
+85
-50
@@ -5,6 +5,7 @@ package bsr_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -32,18 +33,18 @@ func assertContainer(ctx context.Context, t *testing.T, path, state string, typ
|
||||
td := filepath.Join("testdata", t.Name(), state, path)
|
||||
|
||||
// meta
|
||||
wantMeta, err := os.ReadFile(filepath.Join(td, string(typ)+".meta"))
|
||||
wantMeta, err := os.ReadFile(filepath.Join(td, string(typ)+"-recording.meta"))
|
||||
require.NoError(t, err, "unable to find test data file")
|
||||
meta, ok := fs.Files[string(typ)+".meta"]
|
||||
meta, ok := fs.Files[string(typ)+"-recording.meta"]
|
||||
require.True(t, ok, "container is missing meta file")
|
||||
wantChecksumsRegex, err := regexp.Compile(string(wantMeta))
|
||||
require.NoError(t, err)
|
||||
assert.True(t, wantChecksumsRegex.MatchString(meta.Buf.String()))
|
||||
|
||||
// summary
|
||||
wantSummary, err := os.ReadFile(filepath.Join(td, string(typ)+".summary"))
|
||||
wantSummary, err := os.ReadFile(filepath.Join(td, string(typ)+"-recording-summary.json"))
|
||||
require.NoError(t, err, "unable to find test data file")
|
||||
summary, ok := fs.Files[string(typ)+".summary"]
|
||||
summary, ok := fs.Files[string(typ)+"-recording-summary.json"]
|
||||
require.True(t, ok, "container is missing summary file")
|
||||
assert.Equal(t, string(wantSummary), summary.Buf.String())
|
||||
|
||||
@@ -60,7 +61,7 @@ func assertContainer(ctx context.Context, t *testing.T, path, state string, typ
|
||||
wChecksumsRegex = append(wChecksumsRegex, r)
|
||||
}
|
||||
for _, cr := range wChecksumsRegex {
|
||||
assert.True(t, cr.MatchString(checksums.Buf.String()))
|
||||
assert.True(t, cr.MatchString(checksums.Buf.String()), "got:\n%s\nmust match:\n%s", checksums.Buf.String(), cr.String())
|
||||
}
|
||||
|
||||
// SHA256SUM.sig signature file
|
||||
@@ -99,7 +100,7 @@ func assertContainer(ctx context.Context, t *testing.T, path, state string, typ
|
||||
wJournalRegex = append(wJournalRegex, r)
|
||||
}
|
||||
for _, cr := range wJournalRegex {
|
||||
assert.True(t, cr.MatchString(journal.Buf.String()))
|
||||
assert.True(t, cr.MatchString(journal.Buf.String()), "got:\n%s\nmust match:\n%s", journal.Buf.String(), cr.String())
|
||||
}
|
||||
|
||||
if typ == "session" {
|
||||
@@ -123,6 +124,14 @@ func assertContainer(ctx context.Context, t *testing.T, path, state string, typ
|
||||
pubKeySelfSignature, ok := fs.Files["pubKeySelfSignature.sign"]
|
||||
require.True(t, ok, "container is missing pubKeySelfSignature.sign file")
|
||||
assert.NotEmpty(t, pubKeySelfSignature.Buf.String())
|
||||
|
||||
sessionMeta, ok := fs.Files["session-meta.json"]
|
||||
require.True(t, ok, "container is missing session-meta.json file")
|
||||
assert.NotEmpty(t, sessionMeta.Buf.String())
|
||||
sm := &bsr.SessionMeta{}
|
||||
err = json.Unmarshal(sessionMeta.Buf.Bytes(), sm)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, sm, bsr.TestSessionMeta(strings.ReplaceAll(fs.Name, ".bsr", "")))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,8 +242,12 @@ func TestBsr(t *testing.T) {
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
sessionMeta := bsr.TestSessionMeta(tc.id, "TEST")
|
||||
s, err := bsr.NewSession(ctx, sessionMeta, tc.c, tc.keys, tc.opts...)
|
||||
srm := &bsr.SessionRecordingMeta{
|
||||
Id: tc.id,
|
||||
Protocol: bsr.Protocol("TEST"),
|
||||
}
|
||||
sessionMeta := bsr.TestSessionMeta(tc.id)
|
||||
s, err := bsr.NewSession(ctx, srm, sessionMeta, tc.c, tc.keys, tc.opts...)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, s)
|
||||
|
||||
@@ -247,7 +260,7 @@ func TestBsr(t *testing.T) {
|
||||
|
||||
// create all the things
|
||||
for _, conn := range tc.conns {
|
||||
c, err := s.NewConnection(ctx, &bsr.ConnectionMeta{Id: conn.id})
|
||||
c, err := s.NewConnection(ctx, &bsr.ConnectionRecordingMeta{Id: conn.id})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, c)
|
||||
|
||||
@@ -281,7 +294,7 @@ func TestBsr(t *testing.T) {
|
||||
|
||||
createdChannels := make([]*channel, 0, len(conn.channels))
|
||||
for _, chann := range conn.channels {
|
||||
ch, err := c.NewChannel(ctx, &bsr.ChannelMeta{Id: chann.id, Type: "chan"})
|
||||
ch, err := c.NewChannel(ctx, &bsr.ChannelRecordingMeta{Id: chann.id, Type: "chan"})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, ch)
|
||||
|
||||
@@ -370,43 +383,57 @@ func TestNewSessionErrors(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
meta *bsr.SessionMeta
|
||||
f storage.FS
|
||||
keys *kms.Keys
|
||||
wantError error
|
||||
name string
|
||||
meta *bsr.SessionRecordingMeta
|
||||
sessionMeta *bsr.SessionMeta
|
||||
f storage.FS
|
||||
keys *kms.Keys
|
||||
wantError error
|
||||
}{
|
||||
{
|
||||
"nil-meta",
|
||||
nil,
|
||||
bsr.TestSessionMeta("session"),
|
||||
&fstest.MemFS{},
|
||||
keys,
|
||||
errors.New("bsr.NewSession: missing meta: invalid parameter"),
|
||||
},
|
||||
{
|
||||
"nil-session-meta",
|
||||
bsr.TestSessionRecordingMeta("session_recording", bsr.Protocol("TEST")),
|
||||
nil,
|
||||
&fstest.MemFS{},
|
||||
keys,
|
||||
errors.New("bsr.NewSession: missing session meta: invalid parameter"),
|
||||
},
|
||||
{
|
||||
"empty-session-id",
|
||||
bsr.TestSessionMeta("", "TEST"),
|
||||
bsr.TestSessionRecordingMeta("", bsr.Protocol("TEST")),
|
||||
bsr.TestSessionMeta("session"),
|
||||
&fstest.MemFS{},
|
||||
keys,
|
||||
errors.New("bsr.NewSession: missing session id: invalid parameter"),
|
||||
},
|
||||
{
|
||||
"nil-fs",
|
||||
bsr.TestSessionMeta("session", "TEST"),
|
||||
bsr.TestSessionRecordingMeta("session_recording", bsr.Protocol("TEST")),
|
||||
bsr.TestSessionMeta("session"),
|
||||
nil,
|
||||
keys,
|
||||
errors.New("bsr.NewSession: missing storage fs: invalid parameter"),
|
||||
},
|
||||
{
|
||||
"nil-keys",
|
||||
bsr.TestSessionMeta("session", "TEST"),
|
||||
bsr.TestSessionRecordingMeta("session_recording", bsr.Protocol("TEST")),
|
||||
bsr.TestSessionMeta("session"),
|
||||
&fstest.MemFS{},
|
||||
nil,
|
||||
errors.New("bsr.NewSession: missing kms keys: invalid parameter"),
|
||||
},
|
||||
{
|
||||
"missing-bsr-signature",
|
||||
bsr.TestSessionMeta("session", "TEST"),
|
||||
bsr.TestSessionRecordingMeta("session_recording", bsr.Protocol("TEST")),
|
||||
bsr.TestSessionMeta("session"),
|
||||
&fstest.MemFS{},
|
||||
&kms.Keys{
|
||||
PubKey: keys.PubKey,
|
||||
@@ -418,7 +445,8 @@ func TestNewSessionErrors(t *testing.T) {
|
||||
},
|
||||
{
|
||||
"missing-pub-signature",
|
||||
bsr.TestSessionMeta("session", "TEST"),
|
||||
bsr.TestSessionRecordingMeta("session_recording", bsr.Protocol("TEST")),
|
||||
bsr.TestSessionMeta("session"),
|
||||
&fstest.MemFS{},
|
||||
&kms.Keys{
|
||||
PubKey: keys.PubKey,
|
||||
@@ -430,7 +458,8 @@ func TestNewSessionErrors(t *testing.T) {
|
||||
},
|
||||
{
|
||||
"missing-pub-key",
|
||||
bsr.TestSessionMeta("session", "TEST"),
|
||||
bsr.TestSessionRecordingMeta("session_recording", bsr.Protocol("TEST")),
|
||||
bsr.TestSessionMeta("session"),
|
||||
&fstest.MemFS{},
|
||||
&kms.Keys{
|
||||
WrappedBsrKey: keys.WrappedBsrKey,
|
||||
@@ -442,7 +471,8 @@ func TestNewSessionErrors(t *testing.T) {
|
||||
},
|
||||
{
|
||||
"missing-wrapped-bsr-key",
|
||||
bsr.TestSessionMeta("session", "TEST"),
|
||||
bsr.TestSessionRecordingMeta("session_recording", bsr.Protocol("TEST")),
|
||||
bsr.TestSessionMeta("session"),
|
||||
&fstest.MemFS{},
|
||||
&kms.Keys{
|
||||
PubKey: keys.PubKey,
|
||||
@@ -454,7 +484,8 @@ func TestNewSessionErrors(t *testing.T) {
|
||||
},
|
||||
{
|
||||
"missing-wrapped-priv-key",
|
||||
bsr.TestSessionMeta("session", "TEST"),
|
||||
bsr.TestSessionRecordingMeta("session_recording", bsr.Protocol("TEST")),
|
||||
bsr.TestSessionMeta("session"),
|
||||
&fstest.MemFS{},
|
||||
&kms.Keys{
|
||||
PubKey: keys.PubKey,
|
||||
@@ -466,7 +497,8 @@ func TestNewSessionErrors(t *testing.T) {
|
||||
},
|
||||
{
|
||||
"fs-new-error",
|
||||
bsr.TestSessionMeta("session", "TEST"),
|
||||
bsr.TestSessionRecordingMeta("session_recording", bsr.Protocol("TEST")),
|
||||
bsr.TestSessionMeta("session"),
|
||||
fstest.NewMemFS(fstest.WithNewFunc(func(_ context.Context, _ string) (storage.Container, error) {
|
||||
return nil, errors.New("fs new error")
|
||||
})),
|
||||
@@ -477,7 +509,7 @@ func TestNewSessionErrors(t *testing.T) {
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
_, err := bsr.NewSession(ctx, tc.meta, tc.f, tc.keys)
|
||||
_, err := bsr.NewSession(ctx, tc.meta, tc.sessionMeta, tc.f, tc.keys)
|
||||
require.Error(t, err)
|
||||
assert.EqualError(t, err, tc.wantError.Error())
|
||||
})
|
||||
@@ -493,13 +525,13 @@ func TestNewConnectionErrors(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
session *bsr.Session
|
||||
meta *bsr.ConnectionMeta
|
||||
meta *bsr.ConnectionRecordingMeta
|
||||
wantError error
|
||||
}{
|
||||
{
|
||||
"nil-meta",
|
||||
func() *bsr.Session {
|
||||
s, err := bsr.NewSession(ctx, bsr.TestSessionMeta("session", "TEST"), &fstest.MemFS{}, keys)
|
||||
s, err := bsr.NewSession(ctx, bsr.TestSessionRecordingMeta("session_recording", bsr.Protocol("TEST")), bsr.TestSessionMeta("session"), &fstest.MemFS{}, keys)
|
||||
require.NoError(t, err)
|
||||
return s
|
||||
}(),
|
||||
@@ -509,11 +541,11 @@ func TestNewConnectionErrors(t *testing.T) {
|
||||
{
|
||||
"empty-connection-id",
|
||||
func() *bsr.Session {
|
||||
s, err := bsr.NewSession(ctx, bsr.TestSessionMeta("session", "TEST"), &fstest.MemFS{}, keys)
|
||||
s, err := bsr.NewSession(ctx, bsr.TestSessionRecordingMeta("session_recording", bsr.Protocol("TEST")), bsr.TestSessionMeta("session"), &fstest.MemFS{}, keys)
|
||||
require.NoError(t, err)
|
||||
return s
|
||||
}(),
|
||||
&bsr.ConnectionMeta{Id: ""},
|
||||
&bsr.ConnectionRecordingMeta{Id: ""},
|
||||
errors.New("bsr.(Session).NewConnection: missing connection id: invalid parameter"),
|
||||
},
|
||||
}
|
||||
@@ -533,20 +565,21 @@ func TestNewChannelErrors(t *testing.T) {
|
||||
keys, err := kms.CreateKeys(ctx, kms.TestWrapper(t), "session")
|
||||
require.NoError(t, err)
|
||||
|
||||
sessionMeta := bsr.TestSessionMeta("session", "TEST")
|
||||
srm := bsr.TestSessionRecordingMeta("session_recording", bsr.Protocol("TEST"))
|
||||
sessionMeta := bsr.TestSessionMeta("session")
|
||||
cases := []struct {
|
||||
name string
|
||||
connection *bsr.Connection
|
||||
meta *bsr.ChannelMeta
|
||||
meta *bsr.ChannelRecordingMeta
|
||||
wantError error
|
||||
}{
|
||||
{
|
||||
"nil-meta",
|
||||
func() *bsr.Connection {
|
||||
s, err := bsr.NewSession(ctx, sessionMeta, &fstest.MemFS{}, keys, bsr.WithSupportsMultiplex(true))
|
||||
s, err := bsr.NewSession(ctx, srm, sessionMeta, &fstest.MemFS{}, keys, bsr.WithSupportsMultiplex(true))
|
||||
require.NoError(t, err)
|
||||
|
||||
c, err := s.NewConnection(ctx, &bsr.ConnectionMeta{Id: "connection"})
|
||||
c, err := s.NewConnection(ctx, &bsr.ConnectionRecordingMeta{Id: "connection"})
|
||||
require.NoError(t, err)
|
||||
return c
|
||||
}(),
|
||||
@@ -556,40 +589,40 @@ func TestNewChannelErrors(t *testing.T) {
|
||||
{
|
||||
"empty-connection-id",
|
||||
func() *bsr.Connection {
|
||||
s, err := bsr.NewSession(ctx, sessionMeta, &fstest.MemFS{}, keys, bsr.WithSupportsMultiplex(true))
|
||||
s, err := bsr.NewSession(ctx, srm, sessionMeta, &fstest.MemFS{}, keys, bsr.WithSupportsMultiplex(true))
|
||||
require.NoError(t, err)
|
||||
|
||||
c, err := s.NewConnection(ctx, &bsr.ConnectionMeta{Id: "connection"})
|
||||
c, err := s.NewConnection(ctx, &bsr.ConnectionRecordingMeta{Id: "connection"})
|
||||
require.NoError(t, err)
|
||||
return c
|
||||
}(),
|
||||
&bsr.ChannelMeta{Id: ""},
|
||||
&bsr.ChannelRecordingMeta{Id: ""},
|
||||
errors.New("bsr.(Connection).NewChannel: missing channel id: invalid parameter"),
|
||||
},
|
||||
{
|
||||
"not-multiplexed",
|
||||
func() *bsr.Connection {
|
||||
s, err := bsr.NewSession(ctx, sessionMeta, &fstest.MemFS{}, keys, bsr.WithSupportsMultiplex(false))
|
||||
s, err := bsr.NewSession(ctx, srm, sessionMeta, &fstest.MemFS{}, keys, bsr.WithSupportsMultiplex(false))
|
||||
require.NoError(t, err)
|
||||
|
||||
c, err := s.NewConnection(ctx, &bsr.ConnectionMeta{Id: "connection"})
|
||||
c, err := s.NewConnection(ctx, &bsr.ConnectionRecordingMeta{Id: "connection"})
|
||||
require.NoError(t, err)
|
||||
return c
|
||||
}(),
|
||||
&bsr.ChannelMeta{Id: ""},
|
||||
&bsr.ChannelRecordingMeta{Id: ""},
|
||||
errors.New("bsr.(Connection).NewChannel: connection cannot make channels: not supported by protocol"),
|
||||
},
|
||||
{
|
||||
"not-multiplexed-default",
|
||||
func() *bsr.Connection {
|
||||
s, err := bsr.NewSession(ctx, sessionMeta, &fstest.MemFS{}, keys)
|
||||
s, err := bsr.NewSession(ctx, srm, sessionMeta, &fstest.MemFS{}, keys)
|
||||
require.NoError(t, err)
|
||||
|
||||
c, err := s.NewConnection(ctx, &bsr.ConnectionMeta{Id: "connection"})
|
||||
c, err := s.NewConnection(ctx, &bsr.ConnectionRecordingMeta{Id: "connection"})
|
||||
require.NoError(t, err)
|
||||
return c
|
||||
}(),
|
||||
&bsr.ChannelMeta{Id: ""},
|
||||
&bsr.ChannelRecordingMeta{Id: ""},
|
||||
errors.New("bsr.(Connection).NewChannel: connection cannot make channels: not supported by protocol"),
|
||||
},
|
||||
}
|
||||
@@ -609,7 +642,8 @@ func TestChannelNewMessagesWriterErrors(t *testing.T) {
|
||||
keys, err := kms.CreateKeys(ctx, kms.TestWrapper(t), "session")
|
||||
require.NoError(t, err)
|
||||
|
||||
sessionMeta := bsr.TestSessionMeta("session", "TEST")
|
||||
srm := bsr.TestSessionRecordingMeta("session_recording", bsr.Protocol("TEST"))
|
||||
sessionMeta := bsr.TestSessionMeta("session")
|
||||
cases := []struct {
|
||||
name string
|
||||
channel *bsr.Channel
|
||||
@@ -619,13 +653,13 @@ func TestChannelNewMessagesWriterErrors(t *testing.T) {
|
||||
{
|
||||
"invalid-dir",
|
||||
func() *bsr.Channel {
|
||||
s, err := bsr.NewSession(ctx, sessionMeta, &fstest.MemFS{}, keys, bsr.WithSupportsMultiplex(true))
|
||||
s, err := bsr.NewSession(ctx, srm, sessionMeta, &fstest.MemFS{}, keys, bsr.WithSupportsMultiplex(true))
|
||||
require.NoError(t, err)
|
||||
|
||||
c, err := s.NewConnection(ctx, &bsr.ConnectionMeta{Id: "connection"})
|
||||
c, err := s.NewConnection(ctx, &bsr.ConnectionRecordingMeta{Id: "connection"})
|
||||
require.NoError(t, err)
|
||||
|
||||
ch, err := c.NewChannel(ctx, &bsr.ChannelMeta{Id: "channel"})
|
||||
ch, err := c.NewChannel(ctx, &bsr.ChannelRecordingMeta{Id: "channel"})
|
||||
require.NoError(t, err)
|
||||
return ch
|
||||
}(),
|
||||
@@ -649,7 +683,8 @@ func TestChannelNewRequestsWriterErrors(t *testing.T) {
|
||||
keys, err := kms.CreateKeys(ctx, kms.TestWrapper(t), "session")
|
||||
require.NoError(t, err)
|
||||
|
||||
sessionMeta := bsr.TestSessionMeta("session", "TEST")
|
||||
srm := bsr.TestSessionRecordingMeta("session_recording", bsr.Protocol("TEST"))
|
||||
sessionMeta := bsr.TestSessionMeta("session")
|
||||
cases := []struct {
|
||||
name string
|
||||
channel *bsr.Channel
|
||||
@@ -659,13 +694,13 @@ func TestChannelNewRequestsWriterErrors(t *testing.T) {
|
||||
{
|
||||
"invalid-dir",
|
||||
func() *bsr.Channel {
|
||||
s, err := bsr.NewSession(ctx, sessionMeta, &fstest.MemFS{}, keys, bsr.WithSupportsMultiplex(true))
|
||||
s, err := bsr.NewSession(ctx, srm, sessionMeta, &fstest.MemFS{}, keys, bsr.WithSupportsMultiplex(true))
|
||||
require.NoError(t, err)
|
||||
|
||||
c, err := s.NewConnection(ctx, &bsr.ConnectionMeta{Id: "connection"})
|
||||
c, err := s.NewConnection(ctx, &bsr.ConnectionRecordingMeta{Id: "connection"})
|
||||
require.NoError(t, err)
|
||||
|
||||
ch, err := c.NewChannel(ctx, &bsr.ChannelMeta{Id: "channel"})
|
||||
ch, err := c.NewChannel(ctx, &bsr.ChannelRecordingMeta{Id: "channel"})
|
||||
require.NoError(t, err)
|
||||
return ch
|
||||
}(),
|
||||
|
||||
+62
-21
@@ -6,6 +6,7 @@ package bsr
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -22,8 +23,8 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
metaFile = "%s.meta"
|
||||
summaryFile = "%s.summary"
|
||||
metaFile = "%s-recording.meta"
|
||||
summaryFile = "%s-recording-summary.json"
|
||||
checksumFile = "SHA256SUM"
|
||||
sigFile = "SHA256SUM.sig"
|
||||
journalFile = ".journal"
|
||||
@@ -45,12 +46,13 @@ type container struct {
|
||||
container storage.Container
|
||||
|
||||
// Fields primarily used for writing
|
||||
journal *journal.Journal
|
||||
sumName string
|
||||
meta *checksum.File
|
||||
sum *checksum.File
|
||||
checksums *sign.File
|
||||
sigs storage.File
|
||||
journal *journal.Journal
|
||||
sumName string
|
||||
meta *checksum.File
|
||||
sum *checksum.File
|
||||
sumEncoder *json.Encoder
|
||||
checksums *sign.File
|
||||
sigs storage.File
|
||||
|
||||
// Field used for reading
|
||||
shaSums checksum.Sha256Sums
|
||||
@@ -113,6 +115,8 @@ func newContainer(ctx context.Context, t containerType, c storage.Container, key
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cc.sumEncoder = json.NewEncoder(cc.sum)
|
||||
cc.sumEncoder.SetIndent("", " ")
|
||||
|
||||
return cc, nil
|
||||
}
|
||||
@@ -369,6 +373,53 @@ func (c *container) create(ctx context.Context, s string, options ...storage.Opt
|
||||
return jf, nil
|
||||
}
|
||||
|
||||
func (c *container) decodeJsonFile(ctx context.Context, s string, v any) error {
|
||||
const op = "bsr.(container).decodeJsonFile"
|
||||
|
||||
return c.decodeFile(ctx, s, func(_ context.Context, r io.Reader) error {
|
||||
dec := json.NewDecoder(r)
|
||||
if err := dec.Decode(v); err != nil {
|
||||
return fmt.Errorf("%s: %w", op, err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (c *container) decodeFile(ctx context.Context, s string, fn func(context.Context, io.Reader) error) error {
|
||||
const op = "bsr.(container).decodeFile"
|
||||
|
||||
expectedSum, err := c.shaSums.Sum(s)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %w", op, err)
|
||||
}
|
||||
|
||||
f, err := c.container.OpenFile(ctx, s)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %w", op, err)
|
||||
}
|
||||
sha256Reader, err := crypto.NewSha256SumReader(ctx, f)
|
||||
if err != nil {
|
||||
f.Close()
|
||||
return fmt.Errorf("%s: %w", op, err)
|
||||
}
|
||||
defer sha256Reader.Close()
|
||||
|
||||
if err := fn(ctx, sha256Reader); err != nil {
|
||||
return fmt.Errorf("%s: %w", op, err)
|
||||
}
|
||||
|
||||
gotSum, err := sha256Reader.Sum(ctx, crypto.WithHexEncoding(true))
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %w", op, err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(expectedSum, gotSum) {
|
||||
return fmt.Errorf("%s: checksum did not match expected value", op)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// syncBsrKey will take the marshalled bytes of a key, write its contents to a local file,
|
||||
// and then close it. The key file is created using the synchronous storage option, so
|
||||
// close will block until the file is synced to remote storage
|
||||
@@ -421,19 +472,9 @@ func (c *container) WriteMeta(_ context.Context, k, v string) (int, error) {
|
||||
return c.meta.WriteString(fmt.Sprintf("%s: %s\n", k, v))
|
||||
}
|
||||
|
||||
// writeSummaryString writes a string to the container's summary file.
|
||||
func (c *container) writeSummaryString(_ context.Context, s string) (int, error) {
|
||||
return c.sum.WriteString(s)
|
||||
}
|
||||
|
||||
// WriteSummary writes a new line terminated key : value pair to the container's summary file
|
||||
func (c *container) WriteSummary(_ context.Context, k, v string) (int, error) {
|
||||
return c.sum.WriteString(fmt.Sprintf("%s: %s\n", k, v))
|
||||
}
|
||||
|
||||
// WriteSummaryLine writes a new line terminated string to the container's summary file.
|
||||
func (c *container) WriteSummaryLine(_ context.Context, s string) (int, error) {
|
||||
return c.sum.WriteString(s + "\n")
|
||||
// EncodeSummary writes a new line terminated key : value pair to the container's summary file
|
||||
func (c *container) EncodeSummary(_ context.Context, s any) error {
|
||||
return c.sumEncoder.Encode(s)
|
||||
}
|
||||
|
||||
// WriteBinaryChecksum writes a checksum for a binary file to the checksum file.
|
||||
|
||||
@@ -1,787 +0,0 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package bsr
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Scope contains information about the scope of a Boundary domain object
|
||||
type Scope struct {
|
||||
PublicId string
|
||||
Name string // optional
|
||||
Description string // optional
|
||||
Type string
|
||||
ParentId string // optional
|
||||
PrimaryAuthMethodId string // optional
|
||||
}
|
||||
|
||||
func (s Scope) writeMeta(ctx context.Context, c *container, domainObj string) error {
|
||||
_, err := c.WriteMeta(ctx, fmt.Sprintf("%s_scope_publicId", domainObj), s.PublicId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if s.Name != "" {
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_scope_name", domainObj), s.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if s.Description != "" {
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_scope_description", domainObj), s.Description)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_scope_type", domainObj), s.Type)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if s.ParentId != "" {
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_scope_parentId", domainObj), s.ParentId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if s.PrimaryAuthMethodId != "" {
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_scope_primaryAuthMethodId", domainObj), s.PrimaryAuthMethodId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// User contains information about user who initiated this session
|
||||
type User struct {
|
||||
PublicId string
|
||||
Scope Scope
|
||||
Name string // optional field
|
||||
Description string // optional field
|
||||
}
|
||||
|
||||
func (u User) writeMeta(ctx context.Context, c *container) error {
|
||||
_, err := c.WriteMeta(ctx, "user_publicId", u.PublicId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = u.Scope.writeMeta(ctx, c, "user")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if u.Name != "" {
|
||||
_, err = c.WriteMeta(ctx, "user_name", u.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if u.Description != "" {
|
||||
_, err = c.WriteMeta(ctx, "user_description", u.Description)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Target contains information about the target for this session
|
||||
type Target struct {
|
||||
PublicId string
|
||||
Scope Scope
|
||||
Name string // optional field
|
||||
Description string // optional field
|
||||
DefaultPort uint32
|
||||
SessionMaxSeconds uint32
|
||||
SessionConnectionLimit int32
|
||||
WorkerFilter string // optional field
|
||||
EgressWorkerFilter string // optional field
|
||||
IngressWorkerFilter string // optional field
|
||||
}
|
||||
|
||||
func (t Target) writeMeta(ctx context.Context, c *container) error {
|
||||
_, err := c.WriteMeta(ctx, "target_publicId", t.PublicId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = t.Scope.writeMeta(ctx, c, "target")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if t.Name != "" {
|
||||
_, err = c.WriteMeta(ctx, "target_name", t.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if t.Description != "" {
|
||||
_, err = c.WriteMeta(ctx, "target_description", t.Description)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, "target_defaultPort", fmt.Sprintf("%d", t.DefaultPort))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, "target_sessionMaxSeconds", fmt.Sprintf("%d", t.SessionMaxSeconds))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, "target_sessionConnectionLimit", fmt.Sprintf("%d", t.SessionConnectionLimit))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if t.WorkerFilter != "" {
|
||||
_, err = c.WriteMeta(ctx, "target_workerFilter", t.WorkerFilter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if t.IngressWorkerFilter != "" {
|
||||
_, err = c.WriteMeta(ctx, "target_ingressWorkerFilter", t.IngressWorkerFilter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if t.EgressWorkerFilter != "" {
|
||||
_, err = c.WriteMeta(ctx, "target_egressWorkerFilter", t.EgressWorkerFilter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Worker contains information about the worker used to record this session
|
||||
type Worker struct {
|
||||
PublicId string
|
||||
Version string
|
||||
Sha string
|
||||
}
|
||||
|
||||
func (w Worker) writeMeta(ctx context.Context, c *container) error {
|
||||
_, err := c.WriteMeta(ctx, "worker_publicId", w.PublicId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, "worker_version", w.Version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, "worker_sha", w.Sha)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// StaticHostCatalog contains information about the static host catalog for this session
|
||||
type StaticHostCatalog struct {
|
||||
PublicId string
|
||||
ProjectId string
|
||||
Name string // optional field
|
||||
Description string // optional field
|
||||
}
|
||||
|
||||
func (h StaticHostCatalog) writeMeta(ctx context.Context, c *container) error {
|
||||
_, err := c.WriteMeta(ctx, "staticHostCatalog_publicId", h.PublicId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, "staticHostCatalog_projectId", h.ProjectId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if h.Name != "" {
|
||||
_, err = c.WriteMeta(ctx, "staticHostCatalog_name", h.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if h.Description != "" {
|
||||
_, err = c.WriteMeta(ctx, "staticHostCatalog_description", h.Description)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// StaticHost contains information about the static host for this session
|
||||
type StaticHost struct {
|
||||
PublicId string
|
||||
Catalog StaticHostCatalog
|
||||
Name string // optional field
|
||||
Description string // optional field
|
||||
Address string
|
||||
}
|
||||
|
||||
func (h StaticHost) writeMeta(ctx context.Context, c *container) error {
|
||||
_, err := c.WriteMeta(ctx, "staticHost_publicId", h.PublicId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = h.Catalog.writeMeta(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if h.Name != "" {
|
||||
_, err = c.WriteMeta(ctx, "staticHost_name", h.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if h.Description != "" {
|
||||
_, err = c.WriteMeta(ctx, "staticHost_description", h.Description)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, "staticHost_address", h.Address)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DynamicHostCatalog contains information about the dynamic host catalog for this session
|
||||
type DynamicHostCatalog struct {
|
||||
PublicId string
|
||||
ProjectId string
|
||||
Name string // optional field
|
||||
Description string // optional field
|
||||
PluginId string
|
||||
Attributes string
|
||||
}
|
||||
|
||||
func (h DynamicHostCatalog) writeMeta(ctx context.Context, c *container) error {
|
||||
_, err := c.WriteMeta(ctx, "dynamicHostCatalog_publicId", h.PublicId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, "dynamicHostCatalog_projectId", h.ProjectId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if h.Name != "" {
|
||||
_, err = c.WriteMeta(ctx, "dynamicHostCatalog_name", h.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if h.Description != "" {
|
||||
_, err = c.WriteMeta(ctx, "dynamicHostCatalog_description", h.Description)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, "dynamicHostCatalog_pluginId", h.PluginId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, "dynamicHostCatalog_attributes", h.Attributes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DynamicHost contains information about the dynamic host for this session
|
||||
type DynamicHost struct {
|
||||
PublicId string
|
||||
Catalog DynamicHostCatalog
|
||||
Name string // optional field
|
||||
Description string // optional field
|
||||
ExternalId string
|
||||
}
|
||||
|
||||
func (h DynamicHost) writeMeta(ctx context.Context, c *container) error {
|
||||
_, err := c.WriteMeta(ctx, "dynamicHost_publicId", h.PublicId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = h.Catalog.writeMeta(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if h.Name != "" {
|
||||
_, err = c.WriteMeta(ctx, "dynamicHost_name", h.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if h.Description != "" {
|
||||
_, err = c.WriteMeta(ctx, "dynamicHost_description", h.Description)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, "dynamicHost_externalId", h.ExternalId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// StaticCredentialStore represents a static credential store used for this session
|
||||
type StaticCredentialStore struct {
|
||||
PublicId string
|
||||
ProjectId string
|
||||
Name string // optional field
|
||||
Description string // optional field
|
||||
Credentials []StaticCredential
|
||||
}
|
||||
|
||||
func (s StaticCredentialStore) writeMeta(ctx context.Context, c *container) error {
|
||||
prefix := fmt.Sprintf("%s_staticCredentialStore", s.PublicId)
|
||||
_, err := c.WriteMeta(ctx, fmt.Sprintf("%s_publicId", prefix), s.PublicId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_projectId", prefix), s.ProjectId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if s.Name != "" {
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_name", prefix), s.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if s.Description != "" {
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_description", prefix), s.Description)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(s.Credentials) > 0 {
|
||||
credentialPrefix := fmt.Sprintf("%s_credential", prefix)
|
||||
for _, sc := range s.Credentials {
|
||||
err = sc.writeStaticCredentialMeta(ctx, c, credentialPrefix)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// StaticCredential represents a static credential used for this session
|
||||
type StaticCredential interface {
|
||||
writeStaticCredentialMeta(ctx context.Context, c *container, prefix string) error
|
||||
}
|
||||
|
||||
// StaticJsonCredential represents a static json credential used for this session
|
||||
type StaticJsonCredential struct {
|
||||
PublicId string
|
||||
ProjectId string
|
||||
Name string // optional field
|
||||
Description string // optional field
|
||||
ObjectHmac []byte
|
||||
}
|
||||
|
||||
func (s StaticJsonCredential) writeStaticCredentialMeta(ctx context.Context, c *container, p string) error {
|
||||
prefix := fmt.Sprintf("%s_%s_staticJsonCredential", p, s.PublicId)
|
||||
_, err := c.WriteMeta(ctx, fmt.Sprintf("%s_publicId", prefix), s.PublicId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_projectId", prefix), s.ProjectId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if s.Name != "" {
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_name", prefix), s.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if s.Description != "" {
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_description", prefix), s.Description)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_objectHmac", prefix), string(s.ObjectHmac))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// StaticUsernamePasswordCredential represents a Static username password credential used for this session
|
||||
type StaticUsernamePasswordCredential struct {
|
||||
PublicId string
|
||||
ProjectId string
|
||||
Name string // optional field
|
||||
Description string // optional field
|
||||
PasswordHmac []byte
|
||||
}
|
||||
|
||||
func (s StaticUsernamePasswordCredential) writeStaticCredentialMeta(ctx context.Context, c *container, p string) error {
|
||||
prefix := fmt.Sprintf("%s_%s_staticUsernamePasswordCredential", p, s.PublicId)
|
||||
_, err := c.WriteMeta(ctx, fmt.Sprintf("%s_publicId", prefix), s.PublicId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_projectId", prefix), s.ProjectId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if s.Name != "" {
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_name", prefix), s.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if s.Description != "" {
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_description", prefix), s.Description)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_passwordHmac", prefix), string(s.PasswordHmac))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// StaticSshPrivateKeyCredential represents a Static Ssh private key credential used for this session
|
||||
type StaticSshPrivateKeyCredential struct {
|
||||
PublicId string
|
||||
ProjectId string
|
||||
Name string // optional field
|
||||
Description string // optional field
|
||||
PrivateKeyHmac []byte
|
||||
PrivateKeyPassphraseHmac []byte // optional field
|
||||
}
|
||||
|
||||
func (s StaticSshPrivateKeyCredential) writeStaticCredentialMeta(ctx context.Context, c *container, p string) error {
|
||||
prefix := fmt.Sprintf("%s_%s_staticSshPrivateKeyCredential", p, s.PublicId)
|
||||
_, err := c.WriteMeta(ctx, fmt.Sprintf("%s_publicId", prefix), s.PublicId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_projectId", prefix), s.ProjectId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if s.Name != "" {
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_name", prefix), s.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if s.Description != "" {
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_description", prefix), s.Description)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_privateKeyHmac", prefix), string(s.PrivateKeyHmac))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(s.PrivateKeyPassphraseHmac) > 0 {
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_privateKeyPassphraseHmac", prefix), string(s.PrivateKeyPassphraseHmac))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// VaultCredentialStore represents a Vault credential store used for this session
|
||||
type VaultCredentialStore struct {
|
||||
PublicId string
|
||||
ProjectId string
|
||||
Name string // optional field
|
||||
Description string // optional field
|
||||
VaultAddress string
|
||||
Namespace string
|
||||
TlsServerName string
|
||||
TlsSkipVerify bool
|
||||
WorkerFilter string // optional field
|
||||
CredentialLibraries []DynamicCredentialLibraries
|
||||
}
|
||||
|
||||
func (v VaultCredentialStore) writeMeta(ctx context.Context, c *container) error {
|
||||
prefix := fmt.Sprintf("%s_vaultCredentialStore", v.PublicId)
|
||||
_, err := c.WriteMeta(ctx, fmt.Sprintf("%s_publicId", prefix), v.PublicId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_projectId", prefix), v.ProjectId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if v.Name != "" {
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_name", prefix), v.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if v.Description != "" {
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_description", prefix), v.Description)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_vaultAddress", prefix), v.VaultAddress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_namespace", prefix), v.Namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_tlsServerName", prefix), v.TlsServerName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_tlsSkipVerify", prefix), strconv.FormatBool(v.TlsSkipVerify))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if v.WorkerFilter != "" {
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_workerFilter", prefix), v.WorkerFilter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(v.CredentialLibraries) > 0 {
|
||||
credentialPrefix := fmt.Sprintf("%s_credential", prefix)
|
||||
for _, cl := range v.CredentialLibraries {
|
||||
err = cl.writeDynamicCredentialLibraryMeta(ctx, c, credentialPrefix)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DynamicCredentialLibraries represents a dynamic credential library used for this session
|
||||
type DynamicCredentialLibraries interface {
|
||||
writeDynamicCredentialLibraryMeta(ctx context.Context, c *container, prefix string) error
|
||||
}
|
||||
|
||||
// VaultLibrary contains information about the Vault library used for this session
|
||||
type VaultLibrary struct {
|
||||
PublicId string
|
||||
ProjectId string
|
||||
Name string // optional field
|
||||
Description string // optional field
|
||||
VaultPath string
|
||||
HttpMethod string
|
||||
HttpRequestBody []byte // optional field
|
||||
CredentialType string
|
||||
}
|
||||
|
||||
func (v VaultLibrary) writeDynamicCredentialLibraryMeta(ctx context.Context, c *container, p string) error {
|
||||
prefix := fmt.Sprintf("%s_%s_vaultLibrary", p, v.PublicId)
|
||||
_, err := c.WriteMeta(ctx, fmt.Sprintf("%s_publicId", prefix), v.PublicId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_projectId", prefix), v.ProjectId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if v.Name != "" {
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_name", prefix), v.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if v.Description != "" {
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_description", prefix), v.Description)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_vaultPath", prefix), v.VaultPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_httpMethod", prefix), v.HttpMethod)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(v.HttpRequestBody) > 0 {
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_httpRequestBody", prefix), string(v.HttpRequestBody))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_credentialType", prefix), v.CredentialType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// VaultSshCertLibrary contains information about a Vault Ssh Cert library for this session
|
||||
type VaultSshCertLibrary struct {
|
||||
PublicId string
|
||||
ProjectId string
|
||||
Name string // optional field
|
||||
Description string // optional field
|
||||
VaultPath string
|
||||
Username string
|
||||
KeyType string
|
||||
KeyBits int
|
||||
Ttl string // optional field
|
||||
CriticalOptions []byte // optional field
|
||||
Extensions []byte // optional field
|
||||
CredentialType string // optional field
|
||||
}
|
||||
|
||||
func (v VaultSshCertLibrary) writeDynamicCredentialLibraryMeta(ctx context.Context, c *container, p string) error {
|
||||
prefix := fmt.Sprintf("%s_%s_vaultSshCertLibrary", p, v.PublicId)
|
||||
_, err := c.WriteMeta(ctx, fmt.Sprintf("%s_publicId", prefix), v.PublicId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_projectId", prefix), v.ProjectId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if v.Name != "" {
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_name", prefix), v.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if v.Description != "" {
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_description", prefix), v.Description)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_vaultPath", prefix), v.VaultPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_username", prefix), v.Username)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_keyType", prefix), v.KeyType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_keyBits", prefix), strconv.Itoa(v.KeyBits))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if v.Ttl != "" {
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_ttl", prefix), v.Ttl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(v.CriticalOptions) > 0 {
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_criticalOptions", prefix), string(v.CriticalOptions))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(v.Extensions) > 0 {
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_extensions", prefix), string(v.Extensions))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if v.Name != "" {
|
||||
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_credentialType", prefix), v.CredentialType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SessionMeta contains metadata about a session in a BSR.
|
||||
// Most fields are written to the meta file as k:v pairs
|
||||
// Slice fields are written to the meta file as id_k:v
|
||||
// Nested slice fields are written as parentId_parentKey_id_k:v
|
||||
type SessionMeta struct {
|
||||
Id string
|
||||
Protocol Protocol
|
||||
User *User
|
||||
Target *Target
|
||||
Worker *Worker
|
||||
// StaticHost and DynamicHost are mutually exclusive
|
||||
StaticHost *StaticHost
|
||||
DynamicHost *DynamicHost
|
||||
|
||||
StaticCredentialStore []StaticCredentialStore
|
||||
VaultCredentialStore []VaultCredentialStore
|
||||
|
||||
connections map[string]bool
|
||||
}
|
||||
|
||||
func (s SessionMeta) writeMeta(ctx context.Context, c *container) error {
|
||||
_, err := c.WriteMeta(ctx, "id", s.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, "protocol", string(s.Protocol))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = s.User.writeMeta(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = s.Target.writeMeta(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = s.Worker.writeMeta(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if s.StaticHost != nil {
|
||||
err = s.StaticHost.writeMeta(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if s.DynamicHost != nil {
|
||||
err = s.DynamicHost.writeMeta(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(s.StaticCredentialStore) > 0 {
|
||||
for _, sc := range s.StaticCredentialStore {
|
||||
err = sc.writeMeta(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(s.VaultCredentialStore) > 0 {
|
||||
for _, dc := range s.VaultCredentialStore {
|
||||
err = dc.writeMeta(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package bsr
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// SessionRecordingMeta contains metadata about a session in a BSR.
|
||||
// Most fields are written to the meta file as k:v pairs
|
||||
// Slice fields are written to the meta file as id_k:v
|
||||
// Nested slice fields are written as parentId_parentKey_id_k:v
|
||||
type SessionRecordingMeta struct {
|
||||
Id string
|
||||
Protocol Protocol
|
||||
connections map[string]bool
|
||||
}
|
||||
|
||||
func (s *SessionRecordingMeta) writeMeta(ctx context.Context, c *container) error {
|
||||
_, err := c.WriteMeta(ctx, "id", s.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = c.WriteMeta(ctx, "protocol", string(s.Protocol))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// decodeSessionRecordingMeta will populate a SessionRecordingMeta for an opened BSR Session
|
||||
func decodeSessionRecordingMeta(ctx context.Context, r io.Reader) (*SessionRecordingMeta, error) {
|
||||
const op = "bsr.decodeSessionRecordingMeta"
|
||||
|
||||
switch {
|
||||
case r == nil:
|
||||
return nil, fmt.Errorf("%s: missing session meta file: %w", op, ErrInvalidParameter)
|
||||
}
|
||||
|
||||
connections := make(map[string]bool)
|
||||
s := &SessionRecordingMeta{}
|
||||
scanner := bufio.NewScanner(r)
|
||||
for scanner.Scan() {
|
||||
l := scanner.Text()
|
||||
if len(l) == 0 {
|
||||
continue
|
||||
}
|
||||
k, v, ok := strings.Cut(l, ":")
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%s: session meta file contains invalid entry; expecting k: v pair:%s", op, l)
|
||||
}
|
||||
v = strings.TrimSpace(v)
|
||||
switch {
|
||||
case k == "id":
|
||||
s.Id = v
|
||||
case k == "protocol":
|
||||
s.Protocol = Protocol(v)
|
||||
|
||||
// connections
|
||||
case k == "connection":
|
||||
connections[v] = true
|
||||
}
|
||||
}
|
||||
|
||||
s.connections = connections
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// ConnectionRecordingMeta contains metadata about a connection in a BSR.
|
||||
type ConnectionRecordingMeta struct {
|
||||
Id string
|
||||
channels map[string]bool
|
||||
}
|
||||
|
||||
func (c ConnectionRecordingMeta) isValid() bool {
|
||||
switch {
|
||||
case c.Id == "":
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// decodeConnectionRecordingMeta will populate the ConnectionRecordingMeta for a BSR Connection
|
||||
func decodeConnectionRecordingMeta(ctx context.Context, r io.Reader) (*ConnectionRecordingMeta, error) {
|
||||
const op = "bsr.decodeConnectionRecordingMeta"
|
||||
|
||||
switch {
|
||||
case r == nil:
|
||||
return nil, fmt.Errorf("%s: missing connection meta file: %w", op, ErrInvalidParameter)
|
||||
}
|
||||
c := &ConnectionRecordingMeta{}
|
||||
channels := make(map[string]bool)
|
||||
scanner := bufio.NewScanner(r)
|
||||
for scanner.Scan() {
|
||||
l := scanner.Text()
|
||||
if len(l) == 0 {
|
||||
continue
|
||||
}
|
||||
k, v, ok := strings.Cut(l, ":")
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%s: connection meta file contains invalid entry; expecting k: v pair:%s", op, l)
|
||||
}
|
||||
v = strings.TrimSpace(v)
|
||||
switch {
|
||||
case k == "id":
|
||||
c.Id = v
|
||||
case k == "channel":
|
||||
channels[v] = true
|
||||
}
|
||||
}
|
||||
c.channels = channels
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// ChannelRecordingMeta contains metadata about a channel in a BSR.
|
||||
type ChannelRecordingMeta struct {
|
||||
Id string
|
||||
Type string
|
||||
}
|
||||
|
||||
func (c ChannelRecordingMeta) isValid() bool {
|
||||
switch {
|
||||
case c.Id == "":
|
||||
return false
|
||||
case c.Type == "":
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// decodeChannelRecordingMeta will populate the ChannelRecordingMeta for a BSR Channel
|
||||
func decodeChannelRecordingMeta(ctx context.Context, r io.Reader) (*ChannelRecordingMeta, error) {
|
||||
const op = "bsr.decodeChannelRecordingMeta"
|
||||
|
||||
switch {
|
||||
case r == nil:
|
||||
return nil, fmt.Errorf("%s: missing channel meta file: %w", op, ErrInvalidParameter)
|
||||
}
|
||||
|
||||
c := &ChannelRecordingMeta{}
|
||||
scanner := bufio.NewScanner(r)
|
||||
for scanner.Scan() {
|
||||
l := scanner.Text()
|
||||
if len(l) == 0 {
|
||||
continue
|
||||
}
|
||||
k, v, ok := strings.Cut(l, ":")
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%s: channel meta file contains invalid entry; expecting k: v pair:%s", op, l)
|
||||
}
|
||||
v = strings.TrimSpace(v)
|
||||
switch {
|
||||
case k == "id":
|
||||
c.Id = v
|
||||
case k == "channelType":
|
||||
c.Type = v
|
||||
}
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package bsr
|
||||
|
||||
// Scope contains information about the scope of a Boundary domain object
|
||||
type Scope struct {
|
||||
PublicId string
|
||||
Name string // optional
|
||||
Description string // optional
|
||||
Type string
|
||||
ParentId string // optional
|
||||
PrimaryAuthMethodId string // optional
|
||||
}
|
||||
|
||||
// User contains information about user who initiated this session
|
||||
type User struct {
|
||||
PublicId string
|
||||
Scope Scope
|
||||
Name string // optional field
|
||||
Description string // optional field
|
||||
}
|
||||
|
||||
// Target contains information about the target for this session
|
||||
type Target struct {
|
||||
PublicId string
|
||||
Scope Scope
|
||||
Name string // optional field
|
||||
Description string // optional field
|
||||
DefaultPort uint32
|
||||
SessionMaxSeconds uint32
|
||||
SessionConnectionLimit int32
|
||||
WorkerFilter string // optional field
|
||||
EgressWorkerFilter string // optional field
|
||||
IngressWorkerFilter string // optional field
|
||||
}
|
||||
|
||||
// Worker contains information about the worker used to record this session
|
||||
type Worker struct {
|
||||
PublicId string
|
||||
Version string
|
||||
Sha string
|
||||
}
|
||||
|
||||
// StaticHostCatalog contains information about the static host catalog for this session
|
||||
type StaticHostCatalog struct {
|
||||
PublicId string
|
||||
ProjectId string
|
||||
Name string // optional field
|
||||
Description string // optional field
|
||||
}
|
||||
|
||||
// StaticHost contains information about the static host for this session
|
||||
type StaticHost struct {
|
||||
PublicId string
|
||||
Catalog StaticHostCatalog
|
||||
Name string // optional field
|
||||
Description string // optional field
|
||||
Address string
|
||||
}
|
||||
|
||||
// DynamicHostCatalog contains information about the dynamic host catalog for this session
|
||||
type DynamicHostCatalog struct {
|
||||
PublicId string
|
||||
ProjectId string
|
||||
Name string // optional field
|
||||
Description string // optional field
|
||||
PluginId string
|
||||
Attributes string
|
||||
}
|
||||
|
||||
// DynamicHost contains information about the dynamic host for this session
|
||||
type DynamicHost struct {
|
||||
PublicId string
|
||||
Catalog DynamicHostCatalog
|
||||
Name string // optional field
|
||||
Description string // optional field
|
||||
ExternalId string
|
||||
}
|
||||
|
||||
// StaticCredentialStore represents a static credential store used for this session
|
||||
type StaticCredentialStore struct {
|
||||
PublicId string
|
||||
ProjectId string
|
||||
Name string // optional field
|
||||
Description string // optional field
|
||||
StaticJsonCredentials []StaticJsonCredential
|
||||
StaticUsernamePasswordCredentials []StaticUsernamePasswordCredential
|
||||
}
|
||||
|
||||
// StaticJsonCredential represents a static json credential used for this session
|
||||
type StaticJsonCredential struct {
|
||||
PublicId string
|
||||
ProjectId string
|
||||
Name string // optional field
|
||||
Description string // optional field
|
||||
ObjectHmac []byte
|
||||
}
|
||||
|
||||
// StaticUsernamePasswordCredential represents a Static username password credential used for this session
|
||||
type StaticUsernamePasswordCredential struct {
|
||||
PublicId string
|
||||
ProjectId string
|
||||
Name string // optional field
|
||||
Description string // optional field
|
||||
PasswordHmac []byte
|
||||
}
|
||||
|
||||
// StaticSshPrivateKeyCredential represents a Static Ssh private key credential used for this session
|
||||
type StaticSshPrivateKeyCredential struct {
|
||||
PublicId string
|
||||
ProjectId string
|
||||
Name string // optional field
|
||||
Description string // optional field
|
||||
PrivateKeyHmac []byte
|
||||
PrivateKeyPassphraseHmac []byte // optional field
|
||||
}
|
||||
|
||||
// VaultCredentialStore represents a Vault credential store used for this session
|
||||
type VaultCredentialStore struct {
|
||||
PublicId string
|
||||
ProjectId string
|
||||
Name string // optional field
|
||||
Description string // optional field
|
||||
VaultAddress string
|
||||
Namespace string
|
||||
TlsServerName string
|
||||
TlsSkipVerify bool
|
||||
WorkerFilter string // optional field
|
||||
VaultGenericLibraries []VaultLibrary
|
||||
VaultSshCertLibraries []VaultSshCertLibrary
|
||||
}
|
||||
|
||||
// VaultLibrary contains information about the Vault library used for this session
|
||||
type VaultLibrary struct {
|
||||
PublicId string
|
||||
ProjectId string
|
||||
Name string // optional field
|
||||
Description string // optional field
|
||||
VaultPath string
|
||||
HttpMethod string
|
||||
HttpRequestBody []byte // optional field
|
||||
CredentialType string
|
||||
}
|
||||
|
||||
// VaultSshCertLibrary contains information about a Vault Ssh Cert library for this session
|
||||
type VaultSshCertLibrary struct {
|
||||
PublicId string
|
||||
ProjectId string
|
||||
Name string // optional field
|
||||
Description string // optional field
|
||||
VaultPath string
|
||||
Username string
|
||||
KeyType string
|
||||
KeyBits int
|
||||
Ttl string // optional field
|
||||
CriticalOptions []byte // optional field
|
||||
Extensions []byte // optional field
|
||||
CredentialType string // optional field
|
||||
}
|
||||
|
||||
// SessionMeta contains metadata about a session in a BSR.
|
||||
type SessionMeta struct {
|
||||
PublicId string
|
||||
User *User
|
||||
Target *Target
|
||||
Worker *Worker
|
||||
// StaticHost and DynamicHost are mutually exclusive
|
||||
StaticHost *StaticHost
|
||||
DynamicHost *DynamicHost
|
||||
|
||||
StaticCredentialStore []StaticCredentialStore
|
||||
VaultCredentialStore []VaultCredentialStore
|
||||
}
|
||||
@@ -2,10 +2,13 @@ CREATING SHA256SUM.sig
|
||||
CREATED SHA256SUM.sig
|
||||
CREATING SHA256SUM
|
||||
CREATED SHA256SUM
|
||||
CREATING session.meta
|
||||
CREATED session.meta
|
||||
CREATING session.summary
|
||||
CREATED session.summary
|
||||
CREATING session-recording.meta
|
||||
CREATED session-recording.meta
|
||||
CREATING session-meta.json
|
||||
CREATED session-meta.json
|
||||
CLOSED session-meta.json
|
||||
CREATING session-recording-summary.json
|
||||
CREATED session-recording-summary.json
|
||||
CREATING bsrKey.pub
|
||||
CREATED bsrKey.pub
|
||||
CLOSING bsrKey.pub
|
||||
@@ -26,10 +29,10 @@ CREATING pubKeySelfSignature.sign
|
||||
CREATED pubKeySelfSignature.sign
|
||||
CLOSING pubKeySelfSignature.sign
|
||||
CLOSED pubKeySelfSignature.sign
|
||||
CLOSING session.meta
|
||||
CLOSED session.meta
|
||||
CLOSING session.summary
|
||||
CLOSED session.summary
|
||||
CLOSING session-recording.meta
|
||||
CLOSED session-recording.meta
|
||||
CLOSING session-recording-summary.json
|
||||
CLOSED session-recording-summary.json
|
||||
CLOSING SHA256SUM
|
||||
CLOSED SHA256SUM
|
||||
CLOSING SHA256SUM.sig
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
.* wrappedPrivKey
|
||||
.* pubKeyBsrSignature.sign
|
||||
.* pubKeySelfSignature.sign
|
||||
1aac36a2c36e4de69c5bf3522ada1c7f080ac807f2182c013ec8ddf60bedae10 session.meta
|
||||
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 session.summary
|
||||
.* session-meta.json
|
||||
523569b06adc4a1996c7d3833105a48485428e663bf8a11ed9b4d8f84f68b85c session-recording.meta
|
||||
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 session-recording-summary.json
|
||||
@@ -2,10 +2,10 @@ CREATING SHA256SUM.sig
|
||||
CREATED SHA256SUM.sig
|
||||
CREATING SHA256SUM
|
||||
CREATED SHA256SUM
|
||||
CREATING connection.meta
|
||||
CREATED connection.meta
|
||||
CREATING connection.summary
|
||||
CREATED connection.summary
|
||||
CREATING connection-recording.meta
|
||||
CREATED connection-recording.meta
|
||||
CREATING connection-recording-summary.json
|
||||
CREATED connection-recording-summary.json
|
||||
CREATING requests-inbound.data
|
||||
CREATED requests-inbound.data
|
||||
CREATING requests-outbound.data
|
||||
@@ -14,10 +14,10 @@ CLOSING requests-inbound.data
|
||||
CLOSED requests-inbound.data
|
||||
CLOSING requests-outbound.data
|
||||
CLOSED requests-outbound.data
|
||||
CLOSING connection.meta
|
||||
CLOSED connection.meta
|
||||
CLOSING connection.summary
|
||||
CLOSED connection.summary
|
||||
CLOSING connection-recording.meta
|
||||
CLOSED connection-recording.meta
|
||||
CLOSING connection-recording-summary.json
|
||||
CLOSED connection-recording-summary.json
|
||||
CLOSING SHA256SUM
|
||||
CLOSED SHA256SUM
|
||||
CLOSING SHA256SUM.sig
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 requests-inbound.data
|
||||
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 requests-outbound.data
|
||||
e4df3504aaa6fee4426f67ba998cdd90f84c579d98db979e589d8ca2ffd1e733 connection.meta
|
||||
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 connection.summary
|
||||
e4df3504aaa6fee4426f67ba998cdd90f84c579d98db979e589d8ca2ffd1e733 connection-recording.meta
|
||||
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 connection-recording-summary.json
|
||||
+8
-8
@@ -2,10 +2,10 @@ CREATING SHA256SUM.sig
|
||||
CREATED SHA256SUM.sig
|
||||
CREATING SHA256SUM
|
||||
CREATED SHA256SUM
|
||||
CREATING channel.meta
|
||||
CREATED channel.meta
|
||||
CREATING channel.summary
|
||||
CREATED channel.summary
|
||||
CREATING channel-recording.meta
|
||||
CREATED channel-recording.meta
|
||||
CREATING channel-recording-summary.json
|
||||
CREATED channel-recording-summary.json
|
||||
CREATING messages-inbound.data
|
||||
CREATED messages-inbound.data
|
||||
CREATING requests-inbound.data
|
||||
@@ -22,10 +22,10 @@ CLOSING messages-outbound.data
|
||||
CLOSED messages-outbound.data
|
||||
CLOSING requests-outbound.data
|
||||
CLOSED requests-outbound.data
|
||||
CLOSING channel.meta
|
||||
CLOSED channel.meta
|
||||
CLOSING channel.summary
|
||||
CLOSED channel.summary
|
||||
CLOSING channel-recording.meta
|
||||
CLOSED channel-recording.meta
|
||||
CLOSING channel-recording-summary.json
|
||||
CLOSED channel-recording-summary.json
|
||||
CLOSING SHA256SUM
|
||||
CLOSED SHA256SUM
|
||||
CLOSING SHA256SUM.sig
|
||||
|
||||
+2
-2
@@ -2,5 +2,5 @@ e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 messages-inbou
|
||||
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 requests-inbound.data
|
||||
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 messages-outbound.data
|
||||
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 requests-outbound.data
|
||||
27a58452605f6e30ca048cc540e9d963c7270212fcb2c7b73fc69e314ffd1902 channel.meta
|
||||
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 channel.summary
|
||||
27a58452605f6e30ca048cc540e9d963c7270212fcb2c7b73fc69e314ffd1902 channel-recording.meta
|
||||
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 channel-recording-summary.json
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+3
@@ -0,0 +1,3 @@
|
||||
id: session_123456789
|
||||
protocol: TEST
|
||||
connection: conn_1.connection
|
||||
@@ -1,36 +0,0 @@
|
||||
id: session_123456789
|
||||
protocol: TEST
|
||||
user_publicId: user123
|
||||
user_scope_publicId: global
|
||||
user_scope_type: global
|
||||
target_publicId: target123
|
||||
target_scope_publicId: proj123
|
||||
target_scope_type: project
|
||||
target_scope_parentId: org123
|
||||
target_defaultPort: 0
|
||||
target_sessionMaxSeconds: 0
|
||||
target_sessionConnectionLimit: 0
|
||||
worker_publicId: w_12345
|
||||
worker_version: 0.25.5
|
||||
worker_sha: beepboopgitsha
|
||||
staticHost_publicId: host123
|
||||
staticHostCatalog_publicId: staticcat123
|
||||
staticHostCatalog_projectId: proj123
|
||||
staticHost_address: 127.0.0.1
|
||||
scs123_staticCredentialStore_publicId: scs123
|
||||
scs123_staticCredentialStore_projectId: proj123
|
||||
scs123_staticCredentialStore_credential_scjson123_staticJsonCredential_publicId: scjson123
|
||||
scs123_staticCredentialStore_credential_scjson123_staticJsonCredential_projectId: proj123
|
||||
scs123_staticCredentialStore_credential_scjson123_staticJsonCredential_objectHmac: hmac
|
||||
vcs123_vaultCredentialStore_publicId: vcs123
|
||||
vcs123_vaultCredentialStore_projectId: proj123
|
||||
vcs123_vaultCredentialStore_vaultAddress: an/address
|
||||
vcs123_vaultCredentialStore_namespace: name
|
||||
vcs123_vaultCredentialStore_tlsServerName: imaserver
|
||||
vcs123_vaultCredentialStore_tlsSkipVerify: false
|
||||
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_publicId: vl123
|
||||
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_projectId: proj123
|
||||
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_vaultPath: /a/path
|
||||
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_httpMethod: GET
|
||||
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_credentialType: magic
|
||||
connection: conn_1.connection
|
||||
@@ -2,10 +2,13 @@ CREATING SHA256SUM.sig
|
||||
CREATED SHA256SUM.sig
|
||||
CREATING SHA256SUM
|
||||
CREATED SHA256SUM
|
||||
CREATING session.meta
|
||||
CREATED session.meta
|
||||
CREATING session.summary
|
||||
CREATED session.summary
|
||||
CREATING session-recording.meta
|
||||
CREATED session-recording.meta
|
||||
CREATING session-meta.json
|
||||
CREATED session-meta.json
|
||||
CLOSED session-meta.json
|
||||
CREATING session-recording-summary.json
|
||||
CREATED session-recording-summary.json
|
||||
CREATING bsrKey.pub
|
||||
CREATED bsrKey.pub
|
||||
CLOSING bsrKey.pub
|
||||
|
||||
@@ -3,3 +3,4 @@
|
||||
.* wrappedPrivKey
|
||||
.* pubKeyBsrSignature.sign
|
||||
.* pubKeySelfSignature.sign
|
||||
.* session-meta.json
|
||||
@@ -2,7 +2,7 @@ CREATING SHA256SUM.sig
|
||||
CREATED SHA256SUM.sig
|
||||
CREATING SHA256SUM
|
||||
CREATED SHA256SUM
|
||||
CREATING connection.meta
|
||||
CREATED connection.meta
|
||||
CREATING connection.summary
|
||||
CREATED connection.summary
|
||||
CREATING connection-recording.meta
|
||||
CREATED connection-recording.meta
|
||||
CREATING connection-recording-summary.json
|
||||
CREATED connection-recording-summary.json
|
||||
+4
-4
@@ -2,7 +2,7 @@ CREATING SHA256SUM.sig
|
||||
CREATED SHA256SUM.sig
|
||||
CREATING SHA256SUM
|
||||
CREATED SHA256SUM
|
||||
CREATING channel.meta
|
||||
CREATED channel.meta
|
||||
CREATING channel.summary
|
||||
CREATED channel.summary
|
||||
CREATING channel-recording.meta
|
||||
CREATED channel-recording.meta
|
||||
CREATING channel-recording-summary.json
|
||||
CREATED channel-recording-summary.json
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+2
@@ -0,0 +1,2 @@
|
||||
id: session_123456789
|
||||
protocol: TEST
|
||||
@@ -1,35 +0,0 @@
|
||||
id: session_123456789
|
||||
protocol: TEST
|
||||
user_publicId: user123
|
||||
user_scope_publicId: global
|
||||
user_scope_type: global
|
||||
target_publicId: target123
|
||||
target_scope_publicId: proj123
|
||||
target_scope_type: project
|
||||
target_scope_parentId: org123
|
||||
target_defaultPort: 0
|
||||
target_sessionMaxSeconds: 0
|
||||
target_sessionConnectionLimit: 0
|
||||
worker_publicId: w_12345
|
||||
worker_version: 0.25.5
|
||||
worker_sha: beepboopgitsha
|
||||
staticHost_publicId: host123
|
||||
staticHostCatalog_publicId: staticcat123
|
||||
staticHostCatalog_projectId: proj123
|
||||
staticHost_address: 127.0.0.1
|
||||
scs123_staticCredentialStore_publicId: scs123
|
||||
scs123_staticCredentialStore_projectId: proj123
|
||||
scs123_staticCredentialStore_credential_scjson123_staticJsonCredential_publicId: scjson123
|
||||
scs123_staticCredentialStore_credential_scjson123_staticJsonCredential_projectId: proj123
|
||||
scs123_staticCredentialStore_credential_scjson123_staticJsonCredential_objectHmac: hmac
|
||||
vcs123_vaultCredentialStore_publicId: vcs123
|
||||
vcs123_vaultCredentialStore_projectId: proj123
|
||||
vcs123_vaultCredentialStore_vaultAddress: an/address
|
||||
vcs123_vaultCredentialStore_namespace: name
|
||||
vcs123_vaultCredentialStore_tlsServerName: imaserver
|
||||
vcs123_vaultCredentialStore_tlsSkipVerify: false
|
||||
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_publicId: vl123
|
||||
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_projectId: proj123
|
||||
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_vaultPath: /a/path
|
||||
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_httpMethod: GET
|
||||
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_credentialType: magic
|
||||
@@ -2,10 +2,13 @@ CREATING SHA256SUM.sig
|
||||
CREATED SHA256SUM.sig
|
||||
CREATING SHA256SUM
|
||||
CREATED SHA256SUM
|
||||
CREATING session.meta
|
||||
CREATED session.meta
|
||||
CREATING session.summary
|
||||
CREATED session.summary
|
||||
CREATING session-recording.meta
|
||||
CREATED session-recording.meta
|
||||
CREATING session-meta.json
|
||||
CREATED session-meta.json
|
||||
CLOSED session-meta.json
|
||||
CREATING session-recording-summary.json
|
||||
CREATED session-recording-summary.json
|
||||
CREATING bsrKey.pub
|
||||
CREATED bsrKey.pub
|
||||
CLOSING bsrKey.pub
|
||||
@@ -26,10 +29,10 @@ CREATING pubKeySelfSignature.sign
|
||||
CREATED pubKeySelfSignature.sign
|
||||
CLOSING pubKeySelfSignature.sign
|
||||
CLOSED pubKeySelfSignature.sign
|
||||
CLOSING session.meta
|
||||
CLOSED session.meta
|
||||
CLOSING session.summary
|
||||
CLOSED session.summary
|
||||
CLOSING session-recording.meta
|
||||
CLOSED session-recording.meta
|
||||
CLOSING session-recording-summary.json
|
||||
CLOSED session-recording-summary.json
|
||||
CLOSING SHA256SUM
|
||||
CLOSED SHA256SUM
|
||||
CLOSING SHA256SUM.sig
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
.* wrappedPrivKey
|
||||
.* pubKeyBsrSignature.sign
|
||||
.* pubKeySelfSignature.sign
|
||||
1aac36a2c36e4de69c5bf3522ada1c7f080ac807f2182c013ec8ddf60bedae10 session.meta
|
||||
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 session.summary
|
||||
.* session-meta.json
|
||||
523569b06adc4a1996c7d3833105a48485428e663bf8a11ed9b4d8f84f68b85c session-recording.meta
|
||||
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 session-recording-summary.json
|
||||
+8
-8
@@ -2,10 +2,10 @@ CREATING SHA256SUM.sig
|
||||
CREATED SHA256SUM.sig
|
||||
CREATING SHA256SUM
|
||||
CREATED SHA256SUM
|
||||
CREATING connection.meta
|
||||
CREATED connection.meta
|
||||
CREATING connection.summary
|
||||
CREATED connection.summary
|
||||
CREATING connection-recording.meta
|
||||
CREATED connection-recording.meta
|
||||
CREATING connection-recording-summary.json
|
||||
CREATED connection-recording-summary.json
|
||||
CREATING messages-inbound.data
|
||||
CREATED messages-inbound.data
|
||||
CREATING messages-outbound.data
|
||||
@@ -22,10 +22,10 @@ CLOSING requests-inbound.data
|
||||
CLOSED requests-inbound.data
|
||||
CLOSING requests-outbound.data
|
||||
CLOSED requests-outbound.data
|
||||
CLOSING connection.meta
|
||||
CLOSED connection.meta
|
||||
CLOSING connection.summary
|
||||
CLOSED connection.summary
|
||||
CLOSING connection-recording.meta
|
||||
CLOSED connection-recording.meta
|
||||
CLOSING connection-recording-summary.json
|
||||
CLOSED connection-recording-summary.json
|
||||
CLOSING SHA256SUM
|
||||
CLOSED SHA256SUM
|
||||
CLOSING SHA256SUM.sig
|
||||
|
||||
+2
-2
@@ -2,5 +2,5 @@ e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 messages-inbou
|
||||
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 messages-outbound.data
|
||||
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 requests-inbound.data
|
||||
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 requests-outbound.data
|
||||
03edd8ed2a4d678ea79d14538e504b6bb9aaec51c7e3ebf3a4891083d97ac7a9 connection.meta
|
||||
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 connection.summary
|
||||
03edd8ed2a4d678ea79d14538e504b6bb9aaec51c7e3ebf3a4891083d97ac7a9 connection-recording.meta
|
||||
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 connection-recording-summary.json
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
+3
@@ -0,0 +1,3 @@
|
||||
id: session_123456789
|
||||
protocol: TEST
|
||||
connection: conn_1.connection
|
||||
@@ -1,36 +0,0 @@
|
||||
id: session_123456789
|
||||
protocol: TEST
|
||||
user_publicId: user123
|
||||
user_scope_publicId: global
|
||||
user_scope_type: global
|
||||
target_publicId: target123
|
||||
target_scope_publicId: proj123
|
||||
target_scope_type: project
|
||||
target_scope_parentId: org123
|
||||
target_defaultPort: 0
|
||||
target_sessionMaxSeconds: 0
|
||||
target_sessionConnectionLimit: 0
|
||||
worker_publicId: w_12345
|
||||
worker_version: 0.25.5
|
||||
worker_sha: beepboopgitsha
|
||||
staticHost_publicId: host123
|
||||
staticHostCatalog_publicId: staticcat123
|
||||
staticHostCatalog_projectId: proj123
|
||||
staticHost_address: 127.0.0.1
|
||||
scs123_staticCredentialStore_publicId: scs123
|
||||
scs123_staticCredentialStore_projectId: proj123
|
||||
scs123_staticCredentialStore_credential_scjson123_staticJsonCredential_publicId: scjson123
|
||||
scs123_staticCredentialStore_credential_scjson123_staticJsonCredential_projectId: proj123
|
||||
scs123_staticCredentialStore_credential_scjson123_staticJsonCredential_objectHmac: hmac
|
||||
vcs123_vaultCredentialStore_publicId: vcs123
|
||||
vcs123_vaultCredentialStore_projectId: proj123
|
||||
vcs123_vaultCredentialStore_vaultAddress: an/address
|
||||
vcs123_vaultCredentialStore_namespace: name
|
||||
vcs123_vaultCredentialStore_tlsServerName: imaserver
|
||||
vcs123_vaultCredentialStore_tlsSkipVerify: false
|
||||
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_publicId: vl123
|
||||
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_projectId: proj123
|
||||
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_vaultPath: /a/path
|
||||
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_httpMethod: GET
|
||||
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_credentialType: magic
|
||||
connection: conn_1.connection
|
||||
@@ -2,10 +2,13 @@ CREATING SHA256SUM.sig
|
||||
CREATED SHA256SUM.sig
|
||||
CREATING SHA256SUM
|
||||
CREATED SHA256SUM
|
||||
CREATING session.meta
|
||||
CREATED session.meta
|
||||
CREATING session.summary
|
||||
CREATED session.summary
|
||||
CREATING session-recording.meta
|
||||
CREATED session-recording.meta
|
||||
CREATING session-meta.json
|
||||
CREATED session-meta.json
|
||||
CLOSED session-meta.json
|
||||
CREATING session-recording-summary.json
|
||||
CREATED session-recording-summary.json
|
||||
CREATING bsrKey.pub
|
||||
CREATED bsrKey.pub
|
||||
CLOSING bsrKey.pub
|
||||
|
||||
@@ -2,4 +2,5 @@
|
||||
.* wrappedBsrKey
|
||||
.* wrappedPrivKey
|
||||
.* pubKeyBsrSignature.sign
|
||||
.* pubKeySelfSignature.sign
|
||||
.* pubKeySelfSignature.sign
|
||||
.* session-meta.json
|
||||
+4
-4
@@ -2,7 +2,7 @@ CREATING SHA256SUM.sig
|
||||
CREATED SHA256SUM.sig
|
||||
CREATING SHA256SUM
|
||||
CREATED SHA256SUM
|
||||
CREATING connection.meta
|
||||
CREATED connection.meta
|
||||
CREATING connection.summary
|
||||
CREATED connection.summary
|
||||
CREATING connection-recording.meta
|
||||
CREATED connection-recording.meta
|
||||
CREATING connection-recording-summary.json
|
||||
CREATED connection-recording-summary.json
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
+2
@@ -0,0 +1,2 @@
|
||||
id: session_123456789
|
||||
protocol: TEST
|
||||
@@ -1,35 +0,0 @@
|
||||
id: session_123456789
|
||||
protocol: TEST
|
||||
user_publicId: user123
|
||||
user_scope_publicId: global
|
||||
user_scope_type: global
|
||||
target_publicId: target123
|
||||
target_scope_publicId: proj123
|
||||
target_scope_type: project
|
||||
target_scope_parentId: org123
|
||||
target_defaultPort: 0
|
||||
target_sessionMaxSeconds: 0
|
||||
target_sessionConnectionLimit: 0
|
||||
worker_publicId: w_12345
|
||||
worker_version: 0.25.5
|
||||
worker_sha: beepboopgitsha
|
||||
staticHost_publicId: host123
|
||||
staticHostCatalog_publicId: staticcat123
|
||||
staticHostCatalog_projectId: proj123
|
||||
staticHost_address: 127.0.0.1
|
||||
scs123_staticCredentialStore_publicId: scs123
|
||||
scs123_staticCredentialStore_projectId: proj123
|
||||
scs123_staticCredentialStore_credential_scjson123_staticJsonCredential_publicId: scjson123
|
||||
scs123_staticCredentialStore_credential_scjson123_staticJsonCredential_projectId: proj123
|
||||
scs123_staticCredentialStore_credential_scjson123_staticJsonCredential_objectHmac: hmac
|
||||
vcs123_vaultCredentialStore_publicId: vcs123
|
||||
vcs123_vaultCredentialStore_projectId: proj123
|
||||
vcs123_vaultCredentialStore_vaultAddress: an/address
|
||||
vcs123_vaultCredentialStore_namespace: name
|
||||
vcs123_vaultCredentialStore_tlsServerName: imaserver
|
||||
vcs123_vaultCredentialStore_tlsSkipVerify: false
|
||||
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_publicId: vl123
|
||||
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_projectId: proj123
|
||||
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_vaultPath: /a/path
|
||||
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_httpMethod: GET
|
||||
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_credentialType: magic
|
||||
+49
-50
@@ -3,60 +3,30 @@
|
||||
|
||||
package bsr
|
||||
|
||||
func TestSessionMeta(s string, p Protocol) *SessionMeta {
|
||||
scope := Scope{
|
||||
PublicId: "global",
|
||||
Type: "global",
|
||||
}
|
||||
staticCatalog := StaticHostCatalog{
|
||||
PublicId: "staticcat123",
|
||||
ProjectId: "proj123",
|
||||
}
|
||||
creds := make([]StaticCredential, 0)
|
||||
c := StaticJsonCredential{
|
||||
PublicId: "scjson123",
|
||||
ProjectId: "proj123",
|
||||
ObjectHmac: []byte("hmac"),
|
||||
}
|
||||
creds = append(creds, c)
|
||||
staticCredentialStore := make([]StaticCredentialStore, 0)
|
||||
scs := StaticCredentialStore{
|
||||
PublicId: "scs123",
|
||||
ProjectId: "proj123",
|
||||
Credentials: creds,
|
||||
}
|
||||
staticCredentialStore = append(staticCredentialStore, scs)
|
||||
vcreds := make([]DynamicCredentialLibraries, 0)
|
||||
v := VaultLibrary{
|
||||
PublicId: "vl123",
|
||||
ProjectId: "proj123",
|
||||
VaultPath: "/a/path",
|
||||
HttpMethod: "GET",
|
||||
CredentialType: "magic",
|
||||
}
|
||||
vcreds = append(vcreds, v)
|
||||
vaultCredentialStore := make([]VaultCredentialStore, 0)
|
||||
vcs := VaultCredentialStore{
|
||||
PublicId: "vcs123",
|
||||
ProjectId: "proj123",
|
||||
VaultAddress: "an/address",
|
||||
Namespace: "name",
|
||||
TlsServerName: "imaserver",
|
||||
TlsSkipVerify: false,
|
||||
CredentialLibraries: vcreds,
|
||||
}
|
||||
vaultCredentialStore = append(vaultCredentialStore, vcs)
|
||||
sessionMeta := &SessionMeta{
|
||||
func TestSessionRecordingMeta(s string, p Protocol) *SessionRecordingMeta {
|
||||
return &SessionRecordingMeta{
|
||||
Id: s,
|
||||
Protocol: p,
|
||||
}
|
||||
}
|
||||
|
||||
func TestSessionMeta(s string) *SessionMeta {
|
||||
return &SessionMeta{
|
||||
PublicId: s,
|
||||
User: &User{
|
||||
PublicId: "user123",
|
||||
Scope: scope,
|
||||
Scope: Scope{
|
||||
PublicId: "global",
|
||||
Type: "global",
|
||||
},
|
||||
},
|
||||
StaticHost: &StaticHost{
|
||||
PublicId: "host123",
|
||||
Catalog: staticCatalog,
|
||||
Address: "127.0.0.1",
|
||||
Catalog: StaticHostCatalog{
|
||||
PublicId: "staticcat123",
|
||||
ProjectId: "proj123",
|
||||
},
|
||||
Address: "127.0.0.1",
|
||||
},
|
||||
Target: &Target{
|
||||
PublicId: "target123",
|
||||
@@ -74,8 +44,37 @@ func TestSessionMeta(s string, p Protocol) *SessionMeta {
|
||||
Version: "0.25.5",
|
||||
Sha: "beepboopgitsha",
|
||||
},
|
||||
StaticCredentialStore: staticCredentialStore,
|
||||
VaultCredentialStore: vaultCredentialStore,
|
||||
StaticCredentialStore: []StaticCredentialStore{
|
||||
{
|
||||
PublicId: "scs123",
|
||||
ProjectId: "proj123",
|
||||
StaticJsonCredentials: []StaticJsonCredential{
|
||||
{
|
||||
PublicId: "scjson123",
|
||||
ProjectId: "proj123",
|
||||
ObjectHmac: []byte("hmac"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
VaultCredentialStore: []VaultCredentialStore{
|
||||
{
|
||||
PublicId: "vcs123",
|
||||
ProjectId: "proj123",
|
||||
VaultAddress: "an/address",
|
||||
Namespace: "name",
|
||||
TlsServerName: "imaserver",
|
||||
TlsSkipVerify: false,
|
||||
VaultGenericLibraries: []VaultLibrary{
|
||||
{
|
||||
PublicId: "vl123",
|
||||
ProjectId: "proj123",
|
||||
VaultPath: "/a/path",
|
||||
HttpMethod: "GET",
|
||||
CredentialType: "magic",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
return sessionMeta
|
||||
}
|
||||
@@ -25,6 +25,7 @@ type (
|
||||
EndTime time.Time
|
||||
BytesUp uint64
|
||||
BytesDown uint64
|
||||
Errors error
|
||||
}
|
||||
|
||||
// ChannelSummary encapsulates data for a channel, including its id, channel type,
|
||||
|
||||
Reference in new issue
Block a user