openmedialibrary_platform_l.../lib/python3.4/site-packages/wheel/signatures/keys.py

102 lines
3.2 KiB
Python
Raw Normal View History

2016-02-22 11:13:36 +00:00
"""Store and retrieve wheel signing / verifying keys.
2017-10-13 12:49:49 +00:00
Given a scope (a package name, + meaning "all packages", or - meaning
"no packages"), return a list of verifying keys that are trusted for that
2016-02-22 11:13:36 +00:00
scope.
Given a package name, return a list of (scope, key) suggested keys to sign
that package (only the verifying keys; the private signing key is stored
elsewhere).
Keys here are represented as urlsafe_b64encoded strings with no padding.
Tentative command line interface:
# list trusts
wheel trust
# trust a particular key for all
wheel trust + key
# trust key for beaglevote
wheel trust beaglevote key
# stop trusting a key for all
wheel untrust + key
# generate a key pair
wheel keygen
# import a signing key from a file
wheel import keyfile
# export a signing key
wheel export key
"""
import json
import os.path
2017-10-13 12:49:49 +00:00
from ..util import native, load_config_paths, save_config_path
2016-02-22 11:13:36 +00:00
class WheelKeys(object):
SCHEMA = 1
CONFIG_NAME = 'wheel.json'
2017-10-13 12:49:49 +00:00
2016-02-22 11:13:36 +00:00
def __init__(self):
2017-10-13 12:49:49 +00:00
self.data = {'signers': [], 'verifiers': []}
2016-02-22 11:13:36 +00:00
def load(self):
# XXX JSON is not a great database
for path in load_config_paths('wheel'):
conf = os.path.join(native(path), self.CONFIG_NAME)
if os.path.exists(conf):
with open(conf, 'r') as infile:
self.data = json.load(infile)
for x in ('signers', 'verifiers'):
2017-10-13 12:49:49 +00:00
if x not in self.data:
2016-02-22 11:13:36 +00:00
self.data[x] = []
if 'schema' not in self.data:
self.data['schema'] = self.SCHEMA
elif self.data['schema'] != self.SCHEMA:
raise ValueError(
"Bad wheel.json version {0}, expected {1}".format(
self.data['schema'], self.SCHEMA))
break
return self
def save(self):
2017-10-13 12:49:49 +00:00
# Try not to call this a very long time after load()
2016-02-22 11:13:36 +00:00
path = save_config_path('wheel')
conf = os.path.join(native(path), self.CONFIG_NAME)
with open(conf, 'w+') as out:
json.dump(self.data, out, indent=2)
return self
2017-10-13 12:49:49 +00:00
2016-02-22 11:13:36 +00:00
def trust(self, scope, vk):
"""Start trusting a particular key for given scope."""
2017-10-13 12:49:49 +00:00
self.data['verifiers'].append({'scope': scope, 'vk': vk})
2016-02-22 11:13:36 +00:00
return self
2017-10-13 12:49:49 +00:00
2016-02-22 11:13:36 +00:00
def untrust(self, scope, vk):
"""Stop trusting a particular key for given scope."""
2017-10-13 12:49:49 +00:00
self.data['verifiers'].remove({'scope': scope, 'vk': vk})
2016-02-22 11:13:36 +00:00
return self
2017-10-13 12:49:49 +00:00
2016-02-22 11:13:36 +00:00
def trusted(self, scope=None):
"""Return list of [(scope, trusted key), ...] for given scope."""
2017-10-13 12:49:49 +00:00
trust = [(x['scope'], x['vk']) for x in self.data['verifiers']
if x['scope'] in (scope, '+')]
2016-02-22 11:13:36 +00:00
trust.sort(key=lambda x: x[0])
trust.reverse()
return trust
2017-10-13 12:49:49 +00:00
2016-02-22 11:13:36 +00:00
def signers(self, scope):
"""Return list of signing key(s)."""
sign = [(x['scope'], x['vk']) for x in self.data['signers'] if x['scope'] in (scope, '+')]
sign.sort(key=lambda x: x[0])
sign.reverse()
return sign
2017-10-13 12:49:49 +00:00
2016-02-22 11:13:36 +00:00
def add_signer(self, scope, vk):
"""Remember verifying key vk as being valid for signing in scope."""
2017-10-13 12:49:49 +00:00
self.data['signers'].append({'scope': scope, 'vk': vk})