1package logical 2 3import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "time" 8) 9 10// This logic was pulled from the http package so that it can be used for 11// encoding wrapped responses as well. It simply translates the logical 12// response to an http response, with the values we want and omitting the 13// values we don't. 14func LogicalResponseToHTTPResponse(input *Response) *HTTPResponse { 15 httpResp := &HTTPResponse{ 16 Data: input.Data, 17 Warnings: input.Warnings, 18 Headers: input.Headers, 19 } 20 21 if input.Secret != nil { 22 httpResp.LeaseID = input.Secret.LeaseID 23 httpResp.Renewable = input.Secret.Renewable 24 httpResp.LeaseDuration = int(input.Secret.TTL.Seconds()) 25 } 26 27 // If we have authentication information, then 28 // set up the result structure. 29 if input.Auth != nil { 30 httpResp.Auth = &HTTPAuth{ 31 ClientToken: input.Auth.ClientToken, 32 Accessor: input.Auth.Accessor, 33 Policies: input.Auth.Policies, 34 TokenPolicies: input.Auth.TokenPolicies, 35 IdentityPolicies: input.Auth.IdentityPolicies, 36 Metadata: input.Auth.Metadata, 37 LeaseDuration: int(input.Auth.TTL.Seconds()), 38 Renewable: input.Auth.Renewable, 39 EntityID: input.Auth.EntityID, 40 TokenType: input.Auth.TokenType.String(), 41 Orphan: input.Auth.Orphan, 42 } 43 } 44 45 return httpResp 46} 47 48func HTTPResponseToLogicalResponse(input *HTTPResponse) *Response { 49 logicalResp := &Response{ 50 Data: input.Data, 51 Warnings: input.Warnings, 52 Headers: input.Headers, 53 } 54 55 if input.LeaseID != "" { 56 logicalResp.Secret = &Secret{ 57 LeaseID: input.LeaseID, 58 } 59 logicalResp.Secret.Renewable = input.Renewable 60 logicalResp.Secret.TTL = time.Second * time.Duration(input.LeaseDuration) 61 } 62 63 if input.Auth != nil { 64 logicalResp.Auth = &Auth{ 65 ClientToken: input.Auth.ClientToken, 66 Accessor: input.Auth.Accessor, 67 Policies: input.Auth.Policies, 68 TokenPolicies: input.Auth.TokenPolicies, 69 IdentityPolicies: input.Auth.IdentityPolicies, 70 Metadata: input.Auth.Metadata, 71 EntityID: input.Auth.EntityID, 72 Orphan: input.Auth.Orphan, 73 } 74 logicalResp.Auth.Renewable = input.Auth.Renewable 75 logicalResp.Auth.TTL = time.Second * time.Duration(input.Auth.LeaseDuration) 76 switch input.Auth.TokenType { 77 case "service": 78 logicalResp.Auth.TokenType = TokenTypeService 79 case "batch": 80 logicalResp.Auth.TokenType = TokenTypeBatch 81 } 82 } 83 84 return logicalResp 85} 86 87type HTTPResponse struct { 88 RequestID string `json:"request_id"` 89 LeaseID string `json:"lease_id"` 90 Renewable bool `json:"renewable"` 91 LeaseDuration int `json:"lease_duration"` 92 Data map[string]interface{} `json:"data"` 93 WrapInfo *HTTPWrapInfo `json:"wrap_info"` 94 Warnings []string `json:"warnings"` 95 Headers map[string][]string `json:"-"` 96 Auth *HTTPAuth `json:"auth"` 97} 98 99type HTTPAuth struct { 100 ClientToken string `json:"client_token"` 101 Accessor string `json:"accessor"` 102 Policies []string `json:"policies"` 103 TokenPolicies []string `json:"token_policies,omitempty"` 104 IdentityPolicies []string `json:"identity_policies,omitempty"` 105 Metadata map[string]string `json:"metadata"` 106 LeaseDuration int `json:"lease_duration"` 107 Renewable bool `json:"renewable"` 108 EntityID string `json:"entity_id"` 109 TokenType string `json:"token_type"` 110 Orphan bool `json:"orphan"` 111} 112 113type HTTPWrapInfo struct { 114 Token string `json:"token"` 115 Accessor string `json:"accessor"` 116 TTL int `json:"ttl"` 117 CreationTime string `json:"creation_time"` 118 CreationPath string `json:"creation_path"` 119 WrappedAccessor string `json:"wrapped_accessor,omitempty"` 120} 121 122type HTTPSysInjector struct { 123 Response *HTTPResponse 124} 125 126func (h HTTPSysInjector) MarshalJSON() ([]byte, error) { 127 j, err := json.Marshal(h.Response) 128 if err != nil { 129 return nil, err 130 } 131 // Fast path no data or empty data 132 if h.Response.Data == nil || len(h.Response.Data) == 0 { 133 return j, nil 134 } 135 // Marshaling a response will always be a JSON object, meaning it will 136 // always start with '{', so we hijack this to prepend necessary values 137 // Make a guess at the capacity, and write the object opener 138 buf := bytes.NewBuffer(make([]byte, 0, len(j)*2)) 139 buf.WriteRune('{') 140 for k, v := range h.Response.Data { 141 // Marshal each key/value individually 142 mk, err := json.Marshal(k) 143 if err != nil { 144 return nil, err 145 } 146 mv, err := json.Marshal(v) 147 if err != nil { 148 return nil, err 149 } 150 // Write into the final buffer. We'll never have a valid response 151 // without any fields so we can unconditionally add a comma after each. 152 buf.WriteString(fmt.Sprintf("%s: %s, ", mk, mv)) 153 } 154 // Add the rest, without the first '{' 155 buf.Write(j[1:]) 156 return buf.Bytes(), nil 157} 158