{"id":15668090,"url":"https://github.com/evadne/shun","last_synced_at":"2025-06-14T19:05:58.204Z","repository":{"id":40558137,"uuid":"221751017","full_name":"evadne/shun","owner":"evadne","description":"Easy \u0026 flexible traffic filtering with Elixir","archived":false,"fork":false,"pushed_at":"2023-02-01T03:26:13.000Z","size":32,"stargazers_count":82,"open_issues_count":3,"forks_count":3,"subscribers_count":2,"default_branch":"develop","last_synced_at":"2025-03-27T11:38:09.469Z","etag":null,"topics":["elixir","filtering"],"latest_commit_sha":null,"homepage":"https://hexdocs.pm/shun","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/evadne.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-11-14T17:24:18.000Z","updated_at":"2025-01-16T14:23:52.000Z","dependencies_parsed_at":"2023-02-17T01:46:28.155Z","dependency_job_id":null,"html_url":"https://github.com/evadne/shun","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evadne%2Fshun","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evadne%2Fshun/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evadne%2Fshun/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evadne%2Fshun/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/evadne","download_url":"https://codeload.github.com/evadne/shun/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248782260,"owners_count":21160717,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["elixir","filtering"],"created_at":"2024-10-03T14:06:27.370Z","updated_at":"2025-04-13T21:11:42.962Z","avatar_url":"https://github.com/evadne.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Shun\n\nThe Shun library provides URI, IPv4 and IPv6 address verification primitives for Elixir applications. It is useful for Web applications that act on behalf of the customer, e.g. resource pipelines which operate on user-provided URIs.\n\n## Capabilities\n\nThe Shun library provides a way to easily add domain / address verification to your application. It operates based on a set of Rules that are compiled into your custom module, but you are also able to inject function references where needed, to affect the decisions dynamically.\n\nWithin the DSL, each Rule must have a Target. Additionaly, guards and handlers are optionally available.\n\n-  There are three types of Rules: Accept, Reject and Handle. The first two kinds are self-explanatory; the third kind allows you to specify a function reference, so your application can dynamically decide what to do with a Target.\n\n-  There are also three types of Targets: `URI` structs, `:inet` tuples (4-arity for IPv4 or 8-arity for IPv8), or [CIDR Notations][1].\n\n-  For Rules using `URI` structs or tuples, pattern-matching via use of guards is available.\n\n-  For all kinds of Targets, the Handle Rule type allows associating a remote function reference, which allows your Application to dynamically decide what to do with a particular URI or IP Address.\n\n[1]: https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing\n\n## Installation\n\nTo install Shun, add the following line in your application’s dependencies:\n\n```elixir\ndefp deps do\n  [\n    {:shun, \"~\u003e 1.0.2\"}\n  ]\nend\n```\n\n## Usage\n\nThe usual way to use `Shun.Builder` is by installing it in a custom module.\n\n```elixir\ndefmodule MyApp.Shun do\n  use Shun.Builder\n  handle Shun.Preset.IPv6.Embedded\n  reject Shun.Preset.AWS.InstanceMetadata\nend\n```\n\nAdditional Rules can be added using a simple DSL (provided by `Shun.Rule`):\n\n```elixir\ndefmodule MyApp.Shun do\n  use Shun.Builder\n  handle Shun.Preset.IPv6.Embedded\n  reject Shun.Preset.AWS.InstanceMetadata\n  reject \"10.0.0.0/8\"\n  reject %URI{scheme: scheme} when scheme != \"https\"\nend\n```\n\nAfterwards, you can call `Shun.verify/2`, for example:\n\n```elixir\nShun.verify(MyApp.Shun, \"http://google.com\")\n```\n\n## Presets\n\nThe following presets are bundled with Shun:\n\n- `Shun.Preset.IPv4.LinkLocal`\n- `Shun.Preset.IPv4.Loopback`\n- `Shun.Preset.IPv4.Private`\n- `Shun.Preset.IPv6.Embedded`\n- `Shun.Preset.IPv6.LinkLocal`\n- `Shun.Preset.IPv6.Loopback`\n- `Shun.Preset.AWS.InstanceMetadata`\n\nThese Presets provide reject rules that can be plugged into your own Shun provider.\n\nYou can use presets with the `accept`, `reject` or `handle` macros, for example:\n\n```elixir\nreject Shun.Preset.IPv4.LinkLocal # rejects link-local ipv4 addresses\nreject Shun.Preset.AWS.InstanceMetadata # rejects 169.254.169.254\nhandle Shun.Preset.IPv6.Embedded # handles underlying IPv4\nreject Shun.Preset.IPv6.Embedded # rejects all embedded IPv4\n```\n\n## Scenarios\n\nTo accept URLs as long as they do not resolve to undesired IPs:\n\n```elixir\ndefmodule MyApp.Shun do\n  use Shun.Builder\n  # reject \u003cpreset\u003e\n  accept {_, _, _, _}\n  accept {_, _, _, _, _, _, _, _}\n  # Note that a default action for URIs is not provided - this forces all\n  # URIs to be resolved, so IP rules in presets are exercised\nend\n```\n\nTo only accept a few specific URIs:\n\n```elixir\ndefmodule MyApp.Shun do\n  use Shun.Builder\n  accept %URI{host: \"example.com\"}\n  accept %URI{host: \"special.example.com\"}\n  reject %URI{} \n  reject {_, _, _, _}\n  reject {_, _, _, _, _, _, _, _}\nend\n```\n\nTo use a function to decide what to do with the URI:\n\n```elixir\ndefmodule MyApp.Shun do\n  use Shun.Builder\n  reject %URI{scheme: scheme} when scheme != \"https\"\n  handle %URI{}, \u0026handle_uri/1\n\n  defp handle_uri(uri) do\n    cond do\n      uri.host == \"dynamic.example.com\" -\u003e :reject\n      true -\u003e :accept\n    end\n  end\nend\n```\n\nTo only allow URIs from a specific AWS S3 bucket (in virtual hosted-style):\n\n```elixir\ndefmodule MyApp.Shun do\n  use Shun.Builder\n  reject %URI{scheme: scheme} when scheme != \"https\"\n  handle %URI{}, \u0026handle_uri/1\n\n  defp handle_uri(%{host: host}) do\n    bucket_name = System.get_env(\"AWS_BUCKET_NAME\")\n    region_name = System.get_env(\"AWS_REGION\")\n\n    names = [\n      \"#{bucket_name}.s3-accelerate.dualstack.amazonaws.com\",\n      \"#{bucket_name}.s3-accelerate.amazonaws.com\",\n      \"#{bucket_name}.s3.dualstack.#{region_name}.amazonaws.com\",\n      \"#{bucket-name}.s3.#{region_name}.amazonaws.com\",\n      \"#{bucket-name}.s3.amazonaws.com\"\n    ]\n\n    cond do\n      Enum.member?(names, host) -\u003e :accept\n      true -\u003e :reject\n    end\n  end\nend\n```\n\n## Notes\n\n1.  Please see documentation in `Shun.Builder` regarding the order of rules and default actions. The default actions are as follows:\n\n    - IPs are rejected\n    - URIs that have IPs as host are processed as if they were IPs\n    - Other URIs are resolved and are only accepted if all underlying IPs are accepted\n\n    If a catch-all rule is specifically provided, then the default action for that target type will not be generated.\n\n2.  Any Provider module that implements the `Shun.Provider` behaviour can be used.\n\n3.  The DSL as implemented by `Shun.Rule` emits Rules on a per-entry basis. However, it is most likely that you will use `Shun.Builder` so Rules are compiled to function heads ahead of time. `Shun.Builder` does not reorder Rules, so they are evaluated in the original order.\n\n4.  If your application follows redirections, it would be wise to re-validate the URI or IP address on each redirection with Shun.\n\n## Acknowledgements\n\nDuring design and prototype development of this library, the Author has drawn inspiration from the following implementations, and therefore thanks all contributors for their generosity:\n\n- [c-rack/cidr-elixir](https://github.com/c-rack/cidr-elixir)\n- [cobenian/inet_cidr](https://github.com/Cobenian/inet_cidr)\n\nThe author wishes to additionally thank the following individuals for their input during the implemention process:\n\n- [Alvise Susmel](https://github.com/alvises)\n- [Derek Kraan](https://github.com/derekkraan)\n- [Bryan Hunt](https://github.com/mergefailure)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevadne%2Fshun","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fevadne%2Fshun","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevadne%2Fshun/lists"}