-
Notifications
You must be signed in to change notification settings - Fork 1
/
keepassxc-dmenu
executable file
·152 lines (122 loc) · 3.08 KB
/
keepassxc-dmenu
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
#!/bin/tclsh
package require Expect
# exp_internal 1
log_user 0
set timeout -1
proc defined_or_default {varname def} {
upvar $varname var
if {![info exists var]} {
set var $def
}
}
proc die {msg} {
puts stderr $msg
exit 1
}
set config $::env(HOME)/.config/keepassxc-dmenu/config
if {[file exists $config]} {
source $config
} else {
die "Provide config file at $config"
}
if {![info exists kpxc_database_path]} {
die {Variable $kpxc_database_path must be defined}
} elseif {![file exists $kpxc_database_path]} {
die "Database file not found at $kpxc_database_path"
}
defined_or_default kpxc_dmenu {rofi -dmenu -i}
defined_or_default kpxc_pinentry /usr/bin/pinentry-qt
set kpxc_appdir /tmp/keepassxc-dmenu/
file mkdir $kpxc_appdir
exec chmod 700 $kpxc_appdir
cd $kpxc_appdir
proc pinentry_get {} {
spawn "$::kpxc_pinentry"
expect "OK"
send -- "SETDESC Enter Password for $::kpxc_database_path:\r"
expect "OK"
send -- "GETPIN\r"
expect {
"OK" { regexp -line {D (.*)\r} $expect_out(buffer) line pw }
"cancelled" { die "User didn't input password, exiting." }
}
send -- "BYE\r"
wait
return $pw
}
proc enter_pw {kpxc_pw} {
spawn keepassxc-cli open "$::kpxc_database_path"
expect "Enter password"
match_max 5000
set spawn_id $expect_out(spawn_id)
send -- "$kpxc_pw\r"
expect "> "
if {[regexp {Invalid credentials} $expect_out(buffer) match]} {
die "Wrong Password"
}
send -- "ls -R -f\r"
expect "> "
set kpxc_accounts {}
foreach line [lrange [split $expect_out(buffer) "\n"] 1 end] {
set item [string trim $line]
if {($item eq "") || ([string index $item end] in {">" "/"})} {
continue
}
lappend kpxc_accounts $item
}
if {[catch {exec {*}$::kpxc_dmenu << [join $kpxc_accounts "\n"]} result] == 0} {
send -- "show -s \"$result\"\r"
expect "> "
regexp -line {^Password: (.*)\r} $expect_out(buffer) line kpxc_entry_pw
exec {*}{xdotool type --clearmodifiers --file -} << $kpxc_entry_pw
}
unset kpxc_accounts
send -- "quit\r"
wait
close $spawn_id
}
proc readpipe {} {
if {[gets $::pipe line] > 0} {
if {![string eq $line exit]} {
run $::kpxc_pw
} else {
cleanup
}
}
}
proc cleanup {} {
try {
close $::pipe
} finally {
file delete -force -- $::kpxc_appdir
exit 1
}
}
proc run {kpxc_pw} {
try {
enter_pw $kpxc_pw
} on error {result option} {
puts stderr $result
}
}
### GET PASSWORD
set kpxc_pw [pinentry_get]
enter_pw $kpxc_pw
### Go into background and listen on the FIFO
if {[fork] != 0} {
exit
}
disconnect
trap {cleanup} {SIGTERM SIGINT}
set kpxc_pipe run
exec mkfifo $kpxc_pipe
set pipe [open "$kpxc_pipe" {RDWR NONBLOCK}]
fileevent $pipe readable readpipe
if {[info exists kpxc_timeout]} {
set ::state waiting
after [expr {60000 * $kpxc_timeout}] {set ::state timeout}
vwait ::state
cleanup
} else {
vwait forever
}