-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathentry_user_credentials.go
192 lines (156 loc) · 5.99 KB
/
entry_user_credentials.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
package dvls
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
)
type EntryUserCredentialService service
const (
entryPublicEndpoint string = "/api/v1/vault/{vaultId}/entry/{id}"
EntryTypeCredential string = "Credential"
EntrySubTypeDefault string = "Default"
)
// EntryUserCredential represents a DVLS entry/connection.
type EntryUserCredential struct {
ID string `json:"id,omitempty"`
VaultId string `json:"vaultId"`
EntryName string `json:"name"`
Description string `json:"description"`
Path string `json:"path"`
ModifiedOn *ServerTime `json:"modifiedOn,omitempty"`
ModifiedBy string `json:"modifiedBy,omitempty"`
CreatedOn *ServerTime `json:"createdOn,omitempty"`
CreatedBy string `json:"createdBy,omitempty"`
Type string `json:"type"`
SubType string `json:"subType"`
Tags []string `json:"tags,omitempty"`
Credentials EntryCredentials `json:"data,omitempty"`
}
// EntryCredentials represents an EntryUserCredential Credentials fields.
type EntryCredentials struct {
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
}
func entryReplacer(vaultId string, entryId string) string {
replacer := strings.NewReplacer("{vaultId}", vaultId, "{id}", entryId)
return replacer.Replace(entryPublicEndpoint)
}
// validateEntry checks if an EntryUserCredential has the required fields and valid type/subtype.
func (c *EntryUserCredentialService) validateEntry(entry *EntryUserCredential) error {
if entry.VaultId == "" {
return fmt.Errorf("entry must have a VaultId")
}
if entry.Type != EntryTypeCredential {
return fmt.Errorf("unsupported entry type (%s). Only %s is supported", entry.Type, EntryTypeCredential)
}
if entry.SubType == "" {
entry.SubType = EntrySubTypeDefault
} else if entry.SubType != EntrySubTypeDefault {
return fmt.Errorf("unsupported entry subtype (%s). Only %s is supported", entry.SubType, EntrySubTypeDefault)
}
return nil
}
// Get returns a single EntryUserCredential specified by entryId.
func (c *EntryUserCredentialService) Get(vaultId string, entryId string) (EntryUserCredential, error) {
if entryId == "" || vaultId == "" {
return EntryUserCredential{}, fmt.Errorf("both entry ID and vault ID are required for deletion")
}
var entry EntryUserCredential
entryUri := entryReplacer(vaultId, entryId)
reqUrl, err := url.JoinPath(c.client.baseUri, entryUri)
if err != nil {
return EntryUserCredential{}, fmt.Errorf("failed to build entry url. error: %w", err)
}
resp, err := c.client.Request(reqUrl, http.MethodGet, nil)
if err != nil {
return EntryUserCredential{}, fmt.Errorf("error while fetching entry. error: %w", err)
}
err = json.Unmarshal(resp.Response, &entry)
if err != nil {
return EntryUserCredential{}, fmt.Errorf("failed to unmarshal response body. error: %w", err)
}
entry.VaultId = vaultId
if entry.SubType == "" {
entry.SubType = EntrySubTypeDefault
}
return entry, nil
}
// New creates a new EntryUserCredential based on entry.
func (c *EntryUserCredentialService) New(entry EntryUserCredential) (EntryUserCredential, error) {
if err := c.validateEntry(&entry); err != nil {
return EntryUserCredential{}, err
}
entry.ID = ""
baseEntryEndpoint := strings.Replace(entryPublicEndpoint, "/{id}", "", 1)
entryUri := strings.Replace(baseEntryEndpoint, "{vaultId}", entry.VaultId, 1)
reqUrl, err := url.JoinPath(c.client.baseUri, entryUri)
if err != nil {
return EntryUserCredential{}, fmt.Errorf("failed to build entry url. error: %w", err)
}
entryJson, err := json.Marshal(entry)
if err != nil {
return EntryUserCredential{}, fmt.Errorf("failed to marshal body. error: %w", err)
}
resp, err := c.client.Request(reqUrl, http.MethodPost, bytes.NewBuffer(entryJson))
if err != nil {
return EntryUserCredential{}, fmt.Errorf("error while creating entry. error: %w", err)
}
err = json.Unmarshal(resp.Response, &entry)
if err != nil {
return EntryUserCredential{}, fmt.Errorf("failed to unmarshal response body. error: %w", err)
}
return entry, nil
}
// Update updates an EntryUserCredential based on entry.
func (c *EntryUserCredentialService) Update(entry EntryUserCredential) (EntryUserCredential, error) {
if err := c.validateEntry(&entry); err != nil {
return EntryUserCredential{}, err
}
if entry.ID == "" {
return EntryUserCredential{}, fmt.Errorf("entry ID is required for updates")
}
originalEntry, err := c.Get(entry.VaultId, entry.ID)
if err != nil {
return EntryUserCredential{}, fmt.Errorf("failed to fetch original entry. error: %w", err)
}
if originalEntry.SubType != entry.SubType {
return EntryUserCredential{}, fmt.Errorf("entry subType cannot be changed")
}
entryUri := entryReplacer(entry.VaultId, entry.ID)
reqUrl, err := url.JoinPath(c.client.baseUri, entryUri)
if err != nil {
return EntryUserCredential{}, fmt.Errorf("failed to build entry url. error: %w", err)
}
entryJson, err := json.Marshal(entry)
if err != nil {
return EntryUserCredential{}, fmt.Errorf("failed to marshal body. error: %w", err)
}
_, err = c.client.Request(reqUrl, http.MethodPut, bytes.NewBuffer(entryJson))
if err != nil {
return EntryUserCredential{}, fmt.Errorf("error while updating entry. error: %w", err)
}
entry, err = c.Get(entry.VaultId, entry.ID)
if err != nil {
return EntryUserCredential{}, fmt.Errorf("update succeeded but failed to fetch updated entry: %w", err)
}
return entry, nil
}
// Delete deletes an entry based on entry.
func (c *EntryUserCredentialService) Delete(entry EntryUserCredential) error {
if entry.ID == "" || entry.VaultId == "" {
return fmt.Errorf("both entry ID and vault ID are required")
}
entryUri := entryReplacer(entry.VaultId, entry.ID)
reqUrl, err := url.JoinPath(c.client.baseUri, entryUri)
if err != nil {
return fmt.Errorf("failed to build delete entry url. error: %w", err)
}
_, err = c.client.Request(reqUrl, http.MethodDelete, nil)
if err != nil {
return fmt.Errorf("error while deleting entry. error: %w", err)
}
return nil
}