waf.go 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. package cloudflare
  2. import (
  3. "encoding/json"
  4. "github.com/pkg/errors"
  5. )
  6. // WAFPackage represents a WAF package configuration.
  7. type WAFPackage struct {
  8. ID string `json:"id"`
  9. Name string `json:"name"`
  10. Description string `json:"description"`
  11. ZoneID string `json:"zone_id"`
  12. DetectionMode string `json:"detection_mode"`
  13. Sensitivity string `json:"sensitivity"`
  14. ActionMode string `json:"action_mode"`
  15. }
  16. // WAFPackagesResponse represents the response from the WAF packages endpoint.
  17. type WAFPackagesResponse struct {
  18. Response
  19. Result []WAFPackage `json:"result"`
  20. ResultInfo ResultInfo `json:"result_info"`
  21. }
  22. // WAFPackageResponse represents the response from the WAF package endpoint.
  23. type WAFPackageResponse struct {
  24. Response
  25. Result WAFPackage `json:"result"`
  26. ResultInfo ResultInfo `json:"result_info"`
  27. }
  28. // WAFPackageOptions represents options to edit a WAF package.
  29. type WAFPackageOptions struct {
  30. Sensitivity string `json:"sensitivity,omitempty"`
  31. ActionMode string `json:"action_mode,omitempty"`
  32. }
  33. // WAFGroup represents a WAF rule group.
  34. type WAFGroup struct {
  35. ID string `json:"id"`
  36. Name string `json:"name"`
  37. Description string `json:"description"`
  38. RulesCount int `json:"rules_count"`
  39. ModifiedRulesCount int `json:"modified_rules_count"`
  40. PackageID string `json:"package_id"`
  41. Mode string `json:"mode"`
  42. AllowedModes []string `json:"allowed_modes"`
  43. }
  44. // WAFGroupsResponse represents the response from the WAF groups endpoint.
  45. type WAFGroupsResponse struct {
  46. Response
  47. Result []WAFGroup `json:"result"`
  48. ResultInfo ResultInfo `json:"result_info"`
  49. }
  50. // WAFGroupResponse represents the response from the WAF group endpoint.
  51. type WAFGroupResponse struct {
  52. Response
  53. Result WAFGroup `json:"result"`
  54. ResultInfo ResultInfo `json:"result_info"`
  55. }
  56. // WAFRule represents a WAF rule.
  57. type WAFRule struct {
  58. ID string `json:"id"`
  59. Description string `json:"description"`
  60. Priority string `json:"priority"`
  61. PackageID string `json:"package_id"`
  62. Group struct {
  63. ID string `json:"id"`
  64. Name string `json:"name"`
  65. } `json:"group"`
  66. Mode string `json:"mode"`
  67. DefaultMode string `json:"default_mode"`
  68. AllowedModes []string `json:"allowed_modes"`
  69. }
  70. // WAFRulesResponse represents the response from the WAF rules endpoint.
  71. type WAFRulesResponse struct {
  72. Response
  73. Result []WAFRule `json:"result"`
  74. ResultInfo ResultInfo `json:"result_info"`
  75. }
  76. // WAFRuleResponse represents the response from the WAF rule endpoint.
  77. type WAFRuleResponse struct {
  78. Response
  79. Result WAFRule `json:"result"`
  80. ResultInfo ResultInfo `json:"result_info"`
  81. }
  82. // WAFRuleOptions is a subset of WAFRule, for editable options.
  83. type WAFRuleOptions struct {
  84. Mode string `json:"mode"`
  85. }
  86. // ListWAFPackages returns a slice of the WAF packages for the given zone.
  87. //
  88. // API Reference: https://api.cloudflare.com/#waf-rule-packages-list-firewall-packages
  89. func (api *API) ListWAFPackages(zoneID string) ([]WAFPackage, error) {
  90. var p WAFPackagesResponse
  91. var packages []WAFPackage
  92. var res []byte
  93. var err error
  94. uri := "/zones/" + zoneID + "/firewall/waf/packages"
  95. res, err = api.makeRequest("GET", uri, nil)
  96. if err != nil {
  97. return []WAFPackage{}, errors.Wrap(err, errMakeRequestError)
  98. }
  99. err = json.Unmarshal(res, &p)
  100. if err != nil {
  101. return []WAFPackage{}, errors.Wrap(err, errUnmarshalError)
  102. }
  103. if !p.Success {
  104. // TODO: Provide an actual error message instead of always returning nil
  105. return []WAFPackage{}, err
  106. }
  107. for pi := range p.Result {
  108. packages = append(packages, p.Result[pi])
  109. }
  110. return packages, nil
  111. }
  112. // WAFPackage returns a WAF package for the given zone.
  113. //
  114. // API Reference: https://api.cloudflare.com/#waf-rule-packages-firewall-package-details
  115. func (api *API) WAFPackage(zoneID, packageID string) (WAFPackage, error) {
  116. uri := "/zones/" + zoneID + "/firewall/waf/packages/" + packageID
  117. res, err := api.makeRequest("GET", uri, nil)
  118. if err != nil {
  119. return WAFPackage{}, errors.Wrap(err, errMakeRequestError)
  120. }
  121. var r WAFPackageResponse
  122. err = json.Unmarshal(res, &r)
  123. if err != nil {
  124. return WAFPackage{}, errors.Wrap(err, errUnmarshalError)
  125. }
  126. return r.Result, nil
  127. }
  128. // UpdateWAFPackage lets you update the a WAF Package.
  129. //
  130. // API Reference: https://api.cloudflare.com/#waf-rule-packages-edit-firewall-package
  131. func (api *API) UpdateWAFPackage(zoneID, packageID string, opts WAFPackageOptions) (WAFPackage, error) {
  132. uri := "/zones/" + zoneID + "/firewall/waf/packages/" + packageID
  133. res, err := api.makeRequest("PATCH", uri, opts)
  134. if err != nil {
  135. return WAFPackage{}, errors.Wrap(err, errMakeRequestError)
  136. }
  137. var r WAFPackageResponse
  138. err = json.Unmarshal(res, &r)
  139. if err != nil {
  140. return WAFPackage{}, errors.Wrap(err, errUnmarshalError)
  141. }
  142. return r.Result, nil
  143. }
  144. // ListWAFGroups returns a slice of the WAF groups for the given WAF package.
  145. //
  146. // API Reference: https://api.cloudflare.com/#waf-rule-groups-list-rule-groups
  147. func (api *API) ListWAFGroups(zoneID, packageID string) ([]WAFGroup, error) {
  148. var groups []WAFGroup
  149. var res []byte
  150. var err error
  151. uri := "/zones/" + zoneID + "/firewall/waf/packages/" + packageID + "/groups"
  152. res, err = api.makeRequest("GET", uri, nil)
  153. if err != nil {
  154. return []WAFGroup{}, errors.Wrap(err, errMakeRequestError)
  155. }
  156. var r WAFGroupsResponse
  157. err = json.Unmarshal(res, &r)
  158. if err != nil {
  159. return []WAFGroup{}, errors.Wrap(err, errUnmarshalError)
  160. }
  161. if !r.Success {
  162. // TODO: Provide an actual error message instead of always returning nil
  163. return []WAFGroup{}, err
  164. }
  165. for gi := range r.Result {
  166. groups = append(groups, r.Result[gi])
  167. }
  168. return groups, nil
  169. }
  170. // WAFGroup returns a WAF rule group from the given WAF package.
  171. //
  172. // API Reference: https://api.cloudflare.com/#waf-rule-groups-rule-group-details
  173. func (api *API) WAFGroup(zoneID, packageID, groupID string) (WAFGroup, error) {
  174. uri := "/zones/" + zoneID + "/firewall/waf/packages/" + packageID + "/groups/" + groupID
  175. res, err := api.makeRequest("GET", uri, nil)
  176. if err != nil {
  177. return WAFGroup{}, errors.Wrap(err, errMakeRequestError)
  178. }
  179. var r WAFGroupResponse
  180. err = json.Unmarshal(res, &r)
  181. if err != nil {
  182. return WAFGroup{}, errors.Wrap(err, errUnmarshalError)
  183. }
  184. return r.Result, nil
  185. }
  186. // UpdateWAFGroup lets you update the mode of a WAF Group.
  187. //
  188. // API Reference: https://api.cloudflare.com/#waf-rule-groups-edit-rule-group
  189. func (api *API) UpdateWAFGroup(zoneID, packageID, groupID, mode string) (WAFGroup, error) {
  190. opts := WAFRuleOptions{Mode: mode}
  191. uri := "/zones/" + zoneID + "/firewall/waf/packages/" + packageID + "/groups/" + groupID
  192. res, err := api.makeRequest("PATCH", uri, opts)
  193. if err != nil {
  194. return WAFGroup{}, errors.Wrap(err, errMakeRequestError)
  195. }
  196. var r WAFGroupResponse
  197. err = json.Unmarshal(res, &r)
  198. if err != nil {
  199. return WAFGroup{}, errors.Wrap(err, errUnmarshalError)
  200. }
  201. return r.Result, nil
  202. }
  203. // ListWAFRules returns a slice of the WAF rules for the given WAF package.
  204. //
  205. // API Reference: https://api.cloudflare.com/#waf-rules-list-rules
  206. func (api *API) ListWAFRules(zoneID, packageID string) ([]WAFRule, error) {
  207. var rules []WAFRule
  208. var res []byte
  209. var err error
  210. uri := "/zones/" + zoneID + "/firewall/waf/packages/" + packageID + "/rules"
  211. res, err = api.makeRequest("GET", uri, nil)
  212. if err != nil {
  213. return []WAFRule{}, errors.Wrap(err, errMakeRequestError)
  214. }
  215. var r WAFRulesResponse
  216. err = json.Unmarshal(res, &r)
  217. if err != nil {
  218. return []WAFRule{}, errors.Wrap(err, errUnmarshalError)
  219. }
  220. if !r.Success {
  221. // TODO: Provide an actual error message instead of always returning nil
  222. return []WAFRule{}, err
  223. }
  224. for ri := range r.Result {
  225. rules = append(rules, r.Result[ri])
  226. }
  227. return rules, nil
  228. }
  229. // WAFRule returns a WAF rule from the given WAF package.
  230. //
  231. // API Reference: https://api.cloudflare.com/#waf-rules-rule-details
  232. func (api *API) WAFRule(zoneID, packageID, ruleID string) (WAFRule, error) {
  233. uri := "/zones/" + zoneID + "/firewall/waf/packages/" + packageID + "/rules/" + ruleID
  234. res, err := api.makeRequest("GET", uri, nil)
  235. if err != nil {
  236. return WAFRule{}, errors.Wrap(err, errMakeRequestError)
  237. }
  238. var r WAFRuleResponse
  239. err = json.Unmarshal(res, &r)
  240. if err != nil {
  241. return WAFRule{}, errors.Wrap(err, errUnmarshalError)
  242. }
  243. return r.Result, nil
  244. }
  245. // UpdateWAFRule lets you update the mode of a WAF Rule.
  246. //
  247. // API Reference: https://api.cloudflare.com/#waf-rules-edit-rule
  248. func (api *API) UpdateWAFRule(zoneID, packageID, ruleID, mode string) (WAFRule, error) {
  249. opts := WAFRuleOptions{Mode: mode}
  250. uri := "/zones/" + zoneID + "/firewall/waf/packages/" + packageID + "/rules/" + ruleID
  251. res, err := api.makeRequest("PATCH", uri, opts)
  252. if err != nil {
  253. return WAFRule{}, errors.Wrap(err, errMakeRequestError)
  254. }
  255. var r WAFRuleResponse
  256. err = json.Unmarshal(res, &r)
  257. if err != nil {
  258. return WAFRule{}, errors.Wrap(err, errUnmarshalError)
  259. }
  260. return r.Result, nil
  261. }