forked from koding/kite
-
Notifications
You must be signed in to change notification settings - Fork 0
/
kitekey.go
130 lines (108 loc) · 2.9 KB
/
kitekey.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Package kitekey provides method for reading and writing kite.key file.
package kitekey
import (
"bytes"
"errors"
"fmt"
"io/ioutil"
"os"
"os/user"
"path/filepath"
"strings"
"github.com/dgrijalva/jwt-go"
)
const (
kiteDirName = ".kite"
kiteKeyFileName = "kite.key"
)
// KiteClaims represents JWT token claims extended with kontrolKey claim.
type KiteClaims struct {
jwt.StandardClaims
KontrolKey string `json:"kontrolKey,omitempty"`
KontrolURL string `json:"kontrolURL,omitempty"`
}
// KiteHome returns the home path of Kite directory.
// The returned value can be overridden by setting KITE_HOME environment variable.
func KiteHome() (string, error) {
kiteHome := os.Getenv("KITE_HOME")
if kiteHome != "" {
return kiteHome, nil
}
usr, err := user.Current()
if err != nil {
return "", err
}
return filepath.Join(usr.HomeDir, kiteDirName), nil
}
func kiteKeyPath() (string, error) {
kiteHome, err := KiteHome()
if err != nil {
return "", err
}
return filepath.Join(kiteHome, kiteKeyFileName), nil
}
// Read the contents of the kite.key file.
func Read() (string, error) {
keyPath, err := kiteKeyPath()
if err != nil {
return "", err
}
data, err := ioutil.ReadFile(keyPath)
if err != nil {
return "", err
}
return strings.TrimSpace(string(data)), nil
}
// Write over the kite.key file.
func Write(kiteKey string) error {
keyPath, err := kiteKeyPath()
if err != nil {
return err
}
err = os.MkdirAll(filepath.Dir(keyPath), 0700)
if err != nil {
return err
}
// Need to remove the previous key first because we can't write over
// when previous file's mode is 0400.
os.Remove(keyPath)
return ioutil.WriteFile(keyPath, []byte(kiteKey), 0400)
}
// Parse the kite.key file and return it as JWT token.
func Parse() (*jwt.Token, error) {
kiteKey, err := Read()
if err != nil {
return nil, err
}
return jwt.ParseWithClaims(kiteKey, &KiteClaims{}, GetKontrolKey)
}
// ParseFile reads the given kite key file and parses it as a JWT token.
func ParseFile(file string) (*jwt.Token, error) {
kiteKey, err := ioutil.ReadFile(file)
if err != nil {
return nil, err
}
return jwt.ParseWithClaims(string(bytes.TrimSpace(kiteKey)), &KiteClaims{}, GetKontrolKey)
}
// Extractor is used to extract kontrol key from JWT token.
type Extractor struct {
Token *jwt.Token
Claims *KiteClaims
}
// Extract is a keyFunc argument for jwt.Parse function.
func (e *Extractor) Extract(token *jwt.Token) (interface{}, error) {
e.Token = token
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
return nil, errors.New("invalid signing method")
}
claims, ok := token.Claims.(*KiteClaims)
if !ok {
return nil, fmt.Errorf("no kontrol key found")
}
e.Claims = claims
return jwt.ParseRSAPublicKeyFromPEM([]byte(claims.KontrolKey))
}
// GetKontrolKey is used as key getter func for jwt.Parse() function.
func GetKontrolKey(token *jwt.Token) (interface{}, error) {
return (&Extractor{}).Extract(token)
}