@@ -44,14 +44,24 @@ func (t SignedToken) MatchesRequest(req Request) bool {
44
44
t .AppSlugOrPort == req .AppSlugOrPort
45
45
}
46
46
47
- // AppSigningKey is used for signing and encrypting app tokens and API keys.
47
+ // SecurityKey is used for signing and encrypting app tokens and API keys.
48
48
//
49
49
// The first 64 bytes of the key are used for signing tokens with HMAC-SHA256,
50
50
// and the last 32 bytes are used for encrypting API keys with AES-256-GCM.
51
- type SigningKey [96 ]byte
51
+ // We use a single key for both operations to avoid having to store and manage
52
+ // two keys.
53
+ type SecurityKey [96 ]byte
52
54
53
- func KeyFromString (str string ) (SigningKey , error ) {
54
- var key SigningKey
55
+ func (k SecurityKey ) signingKey () []byte {
56
+ return k [:64 ]
57
+ }
58
+
59
+ func (k SecurityKey ) encryptionKey () []byte {
60
+ return k [64 :]
61
+ }
62
+
63
+ func KeyFromString (str string ) (SecurityKey , error ) {
64
+ var key SecurityKey
55
65
decoded , err := hex .DecodeString (str )
56
66
if err != nil {
57
67
return key , xerrors .Errorf ("decode key: %w" , err )
@@ -67,7 +77,7 @@ func KeyFromString(str string) (SigningKey, error) {
67
77
// SignToken generates a signed workspace app token with the given payload. If
68
78
// the payload doesn't have an expiry, it will be set to the current time plus
69
79
// the default expiry.
70
- func (k SigningKey ) SignToken (payload SignedToken ) (string , error ) {
80
+ func (k SecurityKey ) SignToken (payload SignedToken ) (string , error ) {
71
81
if payload .Expiry .IsZero () {
72
82
payload .Expiry = time .Now ().Add (DefaultTokenExpiry )
73
83
}
@@ -78,7 +88,7 @@ func (k SigningKey) SignToken(payload SignedToken) (string, error) {
78
88
79
89
signer , err := jose .NewSigner (jose.SigningKey {
80
90
Algorithm : tokenSigningAlgorithm ,
81
- Key : k [: 64 ] ,
91
+ Key : k . signingKey () ,
82
92
}, nil )
83
93
if err != nil {
84
94
return "" , xerrors .Errorf ("create signer: %w" , err )
@@ -100,7 +110,7 @@ func (k SigningKey) SignToken(payload SignedToken) (string, error) {
100
110
// VerifySignedToken parses a signed workspace app token with the given key and
101
111
// returns the payload. If the token is invalid or expired, an error is
102
112
// returned.
103
- func (k SigningKey ) VerifySignedToken (str string ) (SignedToken , error ) {
113
+ func (k SecurityKey ) VerifySignedToken (str string ) (SignedToken , error ) {
104
114
object , err := jose .ParseSigned (str )
105
115
if err != nil {
106
116
return SignedToken {}, xerrors .Errorf ("parse JWS: %w" , err )
@@ -112,7 +122,7 @@ func (k SigningKey) VerifySignedToken(str string) (SignedToken, error) {
112
122
return SignedToken {}, xerrors .Errorf ("expected token signing algorithm to be %q, got %q" , tokenSigningAlgorithm , object .Signatures [0 ].Header .Algorithm )
113
123
}
114
124
115
- output , err := object .Verify (k [: 64 ] )
125
+ output , err := object .Verify (k . signingKey () )
116
126
if err != nil {
117
127
return SignedToken {}, xerrors .Errorf ("verify JWS: %w" , err )
118
128
}
@@ -135,7 +145,7 @@ type EncryptedAPIKeyPayload struct {
135
145
}
136
146
137
147
// EncryptAPIKey encrypts an API key for subdomain token smuggling.
138
- func (k SigningKey ) EncryptAPIKey (payload EncryptedAPIKeyPayload ) (string , error ) {
148
+ func (k SecurityKey ) EncryptAPIKey (payload EncryptedAPIKeyPayload ) (string , error ) {
139
149
if payload .APIKey == "" {
140
150
return "" , xerrors .New ("API key is empty" )
141
151
}
@@ -155,7 +165,7 @@ func (k SigningKey) EncryptAPIKey(payload EncryptedAPIKeyPayload) (string, error
155
165
jose .A256GCM ,
156
166
jose.Recipient {
157
167
Algorithm : apiKeyEncryptionAlgorithm ,
158
- Key : k [ 64 :] ,
168
+ Key : k . encryptionKey () ,
159
169
},
160
170
& jose.EncrypterOptions {
161
171
Compression : jose .DEFLATE ,
@@ -174,7 +184,7 @@ func (k SigningKey) EncryptAPIKey(payload EncryptedAPIKeyPayload) (string, error
174
184
}
175
185
176
186
// DecryptAPIKey undoes EncryptAPIKey and is used in the subdomain app handler.
177
- func (k SigningKey ) DecryptAPIKey (encryptedAPIKey string ) (string , error ) {
187
+ func (k SecurityKey ) DecryptAPIKey (encryptedAPIKey string ) (string , error ) {
178
188
encrypted , err := base64 .RawURLEncoding .DecodeString (encryptedAPIKey )
179
189
if err != nil {
180
190
return "" , xerrors .Errorf ("base64 decode encrypted API key: %w" , err )
@@ -189,7 +199,7 @@ func (k SigningKey) DecryptAPIKey(encryptedAPIKey string) (string, error) {
189
199
}
190
200
191
201
// Decrypt using the hashed secret.
192
- decrypted , err := object .Decrypt (k [ 64 :] )
202
+ decrypted , err := object .Decrypt (k . encryptionKey () )
193
203
if err != nil {
194
204
return "" , xerrors .Errorf ("decrypt API key: %w" , err )
195
205
}
0 commit comments