class
Analyzer::Ruby::Rails
- Analyzer::Ruby::Rails
- Analyzer::Ruby::RubyEngine
- Analyzer
- Reference
- Object
Defined in:
analyzer/analyzers/ruby/rails.crConstant Summary
-
DEVISE_ROUTES =
[{"GET", "/sign_in"}, {"POST", "/sign_in"}, {"DELETE", "/sign_out"}, {"POST", ""}, {"GET", "/sign_up"}, {"GET", "/edit"}, {"PUT", ""}, {"PATCH", ""}, {"DELETE", ""}, {"GET", "/password/new"}, {"POST", "/password"}, {"GET", "/password/edit"}, {"PUT", "/password"}, {"PATCH", "/password"}, {"GET", "/confirmation/new"}, {"POST", "/confirmation"}, {"GET", "/confirmation"}, {"GET", "/unlock/new"}, {"POST", "/unlock"}, {"GET", "/unlock"}] -
Devise routes generated by
devise_for :scope. Tuples are {METHOD, sub_path} appended to the scope's base path. -
DOORKEEPER_ROUTES =
[{"GET", "/oauth/authorize", "authorizations", "new"}, {"POST", "/oauth/authorize", "authorizations", "create"}, {"DELETE", "/oauth/authorize", "authorizations", "destroy"}, {"POST", "/oauth/token", "tokens", "create"}, {"POST", "/oauth/revoke", "tokens", "revoke"}, {"POST", "/oauth/introspect", "tokens", "introspect"}, {"GET", "/oauth/token/info", "token_info", "show"}, {"GET", "/oauth/applications", "applications", "index"}, {"POST", "/oauth/applications", "applications", "create"}, {"GET", "/oauth/applications/new", "applications", "new"}, {"GET", "/oauth/applications/:id", "applications", "show"}, {"GET", "/oauth/applications/:id/edit", "applications", "edit"}, {"PATCH", "/oauth/applications/:id", "applications", "update"}, {"PUT", "/oauth/applications/:id", "applications", "update"}, {"DELETE", "/oauth/applications/:id", "applications", "destroy"}, {"GET", "/oauth/authorized_applications", "authorized_applications", "index"}, {"DELETE", "/oauth/authorized_applications/:id", "authorized_applications", "destroy"}] -
Routes generated by Doorkeeper's
use_doorkeeper(the de-facto OAuth2 provider for Rails — Mastodon, GitLab, Discourse plugins, …). Each tuple is {METHOD, sub_path, group, action}.groupmatches theskip_controllerssymbols so ause_doorkeeper do skip_controllers :applications endblock drops the right rows, and indexes thecontrollers foo: 'bar'remap used to resolve the implementing controller for params/callees. Paths are appended to/oauthunder the scope whereuse_doorkeeperruns. -
INLINE_ROUTE_BLOCK =
/^(member|collection|new)\s*\{\s*(.+?)\s*\}\s*$/ -
Rails commonly writes compact inline route scopes:
collection { get "preview" }/member { post :use }. The parser is stack-based, so normalize these to the same do/end structure before route extraction. -
LOOP_OPENER =
/^%([wi])[\[\(\{]([^\]\)\}]*)[\]\)\}]\s*\.each(?:_with_index)?\s+do\s*\|\s*([a-z_]\w*)[^|]*\|\s*$/ -
A
%w[...].each do |var|/%i[...].each_with_index do |var, i|block over a STATIC literal list unrolls to one copy of its body per element with the loop variable's#{var}interpolations substituted. discourse alone wraps ~46 routes in%w[users u].each— without this,get "#{root_path}/..."leaks{root_path}into ~130 endpoints (a fabricated path param) AND the real /users + /u variants are lost.Only literal
%w/%ireceivers are expanded: a dynamicModel.scopes.each do |s|cannot be resolved to values at parse time, so it is left for the normal parser (its block opens a neutral frame). -
MAX_LOOP_DEPTH =
3 -
noir scans arbitrary untrusted repos, so loop unrolling must not be a DoS vector — expansion is multiplicative (elements ^ nesting). A crafted
routes.rbwith deep nesting or a huge%w[...]list could otherwise blow up CPU/memory. Real apps use tiny shallow lists (discourse's biggest is the 2-element%w[users u]), so modest caps preserve all genuine recall while bounding the worst case. Over a limit, the block is passed through unexpanded (the pre-unrolling behavior — a transparent frame). -
MAX_LOOP_OUTPUT =
20000 -
MAX_LOOP_VALUES =
100
Instance Method Summary
- #analyze
- #controller_to_endpoint(path : String, url : String, resource : String, path_prefix : String = "", only : Array(String) = [] of String, except : Array(String) = [] of String, singular : Bool = false)