Skip to content
1 change: 1 addition & 0 deletions kpmenulib/clientserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ func StartServer(m *Menu) (err error) {
// Handle packet request
handlePacket := func(packet Packet) bool {
log.Printf("received a client call with args \"%v\"", packet.CliArguments)
m.Configuration.Flags.Autotype = false
m.CliArguments = packet.CliArguments
return Show(m)
}
Expand Down
2 changes: 1 addition & 1 deletion kpmenulib/clipboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"os/exec"
"strings"
"time"

"github.com/google/shlex"
)

Expand Down
40 changes: 31 additions & 9 deletions kpmenulib/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,22 @@ type ConfigurationGeneral struct {
CacheOneTime bool // Cache the password only the first time you write it
CacheTimeout int // Timeout of cache
NoOTP bool // Flag to do not handle OTPs
DisableAutotype bool // Disable autotype
AutotypeConfirm bool // User must always confirm
AutotypeNoAuto bool // Always prompt user to select the entry to autotype
}

// ConfigurationExecutable is the sub-structure of the configuration related to tools executed by kpmenu
type ConfigurationExecutable struct {
CustomPromptPassword string // Custom executable for prompt password
CustomPromptMenu string // Custom executable for prompt menu
CustomPromptEntries string // Custom executable for prompt entries
CustomPromptFields string // Custom executable for prompt fields
CustomClipboardCopy string // Custom executable for clipboard copy
CustomClipboardPaste string // Custom executable for clipboard paste
CustomClipboardClean string // Custom executable for clipboard clean
CustomPromptPassword string // Custom executable for prompt password
CustomPromptMenu string // Custom executable for prompt menu
CustomPromptEntries string // Custom executable for prompt entries
CustomPromptFields string // Custom executable for prompt fields
CustomClipboardCopy string // Custom executable for clipboard copy
CustomClipboardPaste string // Custom executable for clipboard paste
CustomClipboardClean string // Custom executable for clipboard clean
CustomAutotypeWindowID string // Custom executable for fetching title of active window
CustomAutotypeTyper string // Custom executable for typing results
}

// ConfigurationStyle is the sub-structure of the configuration related to style of dmenu
Expand Down Expand Up @@ -67,8 +72,9 @@ type ConfigurationDatabase struct {

// Flags is the sub-structure of the configuration used to handle flags that aren't into the config file
type Flags struct {
Daemon bool
Version bool
Daemon bool
Version bool
Autotype bool
}

// Menu tools used for prompts
Expand All @@ -86,6 +92,12 @@ const (
ClipboardToolCustom = "custom"
)

// Autotype default helpers
const (
AutotypeWindowIdentifier = "quasiauto -title"
AutotypeTyper = "quasiauto"
)

// NewConfiguration initializes a new Configuration pointer
func NewConfiguration() *Configuration {
return &Configuration{
Expand All @@ -107,6 +119,10 @@ func NewConfiguration() *Configuration {
FieldOrder: "Password UserName URL",
FillOtherFields: true,
},
Executable: ConfigurationExecutable{
CustomAutotypeWindowID: AutotypeWindowIdentifier,
CustomAutotypeTyper: AutotypeTyper,
},
}
}

Expand Down Expand Up @@ -147,6 +163,7 @@ func (c *Configuration) InitializeFlags() {
// Flags
flag.BoolVar(&c.Flags.Daemon, "daemon", false, "Start kpmenu directly as daemon")
flag.BoolVarP(&c.Flags.Version, "version", "v", false, "Show kpmenu version")
flag.BoolVar(&c.Flags.Autotype, "autotype", c.Flags.Autotype, "Initiate autotype")

// General
flag.StringVarP(&c.General.Menu, "menu", "m", c.General.Menu, "Choose which menu to use")
Expand All @@ -156,6 +173,9 @@ func (c *Configuration) InitializeFlags() {
flag.BoolVar(&c.General.CacheOneTime, "cacheOneTime", c.General.CacheOneTime, "Cache the database only the first time")
flag.IntVar(&c.General.CacheTimeout, "cacheTimeout", c.General.CacheTimeout, "Timeout of cache in seconds")
flag.BoolVar(&c.General.NoOTP, "nootp", c.General.NoOTP, "Disable OTP handling")
flag.BoolVar(&c.General.DisableAutotype, "noautotype", c.General.DisableAutotype, "Disable autotype handling")
flag.BoolVar(&c.General.AutotypeConfirm, "autotypealwaysconfirm", c.General.AutotypeConfirm, "Always confirm autotype, even when there's only 1 selection")
flag.BoolVar(&c.General.AutotypeNoAuto, "autotypeusersel", c.General.AutotypeNoAuto, "Prompt for autotype entry instead of trying to detect by active window title")

// Executable
flag.StringVar(&c.Executable.CustomPromptPassword, "customPromptPassword", c.Executable.CustomPromptPassword, "Custom executable for prompt password")
Expand All @@ -164,6 +184,8 @@ func (c *Configuration) InitializeFlags() {
flag.StringVar(&c.Executable.CustomPromptFields, "customPromptFields", c.Executable.CustomPromptFields, "Custom executable for prompt fields")
flag.StringVar(&c.Executable.CustomClipboardCopy, "customClipboardCopy", c.Executable.CustomClipboardCopy, "Custom executable for clipboard copy")
flag.StringVar(&c.Executable.CustomClipboardPaste, "customClipboardPaste", c.Executable.CustomClipboardPaste, "Custom executable for clipboard paste")
flag.StringVar(&c.Executable.CustomAutotypeWindowID, "customAutotypeWindowID", c.Executable.CustomAutotypeWindowID, "Custom executable for identifying active window for autotype")
flag.StringVar(&c.Executable.CustomAutotypeTyper, "customAutotypeTyper", c.Executable.CustomAutotypeTyper, "Custom executable for autotype typer")
flag.StringVar(&c.Executable.CustomClipboardClean, "customClipboardClean", c.Executable.CustomClipboardClean, "Custom executable for clipboard clean")

// Style
Expand Down
7 changes: 7 additions & 0 deletions kpmenulib/kpmenulib.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ func Execute(menu *Menu) bool {
}
}

if !menu.Configuration.General.DisableAutotype && menu.Configuration.Flags.Autotype {
if err := PromptAutotype(menu); err.Error != nil {
log.Print(err.Error)
}
return false
}

// Open menu
if err := menu.OpenMenu(); err != nil {
log.Print(err)
Expand Down
17 changes: 11 additions & 6 deletions kpmenulib/otp.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,14 @@ func (o OTPError) Error() string {
// Modern versions of KeepassXC and Keepass2Android store this URL in the `otp` key. A historic version
// stored data ds:
//
// TOTP Seed = SECRET
// TOTP Settings = PERIOD;DIGITS
// TOTP Seed = SECRET
// TOTP Settings = PERIOD;DIGITS
//
// If the `otp` key exists, it should be used and the TOTP values ignored; otherwise, the legacy values can
// be used.
//
// entry is the DB entry for which to generate a code; time is the Unix time to generate for the code --
// generally time.Now().Unix()
//
func CreateOTP(a gokeepasslib.Entry, time int64) (otp string, err error) {
otpa, err := CreateOTPAuth(a)
if err != nil {
Expand Down Expand Up @@ -91,6 +90,9 @@ func (o OTPAuth) Create(time int64) (otp string, err error) {

otp = fmt.Sprint(r % int32(pow(10, o.Digits)))
if len(otp) != o.Digits {
if len(otp) > o.Digits {
return otp, fmt.Errorf("otp length (%d) must be greater than Digits (%d)", len(otp), o.Digits)
}
rpt := strings.Repeat("0", o.Digits-len(otp))
otp = rpt + otp
}
Expand Down Expand Up @@ -165,11 +167,11 @@ func CreateOTPAuth(a gokeepasslib.Entry) (otp OTPAuth, err error) {
// parseOTPAuth parses a Google Authenticator otpauth URL, which is used by
// both KeepassXC and Keepass2Android.
//
// otpauth://TYPE/LABEL?PARAMETERS
// otpauth://TYPE/LABEL?PARAMETERS
//
// e.g., the KeepassXC format is
//
// otpauth://totp/ISSUER:USERNAME?secret=SECRET&period=SECONDS&digits=D&issuer=ISSUER
// otpauth://totp/ISSUER:USERNAME?secret=SECRET&period=SECONDS&digits=D&issuer=ISSUER
//
// where TITLE is the record entry title, e.g. `github`; USERNAME is the entry
// user name, e.g. `xxxserxxx`; SECRET is the TOTP seed secret; SECONDS is the
Expand All @@ -179,7 +181,10 @@ func CreateOTPAuth(a gokeepasslib.Entry) (otp OTPAuth, err error) {
//
// The spec is at https://github.com/google/google-authenticator/wiki/Key-Uri-Format
func parseOTPAuth(s string) (OTPAuth, error) {
otp := OTPAuth{}
otp := OTPAuth{
Digits: 6,
Period: 30,
}
u, err := url.ParseRequestURI(s)
if err != nil {
return otp, err
Expand Down
Loading