Skip to content

Commit dcc726e

Browse files
committed
🚧 SSH Key handling
fixes #22
1 parent 1b63cad commit dcc726e

File tree

3 files changed

+122
-0
lines changed

3 files changed

+122
-0
lines changed

git_repo/repo.py

+37
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@
3030
{self} [--path=<path>] [-v...] <target> (gist|snippet) fetch <gist> [<gist_file>]
3131
{self} [--path=<path>] [-v...] <target> (gist|snippet) create [--secret] <description> [<gist_path> <gist_path>...]
3232
{self} [--path=<path>] [-v...] <target> (gist|snippet) delete <gist> [-f]
33+
{self} [--path=<path>] [-v...] <target> key (list|ls)
34+
{self} [--path=<path>] [-v...] <target> key fetch <key_id>
35+
{self} [--path=<path>] [-v...] <target> key add [--title <key_name>] <key_path>
36+
{self} [--path=<path>] [-v...] <target> key delete <gist> [-f]
37+
{self} [--path=<path>] [-v...] <target> key <user> (list|ls)
38+
{self} [--path=<path>] [-v...] <target> key <user> fetch <key_id>
3339
{self} [--path=<path>] [-v...] <target> config [--config=<gitconfig>]
3440
{self} [-v...] config [--config=<gitconfig>]
3541
{self} --help
@@ -497,6 +503,37 @@ def do_gist_delete(self):
497503
log.info('Successfully deleted gist!')
498504
return 0
499505

506+
@register_action('key', 'list')
507+
def do_key_list(self):
508+
service = self.get_service(lookup_repository=False)
509+
print_iter(service.key_list(self.user))
510+
return 0
511+
512+
@register_action('key', 'fetch')
513+
def do_key_fetch(self):
514+
service = self.get_service(lookup_repository=False)
515+
print(service.key_fetch(self.key_id, self.user))
516+
return 0
517+
518+
@register_action('key', 'add')
519+
@register_action('key', 'create')
520+
def do_key_create(self):
521+
service = self.get_service(lookup_repository=False)
522+
name, key = service.key_create(self.key_path, self.title)
523+
log.info('Successfully added SSH key \'{}\' with id {} !'.format(name, key))
524+
return 0
525+
526+
@register_action('key', 'delete')
527+
def do_ssh_delete(self):
528+
service = self.get_service(lookup_repository=False)
529+
if not self.force: # pragma: no cover
530+
if not confirm('ssh key', self.gist_ref):
531+
return -1
532+
533+
service.key_delete(self.gist_ref)
534+
log.info('Successfully deleted ssh key!')
535+
return 0
536+
500537
@register_action('config')
501538
def do_config(self):
502539
from getpass import getpass

git_repo/services/ext/github.py

+65
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,71 @@ def request_fetch(self, user, repo, request, pull=False, force=False):
330330
raise ResourceNotFoundError('Could not find opened request #{}'.format(request)) from err
331331
raise err
332332

333+
def _get_key(self, key_id, user=None):
334+
try:
335+
id_num = int(key_id)
336+
except ValueError:
337+
raise ResourceError('Key id shall be an integer')
338+
if not user:
339+
key = self.get_key(key_id)
340+
if key:
341+
return key
342+
user = self.gh.user(user)
343+
if not user:
344+
raise ResourceNotFoundError('Could not find user {}'.format(user))
345+
for key in user.iter_keys():
346+
if key.id == id_num:
347+
return key
348+
raise ResourceNotFoundError('Key {} not found.'.format(key_id))
349+
350+
def key_create(self, pubkey_file, name=None):
351+
with open(os.path.join(pubkey_file, pubkey_file), 'r') as f:
352+
key_content = f.read()
353+
if self._check_ssh_key(key_content):
354+
key = self.gh.create_key(name, key_content)
355+
if key:
356+
return key.title, key.id
357+
raise ResourceError('Error creating key {}'.format(name))
358+
359+
def key_list(self, user=None):
360+
current_user = not user or user == self.user
361+
user = self.gh.user(user)
362+
if not user:
363+
raise ResourceNotFoundError('Could not find user {}'.format(user))
364+
if current_user:
365+
yield "{:>9} {:<12} {}"
366+
yield ('key id', 'Modified', 'Key title')
367+
for key in user.iter_keys():
368+
key = self.gh.key(key.id)
369+
keydate = datetime.strptime(
370+
key.last_modified,
371+
'%a, %d %b %Y %H:%M:%S GMT'
372+
)
373+
if keydate.year < datetime.now().year:
374+
date_fmt = "%b %d %Y"
375+
else:
376+
date_fmt = "%b %d %H:%M"
377+
378+
yield (key.id, keydate.strftime(date_fmt), key.title)
379+
else:
380+
yield "{:>8} {:<60}"
381+
yield ('key id', 'contents')
382+
for key in user.iter_keys():
383+
yield (key.id, key.key[:59]+'…')
384+
385+
def key_fetch(self, key_id, user=None):
386+
return self._get_key(key_id, user).key
387+
388+
def key_delete(self, pubkey):
389+
try:
390+
key = self.gh.key(int(pubkey))
391+
except ValueError:
392+
raise ResourceError('Key id shall be an integer')
393+
if key:
394+
if key.delete():
395+
return
396+
raise ResourceNotFoundError('Could not find key {}'.format(pubkey))
397+
333398
@classmethod
334399
def get_auth_token(cls, login, password, prompt=None):
335400
import platform

git_repo/services/service.py

+20
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,26 @@ def request_fetch(self, user, repo, request, pull=False, force=False): #pragma:
580580
def request_create(self, user, repo, from_branch, onto_branch, title, description=None, auto_slug=False):
581581
raise NotImplementedError
582582

583+
@staticmethod
584+
def _check_ssh_key(key):
585+
if not key.startswith('ssh-'):
586+
raise ResourceError('Key is invalid: does not start with "ssh-"')
587+
if not len(key.strip().splitlines()) == 1:
588+
raise ResourceError('Key is invalid: has more than one line')
589+
return True
590+
591+
def key_create(self, pubkey_file, name):
592+
raise NotImplementedError
593+
594+
def key_delete(self, pubkey):
595+
raise NotImplementedError
596+
597+
def key_list(self):
598+
raise NotImplementedError
599+
600+
def key_fetch(self):
601+
raise NotImplementedError
602+
583603
@property
584604
def get_parent_project_url(self, user, repo, rw=True): #pragma: no cover
585605
raise NotImplementedError

0 commit comments

Comments
 (0)