Skip to content

Commit 3aef1fa

Browse files
committed
Added file storage
1 parent f72ba0c commit 3aef1fa

File tree

14 files changed

+761
-381
lines changed

14 files changed

+761
-381
lines changed

client.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ type Client struct {
3434
sync.Mutex
3535
*http.Client
3636

37+
// Parent object for client options
38+
Parent any
39+
3740
endpoint *url.URL
3841
ua string
3942
rate float32 // number of requests allowed per second

clientopts.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,16 @@ func OptHeader(key, value string) ClientOpt {
113113
return nil
114114
}
115115
}
116+
117+
// OptParent sets the parent client for this client, which is
118+
// used for setting additional client options in the parent
119+
func OptParent(v any) ClientOpt {
120+
return func(client *Client) error {
121+
if v == nil {
122+
return ErrBadParameter.With("OptParent")
123+
} else {
124+
client.Parent = v
125+
}
126+
return nil
127+
}
128+
}

cmd/api/anthropic.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func anthropicParse(flags *Flags, opts ...client.ClientOpt) error {
5454

5555
func anthropicChat(w *tablewriter.Writer, args []string) error {
5656
// Request -> Response
57-
message := schema.NewMessage(schema.Anthropic, "user", nil)
57+
message := schema.NewMessage("user")
5858
for _, arg := range args {
5959
message.Add(arg)
6060
}

cmd/api/bitwarden.go

Lines changed: 39 additions & 223 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,10 @@ const (
3434
)
3535

3636
var (
37-
bwClient *bitwarden.Client
38-
bwClientId, bwClientSecret string
39-
bwPassword string
40-
bwConfigDir string
41-
bwForce bool
37+
bwClient *bitwarden.Client
38+
bwPassword string
39+
bwConfigDir string
40+
bwForce bool
4241
)
4342

4443
///////////////////////////////////////////////////////////////////////////////
@@ -58,7 +57,6 @@ func bwRegister(flags *Flags) {
5857
Parse: bwParse,
5958
Fn: []Fn{
6059
{Name: "auth", Description: "Authenticate with Bitwarden", Call: bwAuth},
61-
{Name: "sync", Description: "Sync items from Bitwarden", Call: bwSync},
6260
{Name: "folders", Description: "Retrieve folders", Call: bwFolders},
6361
{Name: "logins", Description: "Retrieve login items", Call: bwLogins, MaxArgs: 1},
6462
{Name: "password", Description: "Print a password to stdout", Call: bwGetPassword, MinArgs: 1, MaxArgs: 1},
@@ -67,12 +65,6 @@ func bwRegister(flags *Flags) {
6765
}
6866

6967
func bwParse(flags *Flags, opts ...client.ClientOpt) error {
70-
if client, err := bitwarden.New(opts...); err != nil {
71-
return err
72-
} else {
73-
bwClient = client
74-
}
75-
7668
// Get config directory
7769
if config, err := os.UserConfigDir(); err != nil {
7870
return err
@@ -84,14 +76,23 @@ func bwParse(flags *Flags, opts ...client.ClientOpt) error {
8476
}
8577

8678
// Set defaults
87-
bwClientId = flags.GetString("bitwarden-client-id")
88-
bwClientSecret = flags.GetString("bitwarden-client-secret")
89-
if bwClientId == "" || bwClientSecret == "" {
79+
clientId := flags.GetString("bitwarden-client-id")
80+
clientSecret := flags.GetString("bitwarden-client-secret")
81+
if clientId == "" || clientSecret == "" {
9082
return ErrBadParameter.With("Missing -bitwarden-client-id or -bitwarden-client-secret argument")
9183
}
9284
bwForce = flags.GetBool("force")
9385
bwPassword = flags.GetString("bitwarden-password")
9486

87+
// Create the client
88+
opts = append(opts, bitwarden.OptCredentials(clientId, clientSecret))
89+
opts = append(opts, bitwarden.OptFileStorage(bwConfigDir))
90+
if client, err := bitwarden.New(opts...); err != nil {
91+
return err
92+
} else {
93+
bwClient = client
94+
}
95+
9596
// Return success
9697
return nil
9798
}
@@ -100,173 +101,58 @@ func bwParse(flags *Flags, opts ...client.ClientOpt) error {
100101
// API METHODS
101102

102103
func bwAuth(w *tablewriter.Writer, _ []string) error {
103-
// Load session or create a new one
104-
session, err := bwReadSession()
105-
if err != nil {
106-
return err
107-
}
108-
109-
// Login options
110-
opts := []bitwarden.LoginOpt{
111-
bitwarden.OptCredentials(bwClientId, bwClientSecret),
112-
}
113-
if session.Device == nil {
114-
opts = append(opts, bitwarden.OptDevice(schema.Device{
115-
Name: bwName,
116-
}))
117-
}
104+
opts := []bitwarden.RequestOpt{}
118105
if bwForce {
119106
opts = append(opts, bitwarden.OptForce())
120107
}
121108

122-
// Perform the login
123-
if err := bwClient.Login(session, opts...); err != nil {
124-
return err
125-
}
126-
127-
// Save session
128-
if err := bwWriteSession(session); err != nil {
109+
// Login
110+
if err := bwClient.Login(opts...); err != nil {
129111
return err
130112
}
131113

132-
// Print out session
133-
w.Write(session)
134-
135-
// Return success
136-
return nil
137-
}
138-
139-
func bwSync(w *tablewriter.Writer, _ []string) error {
140-
// Load session or create a new one
141-
session, err := bwReadSession()
142-
if err != nil {
143-
return err
144-
}
145-
// If the session is not valid, then return an error
146-
if !session.IsValid() {
147-
return ErrOutOfOrder.With("Session is not valid, login first")
148-
}
149-
// Perform the sync
150-
sync, err := bwClient.Sync(session)
151-
if err != nil {
152-
return err
153-
} else if err := bwWrite("profile.json", sync.Profile); err != nil {
154-
return err
155-
} else if err := bwWrite("folders.json", sync.Folders); err != nil {
156-
return err
157-
} else if err := bwWrite("ciphers.json", sync.Ciphers); err != nil {
158-
return err
159-
} else if err := bwWrite("domains.json", sync.Domains); err != nil {
114+
// Sync
115+
if profile, err := bwClient.Sync(opts...); err != nil {
160116
return err
117+
} else {
118+
return w.Write(profile)
161119
}
162-
163-
// Output the profile
164-
w.Write(sync.Profile)
165-
166-
// Return success
167-
return nil
168120
}
169121

170122
func bwFolders(w *tablewriter.Writer, _ []string) error {
171-
// Load the profile
172-
profile, err := bwReadProfile()
173-
if err != nil {
174-
return err
123+
opts := []bitwarden.RequestOpt{}
124+
if bwForce {
125+
opts = append(opts, bitwarden.OptForce())
175126
}
176-
177-
// Load session or create a new one
178-
session, err := bwReadSession()
127+
folders, err := bwClient.Folders(opts...)
179128
if err != nil {
180129
return err
181130
}
182131

183-
// Make an encryption key
184-
if bwPassword == "" {
185-
if v, err := bwReadPasswordFromTerminal(); err != nil {
186-
return err
187-
} else {
188-
bwPassword = v
189-
}
190-
}
191-
if err := session.CacheKey(profile.Key, profile.Email, bwPassword); err != nil {
192-
return err
193-
}
194-
195-
// Read the folders
196-
folders := schema.Folders{}
197-
if err := bwRead("folders.json", &folders); err != nil {
198-
return err
199-
}
200-
201132
// Decrypt the folders from the session
202-
for i, folder := range folders {
203-
if decrypted, err := folder.Decrypt(session); err != nil {
204-
return err
205-
} else {
206-
folders[i] = decrypted.(*schema.Folder)
207-
}
133+
var result []*schema.Folder
134+
for folder := folders.Next(); folder != nil; folder = folders.Next() {
135+
result = append(result, folders.Decrypt(folder))
208136
}
209-
210-
// Output the folders
211-
w.Write(folders)
212-
213-
// Return success
214-
return nil
137+
return w.Write(result)
215138
}
216139

217140
func bwLogins(w *tablewriter.Writer, _ []string) error {
218-
// Load the profile
219-
profile, err := bwReadProfile()
220-
if err != nil {
221-
return err
141+
opts := []bitwarden.RequestOpt{}
142+
if bwForce {
143+
opts = append(opts, bitwarden.OptForce())
222144
}
223-
224-
// Load session or create a new one
225-
session, err := bwReadSession()
145+
ciphers, err := bwClient.Ciphers(opts...)
226146
if err != nil {
227147
return err
228148
}
229149

230-
// Make an encryption key
231-
if bwPassword == "" {
232-
if v, err := bwReadPasswordFromTerminal(); err != nil {
233-
return err
234-
} else {
235-
bwPassword = v
236-
}
237-
}
238-
if err := session.CacheKey(profile.Key, profile.Email, bwPassword); err != nil {
239-
return err
240-
}
241-
242-
// Read the ciphers
243-
ciphers := schema.Ciphers{}
244-
result := []bwCipher{}
245-
if err := bwRead("ciphers.json", &ciphers); err != nil {
246-
return err
247-
}
248150
// Decrypt the ciphers from the session
249-
for _, cipher := range ciphers {
250-
if cipher.Type != schema.CipherTypeLogin {
251-
continue
252-
}
253-
if decrypted, err := cipher.Decrypt(session); err != nil {
254-
return err
255-
} else {
256-
result = append(result, bwCipher{
257-
Name: decrypted.(*schema.Cipher).Name,
258-
Username: decrypted.(*schema.Cipher).Login.Username,
259-
URI: decrypted.(*schema.Cipher).Login.URI,
260-
Folder: decrypted.(*schema.Cipher).FolderId,
261-
})
262-
}
151+
var result []*schema.Cipher
152+
for cipher := ciphers.Next(); cipher != nil; cipher = ciphers.Next() {
153+
result = append(result, ciphers.Decrypt(cipher))
263154
}
264-
265-
// Output the ciphers
266-
w.Write(result)
267-
268-
// Return success
269-
return nil
155+
return w.Write(result)
270156
}
271157

272158
func bwGetPassword(w *tablewriter.Writer, _ []string) error {
@@ -291,73 +177,3 @@ func bwReadPasswordFromTerminal() (string, error) {
291177
return string(value), nil
292178
}
293179
}
294-
295-
func bwReadProfile() (*schema.Profile, error) {
296-
result := schema.NewProfile()
297-
filename := filepath.Join(bwConfigDir, "profile.json")
298-
if _, err := os.Stat(filename); os.IsNotExist(err) {
299-
// Return an error
300-
return nil, ErrNotFound.With("Profile not found")
301-
} else if err != nil {
302-
return nil, err
303-
}
304-
305-
// Open the file
306-
file, err := os.Open(filename)
307-
if err != nil {
308-
return nil, err
309-
}
310-
defer file.Close()
311-
312-
// Read and return the session
313-
return result, result.Read(file)
314-
}
315-
316-
func bwReadSession() (*schema.Session, error) {
317-
result := schema.NewSession()
318-
filename := filepath.Join(bwConfigDir, "session.json")
319-
if _, err := os.Stat(filename); os.IsNotExist(err) {
320-
// Return a new, empty session
321-
return result, nil
322-
} else if err != nil {
323-
return nil, err
324-
}
325-
326-
// Open the file
327-
file, err := os.Open(filename)
328-
if err != nil {
329-
return nil, err
330-
}
331-
defer file.Close()
332-
333-
// Read and return the session
334-
return result, result.Read(file)
335-
}
336-
337-
func bwWriteSession(session *schema.Session) error {
338-
return bwWrite("session.json", session)
339-
}
340-
341-
func bwWrite(filename string, obj schema.ReaderWriter) error {
342-
path := filepath.Join(bwConfigDir, filename)
343-
w, err := os.Create(path)
344-
if err != nil {
345-
return err
346-
}
347-
defer w.Close()
348-
349-
// Write the object and return any errors
350-
return obj.Write(w)
351-
}
352-
353-
func bwRead(filename string, obj schema.ReaderWriter) error {
354-
path := filepath.Join(bwConfigDir, filename)
355-
r, err := os.Open(path)
356-
if err != nil {
357-
return err
358-
}
359-
defer r.Close()
360-
361-
// Write the object and return any errors
362-
return obj.Read(r)
363-
}

0 commit comments

Comments
 (0)