Initial version
This commit is contained in:
commit
d64b2d5e0b
158
password_reset/__init__.py
Normal file
158
password_reset/__init__.py
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
import getpass
|
||||||
|
from gi.repository import GnomeKeyring
|
||||||
|
from xdg import BaseDirectory
|
||||||
|
import gnupg
|
||||||
|
import os
|
||||||
|
import collections
|
||||||
|
|
||||||
|
|
||||||
|
class OrderedSet(collections.MutableSet):
|
||||||
|
def __init__(self, iterable=None):
|
||||||
|
self.end = end = []
|
||||||
|
end += [None, end, end] # sentinel node for doubly linked list
|
||||||
|
self.map = {} # key --> [key, prev, next]
|
||||||
|
if iterable is not None:
|
||||||
|
self |= iterable
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self.map)
|
||||||
|
|
||||||
|
def __contains__(self, key):
|
||||||
|
return key in self.map
|
||||||
|
|
||||||
|
def add(self, key):
|
||||||
|
if key not in self.map:
|
||||||
|
end = self.end
|
||||||
|
curr = end[1]
|
||||||
|
curr[2] = end[1] = self.map[key] = [key, curr, end]
|
||||||
|
|
||||||
|
def discard(self, key):
|
||||||
|
if key in self.map:
|
||||||
|
key, prev, next = self.map.pop(key)
|
||||||
|
prev[2] = next
|
||||||
|
next[1] = prev
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
end = self.end
|
||||||
|
curr = end[2]
|
||||||
|
while curr is not end:
|
||||||
|
yield curr[0]
|
||||||
|
curr = curr[2]
|
||||||
|
|
||||||
|
def __reversed__(self):
|
||||||
|
end = self.end
|
||||||
|
curr = end[1]
|
||||||
|
while curr is not end:
|
||||||
|
yield curr[0]
|
||||||
|
curr = curr[1]
|
||||||
|
|
||||||
|
def pop(self, last=True):
|
||||||
|
if not self:
|
||||||
|
raise KeyError('set is empty')
|
||||||
|
key = self.end[1][0] if last else self.end[2][0]
|
||||||
|
self.discard(key)
|
||||||
|
return key
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
if not self:
|
||||||
|
return '%s()' % (self.__class__.__name__,)
|
||||||
|
return '%s(%r)' % (self.__class__.__name__, list(self))
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
if isinstance(other, OrderedSet):
|
||||||
|
return len(self) == len(other) and list(self) == list(other)
|
||||||
|
return set(self) == set(other)
|
||||||
|
|
||||||
|
|
||||||
|
def check_password(info, old_passwords, new_password=None):
|
||||||
|
for idx, password in enumerate(old_passwords):
|
||||||
|
if password == new_password:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if info.get_secret() == password:
|
||||||
|
print("Found matching password for record {}: {}".format(
|
||||||
|
idx, info.get_display_name()))
|
||||||
|
|
||||||
|
if new_password is not None:
|
||||||
|
info.set_secret(new_password)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def main(args):
|
||||||
|
cache_file = os.path.join(BaseDirectory.save_cache_path('password_reset'),
|
||||||
|
'old-passwords')
|
||||||
|
old_password = getpass.getpass("Enter the password we are looking for: ")
|
||||||
|
new_password = getpass.getpass("Enter the new password: ")
|
||||||
|
|
||||||
|
passwords = OrderedSet()
|
||||||
|
gpg = gnupg.GPG()
|
||||||
|
|
||||||
|
# Read cache file contents
|
||||||
|
if os.path.isfile(cache_file):
|
||||||
|
with open(cache_file) as f:
|
||||||
|
contents = gpg.decrypt(f.read())
|
||||||
|
|
||||||
|
for password in str(contents).split('\n'):
|
||||||
|
passwords.add(password)
|
||||||
|
|
||||||
|
if old_password != '':
|
||||||
|
passwords.add(old_password)
|
||||||
|
|
||||||
|
if new_password != '':
|
||||||
|
passwords.add(new_password)
|
||||||
|
else:
|
||||||
|
new_password = None
|
||||||
|
|
||||||
|
password_file = '\n'.join(passwords)
|
||||||
|
|
||||||
|
# Write the cache file
|
||||||
|
encrypted_password_file = gpg.encrypt('\n'.join(passwords), 'D9D2E96E')
|
||||||
|
|
||||||
|
with open(cache_file, 'w') as f:
|
||||||
|
f.write(str(encrypted_password_file))
|
||||||
|
|
||||||
|
# Fetch all the keyrings
|
||||||
|
result, keyrings = GnomeKeyring.list_keyring_names_sync()
|
||||||
|
if result != GnomeKeyring.Result.OK:
|
||||||
|
print("Failed to fetch keyrings")
|
||||||
|
|
||||||
|
return 1
|
||||||
|
|
||||||
|
update_count = 0
|
||||||
|
|
||||||
|
for keyring in keyrings:
|
||||||
|
result, items = GnomeKeyring.list_item_ids_sync(keyring)
|
||||||
|
|
||||||
|
# Read contents of the keyring
|
||||||
|
if result != GnomeKeyring.Result.OK:
|
||||||
|
print("Failed to fetch keyring items from {}".format(keyring))
|
||||||
|
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Iterate over all keys
|
||||||
|
for itemid in items:
|
||||||
|
result, info = GnomeKeyring.item_get_info_full_sync(
|
||||||
|
keyring,
|
||||||
|
itemid,
|
||||||
|
GnomeKeyring.ItemInfoFlags.SECRET)
|
||||||
|
|
||||||
|
if result != GnomeKeyring.Result.OK:
|
||||||
|
print("Failed to get item {} from keyring {}".format(
|
||||||
|
itemid,
|
||||||
|
keyring))
|
||||||
|
|
||||||
|
continue
|
||||||
|
|
||||||
|
if check_password(info, passwords, new_password=new_password):
|
||||||
|
result = GnomeKeyring.item_set_info_sync(keyring, itemid, info)
|
||||||
|
|
||||||
|
if result != GnomeKeyring.Result.OK:
|
||||||
|
print("Failed to save item {} in keyring {}".format(
|
||||||
|
info.get_display_name(), keyring))
|
||||||
|
else:
|
||||||
|
update_count += 1
|
||||||
|
|
||||||
|
print("Updated {} keys".format(update_count))
|
6
reset_passwords
Executable file
6
reset_passwords
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
#! /usr/bin/env python3
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from password_reset import main
|
||||||
|
|
||||||
|
main(sys.argv)
|
Loading…
Reference in New Issue
Block a user