Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit5eff8c6

Browse files
authored
Merge pull requestsigmavirus24#886 from jacquerie/add-gpg-keys
Add support for GPG keys
2 parentsb8e7aa8 +6506039 commit5eff8c6

File tree

12 files changed

+428
-8
lines changed

12 files changed

+428
-8
lines changed

‎src/github3/github.py‎

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,24 @@ def create_gist(self, description, files, public=True):
335335
json=self._json(self._post(url,data=new_gist),201)
336336
returnself._instance_or_null(gists.Gist,json)
337337

338+
@requires_auth
339+
defcreate_gpg_key(self,armored_public_key):
340+
"""Create a new GPG key.
341+
342+
.. versionadded:: 1.2.0
343+
344+
:param str armored_public_key:
345+
(required), your GPG key, generated in ASCII-armored format
346+
:returns:
347+
the created GPG key if successful, otherwise ``None``
348+
:rtype:
349+
:class:`~github3.users.GPGKey`
350+
"""
351+
url=self._build_url('user','gpg_keys')
352+
data= {'armored_public_key':armored_public_key}
353+
json=self._json(self._post(url,data=data),201)
354+
returnself._instance_or_null(users.GPGKey,json)
355+
338356
@requires_auth
339357
defcreate_issue(self,owner,repository,title,body=None,assignee=None,
340358
milestone=None,labels=[],assignees=None):
@@ -740,6 +758,39 @@ def gitignore_templates(self):
740758
url=self._build_url('gitignore','templates')
741759
returnself._json(self._get(url),200)or []
742760

761+
@requires_auth
762+
defgpg_key(self,id_num):
763+
"""Retrieve the GPG key of the authenticated user specified by id_num.
764+
765+
.. versionadded:: 1.2.0
766+
767+
:returns:
768+
the GPG key specified by id_num
769+
:rtype:
770+
:class:`~github3.users.GPGKey`
771+
"""
772+
url=self._build_url('user','gpg_keys',id_num)
773+
json=self._json(self._get(url),200)
774+
returnself._instance_or_null(users.GPGKey,json)
775+
776+
@requires_auth
777+
defgpg_keys(self,number=-1,etag=None):
778+
"""Iterate over the GPG keys of the authenticated user.
779+
780+
.. versionadded:: 1.2.0
781+
782+
:param int number: (optional), number of GPG keys to return. Default:
783+
-1 returns all available GPG keys
784+
:param str etag: (optional), ETag from a previous request to the same
785+
endpoint
786+
:returns:
787+
generator of the GPG keys belonging to the authenticated user
788+
:rtype:
789+
:class:`~github3.users.GPGKey`
790+
"""
791+
url=self._build_url('user','gpg_keys')
792+
returnself._iter(int(number),url,users.GPGKey,etag=etag)
793+
743794
@requires_auth
744795
defis_following(self,username):
745796
"""Check if the authenticated user is following login.

‎src/github3/users.py‎

Lines changed: 149 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,103 @@
1212
from .eventsimportEvent
1313

1414

15+
classGPGKey(models.GitHubCore):
16+
"""The object representing a user's GPG key.
17+
18+
.. versionadded:: 1.2.0
19+
20+
Please see GitHub's `GPG Key Documentation` for more information.
21+
22+
.. _GPG Key Documentation:
23+
https://developer.github.com/v3/users/gpg_keys/
24+
25+
.. attribute:: can_certify
26+
27+
Whether this GPG key can be used to sign a key.
28+
29+
.. attribute:: can_encrypt_comms
30+
31+
Whether this GPG key can be used to encrypt communications.
32+
33+
.. attribute:: can_encrypt_storage
34+
35+
Whether this GPG key can be used to encrypt storage.
36+
37+
.. attribute:: can_sign
38+
39+
Whether this GPG key can be used to sign some data.
40+
41+
.. attribute:: created_at
42+
43+
A :class:`~datetime.datetime` representing the date and time when
44+
this GPG key was created.
45+
46+
.. attribute:: emails
47+
48+
A list of :class:`~github3.users.ShortEmail` attached to this GPG
49+
key.
50+
51+
.. attribute:: expires_at
52+
53+
A :class:`~datetime.datetime` representing the date and time when
54+
this GPG key will expire.
55+
56+
.. attribute:: id
57+
58+
The unique identifier of this GPG key.
59+
60+
.. attribute:: key_id
61+
62+
A hexadecimal string that identifies this GPG key.
63+
64+
.. attribute:: primary_key_id
65+
66+
The unique identifier of the primary key of this GPG key.
67+
68+
.. attribute:: public_key
69+
70+
The public key contained in this GPG key. This is not a GPG formatted
71+
key, and is not suitable to be used directly in programs like GPG.
72+
73+
.. attribute:: subkeys
74+
75+
A list of :class:`~github3.users.GPGKey` of the subkeys of this GPG
76+
key.
77+
"""
78+
79+
def_update_attributes(self,key):
80+
self.can_certify=key['can_certify']
81+
self.can_encrypt_comms=key['can_encrypt_comms']
82+
self.can_encrypt_storage=key['can_encrypt_storage']
83+
self.can_sign=key['can_sign']
84+
self.created_at=self._strptime(key['created_at'])
85+
self.emails= [ShortEmail(email,self)foremailinkey['emails']]
86+
self.expires_at=self._strptime(key['expires_at'])
87+
self.id=key['id']
88+
self.key_id=key['key_id']
89+
self.primary_key_id=key['primary_key_id']
90+
self.public_key=key['public_key']
91+
self.subkeys= [GPGKey(subkey,self)forsubkeyinkey['subkeys']]
92+
93+
def_repr(self):
94+
return'<GPG Key [{0}]>'.format(self.key_id)
95+
96+
def__str__(self):
97+
returnself.key_id
98+
99+
@requires_auth
100+
defdelete(self):
101+
"""Delete this GPG key.
102+
103+
:returns:
104+
True if successful, False otherwise
105+
:rtype:
106+
bool
107+
"""
108+
url=self._build_url('user','gpg_keys',self.id)
109+
returnself._boolean(self._delete(url),204,404)
110+
111+
15112
classKey(models.GitHubCore):
16113
"""The object representing a user's SSH key.
17114
@@ -121,15 +218,26 @@ def is_free(self):
121218
returnself.name=='free'# (No coverage)
122219

123220

124-
classEmail(models.GitHubCore):
125-
"""The object used to represent an AuthenticatedUser'semail.
221+
class_Email(models.GitHubCore):
222+
"""Baseemail object."""
126223

127-
Please see GitHub's `Emails documentation`_ for more information.
224+
class_name='_Email'
128225

129-
.. _Emails documentation:
130-
https://developer.github.com/v3/users/emails/
226+
def_update_attributes(self,email):
227+
self.email=email['email']
228+
self.verified=email['verified']
229+
230+
def_repr(self):
231+
return'<{0} [{1}]>'.format(self.class_name,self.email)
232+
233+
def__str__(self):
234+
returnself.email
235+
236+
237+
classShortEmail(_Email):
238+
"""The object used to represent an email attached to a GPG key.
131239
132-
The attributes represented on this object include:
240+
This object has the following attributes:
133241
134242
.. attribute:: email
135243
@@ -139,16 +247,35 @@ class Email(models.GitHubCore):
139247
140248
A boolean value representing whether the address has been verified or
141249
not
250+
"""
251+
252+
class_name='ShortEmail'
253+
254+
255+
classEmail(_Email):
256+
"""The object used to represent an AuthenticatedUser's email.
257+
258+
Please see GitHub's `Emails documentation`_ for more information.
259+
260+
.. _Emails documentation:
261+
https://developer.github.com/v3/users/emails/
262+
263+
This object has all of the attributes of :class:`ShortEmail` as well as
264+
the following attributes:
142265
143266
.. attribute:: primary
144267
145268
A boolean value representing whether the address is the primary
146269
address for the user or not
270+
271+
.. attribute:: visibility
272+
273+
A string value representing whether an authenticated user can view the
274+
email address. Use ``public`` to allow it, ``private`` to disallow it.
147275
"""
148276

149277
def_update_attributes(self,email):
150-
self.email=email['email']
151-
self.verified=email['verified']
278+
super(Email,self)._update_attributes(email)
152279
self.primary=email['primary']
153280
self.visibility=email['visibility']
154281

@@ -276,6 +403,20 @@ def following(self, number=-1, etag=None):
276403
url=self._build_url('following',base_url=self._api)
277404
returnself._iter(int(number),url,ShortUser,etag=etag)
278405

406+
defgpg_keys(self,number=-1,etag=None):
407+
"""Iterate over the GPG keys of this user.
408+
409+
.. versionadded:: 1.2.0
410+
411+
:param int number: (optional), number of GPG keys to return. Default:
412+
-1 returns all available GPG keys
413+
:param str etag: (optional), ETag from a previous request to the same
414+
endpoint
415+
:returns: generator of :class:`GPGKey <GPGKey>`\ s
416+
"""
417+
url=self._build_url('gpg_keys',base_url=self._api)
418+
returnself._iter(int(number),url,GPGKey,etag=etag)
419+
279420
defkeys(self,number=-1,etag=None):
280421
r"""Iterate over the public keys of this user.
281422

‎tests/cassettes/GPGKey_delete.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"http_interactions": [{"request": {"body": {"string": "{\"armored_public_key\": \"-----BEGIN PGP PUBLIC KEY BLOCK-----\\n\\nmI0EW3Gx5AEEAKkl8uAp56B9WlVMRl3ibQN99x/7JAkCWHVU1NjfAa4/AOmhG2Bl\\nFmSCfQ6CBVgOGpdaMtzyq0YxYgvhnhzwwaEZ6mrwz2in1Mo8iOVkXv2eK3ov24PU\\naLoYxiGMtNT8nKQjJLLWrEjrJOnNNGkSUHM8eAVlz3TonZALp0lOsIg/ABEBAAG0\\naUphY29wbyBOb3RhcnN0ZWZhbm8gKENyZWF0ZWQgZm9yIGEgdGVzdCBmb3IgZ2l0\\naHViMy5weSBhbmQgdGhlbiBkZWxldGVkLikgPGphY29wby5ub3RhcnN0ZWZhbm9A\\nZ21haWwuY29tPojOBBMBCgA4FiEEux/Ns2l9RasyufUE8C5SQOx2rKgFAltxseQC\\nGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQ8C5SQOx2rKhwEgQApsTrwmfh\\nPgwzX4zPtVvwKq+MYU6idhS2hwouHYPzgsVNOt5P6vW2V9jF9NQrK1gVXMSn1S16\\n6iE/X8R5rkRYbAXlvFnww4xaVCWSrXBhBGDbOCQ4fSuTNEWXREhwHAHnP4nDR+mh\\nmba6f9pMZBZalz8/0jYf2Q2ds5PEhzCQk6K4jQRbcbHkAQQAt9A5ebOFcxFyfxmt\\nOeEkmQArt31U1yATLQQto9AmpQnPk1OHjEsv+4MWaydTnuWKG1sxZb9BQRq8T8ho\\njFcYXg3CAdz2Pi6dA+I6dSKgknVY2qTFURSegFcKOiVJd48oEScMyjnRcn+gDM3Y\\nS3shYhDt1ff6cStm344+HWFyBPcAEQEAAYi2BBgBCgAgFiEEux/Ns2l9RasyufUE\\n8C5SQOx2rKgFAltxseQCGwwACgkQ8C5SQOx2rKhlfgP/dhFe09wMtVE6qXpQAXWU\\nT34sJD7GTcyYCleGtAgbtFD+7j9rk7VTG4hGZlDvW6FMdEQBE18Hd+0UhO1TA0c1\\nXTLKl8sNmIg+Ph3yiED8Nn+ByNk7KqX3SeCNvAFkTZI3yeTAynUmQin68ZqrwMjp\\nIMGmjyjdODb4qOpFvBPAlM8=\\n=2MWr\\n-----END PGP PUBLIC KEY BLOCK-----\"}", "encoding": "utf-8"}, "headers": {"Content-Length": ["1189"], "Accept-Encoding": ["gzip, deflate"], "Accept": ["application/vnd.github.v3.full+json"], "User-Agent": ["github3.py/1.1.0"], "Accept-Charset": ["utf-8"], "Connection": ["keep-alive"], "Content-Type": ["application/json"], "Authorization": ["token <AUTH_TOKEN>"]}, "method": "POST", "uri": "https://api.github.com/user/gpg_keys"}, "response": {"body": {"string": "{\"id\":414858,\"primary_key_id\":null,\"key_id\":\"F02E5240EC76ACA8\",\"raw_key\":\"-----BEGIN PGP PUBLIC KEY BLOCK-----\\n\\nmI0EW3Gx5AEEAKkl8uAp56B9WlVMRl3ibQN99x/7JAkCWHVU1NjfAa4/AOmhG2Bl\\nFmSCfQ6CBVgOGpdaMtzyq0YxYgvhnhzwwaEZ6mrwz2in1Mo8iOVkXv2eK3ov24PU\\naLoYxiGMtNT8nKQjJLLWrEjrJOnNNGkSUHM8eAVlz3TonZALp0lOsIg/ABEBAAG0\\naUphY29wbyBOb3RhcnN0ZWZhbm8gKENyZWF0ZWQgZm9yIGEgdGVzdCBmb3IgZ2l0\\naHViMy5weSBhbmQgdGhlbiBkZWxldGVkLikgPGphY29wby5ub3RhcnN0ZWZhbm9A\\nZ21haWwuY29tPojOBBMBCgA4FiEEux/Ns2l9RasyufUE8C5SQOx2rKgFAltxseQC\\nGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQ8C5SQOx2rKhwEgQApsTrwmfh\\nPgwzX4zPtVvwKq+MYU6idhS2hwouHYPzgsVNOt5P6vW2V9jF9NQrK1gVXMSn1S16\\n6iE/X8R5rkRYbAXlvFnww4xaVCWSrXBhBGDbOCQ4fSuTNEWXREhwHAHnP4nDR+mh\\nmba6f9pMZBZalz8/0jYf2Q2ds5PEhzCQk6K4jQRbcbHkAQQAt9A5ebOFcxFyfxmt\\nOeEkmQArt31U1yATLQQto9AmpQnPk1OHjEsv+4MWaydTnuWKG1sxZb9BQRq8T8ho\\njFcYXg3CAdz2Pi6dA+I6dSKgknVY2qTFURSegFcKOiVJd48oEScMyjnRcn+gDM3Y\\nS3shYhDt1ff6cStm344+HWFyBPcAEQEAAYi2BBgBCgAgFiEEux/Ns2l9RasyufUE\\n8C5SQOx2rKgFAltxseQCGwwACgkQ8C5SQOx2rKhlfgP/dhFe09wMtVE6qXpQAXWU\\nT34sJD7GTcyYCleGtAgbtFD+7j9rk7VTG4hGZlDvW6FMdEQBE18Hd+0UhO1TA0c1\\nXTLKl8sNmIg+Ph3yiED8Nn+ByNk7KqX3SeCNvAFkTZI3yeTAynUmQin68ZqrwMjp\\nIMGmjyjdODb4qOpFvBPAlM8=\\n=2MWr\\n-----END PGP PUBLIC KEY BLOCK-----\",\"public_key\":\"xo0EW3Gx5AEEAKkl8uAp56B9WlVMRl3ibQN99x/7JAkCWHVU1NjfAa4/AOmhG2BlFmSCfQ6CBVgOGpdaMtzyq0YxYgvhnhzwwaEZ6mrwz2in1Mo8iOVkXv2eK3ov24PUaLoYxiGMtNT8nKQjJLLWrEjrJOnNNGkSUHM8eAVlz3TonZALp0lOsIg/ABEBAAE=\",\"emails\":[{\"email\":\"jacopo.notarstefano@gmail.com\",\"verified\":true}],\"subkeys\":[{\"id\":414859,\"primary_key_id\":414858,\"key_id\":\"FC1199D5F1EEEE32\",\"raw_key\":null,\"public_key\":\"zo0EW3Gx5AEEALfQOXmzhXMRcn8ZrTnhJJkAK7d9VNcgEy0ELaPQJqUJz5NTh4xLL/uDFmsnU57lihtbMWW/QUEavE/IaIxXGF4NwgHc9j4unQPiOnUioJJ1WNqkxVEUnoBXCjolSXePKBEnDMo50XJ/oAzN2Et7IWIQ7dX3+nErZt+OPh1hcgT3ABEBAAE=\",\"emails\":[],\"subkeys\":[],\"can_sign\":false,\"can_encrypt_comms\":true,\"can_encrypt_storage\":true,\"can_certify\":false,\"created_at\":\"2018-08-18T20:03:09.000+02:00\",\"expires_at\":null}],\"can_sign\":true,\"can_encrypt_comms\":false,\"can_encrypt_storage\":false,\"can_certify\":true,\"created_at\":\"2018-08-18T20:03:09.000+02:00\",\"expires_at\":null}", "encoding": "utf-8"}, "headers": {"Content-Length": ["2146"], "X-XSS-Protection": ["1; mode=block"], "Content-Security-Policy": ["default-src 'none'"], "Access-Control-Expose-Headers": ["ETag, Link, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval"], "Access-Control-Allow-Origin": ["*"], "X-Frame-Options": ["deny"], "Status": ["201 Created"], "X-GitHub-Request-Id": ["8C20:07E1:FE0EB2:1CBF9F1:5B785F5D"], "ETag": ["\"5af8c12c884e0c82e9fb6954de058ccd\""], "Date": ["Sat, 18 Aug 2018 18:03:09 GMT"], "X-RateLimit-Remaining": ["4994"], "Strict-Transport-Security": ["max-age=31536000; includeSubdomains; preload"], "Server": ["GitHub.com"], "X-OAuth-Scopes": ["admin:gpg_key"], "X-GitHub-Media-Type": ["github.v3; param=full; format=json"], "X-Content-Type-Options": ["nosniff"], "X-Runtime-rack": ["0.050927"], "Vary": ["Accept, Authorization, Cookie, X-GitHub-OTP"], "X-RateLimit-Limit": ["5000"], "Cache-Control": ["private, max-age=60, s-maxage=60"], "Referrer-Policy": ["origin-when-cross-origin, strict-origin-when-cross-origin"], "Content-Type": ["application/json; charset=utf-8"], "X-Accepted-OAuth-Scopes": ["admin:gpg_key, write:gpg_key"], "X-RateLimit-Reset": ["1534618941"]}, "status": {"message": "Created", "code": 201}, "url": "https://api.github.com/user/gpg_keys"}, "recorded_at": "2018-08-18T18:03:09"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Content-Length": ["0"], "Accept-Encoding": ["gzip, deflate"], "Accept": ["application/vnd.github.v3.full+json"], "User-Agent": ["github3.py/1.1.0"], "Accept-Charset": ["utf-8"], "Connection": ["keep-alive"], "Content-Type": ["application/json"], "Authorization": ["token <AUTH_TOKEN>"]}, "method": "DELETE", "uri": "https://api.github.com/user/gpg_keys/414858"}, "response": {"body": {"string": "", "encoding": null}, "headers": {"Status": ["204 No Content"], "X-RateLimit-Remaining": ["4993"], "X-GitHub-Media-Type": ["github.v3; param=full; format=json"], "X-Runtime-rack": ["0.036032"], "X-Content-Type-Options": ["nosniff"], "Access-Control-Allow-Origin": ["*"], "Access-Control-Expose-Headers": ["ETag, Link, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval"], "X-GitHub-Request-Id": ["8C20:07E1:FE0EC7:1CBFA18:5B785F5D"], "Strict-Transport-Security": ["max-age=31536000; includeSubdomains; preload"], "X-XSS-Protection": ["1; mode=block"], "Server": ["GitHub.com"], "Content-Security-Policy": ["default-src 'none'"], "X-RateLimit-Limit": ["5000"], "Date": ["Sat, 18 Aug 2018 18:03:09 GMT"], "X-OAuth-Scopes": ["admin:gpg_key"], "Referrer-Policy": ["origin-when-cross-origin, strict-origin-when-cross-origin"], "Content-Type": ["application/octet-stream"], "X-Accepted-OAuth-Scopes": ["admin:gpg_key"], "X-Frame-Options": ["deny"], "X-RateLimit-Reset": ["1534618941"]}, "status": {"message": "No Content", "code": 204}, "url": "https://api.github.com/user/gpg_keys/414858"}, "recorded_at": "2018-08-18T18:03:09"}], "recorded_with": "betamax/0.8.1"}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp