class

Noir::ElixirPlugJudge

Inherits Reference < Object

Decides whether a Phoenix/Plug plug can refuse an anonymous caller by reading its definition rather than its name. A module plug is judged by its call/2, a function plug (plug :require_user) by the def of that name in the plugging module or a module it imports; each together with the local helpers it calls and, a few hops deep, the remote helpers it resolves through aliases (H.unauthorized(conn, ...)).

A guard reads who the caller is (a current_user-style assign, an authorization/token header, a Guardian/Pow resource) and can refuse: a 401/403, a redirect to a login page, or, for a plug that halts, a 404 that hides the resource. A plug that only loads the user (AuthPlug assigning current_user) or redirects elsewhere (RequireLoggedOut sending users to their dashboard, a first-launch redirect to registration) is not one.

ponytail: textual over the reachable function bodies, not path-sensitive; a refusal that fires only for signed-in users (a ban check returning 403) still reads as a guard.

Constants

BASIC_AUTH = /\bPlug\.BasicAuth\.basic_auth\s*\(|(?<!def )(?<!defp )\bbasic_auth\s*\(\s*conn\b/

Plug's own Plug.BasicAuth.basic_auth/2 answers 401 and halts.

BUILTIN_FUNCTION_PLUGS = Set {"accepts", "fetch_session", "fetch_flash", "fetch_live_flash", "protect_from_forgery", "put_secure_browser_headers", "put_root_layout", "put_layout", "put_new_layout", "put_view", "put_new_view", "fetch_query_params", "fetch_cookies", "match", "dispatch"}

Phoenix/Plug function plugs that never refuse a caller.

GUARDIAN_MINT = /\bGuardian\.encode_and_sign!?\b/

Minting a token is not a read of the caller. Actions ignore it; module plugs such as Guardian.Plug.EnsureAuthenticated still match IDENTITY.

HALT = /\bhalt\b/
IDENTITY = /\bcurrent_(?:user|account|member|resource|scope|identity)\b|get_req_header\([^)]*["'][^"']*(?:auth|token|key|signature)|\bGuardian\.|\bPow\.Plug\b|get_session\([^)]*(?:user|token)/i
LOCAL_CALL = /(?<![\w.:@])([a-z_]\w*[!?]?)\s*\(/
LOGIN_PATH = /["'][^"'\n]*\/(?:[\w-]+\/)*(?:log[_-]?in|sign[_-]?in)\b|Routes\.\w*(?:session|login)\w*_path\b/i
MAX_FUNCTIONS = 40
REMOTE_CALL = /(?<![\w.])((?:[A-Z]\w*\.)*[A-Z]\w*)\.([a-z_]\w*[!?]?)\s*\(/
STRONG_REFUSAL = /(?<![\w.])40[13](?![\d.])|:unauthorized\b|:forbidden\b/
WEAK_REFUSAL = /(?<![\w.])404(?![\d.])|:not_found\b/

Constructors

new(files : Array(String), reader : Proc(String, Array(String) | Nil))
Source

Instance methods

action_refuses?(name : String, path : String, line_index : Int32) : Bool

The action itself refuses: it reads the caller and answers 401/403 or sends them to log in (with %User{} <- conn.assigns[:current_user] ... else _ -> unauthorized(conn)). One helper hop deep.

Source
function_plug(name : String, path : String, line_index : Int32) : Bool | Nil
Source
module_plug(ref : String, from_path : String) : Bool | Nil

true/false once the definition is read; nil when it is not in the tree.

Source

Nested types