2016-05-02 02:39:45 +00:00
|
|
|
package logical
|
|
|
|
|
2016-08-08 15:55:24 +00:00
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
2016-09-29 19:03:47 +00:00
|
|
|
"time"
|
2016-08-08 15:55:24 +00:00
|
|
|
)
|
2016-06-07 20:01:09 +00:00
|
|
|
|
2016-05-16 20:12:45 +00:00
|
|
|
// This logic was pulled from the http package so that it can be used for
|
|
|
|
// encoding wrapped responses as well. It simply translates the logical request
|
|
|
|
// to an http response, with the values we want and omitting the values we
|
|
|
|
// don't.
|
2016-09-29 19:03:47 +00:00
|
|
|
func LogicalResponseToHTTPResponse(input *Response) *HTTPResponse {
|
|
|
|
httpResp := &HTTPResponse{
|
2016-05-02 02:39:45 +00:00
|
|
|
Data: input.Data,
|
|
|
|
Warnings: input.Warnings(),
|
|
|
|
}
|
2016-05-02 04:08:07 +00:00
|
|
|
|
2016-05-02 02:39:45 +00:00
|
|
|
if input.Secret != nil {
|
2016-09-29 19:03:47 +00:00
|
|
|
httpResp.LeaseID = input.Secret.LeaseID
|
|
|
|
httpResp.Renewable = input.Secret.Renewable
|
|
|
|
httpResp.LeaseDuration = int(input.Secret.TTL.Seconds())
|
2016-05-02 02:39:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// If we have authentication information, then
|
|
|
|
// set up the result structure.
|
|
|
|
if input.Auth != nil {
|
2016-09-29 19:03:47 +00:00
|
|
|
httpResp.Auth = &HTTPAuth{
|
2016-05-02 02:39:45 +00:00
|
|
|
ClientToken: input.Auth.ClientToken,
|
|
|
|
Accessor: input.Auth.Accessor,
|
|
|
|
Policies: input.Auth.Policies,
|
|
|
|
Metadata: input.Auth.Metadata,
|
|
|
|
LeaseDuration: int(input.Auth.TTL.Seconds()),
|
|
|
|
Renewable: input.Auth.Renewable,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-29 19:03:47 +00:00
|
|
|
return httpResp
|
|
|
|
}
|
|
|
|
|
|
|
|
func HTTPResponseToLogicalResponse(input *HTTPResponse) *Response {
|
|
|
|
logicalResp := &Response{
|
|
|
|
Data: input.Data,
|
|
|
|
warnings: input.Warnings,
|
|
|
|
}
|
|
|
|
|
|
|
|
if input.LeaseID != "" {
|
|
|
|
logicalResp.Secret = &Secret{
|
|
|
|
LeaseID: input.LeaseID,
|
|
|
|
}
|
|
|
|
logicalResp.Secret.Renewable = input.Renewable
|
|
|
|
logicalResp.Secret.TTL = time.Second * time.Duration(input.LeaseDuration)
|
|
|
|
}
|
|
|
|
|
|
|
|
if input.Auth != nil {
|
|
|
|
logicalResp.Auth = &Auth{
|
|
|
|
ClientToken: input.Auth.ClientToken,
|
|
|
|
Accessor: input.Auth.Accessor,
|
|
|
|
Policies: input.Auth.Policies,
|
|
|
|
Metadata: input.Auth.Metadata,
|
|
|
|
}
|
|
|
|
logicalResp.Auth.Renewable = input.Auth.Renewable
|
|
|
|
logicalResp.Auth.TTL = time.Second * time.Duration(input.Auth.LeaseDuration)
|
|
|
|
}
|
|
|
|
|
2016-05-02 02:39:45 +00:00
|
|
|
return logicalResp
|
|
|
|
}
|
|
|
|
|
|
|
|
type HTTPResponse struct {
|
2016-07-25 20:54:43 +00:00
|
|
|
RequestID string `json:"request_id"`
|
2016-05-02 02:39:45 +00:00
|
|
|
LeaseID string `json:"lease_id"`
|
|
|
|
Renewable bool `json:"renewable"`
|
|
|
|
LeaseDuration int `json:"lease_duration"`
|
|
|
|
Data map[string]interface{} `json:"data"`
|
2016-05-02 04:08:07 +00:00
|
|
|
WrapInfo *HTTPWrapInfo `json:"wrap_info"`
|
2016-05-02 02:39:45 +00:00
|
|
|
Warnings []string `json:"warnings"`
|
|
|
|
Auth *HTTPAuth `json:"auth"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type HTTPAuth struct {
|
|
|
|
ClientToken string `json:"client_token"`
|
|
|
|
Accessor string `json:"accessor"`
|
|
|
|
Policies []string `json:"policies"`
|
|
|
|
Metadata map[string]string `json:"metadata"`
|
|
|
|
LeaseDuration int `json:"lease_duration"`
|
|
|
|
Renewable bool `json:"renewable"`
|
|
|
|
}
|
2016-05-02 04:08:07 +00:00
|
|
|
|
|
|
|
type HTTPWrapInfo struct {
|
2016-09-23 16:32:07 +00:00
|
|
|
Token string `json:"token"`
|
|
|
|
TTL int `json:"ttl"`
|
|
|
|
CreationTime string `json:"creation_time"`
|
|
|
|
WrappedAccessor string `json:"wrapped_accessor,omitempty"`
|
2016-05-02 04:08:07 +00:00
|
|
|
}
|
2016-08-08 15:55:24 +00:00
|
|
|
|
|
|
|
type HTTPSysInjector struct {
|
|
|
|
Response *HTTPResponse
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h HTTPSysInjector) MarshalJSON() ([]byte, error) {
|
|
|
|
j, err := json.Marshal(h.Response)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fast path no data or empty data
|
|
|
|
if h.Response.Data == nil || len(h.Response.Data) == 0 {
|
|
|
|
return j, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Marshaling a response will always be a JSON object, meaning it will
|
|
|
|
// always start with '{', so we hijack this to prepend necessary values
|
|
|
|
|
|
|
|
// Make a guess at the capacity, and write the object opener
|
2016-08-09 11:16:40 +00:00
|
|
|
buf := bytes.NewBuffer(make([]byte, 0, len(j)*2))
|
2016-08-08 15:55:24 +00:00
|
|
|
buf.WriteRune('{')
|
|
|
|
|
|
|
|
for k, v := range h.Response.Data {
|
|
|
|
// Marshal each key/value individually
|
|
|
|
mk, err := json.Marshal(k)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
mv, err := json.Marshal(v)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
// Write into the final buffer. We'll never have a valid response
|
|
|
|
// without any fields so we can unconditionally add a comma after each.
|
|
|
|
buf.WriteString(fmt.Sprintf("%s: %s, ", mk, mv))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add the rest, without the first '{'
|
|
|
|
buf.Write(j[1:])
|
|
|
|
|
|
|
|
return buf.Bytes(), nil
|
|
|
|
}
|