Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions internal/mocks/devicemanagement_mocks.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion internal/usecase/amtexplorer/wsman.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,12 @@ func (g GoWSMANMessages) SetupWsmanClient(device entity.Device, logAMTMessages b
clientParams.PinnedCert = *device.CertHash
}

clientParams.Password, _ = g.safeRequirements.Decrypt(device.Password)
decryptedPassword, err := g.safeRequirements.Decrypt(device.Password)
if err != nil {
return nil, err
}

clientParams.Password = decryptedPassword

connectionsMu.Lock()
defer connectionsMu.Unlock()
Expand Down
23 changes: 17 additions & 6 deletions internal/usecase/ciraconfigs/usecase.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,10 @@ func (uc *UseCase) Delete(ctx context.Context, configName, tenantID string) erro
}

func (uc *UseCase) Update(ctx context.Context, d *dto.CIRAConfig) (*dto.CIRAConfig, error) {
d1 := uc.dtoToEntity(d)
d1, err := uc.dtoToEntity(d)
if err != nil {
return nil, err
}

updated, err := uc.repo.Update(ctx, d1)
if err != nil {
Expand All @@ -111,9 +114,12 @@ func (uc *UseCase) Update(ctx context.Context, d *dto.CIRAConfig) (*dto.CIRAConf
}

func (uc *UseCase) Insert(ctx context.Context, d *dto.CIRAConfig) (*dto.CIRAConfig, error) {
d1 := uc.dtoToEntity(d)
d1, err := uc.dtoToEntity(d)
if err != nil {
return nil, err
}

_, err := uc.repo.Insert(ctx, d1)
_, err = uc.repo.Insert(ctx, d1)
if err != nil {
return nil, ErrDatabase.Wrap("Insert", "uc.repo.Insert", err)
}
Expand All @@ -129,7 +135,7 @@ func (uc *UseCase) Insert(ctx context.Context, d *dto.CIRAConfig) (*dto.CIRAConf
}

// convert dto.CIRAConfig to entity.CIRAConfig.
func (uc *UseCase) dtoToEntity(d *dto.CIRAConfig) *entity.CIRAConfig {
func (uc *UseCase) dtoToEntity(d *dto.CIRAConfig) (*entity.CIRAConfig, error) {
d1 := &entity.CIRAConfig{
ConfigName: d.ConfigName,
MPSAddress: d.MPSAddress,
Expand All @@ -145,10 +151,15 @@ func (uc *UseCase) dtoToEntity(d *dto.CIRAConfig) *entity.CIRAConfig {
GenerateRandomPassword: d.GenerateRandomPassword,
Version: d.Version,
}

var err error
// Encrypt password before storing
d1.Password, _ = uc.safeRequirements.Encrypt(d.Password)
d1.Password, err = uc.safeRequirements.Encrypt(d.Password)
if err != nil {
return nil, ErrCIRAConfigsUseCase.Wrap("dtoToEntity", "failed to encrypt password", err)
}

return d1
return d1, nil
}

// convert entity.CIRAConfig to dto.CIRAConfig.
Expand Down
12 changes: 10 additions & 2 deletions internal/usecase/devices/interceptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,17 @@ func (uc *UseCase) getOrCreateConnection(c context.Context, conn *websocket.Conn
}

func (uc *UseCase) createNewConnection(c context.Context, conn *websocket.Conn, key string, device *entity.Device) (*DeviceConnection, error) {
wsmanConnection := uc.redirection.SetupWsmanClient(*device, true, true)
wsmanConnection, err := uc.redirection.SetupWsmanClient(*device, true, true)
if err != nil {
return nil, err
}

decryptedPassword, err := uc.safeRequirements.Decrypt(device.Password)
if err != nil {
return nil, err
}

device.Password, _ = uc.safeRequirements.Decrypt(device.Password)
device.Password = decryptedPassword

ctx, cancel := context.WithCancel(c)
now := time.Now()
Expand Down
12 changes: 6 additions & 6 deletions internal/usecase/devices/interceptor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func TestRedirect(t *testing.T) {
Username: "user",
Password: "pass",
}, nil)
mockRedir.EXPECT().SetupWsmanClient(gomock.Any(), true, true).Return(wsman.Messages{})
mockRedir.EXPECT().SetupWsmanClient(gomock.Any(), true, true).Return(wsman.Messages{}, nil)
mockRedir.EXPECT().RedirectConnect(gomock.Any(), gomock.Any()).Return(ErrInterceptorGeneral)
},
expectedErr: ErrInterceptorGeneral,
Expand Down Expand Up @@ -138,7 +138,7 @@ func TestRedirectSuccessfulFlow(t *testing.T) {

// Mock successful flow up to RedirectConnect, then fail to avoid goroutines
mockRepo.EXPECT().GetByID(gomock.Any(), testGUID, "").Return(device, nil)
mockRedirection.EXPECT().SetupWsmanClient(*device, true, true).Return(wsman.Messages{})
mockRedirection.EXPECT().SetupWsmanClient(*device, true, true).Return(wsman.Messages{}, nil)
// Return error to avoid starting problematic goroutines but still test the flow
mockRedirection.EXPECT().RedirectConnect(gomock.Any(), gomock.Any()).Return(ErrConnectionFailed)

Expand Down Expand Up @@ -211,15 +211,15 @@ func TestRedirectConnectionReuse(t *testing.T) {

// First call - create new connection but fail at connect to avoid goroutines
mockRepo.EXPECT().GetByID(gomock.Any(), testGUID, "").Return(device, nil)
mockRedirection.EXPECT().SetupWsmanClient(*device, true, true).Return(wsman.Messages{})
mockRedirection.EXPECT().SetupWsmanClient(*device, true, true).Return(wsman.Messages{}, nil)
mockRedirection.EXPECT().RedirectConnect(gomock.Any(), gomock.Any()).Return(ErrFirstConnectionFailed)

err := uc.Redirect(context.Background(), mockConn, testGUID, testMode)
require.Error(t, err)

// Second call - also fail to avoid goroutines but test reuse logic
mockRepo.EXPECT().GetByID(gomock.Any(), testGUID, "").Return(device, nil)
mockRedirection.EXPECT().SetupWsmanClient(*device, true, true).Return(wsman.Messages{})
mockRedirection.EXPECT().SetupWsmanClient(*device, true, true).Return(wsman.Messages{}, nil)
mockRedirection.EXPECT().RedirectConnect(gomock.Any(), gomock.Any()).Return(ErrSecondConnectionFailed)

err = uc.Redirect(context.Background(), mockConn, testGUID, testMode)
Expand Down Expand Up @@ -305,7 +305,7 @@ func TestRedirectWithErrorScenarios(t *testing.T) {

device := &entity.Device{GUID: testGUID, Username: "user", Password: "pass"}
mockRepo.EXPECT().GetByID(gomock.Any(), testGUID, "").Return(device, nil)
mockRedir.EXPECT().SetupWsmanClient(*device, true, true).Return(wsman.Messages{})
mockRedir.EXPECT().SetupWsmanClient(*device, true, true).Return(wsman.Messages{}, nil)
mockRedir.EXPECT().RedirectConnect(gomock.Any(), gomock.Any()).Return(ErrConnectionFailed)
},
expectedErr: "connection failed",
Expand Down Expand Up @@ -383,7 +383,7 @@ func TestRedirectConnectionFlowCoverage(t *testing.T) {

device := &entity.Device{GUID: "test-device", Username: "user", Password: "pass"}
mockRepo.EXPECT().GetByID(gomock.Any(), "test-device", "").Return(device, nil)
mockRedir.EXPECT().SetupWsmanClient(*device, true, true).Return(wsman.Messages{})
mockRedir.EXPECT().SetupWsmanClient(*device, true, true).Return(wsman.Messages{}, nil)
// Return error to avoid starting goroutines, but still exercise connection creation
mockRedir.EXPECT().RedirectConnect(gomock.Any(), gomock.Any()).Return(ErrTestError)
},
Expand Down
2 changes: 1 addition & 1 deletion internal/usecase/devices/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ type (
}

Redirection interface {
SetupWsmanClient(device entity.Device, isRedirection, logMessages bool) wsman.Messages
SetupWsmanClient(device entity.Device, isRedirection, logMessages bool) (wsman.Messages, error)
RedirectConnect(ctx context.Context, deviceConnection *DeviceConnection) error
RedirectClose(ctx context.Context, deviceConnection *DeviceConnection) error
RedirectListen(ctx context.Context, deviceConnection *DeviceConnection) ([]byte, error)
Expand Down
11 changes: 8 additions & 3 deletions internal/usecase/devices/redirection.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type Redirector struct {
SafeRequirements security.Cryptor
}

func (g *Redirector) SetupWsmanClient(device entity.Device, isRedirection, logAMTMessages bool) wsman.Messages {
func (g *Redirector) SetupWsmanClient(device entity.Device, isRedirection, logAMTMessages bool) (wsman.Messages, error) {
clientParams := client.Parameters{
Target: device.Hostname,
Username: device.Username,
Expand All @@ -29,9 +29,14 @@ func (g *Redirector) SetupWsmanClient(device entity.Device, isRedirection, logAM
clientParams.PinnedCert = *device.CertHash
}

clientParams.Password, _ = g.SafeRequirements.Decrypt(device.Password)
decryptedPassword, err := g.SafeRequirements.Decrypt(device.Password)
if err != nil {
return wsman.Messages{}, err
}

clientParams.Password = decryptedPassword

return wsman.NewMessages(clientParams)
return wsman.NewMessages(clientParams), nil
}

func NewRedirector(safeRequirements security.Cryptor) *Redirector {
Expand Down
34 changes: 9 additions & 25 deletions internal/usecase/devices/redirection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ func initRedirectionTest(t *testing.T) (*devices.Redirector, *mocks.MockRedirect
}

type redTest struct {
name string
redMock func(*mocks.MockRedirection)
res any
name string
res any
err error
}

func TestSetupWsmanClient(t *testing.T) {
Expand All @@ -44,21 +44,8 @@ func TestSetupWsmanClient(t *testing.T) {
tests := []redTest{
{
name: "success",
redMock: func(redirect *mocks.MockRedirection) {
redirect.EXPECT().
SetupWsmanClient(gomock.Any(), false, true).
Return(wsman.Messages{})
},
res: wsman.Messages{},
},
{
name: "fail",
redMock: func(redirect *mocks.MockRedirection) {
redirect.EXPECT().
SetupWsmanClient(gomock.Any(), true, true).
Return(wsman.Messages{})
},
res: wsman.Messages{},
res: wsman.Messages{},
err: nil,
},
}

Expand All @@ -67,17 +54,14 @@ func TestSetupWsmanClient(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()

redirector, redirect, _ := initRedirectionTest(t)

tc.redMock(redirect)
redirector, _, _ := initRedirectionTest(t)

redirector.SafeRequirements = security.Crypto{
EncryptionKey: "test",
}
redirector.SafeRequirements = mocks.MockCrypto{}

res := redirector.SetupWsmanClient(*device, true, true)
res, err := redirector.SetupWsmanClient(*device, true, true)

require.IsType(t, tc.res, res)
require.Equal(t, tc.err, err)
})
}
}
Expand Down
10 changes: 9 additions & 1 deletion internal/usecase/devices/wsman/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,15 @@ func (g GoWSMANMessages) SetupWsmanClient(device entity.Device, isRedirection, l
errChan := make(chan error, 1)
// Queue the request
requestQueue <- func() {
device.Password, _ = g.safeRequirements.Decrypt(device.Password)
decryptedPassword, err := g.safeRequirements.Decrypt(device.Password)
if err != nil {
errChan <- err

return
}

device.Password = decryptedPassword

if device.MPSUsername != "" {
if len(Connections) == 0 {
errChan <- ErrCIRADeviceNotConnected
Expand Down
22 changes: 17 additions & 5 deletions internal/usecase/domains/usecase.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,10 @@ func (uc *UseCase) Delete(ctx context.Context, domainName, tenantID string) erro
}

func (uc *UseCase) Update(ctx context.Context, d *dto.Domain) (*dto.Domain, error) {
d1 := uc.dtoToEntity(d)
d1, err := uc.dtoToEntity(d)
if err != nil {
return nil, err
}

updated, err := uc.repo.Update(ctx, d1)
if err != nil {
Expand All @@ -199,7 +202,11 @@ func (uc *UseCase) Insert(ctx context.Context, d *dto.Domain) (*dto.Domain, erro
return nil, err
}

d1 := uc.dtoToEntity(d)
d1, err := uc.dtoToEntity(d)
if err != nil {
return nil, err
}

d1.ExpirationDate = cert.NotAfter.Format(time.RFC3339)

// Store certificate in Vault (if available) - cert goes to Vault, not DB
Expand Down Expand Up @@ -267,7 +274,7 @@ func DecryptAndCheckCertExpiration(domain dto.Domain) (*x509.Certificate, error)
}

// convert dto.Domain to entity.Domain.
func (uc *UseCase) dtoToEntity(d *dto.Domain) *entity.Domain {
func (uc *UseCase) dtoToEntity(d *dto.Domain) (*entity.Domain, error) {
d1 := &entity.Domain{
ProfileName: d.ProfileName,
DomainSuffix: d.DomainSuffix,
Expand All @@ -278,9 +285,14 @@ func (uc *UseCase) dtoToEntity(d *dto.Domain) *entity.Domain {
Version: d.Version,
}

d1.ProvisioningCertPassword, _ = uc.safeRequirements.Encrypt(d.ProvisioningCertPassword)
var err error

return d1
d1.ProvisioningCertPassword, err = uc.safeRequirements.Encrypt(d.ProvisioningCertPassword)
if err != nil {
return nil, ErrDomainsUseCase.Wrap("dtoToEntity", "failed to encrypt provisioning cert password", err)
}

return d1, nil
}

// convert entity.Domain to dto.Domain.
Expand Down
29 changes: 22 additions & 7 deletions internal/usecase/profiles/usecase.go
Original file line number Diff line number Diff line change
Expand Up @@ -481,9 +481,12 @@ func (uc *UseCase) isWifiProfileExists(ctx context.Context, d *dto.Profile, acti
}

func (uc *UseCase) Update(ctx context.Context, d *dto.Profile) (*dto.Profile, error) {
d1 := uc.dtoToEntity(d)
d1, err := uc.dtoToEntity(d)
if err != nil {
return nil, err
}

err := uc.isWifiProfileExists(ctx, d, "update")
err = uc.isWifiProfileExists(ctx, d, "update")
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -530,7 +533,10 @@ func (uc *UseCase) Update(ctx context.Context, d *dto.Profile) (*dto.Profile, er
}

func (uc *UseCase) Insert(ctx context.Context, d *dto.Profile) (*dto.Profile, error) {
d1 := uc.dtoToEntity(d)
d1, err := uc.dtoToEntity(d)
if err != nil {
return nil, err
}

if err := uc.isWifiProfileExists(ctx, d, "insert"); err != nil {
return nil, err
Expand Down Expand Up @@ -612,7 +618,7 @@ func (uc *UseCase) createdProfile(ctx context.Context, d *dto.Profile) (*dto.Pro
}

// convert dto.Profile to entity.Profile.
func (uc *UseCase) dtoToEntity(d *dto.Profile) *entity.Profile {
func (uc *UseCase) dtoToEntity(d *dto.Profile) (*entity.Profile, error) {
// convert []string to comma separated string
tags := strings.Join(d.Tags, ", ")

Expand Down Expand Up @@ -642,10 +648,19 @@ func (uc *UseCase) dtoToEntity(d *dto.Profile) *entity.Profile {
UEFIWiFiSyncEnabled: d.UEFIWiFiSyncEnabled,
}

d1.AMTPassword, _ = uc.safeRequirements.Encrypt(d.AMTPassword)
d1.MEBXPassword, _ = uc.safeRequirements.Encrypt(d.MEBXPassword)
var err error

return d1
d1.AMTPassword, err = uc.safeRequirements.Encrypt(d.AMTPassword)
if err != nil {
return nil, ErrProfilesUseCase.Wrap("dtoToEntity", "failed to encrypt AMT password", err)
}

d1.MEBXPassword, err = uc.safeRequirements.Encrypt(d.MEBXPassword)
if err != nil {
return nil, ErrProfilesUseCase.Wrap("dtoToEntity", "failed to encrypt MEBX password", err)
}

return d1, nil
}

// convert entity.Profile to dto.Profile.
Expand Down
Loading
Loading