Skip to content

Commit a9b4923

Browse files
committed
feat(secrets): update ui
1 parent de36e37 commit a9b4923

File tree

8 files changed

+177
-75
lines changed

8 files changed

+177
-75
lines changed

db/SecretStorage.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ type SecretStorageType string
55
const (
66
SecretStorageTypeLocal SecretStorageType = "local"
77
SecretStorageTypeVault SecretStorageType = "vault"
8+
SecretStorageTypeDvls SecretStorageType = "dvls"
89
)
910

1011
type SecretStorage struct {
@@ -15,5 +16,5 @@ type SecretStorage struct {
1516
Params MapStringAnyField `db:"params" json:"params"`
1617
ReadOnly bool `db:"readonly" json:"readonly"`
1718

18-
VaultToken string `db:"-" json:"vault_token,omitempty" backup:"-"`
19+
Secret string `db:"-" json:"secret,omitempty" backup:"-"`
1920
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package server
2+
3+
import (
4+
"github.com/semaphoreui/semaphore/db"
5+
)
6+
7+
type DvlsStorageTokenDeserializer interface {
8+
DeserializeSecret(key *db.AccessKey) error
9+
}
10+
11+
type DvlsAccessKeyDeserializer struct {
12+
}
13+
14+
func NewDvlsAccessKeyDeserializer(
15+
_ db.AccessKeyManager,
16+
_ db.SecretStorageRepository,
17+
_ VaultStorageTokenDeserializer,
18+
) *DvlsAccessKeyDeserializer {
19+
return &DvlsAccessKeyDeserializer{}
20+
}
21+
22+
func (d *DvlsAccessKeyDeserializer) DeleteSecret(key *db.AccessKey) error {
23+
return nil
24+
}
25+
26+
func (d *DvlsAccessKeyDeserializer) SerializeSecret(key *db.AccessKey) (err error) {
27+
return
28+
}
29+
30+
func (d *DvlsAccessKeyDeserializer) DeserializeSecret(key *db.AccessKey) (res string, err error) {
31+
return
32+
}

pro/services/server/access_key_serializer_rdm.go

Lines changed: 0 additions & 32 deletions
This file was deleted.

services/server/access_key_encryption_svc.go

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ import (
44
"encoding/json"
55
"errors"
66
"fmt"
7+
"strings"
8+
79
"github.com/semaphoreui/semaphore/db"
810
pro "github.com/semaphoreui/semaphore/pro/services/server"
9-
"strings"
1011
)
1112

1213
const RekeyBatchSize = 100
@@ -56,24 +57,48 @@ type accessKeyEncryptionServiceImpl struct {
5657
secretStorageRepo db.SecretStorageRepository
5758
}
5859

59-
func (s *accessKeyEncryptionServiceImpl) getDeserializer(key *db.AccessKey) AccessKeyDeserializer {
60+
func (s *accessKeyEncryptionServiceImpl) getDeserializer(key *db.AccessKey) (AccessKeyDeserializer, error) {
6061
if key.SourceStorageID == nil {
61-
return &LocalAccessKeyDeserializer{}
62+
return &LocalAccessKeyDeserializer{}, nil
6263
}
6364

64-
return pro.NewVaultAccessKeyDeserializer(s.accessKeyRepo, s.secretStorageRepo, s)
65+
storage, err := s.secretStorageRepo.GetSecretStorage(*key.ProjectID, *key.SourceStorageID)
66+
if err != nil {
67+
return nil, err
68+
}
69+
70+
switch storage.Type {
71+
case db.SecretStorageTypeVault:
72+
return pro.NewVaultAccessKeyDeserializer(s.accessKeyRepo, s.secretStorageRepo, s), nil
73+
case db.SecretStorageTypeDvls:
74+
return pro.NewDvlsAccessKeyDeserializer(s.accessKeyRepo, s.secretStorageRepo, s), nil
75+
}
76+
77+
return nil, fmt.Errorf("unsupported secret storage type '%s'", storage.Type)
6578
}
6679

6780
func (s *accessKeyEncryptionServiceImpl) DeleteSecret(key *db.AccessKey) error {
68-
return s.getDeserializer(key).DeleteSecret(key)
81+
d, err := s.getDeserializer(key)
82+
if err != nil {
83+
return err
84+
}
85+
return d.DeleteSecret(key)
6986
}
7087

7188
func (s *accessKeyEncryptionServiceImpl) SerializeSecret(key *db.AccessKey) error {
72-
return s.getDeserializer(key).SerializeSecret(key)
89+
d, err := s.getDeserializer(key)
90+
if err != nil {
91+
return err
92+
}
93+
return d.SerializeSecret(key)
7394
}
7495

7596
func (s *accessKeyEncryptionServiceImpl) DeserializeSecret(key *db.AccessKey) error {
76-
ciphertext, err := s.getDeserializer(key).DeserializeSecret(key)
97+
d, err := s.getDeserializer(key)
98+
if err != nil {
99+
return err
100+
}
101+
ciphertext, err := d.DeserializeSecret(key)
77102
if err != nil {
78103
return err
79104
}

services/server/secret_storage_svc.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ func (s *SecretStorageServiceImpl) Create(storage db.SecretStorage) (res db.Secr
6666
Name: random.String(10),
6767
Type: db.AccessKeyString,
6868
ProjectID: &storage.ProjectID,
69-
String: storage.VaultToken,
69+
String: storage.Secret,
7070
Owner: db.AccessKeyVault,
7171
StorageID: &res.ID,
7272
}
@@ -92,12 +92,12 @@ func (s *SecretStorageServiceImpl) Update(storage db.SecretStorage) (err error)
9292
}
9393

9494
if len(keys) == 0 {
95-
if storage.VaultToken != "" {
95+
if storage.Secret != "" {
9696
_, err = s.accessKeyService.Create(db.AccessKey{
9797
Name: random.String(10),
9898
Type: db.AccessKeyString,
9999
ProjectID: &storage.ProjectID,
100-
String: storage.VaultToken,
100+
String: storage.Secret,
101101
Owner: db.AccessKeyVault,
102102
StorageID: &storage.ID,
103103
})
@@ -107,14 +107,14 @@ func (s *SecretStorageServiceImpl) Update(storage db.SecretStorage) (err error)
107107
}
108108
} else {
109109
vault := keys[0]
110-
if storage.VaultToken == "" {
110+
if storage.Secret == "" {
111111
// Do nothing if the vault token is empty,
112112
// as it means the user haven't set a new token.
113113

114114
//err = s.keyRepo.DeleteAccessKey(storage.ProjectID, vault.ID)
115115
} else {
116116
vault.OverrideSecret = true
117-
vault.String = storage.VaultToken
117+
vault.String = storage.Secret
118118
err = s.accessKeyService.Update(vault)
119119
}
120120
}

web/src/assets/scss/components.scss

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,18 @@
3030
align-items: center;
3131
flex-wrap: wrap;
3232
}
33+
}
34+
35+
.TextInput {
36+
37+
}
38+
39+
.TextInput--no-legend {
40+
legend {
41+
width: 0 !important;
42+
}
43+
44+
.v-label.v-label--active {
45+
display: none;
46+
}
3347
}

web/src/components/SecretStorageForm.vue

Lines changed: 91 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -22,52 +22,115 @@
2222
dense
2323
></v-text-field>
2424

25-
<!--
26-
<v-select
27-
v-model="item.type"
28-
:label="$t('type')"
29-
:rules="[v => !!v || $t('type_required')]"
30-
:items="secretStorageTypes"
31-
item-value="id"
32-
item-text="name"
33-
required
25+
<v-text-field
26+
v-model="item.params.url"
27+
:label="$t('Server URL')"
3428
:disabled="formSaving"
29+
:rules="[v => !!v || $t('url_required')]"
30+
required
31+
data-testid="secretStorage-vaultURL"
3532
outlined
3633
dense
37-
/>
38-
-->
34+
></v-text-field>
3935

4036
<div v-if="item.type === 'vault'">
4137

4238
<v-text-field
43-
v-model="item.params.url"
44-
:label="$t('Server URL')"
39+
v-model="item.secret"
40+
:label="$t('Token')"
4541
:disabled="formSaving"
46-
:rules="[v => !!v || $t('url_required')]"
42+
:rules="[v => !!v || itemId !== 'new' || $t('token_required')]"
4743
required
48-
data-testid="secretStorage-vaultURL"
44+
data-testid="secretStorage-vaultToken"
4945
outlined
5046
dense
47+
append-icon="mdi-lock"
5148
></v-text-field>
5249

50+
</div>
51+
52+
<div v-else-if="item.type === 'dvls'">
53+
54+
<v-checkbox
55+
class="pt-0 mb-2"
56+
style="margin-top: -5px;"
57+
v-model="item.params.insecure_tls"
58+
label="Skip TLS certificate verification (insecure)"
59+
:disabled="formSaving"
60+
/>
61+
5362
<v-text-field
54-
v-model="item.vault_token"
55-
:label="$t('Token')"
63+
v-model="item.params.vault_id"
64+
:label="$t('Vault ID')"
5665
:disabled="formSaving"
57-
:rules="[v => !!v || itemId !== 'new' || $t('token_required')]"
66+
:rules="[v => !!v || itemId !== 'new' || $t('key_required')]"
5867
required
59-
data-testid="secretStorage-vaultToken"
68+
data-testid="secretStorage-dvlsKey"
69+
outlined
70+
dense
71+
></v-text-field>
72+
73+
<v-text-field
74+
v-model="item.params.app_key"
75+
:label="$t('App Key')"
76+
:disabled="formSaving"
77+
:rules="[v => !!v || itemId !== 'new' || $t('key_required')]"
78+
required
79+
data-testid="secretStorage-dvlsKey"
80+
outlined
81+
dense
82+
></v-text-field>
83+
84+
<div class="d-flex justify-space-between align-center">
85+
<b style="font-size: 13px; margin-left: 5px;">App secret</b>
86+
<v-btn-toggle
87+
v-model="secretStorage"
88+
tile
89+
group
90+
>
91+
<v-btn value="database" small class="mr-0 mt-0" style="border-radius: 4px;">
92+
Store in DB
93+
</v-btn>
94+
<v-btn value="env" small class="mr-0 mt-0" style="border-radius: 4px;">
95+
Read from ENV
96+
</v-btn>
97+
</v-btn-toggle>
98+
</div>
99+
100+
<v-text-field
101+
v-if="secretStorage === 'database'"
102+
class="TextInput TextInput--no-legend"
103+
v-model="item.secret"
104+
:label="$t('Secret')"
105+
:disabled="formSaving"
106+
:rules="[v => !!v || itemId !== 'new' || $t('secret_required')]"
107+
required
108+
data-testid="secretStorage-dvlsSecret"
60109
outlined
61110
dense
62111
append-icon="mdi-lock"
63112
></v-text-field>
64113

65-
<!-- <v-checkbox-->
66-
<!-- v-model="item.readonly"-->
67-
<!-- :label="$t('Read only')"-->
68-
<!-- :disabled="formSaving"-->
69-
<!-- />-->
114+
<v-text-field
115+
v-else
116+
class="TextInput TextInput--no-legend"
117+
v-model="item.source_storage_key"
118+
:label="$t('Env var name')"
119+
:disabled="formSaving"
120+
:rules="[v => !!v || itemId !== 'new' || $t('envvar_required')]"
121+
required
122+
data-testid="secretStorage-dvlsSecret"
123+
outlined
124+
dense
125+
></v-text-field>
126+
70127
</div>
128+
129+
<v-checkbox
130+
v-model="item.readonly"
131+
:label="$t('Read only')"
132+
:disabled="formSaving"
133+
/>
71134
</v-form>
72135
</template>
73136
<script>
@@ -82,10 +145,7 @@ export default {
82145
83146
data() {
84147
return {
85-
secretStorageTypes: [{
86-
id: 'vault',
87-
name: 'Hashicorp Vault',
88-
}],
148+
secretStorage: 'database',
89149
};
90150
},
91151
@@ -102,7 +162,9 @@ export default {
102162
this.item.params = {};
103163
}
104164
105-
this.item.type = this.itemType;
165+
if (this.itemId === 'new') {
166+
this.item.type = this.itemType;
167+
}
106168
},
107169
108170
getItemsUrl() {

web/src/views/project/SecretStorages.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
<EditDialog
1919
v-model="editDialog"
2020
:save-button-text="itemId === 'new' ? $t('create') : $t('save')"
21-
:title="`${itemId === 'new' ? $t('nnew') : $t('edit')} Hashicorp Vault Storage`"
21+
:title="`${itemId === 'new' ? $t('nnew') : $t('edit')} ${itemType} Storage`"
2222
:max-width="450"
2323
@save="loadItems()"
2424
>

0 commit comments

Comments
 (0)