Skip to content

Commit e568fca

Browse files
authored
fix: supports null values for MEBX and MPSPasswords (#753)
1 parent ae4e0fa commit e568fca

File tree

5 files changed

+232
-34
lines changed

5 files changed

+232
-34
lines changed

internal/entity/device.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ type Device struct {
1818
DeviceInfo string
1919
Username string
2020
Password string
21-
MPSPassword string
22-
MEBXPassword string
21+
MPSPassword *string
22+
MEBXPassword *string
2323
UseTLS bool
2424
AllowSelfSigned bool
2525
CertHash *string

internal/usecase/devices/repo.go

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,18 @@ func (uc *UseCase) GetByID(ctx context.Context, guid, tenantID string, includeSe
7979
return nil, ErrDeviceUseCase.Wrap("GetByID", "uc.safeRequirements.Decrypt Password", err)
8080
}
8181

82-
d2.MPSPassword, err = uc.safeRequirements.Decrypt(data.MPSPassword)
83-
if err != nil {
84-
return nil, ErrDeviceUseCase.Wrap("GetByID", "uc.safeRequirements.Decrypt MPSPassword", err)
82+
if data.MPSPassword != nil {
83+
d2.MPSPassword, err = uc.safeRequirements.Decrypt(*data.MPSPassword)
84+
if err != nil {
85+
return nil, ErrDeviceUseCase.Wrap("GetByID", "uc.safeRequirements.Decrypt MPSPassword", err)
86+
}
8587
}
8688

87-
d2.MEBXPassword, err = uc.safeRequirements.Decrypt(data.MEBXPassword)
88-
if err != nil {
89-
return nil, ErrDeviceUseCase.Wrap("GetByID", "uc.safeRequirements.Decrypt MEBXPassword", err)
89+
if data.MEBXPassword != nil {
90+
d2.MEBXPassword, err = uc.safeRequirements.Decrypt(*data.MEBXPassword)
91+
if err != nil {
92+
return nil, ErrDeviceUseCase.Wrap("GetByID", "uc.safeRequirements.Decrypt MEBXPassword", err)
93+
}
9094
}
9195
}
9296

@@ -143,7 +147,10 @@ func (uc *UseCase) Delete(ctx context.Context, guid, tenantID string) error {
143147
}
144148

145149
func (uc *UseCase) Update(ctx context.Context, d *dto.Device) (*dto.Device, error) {
146-
d1 := uc.dtoToEntity(d)
150+
d1, err := uc.dtoToEntity(d)
151+
if err != nil {
152+
return nil, err
153+
}
147154

148155
updated, err := uc.repo.Update(ctx, d1)
149156
if err != nil {
@@ -168,13 +175,16 @@ func (uc *UseCase) Update(ctx context.Context, d *dto.Device) (*dto.Device, erro
168175
}
169176

170177
func (uc *UseCase) Insert(ctx context.Context, d *dto.Device) (*dto.Device, error) {
171-
d1 := uc.dtoToEntity(d)
178+
d1, err := uc.dtoToEntity(d)
179+
if err != nil {
180+
return nil, err
181+
}
172182

173183
if d1.GUID == "" {
174184
d1.GUID = uuid.New().String()
175185
}
176186

177-
_, err := uc.repo.Insert(ctx, d1)
187+
_, err = uc.repo.Insert(ctx, d1)
178188
if err != nil {
179189
return nil, ErrDatabase.Wrap("Insert", "uc.repo.Insert", err)
180190
}

internal/usecase/devices/repo_test.go

Lines changed: 176 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ import (
1414
"github.com/device-management-toolkit/console/pkg/logger"
1515
)
1616

17+
func ptr(s string) *string {
18+
return &s
19+
}
20+
1721
type testUsecase struct {
1822
name string
1923
guid string
@@ -291,8 +295,8 @@ func TestUpdate(t *testing.T) {
291295
GUID: "device-guid-123",
292296
TenantID: "tenant-id-456",
293297
Password: "encrypted",
294-
MPSPassword: "encrypted",
295-
MEBXPassword: "encrypted",
298+
MPSPassword: nil,
299+
MEBXPassword: nil,
296300
Tags: "hello,test",
297301
}
298302

@@ -367,8 +371,8 @@ func TestInsert(t *testing.T) {
367371
device := &entity.Device{
368372
GUID: "device-guid-123",
369373
Password: "encrypted",
370-
MPSPassword: "encrypted",
371-
MEBXPassword: "encrypted",
374+
MPSPassword: nil,
375+
MEBXPassword: nil,
372376
TenantID: "tenant-id-456",
373377
}
374378

@@ -388,8 +392,8 @@ func TestInsert(t *testing.T) {
388392
device := &entity.Device{
389393
GUID: "device-guid-123",
390394
Password: "encrypted",
391-
MPSPassword: "encrypted",
392-
MEBXPassword: "encrypted",
395+
MPSPassword: nil,
396+
MEBXPassword: nil,
393397
TenantID: "tenant-id-456",
394398
}
395399

@@ -431,3 +435,169 @@ func TestInsert(t *testing.T) {
431435
})
432436
}
433437
}
438+
439+
func TestUpdateWithPasswords(t *testing.T) {
440+
t.Parallel()
441+
442+
// Entity with encrypted passwords (what gets stored in DB)
443+
deviceWithPasswords := &entity.Device{
444+
GUID: "device-guid-123",
445+
TenantID: "tenant-id-456",
446+
Password: "encrypted",
447+
MPSPassword: ptr("encrypted"),
448+
MEBXPassword: ptr("encrypted"),
449+
Tags: "hello,test",
450+
}
451+
452+
// DTO with plaintext passwords (what comes from API)
453+
deviceDTOWithPasswords := &dto.Device{
454+
GUID: "device-guid-123",
455+
TenantID: "tenant-id-456",
456+
Tags: []string{"hello", "test"},
457+
MPSPassword: "mpspass",
458+
MEBXPassword: "mebxpass",
459+
}
460+
461+
// Expected DTO result (passwords not returned without includeSecrets)
462+
expectedDTO := &dto.Device{
463+
GUID: "device-guid-123",
464+
TenantID: "tenant-id-456",
465+
Tags: []string{"hello", "test"},
466+
MPSPassword: "encrypted",
467+
MEBXPassword: "encrypted",
468+
}
469+
470+
t.Run("successful update with passwords", func(t *testing.T) {
471+
t.Parallel()
472+
473+
useCase, repo, management := devicesTest(t)
474+
475+
repo.EXPECT().
476+
Update(context.Background(), deviceWithPasswords).
477+
Return(true, nil)
478+
repo.EXPECT().
479+
GetByID(context.Background(), "device-guid-123", "tenant-id-456").
480+
Return(deviceWithPasswords, nil)
481+
management.EXPECT().
482+
DestroyWsmanClient(*expectedDTO)
483+
484+
result, err := useCase.Update(context.Background(), deviceDTOWithPasswords)
485+
486+
require.NoError(t, err)
487+
require.Equal(t, expectedDTO, result)
488+
})
489+
}
490+
491+
func TestInsertWithPasswords(t *testing.T) {
492+
t.Parallel()
493+
494+
t.Run("successful insertion with passwords", func(t *testing.T) {
495+
t.Parallel()
496+
497+
useCase, repo, _ := devicesTest(t)
498+
499+
// Entity with encrypted passwords
500+
deviceWithPasswords := &entity.Device{
501+
GUID: "device-guid-123",
502+
TenantID: "tenant-id-456",
503+
Password: "encrypted",
504+
MPSPassword: ptr("encrypted"),
505+
MEBXPassword: ptr("encrypted"),
506+
}
507+
508+
repo.EXPECT().
509+
Insert(context.Background(), deviceWithPasswords).
510+
Return("unique-device-id", nil)
511+
repo.EXPECT().
512+
GetByID(context.Background(), "device-guid-123", "tenant-id-456").
513+
Return(deviceWithPasswords, nil)
514+
515+
// DTO with plaintext passwords
516+
deviceDTO := &dto.Device{
517+
GUID: "device-guid-123",
518+
TenantID: "tenant-id-456",
519+
Tags: []string{""},
520+
MPSPassword: "mpspass",
521+
MEBXPassword: "mebxpass",
522+
}
523+
524+
insertedDevice, err := useCase.Insert(context.Background(), deviceDTO)
525+
526+
require.NoError(t, err)
527+
require.Equal(t, deviceDTO.TenantID, insertedDevice.TenantID)
528+
require.Equal(t, "encrypted", insertedDevice.MPSPassword)
529+
require.Equal(t, "encrypted", insertedDevice.MEBXPassword)
530+
})
531+
}
532+
533+
func TestGetByIDWithSecrets(t *testing.T) {
534+
t.Parallel()
535+
536+
// Entity with encrypted passwords from DB
537+
deviceWithPasswords := &entity.Device{
538+
GUID: "device-guid-123",
539+
TenantID: "tenant-id-456",
540+
Password: "encrypted",
541+
MPSPassword: ptr("encrypted"),
542+
MEBXPassword: ptr("encrypted"),
543+
}
544+
545+
// Expected DTO with decrypted passwords
546+
expectedDTO := &dto.Device{
547+
GUID: "device-guid-123",
548+
TenantID: "tenant-id-456",
549+
Tags: nil,
550+
Password: "decrypted",
551+
MPSPassword: "decrypted",
552+
MEBXPassword: "decrypted",
553+
}
554+
555+
t.Run("successful retrieval with secrets", func(t *testing.T) {
556+
t.Parallel()
557+
558+
useCase, repo, _ := devicesTest(t)
559+
560+
repo.EXPECT().
561+
GetByID(context.Background(), "device-guid-123", "tenant-id-456").
562+
Return(deviceWithPasswords, nil)
563+
564+
got, err := useCase.GetByID(context.Background(), "device-guid-123", "tenant-id-456", true)
565+
566+
require.NoError(t, err)
567+
require.Equal(t, expectedDTO, got)
568+
})
569+
570+
t.Run("retrieval with secrets - nil passwords", func(t *testing.T) {
571+
t.Parallel()
572+
573+
useCase, repo, _ := devicesTest(t)
574+
575+
// Entity with nil passwords
576+
deviceNilPasswords := &entity.Device{
577+
GUID: "device-guid-123",
578+
TenantID: "tenant-id-456",
579+
Password: "encrypted",
580+
MPSPassword: nil,
581+
MEBXPassword: nil,
582+
}
583+
584+
repo.EXPECT().
585+
GetByID(context.Background(), "device-guid-123", "tenant-id-456").
586+
Return(deviceNilPasswords, nil)
587+
588+
// Expected DTO - passwords should be empty strings when nil
589+
expectedDTONilPasswords := &dto.Device{
590+
GUID: "device-guid-123",
591+
TenantID: "tenant-id-456",
592+
Tags: nil,
593+
Password: "decrypted",
594+
MPSPassword: "",
595+
MEBXPassword: "",
596+
}
597+
598+
got, err := useCase.GetByID(context.Background(), "device-guid-123", "tenant-id-456", true)
599+
600+
require.NoError(t, err)
601+
require.Equal(t, expectedDTONilPasswords, got)
602+
})
603+
}

internal/usecase/devices/usecase.go

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ func New(r Repository, d WSMAN, redirection Redirection, log logger.Interface, s
6666
}
6767

6868
// convert dto.Device to entity.Device.
69-
func (uc *UseCase) dtoToEntity(d *dto.Device) *entity.Device {
69+
func (uc *UseCase) dtoToEntity(d *dto.Device) (*entity.Device, error) {
7070
// convert []string to comma separated string
7171
if d.Tags == nil {
7272
d.Tags = []string{}
@@ -90,8 +90,6 @@ func (uc *UseCase) dtoToEntity(d *dto.Device) *entity.Device {
9090
// DeviceInfo: d.DeviceInfo,
9191
Username: d.Username,
9292
Password: d.Password,
93-
MPSPassword: d.MPSPassword,
94-
MEBXPassword: d.MEBXPassword,
9593
UseTLS: d.UseTLS,
9694
AllowSelfSigned: d.AllowSelfSigned,
9795
}
@@ -100,17 +98,29 @@ func (uc *UseCase) dtoToEntity(d *dto.Device) *entity.Device {
10098

10199
d1.Password, err = uc.safeRequirements.Encrypt(d1.Password)
102100
if err != nil {
103-
uc.log.Error("Error encrypting password")
101+
return nil, ErrDeviceUseCase.Wrap("dtoToEntity", "failed to encrypt password", err)
104102
}
105103

106-
d1.MPSPassword, err = uc.safeRequirements.Encrypt(d1.MPSPassword)
107-
if err != nil {
108-
uc.log.Error("Error encrypting MPS password")
104+
if d.MPSPassword == "" {
105+
d1.MPSPassword = nil
106+
} else {
107+
encrypted, err := uc.safeRequirements.Encrypt(d.MPSPassword)
108+
if err != nil {
109+
return nil, ErrDeviceUseCase.Wrap("dtoToEntity", "failed to encrypt MPS password", err)
110+
}
111+
112+
d1.MPSPassword = &encrypted
109113
}
110114

111-
d1.MEBXPassword, err = uc.safeRequirements.Encrypt(d1.MEBXPassword)
112-
if err != nil {
113-
uc.log.Error("Error encrypting MEBX password")
115+
if d.MEBXPassword == "" {
116+
d1.MEBXPassword = nil
117+
} else {
118+
encrypted, err := uc.safeRequirements.Encrypt(d.MEBXPassword)
119+
if err != nil {
120+
return nil, ErrDeviceUseCase.Wrap("dtoToEntity", "failed to encrypt MEBX password", err)
121+
}
122+
123+
d1.MEBXPassword = &encrypted
114124
}
115125

116126
if d.CertHash == "" {
@@ -119,7 +129,7 @@ func (uc *UseCase) dtoToEntity(d *dto.Device) *entity.Device {
119129
d1.CertHash = &d.CertHash
120130
}
121131

122-
return d1
132+
return d1, nil
123133
}
124134

125135
// convert entity.Device to dto.Device.
@@ -154,5 +164,13 @@ func (uc *UseCase) entityToDTO(d *entity.Device) *dto.Device {
154164
d1.CertHash = *d.CertHash
155165
}
156166

167+
if d.MPSPassword != nil {
168+
d1.MPSPassword = *d.MPSPassword
169+
}
170+
171+
if d.MEBXPassword != nil {
172+
d1.MEBXPassword = *d.MEBXPassword
173+
}
174+
157175
return d1
158176
}

internal/usecase/sqldb/device_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ func setupDeviceTable(t *testing.T) *sql.DB {
4343
deviceinfo TEXT NOT NULL DEFAULT '',
4444
username TEXT NOT NULL DEFAULT '',
4545
password TEXT NOT NULL DEFAULT '',
46-
mpspassword TEXT NOT NULL DEFAULT '',
47-
mebxpassword TEXT NOT NULL DEFAULT '',
46+
mpspassword TEXT,
47+
mebxpassword TEXT,
4848
usetls BOOLEAN NOT NULL DEFAULT FALSE,
4949
allowselfsigned BOOLEAN NOT NULL DEFAULT FALSE,
5050
certhash TEXT NOT NULL DEFAULT ''
@@ -656,8 +656,8 @@ func TestDeviceRepo_Delete(t *testing.T) {
656656
deviceinfo TEXT NOT NULL DEFAULT '',
657657
username TEXT NOT NULL DEFAULT '',
658658
password TEXT NOT NULL DEFAULT '',
659-
mpspassword TEXT NOT NULL DEFAULT '',
660-
mebxpassword TEXT NOT NULL DEFAULT '',
659+
mpspassword TEXT,
660+
mebxpassword TEXT,
661661
usetls BOOLEAN NOT NULL DEFAULT FALSE,
662662
allowselfsigned BOOLEAN NOT NULL DEFAULT FALSE
663663
);
@@ -806,8 +806,8 @@ func TestDeviceRepo_Update(t *testing.T) {
806806
deviceinfo TEXT NOT NULL DEFAULT '',
807807
username TEXT NOT NULL DEFAULT '',
808808
password TEXT NOT NULL DEFAULT '',
809-
mpspassword TEXT NOT NULL DEFAULT '',
810-
mebxpassword TEXT NOT NULL DEFAULT '',
809+
mpspassword TEXT,
810+
mebxpassword TEXT,
811811
usetls BOOLEAN NOT NULL DEFAULT FALSE,
812812
allowselfsigned BOOLEAN NOT NULL DEFAULT FALSE,
813813
certhash TEXT NOT NULL DEFAULT ''

0 commit comments

Comments
 (0)