@@ -141,51 +141,73 @@ func (k macOSXKeychain) ListUsers(service string) ([]string, error) {
141141 return []string {}, nil
142142 }
143143
144- out , err := exec .Command (execPathKeychain , "dump-keyring" ).CombinedOutput ()
144+ // Get the default keychain since there can be multiple keychains
145+ defaultKeychainOut , err := exec .Command (execPathKeychain , "default-keychain" ).CombinedOutput ()
145146 if err != nil {
146147 return nil , err
147148 }
149+ // Take first line in case multiple default keychains are returned
150+ firstLine := strings .SplitN (strings .TrimSpace (string (defaultKeychainOut )), "\n " , 2 )[0 ]
151+ defaultKeychain := strings .Trim (strings .TrimSpace (firstLine ), `"` )
152+
153+ // dump-keychain (not dump-keyring) requires a keychain path
154+ out , err := exec .Command (execPathKeychain , "dump-keychain" , defaultKeychain ).CombinedOutput ()
155+ if err != nil {
156+ return nil , err
157+ }
158+
159+ // Parse dump-keychain output. Format:
160+ // keychain: "/Users/username/Library/Keychains/login.keychain-db"
161+ // class: "genp"
162+ // attributes:
163+ // "svce"<blob>="service-name"
164+ // "acct"<blob>="account-name"
165+ valueOf := func (s , prefix string ) string {
166+ return strings .Trim (strings .TrimSpace (strings .TrimPrefix (strings .TrimSpace (s ), prefix )), `"` )
167+ }
148168
149169 var users []string
150170 seenUsers := make (map [string ]bool )
171+ var currentKeychain , currentSvc , currentAcct string
151172 lines := strings .Split (string (out ), "\n " )
152-
153- // Parse dump-keyring output looking for generic passwords matching our service
154- // Format: keychain: "/Users/username/Library/Keychains/login.keychain-db"
155- // class: "genp"
156- // attributes:
157- // "svce"<blob>="service-name"
158- // "acct"<blob>="account-name"
159- for i := 0 ; i < len (lines ); i ++ {
160- line := strings .TrimSpace (lines [i ])
161-
162- // Look for service attribute matching our service
163- if strings .Contains (line , `"svce"` ) && strings .Contains (line , `="` + service + `"` ) {
164- // Found a matching service, now look for the account attribute
165- // It should be nearby in the attributes section
166- for j := i - 10 ; j < i + 10 && j < len (lines ) && j >= 0 ; j ++ {
167- acctLine := strings .TrimSpace (lines [j ])
168- if strings .Contains (acctLine , `"acct"` ) {
169- // Extract account name from: "acct"<blob>="username"
170- if idx := strings .Index (acctLine , `="` ); idx != - 1 {
171- start := idx + 2
172- if end := strings .Index (acctLine [start :], `"` ); end != - 1 {
173- username := acctLine [start : start + end ]
174- if ! seenUsers [username ] {
175- seenUsers [username ] = true
176- users = append (users , username )
177- }
178- break
179- }
180- }
173+
174+ for _ , line := range lines {
175+ switch {
176+ case strings .HasPrefix (strings .TrimSpace (line ), "keychain:" ):
177+ // Save previous entry if it matched
178+ if currentKeychain == defaultKeychain && currentSvc == service && currentAcct != "" && ! seenUsers [currentAcct ] {
179+ seenUsers [currentAcct ] = true
180+ users = append (users , currentAcct )
181+ }
182+ currentKeychain = valueOf (line , "keychain:" )
183+ currentSvc = ""
184+ currentAcct = ""
185+ case strings .Contains (line , `"svce"` ):
186+ if idx := strings .Index (line , `="` ); idx != - 1 {
187+ start := idx + 2
188+ if end := strings .Index (line [start :], `"` ); end != - 1 {
189+ currentSvc = line [start : start + end ]
190+ }
191+ }
192+ case strings .Contains (line , `"acct"` ):
193+ if idx := strings .Index (line , `="` ); idx != - 1 {
194+ start := idx + 2
195+ if end := strings .Index (line [start :], `"` ); end != - 1 {
196+ currentAcct = line [start : start + end ]
181197 }
182198 }
183199 }
184200 }
201+ // Don't forget the last entry
202+ if currentKeychain == defaultKeychain && currentSvc == service && currentAcct != "" && ! seenUsers [currentAcct ] {
203+ users = append (users , currentAcct )
204+ }
185205
186206 return users , nil
187207}
188208
189209func init () {
190- provider = macOSXKeychain {}
210+ p := macOSXKeychain {}
211+ provider = p
212+ restoreProvider = func () { provider = p }
191213}
0 commit comments