vpndetection_middleware (vpndetection v3.3.2)

View Source

The framework-agnostic half of a web middleware: resolve a client address, classify it, and decide whether the condition matched.

An adapter - vpndetection_cowboy is the one we publish - keeps only the parts that are genuinely framework-shaped and shares everything here, so the shared conformance corpus is asserted once for Erlang rather than once per framework.

Blocking is opt-in. Without a block_condition this only enriches: every request carries a lookup() and what it means is the application's decision.

Summary

Functions

Whether a condition was configured at all.

Release the client this core built. A client PASSED IN stays open, because its owner is whoever passed it.

Classify one request.

Build a core, refusing a condition that constrains nothing.

Types

core/0

-opaque core()

lookup/0

-type lookup() ::
          #{blocked := boolean(),
            ip := binary() | undefined,
            result := vpndetection_result:result() | undefined,
            error := vpndetection_error:error() | undefined}.

options/0

-type options() ::
          #{client => vpndetection:client(),
            api_key => binary() | string(),
            base_url => binary() | string(),
            timeout_ms => pos_integer(),
            retries => non_neg_integer(),
            ip_selector => vpndetection_selectors:selector(),
            block_condition => vpndetection_condition:conditions(),
            fail_closed => boolean(),
            on_missing_field => warn | error | ignore,
            on_warn => fun((binary()) -> any())}.

Functions

blocking(Core)

-spec blocking(core()) -> boolean().

Whether a condition was configured at all.

close(Core)

-spec close(core()) -> ok.

Release the client this core built. A client PASSED IN stays open, because its owner is whoever passed it.

evaluate(Core, View)

-spec evaluate(core(), vpndetection_selectors:view()) ->
                  {ok, lookup()} | {error, {missing_members, [binary()], binary()}}.

Classify one request.

A failed LOOKUP is not an error here: it lands on the error key and the request is let through. What CAN fail is a misconfiguration - a condition naming a member the plan does not serve, with on_missing_field set to error.

new(Options)

-spec new(options()) -> {ok, core()} | {error, term()}.

Build a core, refusing a condition that constrains nothing.