@@ -164,12 +164,91 @@ def create(self, cp):
164164
165165
166166class KeyringCredentialsManager (AbstractCredentialsManager ):
167+ def _start_SecretService_Keyring (self ):
168+ import os
169+ import subprocess
170+
171+ keyring_daemon = '/usr/bin/gnome-keyring-daemon'
172+ if not os .path .exists (keyring_daemon ):
173+ # Gnome Keyring Daemon in not installed.
174+ # return quickly since there is nothing to do.
175+ return
176+
177+ # Starts and unlock GNOME keyring when running headless.
178+
179+ if 'DISPLAY' in os .environ :
180+ # Looks like we have desktop session
181+ # Continue to the normal desktop unlock procedures.
182+ return
183+ if 'DBUS_SESSION_BUS_ADDRESS' in os .environ :
184+ # Ensure DBUS has launced for headless GNOME_KEYRING.
185+ pass
186+ else :
187+ raise SystemExit ("""
188+ The DBUS_SESSION_BUS_ADDRESS environment variable is not set which
189+ probably means that DBUS is not running.
190+ """ )
191+
192+ # Ensure the GNOME_KEYRING is started.
193+ if 'GNOME_KEYRING_CONTORL' in os .environ :
194+ if not os .path .exists (os .environ .get ('GNOME_KEYRING_CONTROL' )):
195+ # Make the uses .local directory. Otherwise
196+ # initial keyring creation will fail.
197+ if not os .path .exists (os .path .expanduser ('~/.local' )):
198+ os .makedirs (os .path .expanduser ('~/.local' ), mode = 0o700 )
199+ # GNOME Keyring daemon is not running, so we start it here.
200+ process = subprocess .Popen ([keyring_daemon ,
201+ '--start' , '--components=secrets' ],
202+ stdin = subprocess .DEVNULL ,
203+ stdout = subprocess .DEVNULL ,
204+ stderr = subprocess .DEVNULL )
205+ process .communicate (timeout = 5 )
206+ try :
207+ import secretstorage
208+ dbus = secretstorage .dbus_init ()
209+ collection = secretstorage .get_default_collection (dbus )
210+ if collection .is_locked ():
211+ pass
212+ else :
213+ return
214+ except BaseException :
215+ collection = None
216+ self ._unlock_SecretService_Keyring (keyring_daemon , collection )
217+
218+ def _unlock_SecretService_Keyring (self , keyring_daemon , collection ):
219+ import os
220+ import subprocess
221+ keyringf = os .path .expanduser ('~/.local/share/keyrings/login.keyring' )
222+ keystore = os .path .expanduser ('~/.local/share/keyrings/user.keystore' )
223+ if not os .path .exists (keyringf ) and not os .path .exists (keystore ):
224+ prompt = 'New keyring password: '
225+ else :
226+ prompt = 'Keyring password: '
227+
228+ password = getpass .getpass (prompt = prompt )
229+ password = (password + '\n ' ).encode ('UTF-8' )
230+ process = subprocess .Popen ([keyring_daemon ,
231+ '--unlock' , '--replace' ,
232+ '--components=secrets' ],
233+ stdin = subprocess .PIPE ,
234+ stdout = subprocess .DEVNULL ,
235+ stderr = subprocess .DEVNULL )
236+ process .communicate (input = password , timeout = 5 )
237+ if collection is None :
238+ import secretstorage
239+ dbus = secretstorage .dbus_init ()
240+ collection = secretstorage .get_default_collection (dbus )
241+ if collection .is_locked ():
242+ raise SystemExit ('Unable to unlock keyring.' )
243+
167244 def _process_options (self , options ):
168245 if options is None :
169246 raise RuntimeError ('options may not be None' )
170247 self ._backend_cls_name = options
171248
172249 def _load_backend (self ):
250+ if self ._backend_cls_name == 'keyring.backends.SecretService.Keyring' :
251+ self ._start_SecretService_Keyring ()
173252 keyring_backend = keyring .core .load_keyring (self ._backend_cls_name )
174253 keyring .set_keyring (keyring_backend )
175254
0 commit comments