@@ -37,6 +37,8 @@ import (
3737 "github.com/alecthomas/repr"
3838 "github.com/anmitsu/go-shlex"
3939 gitConfig "github.com/go-git/go-git/v5/config"
40+ "github.com/pquerna/otp"
41+ "github.com/pquerna/otp/totp"
4042)
4143
4244type CLI struct {
@@ -295,6 +297,62 @@ func englishPlural(singular, plural string, count int) string {
295297 return plural
296298}
297299
300+ func decryptEntry (agentExecutable string , agentExpire time.Duration , agentMemlock bool , agentSocket , identities , passwordStore , name string ) (string , error ) {
301+ if agentSocket == "" {
302+ return crypto .DecryptEntry (identities , passwordStore , name )
303+ }
304+
305+ file , err := pago .EntryFile (passwordStore , name )
306+ if err != nil {
307+ return "" , err
308+ }
309+
310+ encryptedData , err := os .ReadFile (file )
311+ if err != nil {
312+ return "" , fmt .Errorf ("failed to read password file: %v" , err )
313+ }
314+
315+ if err := agent .Ping (agentSocket ); err != nil {
316+ // Ping failed.
317+ // Attempt to start the agent.
318+ identitiesText , err := crypto .DecryptIdentities (identities )
319+ if err != nil {
320+ return "" , err
321+ }
322+
323+ if err := agent .StartProcess (agentExecutable , agentExpire , agentMemlock , agentSocket , identitiesText ); err != nil {
324+ return "" , fmt .Errorf ("failed to start agent: %v" , err )
325+ }
326+ }
327+
328+ content , err := agent .Decrypt (agentSocket , encryptedData )
329+ if err != nil {
330+ return "" , err
331+ }
332+
333+ return content , nil
334+ }
335+
336+ func getOTP (otpURL string ) (string , error ) {
337+ otpKey , err := otp .NewKeyFromURL (otpURL )
338+ if err != nil {
339+ return "" , fmt .Errorf ("failed to parse otpauth URL: %w" , err )
340+ }
341+
342+ opts := totp.ValidateOpts {
343+ Period : uint (otpKey .Period ()),
344+ Digits : otpKey .Digits (),
345+ Algorithm : otpKey .Algorithm (),
346+ }
347+
348+ code , err := totp .GenerateCodeCustom (otpKey .Secret (), time .Now (), opts )
349+ if err != nil {
350+ return "" , fmt .Errorf ("failed to generate TOTP code: %w" , err )
351+ }
352+
353+ return code , nil
354+ }
355+
298356func getPassword (agentExecutable string , agentExpire time.Duration , agentMemlock bool , agentSocket , identities , passwordStore , name , key string ) (string , error ) {
299357 content , err := decryptEntry (agentExecutable , agentExpire , agentMemlock , agentSocket , identities , passwordStore , name )
300358 if err != nil {
@@ -322,7 +380,13 @@ func getPassword(agentExecutable string, agentExpire time.Duration, agentMemlock
322380 return "" , fmt .Errorf ("key %q in entry %q is a table" , key , name )
323381
324382 case reflect .String :
325- return v .String (), nil
383+ s := v .String ()
384+
385+ if key == "otp" {
386+ return getOTP (s )
387+ }
388+
389+ return s , nil
326390 }
327391
328392 var buf bytes.Buffer
@@ -334,42 +398,6 @@ func getPassword(agentExecutable string, agentExpire time.Duration, agentMemlock
334398 return buf .String (), nil
335399}
336400
337- func decryptEntry (agentExecutable string , agentExpire time.Duration , agentMemlock bool , agentSocket , identities , passwordStore , name string ) (string , error ) {
338- if agentSocket == "" {
339- return crypto .DecryptEntry (identities , passwordStore , name )
340- }
341-
342- file , err := pago .EntryFile (passwordStore , name )
343- if err != nil {
344- return "" , err
345- }
346-
347- encryptedData , err := os .ReadFile (file )
348- if err != nil {
349- return "" , fmt .Errorf ("failed to read password file: %v" , err )
350- }
351-
352- if err := agent .Ping (agentSocket ); err != nil {
353- // Ping failed.
354- // Attempt to start the agent.
355- identitiesText , err := crypto .DecryptIdentities (identities )
356- if err != nil {
357- return "" , err
358- }
359-
360- if err := agent .StartProcess (agentExecutable , agentExpire , agentMemlock , agentSocket , identitiesText ); err != nil {
361- return "" , fmt .Errorf ("failed to start agent: %v" , err )
362- }
363- }
364-
365- content , err := agent .Decrypt (agentSocket , encryptedData )
366- if err != nil {
367- return "" , err
368- }
369-
370- return content , nil
371- }
372-
373401func (cmd * ClipCmd ) Run (config * Config ) error {
374402 if config .Verbose {
375403 printRepr (cmd )
0 commit comments