| 2677 | |
| 2678 | |
| 2679 | class PGPKeyring(collections_abc.Container, collections_abc.Iterable, collections_abc.Sized): |
| 2680 | def __init__(self, *args): |
| 2681 | """ |
| 2682 | PGPKeyring objects represent in-memory keyrings that can contain any combination of supported private and public |
| 2683 | keys. It can not currently be conveniently exported to a format that can be understood by GnuPG. |
| 2684 | """ |
| 2685 | super(PGPKeyring, self).__init__() |
| 2686 | self._keys = {} |
| 2687 | self._pubkeys = collections.deque() |
| 2688 | self._privkeys = collections.deque() |
| 2689 | self._aliases = collections.deque([{}]) |
| 2690 | self.load(*args) |
| 2691 | |
| 2692 | def __contains__(self, alias): |
| 2693 | aliases = set().union(*self._aliases) |
| 2694 | |
| 2695 | if isinstance(alias, str): |
| 2696 | return alias in aliases or alias.replace(' ', '') in aliases |
| 2697 | |
| 2698 | return alias in aliases # pragma: no cover |
| 2699 | |
| 2700 | def __len__(self): |
| 2701 | return len(self._keys) |
| 2702 | |
| 2703 | def __iter__(self): # pragma: no cover |
| 2704 | for pgpkey in itertools.chain(self._pubkeys, self._privkeys): |
| 2705 | yield pgpkey |
| 2706 | |
| 2707 | def _get_key(self, alias): |
| 2708 | for m in self._aliases: |
| 2709 | if alias in m: |
| 2710 | return self._keys[m[alias]] |
| 2711 | |
| 2712 | if alias.replace(' ', '') in m: |
| 2713 | return self._keys[m[alias.replace(' ', '')]] |
| 2714 | |
| 2715 | raise KeyError(alias) |
| 2716 | |
| 2717 | def _get_keys(self, alias): |
| 2718 | return [self._keys[m[alias]] for m in self._aliases if alias in m] |
| 2719 | |
| 2720 | def _sort_alias(self, alias): |
| 2721 | # remove alias from all levels of _aliases, and sort by created time and key half |
| 2722 | # so the order of _aliases from left to right: |
| 2723 | # - newer keys come before older ones |
| 2724 | # - private keys come before public ones |
| 2725 | # |
| 2726 | # this list is sorted in the opposite direction from that, because they will be placed into self._aliases |
| 2727 | # from right to left. |
| 2728 | pkids = sorted(list(set().union(m.pop(alias) for m in self._aliases if alias in m)), |
| 2729 | key=lambda pkid: (self._keys[pkid].created, self._keys[pkid].is_public)) |
| 2730 | |
| 2731 | # drop the now-sorted aliases into place |
| 2732 | for depth, pkid in enumerate(pkids): |
| 2733 | self._aliases[depth][alias] = pkid |
| 2734 | |
| 2735 | # finally, remove any empty dicts left over |
| 2736 | while {} in self._aliases: # pragma: no cover |
no outgoing calls
searching dependent graphs…