@@ -44,19 +44,25 @@ type CredentialsGetInput struct {
4444}
4545
4646type CredentialsCreateInput struct {
47- Name string
48- Domain string
49- Values map [string ]string
50- SSOProvider string
51- TotpSecret string
52- Output string
47+ Name string
48+ Domain string
49+ Values map [string ]string
50+ SSOProvider string
51+ TotpSecret string
52+ TotpAlgorithm string
53+ TotpDigits * int
54+ TotpPeriod * int
55+ Output string
5356}
5457
5558type CredentialsUpdateInput struct {
5659 Identifier string
5760 Name string
5861 SSOProvider string
5962 TotpSecret string
63+ TotpAlgorithm string
64+ TotpDigits * int
65+ TotpPeriod * int
6066 Values map [string ]string
6167 RemoveValueKeys []string
6268 Output string
@@ -176,6 +182,29 @@ func (c CredentialsCmd) Get(ctx context.Context, in CredentialsGetInput) error {
176182 return nil
177183}
178184
185+ func validateTotpSettings (secret , algorithm string , digits , period * int ) error {
186+ if algorithm == "" && digits == nil && period == nil {
187+ return nil
188+ }
189+ if secret == "" {
190+ return fmt .Errorf ("TOTP settings require --totp-secret" )
191+ }
192+ if algorithm != "" {
193+ switch strings .ToUpper (algorithm ) {
194+ case "SHA1" , "SHA256" , "SHA512" :
195+ default :
196+ return fmt .Errorf ("--totp-algorithm must be SHA1, SHA256, or SHA512" )
197+ }
198+ }
199+ if digits != nil && (* digits < 6 || * digits > 9 ) {
200+ return fmt .Errorf ("--totp-digits must be between 6 and 9" )
201+ }
202+ if period != nil && (* period < 15 || * period > 300 ) {
203+ return fmt .Errorf ("--totp-period must be between 15 and 300" )
204+ }
205+ return nil
206+ }
207+
179208func (c CredentialsCmd ) Create (ctx context.Context , in CredentialsCreateInput ) error {
180209 if err := validateJSONOutput (in .Output ); err != nil {
181210 return err
@@ -191,6 +220,9 @@ func (c CredentialsCmd) Create(ctx context.Context, in CredentialsCreateInput) e
191220 return fmt .Errorf ("at least one --value is required" )
192221 }
193222
223+ if err := validateTotpSettings (in .TotpSecret , in .TotpAlgorithm , in .TotpDigits , in .TotpPeriod ); err != nil {
224+ return err
225+ }
194226 params := kernel.CredentialNewParams {
195227 CreateCredentialRequest : kernel.CreateCredentialRequestParam {
196228 Name : in .Name ,
@@ -204,6 +236,15 @@ func (c CredentialsCmd) Create(ctx context.Context, in CredentialsCreateInput) e
204236 if in .TotpSecret != "" {
205237 params .CreateCredentialRequest .TotpSecret = kernel .Opt (in .TotpSecret )
206238 }
239+ if in .TotpAlgorithm != "" {
240+ params .CreateCredentialRequest .TotpAlgorithm = kernel .CreateCredentialRequestTotpAlgorithm (strings .ToUpper (in .TotpAlgorithm ))
241+ }
242+ if in .TotpDigits != nil {
243+ params .CreateCredentialRequest .TotpDigits = kernel .Int (int64 (* in .TotpDigits ))
244+ }
245+ if in .TotpPeriod != nil {
246+ params .CreateCredentialRequest .TotpPeriod = kernel .Int (int64 (* in .TotpPeriod ))
247+ }
207248
208249 if in .Output != "json" {
209250 pterm .Info .Printf ("Creating credential '%s'...\n " , in .Name )
@@ -252,6 +293,9 @@ func (c CredentialsCmd) Update(ctx context.Context, in CredentialsUpdateInput) e
252293 if err := validateJSONOutput (in .Output ); err != nil {
253294 return err
254295 }
296+ if err := validateTotpSettings (in .TotpSecret , in .TotpAlgorithm , in .TotpDigits , in .TotpPeriod ); err != nil {
297+ return err
298+ }
255299
256300 params := kernel.CredentialUpdateParams {
257301 UpdateCredentialRequest : kernel.UpdateCredentialRequestParam {},
@@ -265,6 +309,15 @@ func (c CredentialsCmd) Update(ctx context.Context, in CredentialsUpdateInput) e
265309 if in .TotpSecret != "" {
266310 params .UpdateCredentialRequest .TotpSecret = kernel .Opt (in .TotpSecret )
267311 }
312+ if in .TotpAlgorithm != "" {
313+ params .UpdateCredentialRequest .TotpAlgorithm = kernel .UpdateCredentialRequestTotpAlgorithm (strings .ToUpper (in .TotpAlgorithm ))
314+ }
315+ if in .TotpDigits != nil {
316+ params .UpdateCredentialRequest .TotpDigits = kernel .Int (int64 (* in .TotpDigits ))
317+ }
318+ if in .TotpPeriod != nil {
319+ params .UpdateCredentialRequest .TotpPeriod = kernel .Int (int64 (* in .TotpPeriod ))
320+ }
268321 if len (in .Values ) > 0 {
269322 params .UpdateCredentialRequest .Values = in .Values
270323 }
@@ -398,7 +451,7 @@ var credentialsDeleteCmd = &cobra.Command{
398451var credentialsTotpCodeCmd = & cobra.Command {
399452 Use : "totp-code <id-or-name>" ,
400453 Short : "Get the current TOTP code for a credential" ,
401- Long : `Returns the current 6-digit TOTP code for a credential with a configured totp_secret.` ,
454+ Long : `Returns the current TOTP code for a credential with a configured totp_secret.` ,
402455 Args : cobra .ExactArgs (1 ),
403456 RunE : runCredentialsTotpCode ,
404457}
@@ -427,15 +480,21 @@ func init() {
427480 credentialsCreateCmd .Flags ().String ("domain" , "" , "Target domain this credential is for (required)" )
428481 credentialsCreateCmd .Flags ().StringArray ("value" , []string {}, "Field name=value pair (repeatable, e.g., --value username=myuser --value password=mypass)" )
429482 credentialsCreateCmd .Flags ().String ("sso-provider" , "" , "SSO provider (e.g., google, github, microsoft)" )
430- credentialsCreateCmd .Flags ().String ("totp-secret" , "" , "Base32-encoded TOTP secret for 2FA" )
483+ credentialsCreateCmd .Flags ().String ("totp-secret" , "" , "Base32 secret (16-128 characters) or otpauth:// URI for 2FA" )
484+ credentialsCreateCmd .Flags ().String ("totp-algorithm" , "" , "TOTP algorithm: SHA1, SHA256, or SHA512 (default SHA1)" )
485+ credentialsCreateCmd .Flags ().Int ("totp-digits" , 6 , "TOTP code digits: 6-9 (default 6)" )
486+ credentialsCreateCmd .Flags ().Int ("totp-period" , 30 , "TOTP period in seconds: 15-300 (default 30)" )
431487 _ = credentialsCreateCmd .MarkFlagRequired ("name" )
432488 _ = credentialsCreateCmd .MarkFlagRequired ("domain" )
433489
434490 // Update flags
435491 addJSONOutputFlag (credentialsUpdateCmd )
436492 credentialsUpdateCmd .Flags ().String ("name" , "" , "New name for the credential" )
437493 credentialsUpdateCmd .Flags ().String ("sso-provider" , "" , "SSO provider (set to empty string to remove)" )
438- credentialsUpdateCmd .Flags ().String ("totp-secret" , "" , "Base32-encoded TOTP secret (set to empty string to remove)" )
494+ credentialsUpdateCmd .Flags ().String ("totp-secret" , "" , "Base32 secret (16-128 characters) or otpauth:// URI" )
495+ credentialsUpdateCmd .Flags ().String ("totp-algorithm" , "" , "TOTP algorithm: SHA1, SHA256, or SHA512" )
496+ credentialsUpdateCmd .Flags ().Int ("totp-digits" , 6 , "TOTP code digits: 6-9" )
497+ credentialsUpdateCmd .Flags ().Int ("totp-period" , 30 , "TOTP period in seconds: 15-300" )
439498 credentialsUpdateCmd .Flags ().StringArray ("value" , []string {}, "Field name=value pair to update (repeatable)" )
440499 credentialsUpdateCmd .Flags ().StringArray ("remove-value-key" , []string {}, "Field name to remove from the credential's stored values (repeatable). Removals are applied before --value is merged, so a key given to both keeps its new value" )
441500
@@ -477,6 +536,13 @@ func runCredentialsGet(cmd *cobra.Command, args []string) error {
477536 })
478537}
479538
539+ func optionalIntFlag (cmd * cobra.Command , name string , value int ) * int {
540+ if cmd .Flags ().Changed (name ) {
541+ return & value
542+ }
543+ return nil
544+ }
545+
480546func runCredentialsCreate (cmd * cobra.Command , args []string ) error {
481547 client := getKernelClient (cmd )
482548 output , _ := cmd .Flags ().GetString ("output" )
@@ -485,6 +551,9 @@ func runCredentialsCreate(cmd *cobra.Command, args []string) error {
485551 valuePairs , _ := cmd .Flags ().GetStringArray ("value" )
486552 ssoProvider , _ := cmd .Flags ().GetString ("sso-provider" )
487553 totpSecret , _ := cmd .Flags ().GetString ("totp-secret" )
554+ algorithm , _ := cmd .Flags ().GetString ("totp-algorithm" )
555+ digits , _ := cmd .Flags ().GetInt ("totp-digits" )
556+ period , _ := cmd .Flags ().GetInt ("totp-period" )
488557
489558 // Parse value pairs into map
490559 values := make (map [string ]string )
@@ -499,12 +568,15 @@ func runCredentialsCreate(cmd *cobra.Command, args []string) error {
499568 svc := client .Credentials
500569 c := CredentialsCmd {credentials : & svc }
501570 return c .Create (cmd .Context (), CredentialsCreateInput {
502- Name : name ,
503- Domain : domain ,
504- Values : values ,
505- SSOProvider : ssoProvider ,
506- TotpSecret : totpSecret ,
507- Output : output ,
571+ Name : name ,
572+ Domain : domain ,
573+ Values : values ,
574+ SSOProvider : ssoProvider ,
575+ TotpSecret : totpSecret ,
576+ TotpAlgorithm : algorithm ,
577+ TotpDigits : optionalIntFlag (cmd , "totp-digits" , digits ),
578+ TotpPeriod : optionalIntFlag (cmd , "totp-period" , period ),
579+ Output : output ,
508580 })
509581}
510582
@@ -514,6 +586,9 @@ func runCredentialsUpdate(cmd *cobra.Command, args []string) error {
514586 name , _ := cmd .Flags ().GetString ("name" )
515587 ssoProvider , _ := cmd .Flags ().GetString ("sso-provider" )
516588 totpSecret , _ := cmd .Flags ().GetString ("totp-secret" )
589+ algorithm , _ := cmd .Flags ().GetString ("totp-algorithm" )
590+ digits , _ := cmd .Flags ().GetInt ("totp-digits" )
591+ period , _ := cmd .Flags ().GetInt ("totp-period" )
517592 valuePairs , _ := cmd .Flags ().GetStringArray ("value" )
518593 removeValueKeys , _ := cmd .Flags ().GetStringArray ("remove-value-key" )
519594
@@ -534,6 +609,9 @@ func runCredentialsUpdate(cmd *cobra.Command, args []string) error {
534609 Name : name ,
535610 SSOProvider : ssoProvider ,
536611 TotpSecret : totpSecret ,
612+ TotpAlgorithm : algorithm ,
613+ TotpDigits : optionalIntFlag (cmd , "totp-digits" , digits ),
614+ TotpPeriod : optionalIntFlag (cmd , "totp-period" , period ),
537615 Values : values ,
538616 RemoveValueKeys : removeValueKeys ,
539617 Output : output ,
0 commit comments