1// Copyright 2016 The go-github AUTHORS. All rights reserved.
2//
3// Use of this source code is governed by a BSD-style
4// license that can be found in the LICENSE file.
5
6package github
7
8import (
9	"context"
10	"fmt"
11	"time"
12)
13
14// GPGKey represents a GitHub user's public GPG key used to verify GPG signed commits and tags.
15//
16// https://developer.github.com/changes/2016-04-04-git-signing-api-preview/
17type GPGKey struct {
18	ID                *int64     `json:"id,omitempty"`
19	PrimaryKeyID      *int64     `json:"primary_key_id,omitempty"`
20	KeyID             *string    `json:"key_id,omitempty"`
21	PublicKey         *string    `json:"public_key,omitempty"`
22	Emails            []GPGEmail `json:"emails,omitempty"`
23	Subkeys           []GPGKey   `json:"subkeys,omitempty"`
24	CanSign           *bool      `json:"can_sign,omitempty"`
25	CanEncryptComms   *bool      `json:"can_encrypt_comms,omitempty"`
26	CanEncryptStorage *bool      `json:"can_encrypt_storage,omitempty"`
27	CanCertify        *bool      `json:"can_certify,omitempty"`
28	CreatedAt         *time.Time `json:"created_at,omitempty"`
29	ExpiresAt         *time.Time `json:"expires_at,omitempty"`
30}
31
32// String stringifies a GPGKey.
33func (k GPGKey) String() string {
34	return Stringify(k)
35}
36
37// GPGEmail represents an email address associated to a GPG key.
38type GPGEmail struct {
39	Email    *string `json:"email,omitempty"`
40	Verified *bool   `json:"verified,omitempty"`
41}
42
43// ListGPGKeys lists the public GPG keys for a user. Passing the empty
44// string will fetch keys for the authenticated user. It requires authentication
45// via Basic Auth or via OAuth with at least read:gpg_key scope.
46//
47// GitHub API docs: https://developer.github.com/v3/users/gpg_keys/#list-gpg-keys-for-a-user
48func (s *UsersService) ListGPGKeys(ctx context.Context, user string, opt *ListOptions) ([]*GPGKey, *Response, error) {
49	var u string
50	if user != "" {
51		u = fmt.Sprintf("users/%v/gpg_keys", user)
52	} else {
53		u = "user/gpg_keys"
54	}
55	u, err := addOptions(u, opt)
56	if err != nil {
57		return nil, nil, err
58	}
59
60	req, err := s.client.NewRequest("GET", u, nil)
61	if err != nil {
62		return nil, nil, err
63	}
64
65	// TODO: remove custom Accept header when this API fully launches.
66	req.Header.Set("Accept", mediaTypeGitSigningPreview)
67
68	var keys []*GPGKey
69	resp, err := s.client.Do(ctx, req, &keys)
70	if err != nil {
71		return nil, resp, err
72	}
73
74	return keys, resp, nil
75}
76
77// GetGPGKey gets extended details for a single GPG key. It requires authentication
78// via Basic Auth or via OAuth with at least read:gpg_key scope.
79//
80// GitHub API docs: https://developer.github.com/v3/users/gpg_keys/#get-a-single-gpg-key
81func (s *UsersService) GetGPGKey(ctx context.Context, id int64) (*GPGKey, *Response, error) {
82	u := fmt.Sprintf("user/gpg_keys/%v", id)
83	req, err := s.client.NewRequest("GET", u, nil)
84	if err != nil {
85		return nil, nil, err
86	}
87
88	// TODO: remove custom Accept header when this API fully launches.
89	req.Header.Set("Accept", mediaTypeGitSigningPreview)
90
91	key := &GPGKey{}
92	resp, err := s.client.Do(ctx, req, key)
93	if err != nil {
94		return nil, resp, err
95	}
96
97	return key, resp, nil
98}
99
100// CreateGPGKey creates a GPG key. It requires authenticatation via Basic Auth
101// or OAuth with at least write:gpg_key scope.
102//
103// GitHub API docs: https://developer.github.com/v3/users/gpg_keys/#create-a-gpg-key
104func (s *UsersService) CreateGPGKey(ctx context.Context, armoredPublicKey string) (*GPGKey, *Response, error) {
105	gpgKey := &struct {
106		ArmoredPublicKey string `json:"armored_public_key"`
107	}{ArmoredPublicKey: armoredPublicKey}
108	req, err := s.client.NewRequest("POST", "user/gpg_keys", gpgKey)
109	if err != nil {
110		return nil, nil, err
111	}
112
113	// TODO: remove custom Accept header when this API fully launches.
114	req.Header.Set("Accept", mediaTypeGitSigningPreview)
115
116	key := &GPGKey{}
117	resp, err := s.client.Do(ctx, req, key)
118	if err != nil {
119		return nil, resp, err
120	}
121
122	return key, resp, nil
123}
124
125// DeleteGPGKey deletes a GPG key. It requires authentication via Basic Auth or
126// via OAuth with at least admin:gpg_key scope.
127//
128// GitHub API docs: https://developer.github.com/v3/users/gpg_keys/#delete-a-gpg-key
129func (s *UsersService) DeleteGPGKey(ctx context.Context, id int64) (*Response, error) {
130	u := fmt.Sprintf("user/gpg_keys/%v", id)
131	req, err := s.client.NewRequest("DELETE", u, nil)
132	if err != nil {
133		return nil, err
134	}
135
136	// TODO: remove custom Accept header when this API fully launches.
137	req.Header.Set("Accept", mediaTypeGitSigningPreview)
138
139	return s.client.Do(ctx, req, nil)
140}
141