@@ -4,6 +4,7 @@ private import codeql_ruby.controlflow.CfgNodes
44private import codeql_ruby.DataFlow
55private import codeql_ruby.dataflow.RemoteFlowSources
66private import codeql_ruby.ast.internal.Module
7+ private import ActionView
78
89private class ActionControllerBaseAccess extends ConstantReadAccess {
910 ActionControllerBaseAccess ( ) {
@@ -45,26 +46,58 @@ class ActionControllerControllerClass extends ClassDeclaration {
4546 other .getModule ( ) = resolveScopeExpr ( this .getSuperclassExpr ( ) )
4647 )
4748 }
49+
50+ /**
51+ * Gets a `ActionControllerActionMethod` defined in this class.
52+ */
53+ ActionControllerActionMethod getAnAction ( ) { result = this .getAMethod ( ) }
4854}
4955
5056/**
51- * A call to the `params` method within the context of an
52- * `ActionControllerControllerClass`. For example, the `params` call in:
53- *
54- * ```rb
55- * class FooController < ActionController::Base
56- * def delete_handler
57- * uid = params[:id]
58- * User.delete_all("id = ?", uid)
59- * end
60- * end
61- * ```
57+ * An instance method defined within an `ActionController` controller class.
58+ * This may be the target of a route handler, if such a route is defined.
6259 */
63- class ActionControllerParamsCall extends MethodCall {
60+ class ActionControllerActionMethod extends Method , HTTP:: Server:: RequestHandler:: Range {
61+ private ActionControllerControllerClass controllerClass ;
62+
63+ ActionControllerActionMethod ( ) { this = controllerClass .getAMethod ( ) }
64+
65+ /**
66+ * Establishes a mapping between a method within the file
67+ * `<source_prefix>/app/controllers/<subpath>_controller.rb` and the
68+ * corresponding template file at
69+ * `<source_prefix>/app/views/<subpath>/<method_name>.html.erb`.
70+ */
71+ ErbFile getDefaultTemplateFile ( ) {
72+ exists ( string templatePath , string sourcePrefix , string subPath , string controllerPath |
73+ controllerPath = this .getLocation ( ) .getFile ( ) .getAbsolutePath ( ) and
74+ sourcePrefix = controllerPath .regexpCapture ( "^(.*)/app/controllers/.*$" , 1 ) and
75+ controllerPath = sourcePrefix + "/app/controllers/" + subPath + "_controller.rb" and
76+ templatePath = sourcePrefix + "/app/views/" + subPath + "/" + this .getName ( ) + ".html.erb"
77+ |
78+ result .getAbsolutePath ( ) = templatePath
79+ )
80+ }
81+
82+ // params come from `params` method rather than a method parameter
83+ override Parameter getARoutedParameter ( ) { none ( ) }
84+
85+ override string getFramework ( ) { result = "ActionController" }
86+
87+ /** Gets a call to render from within this method. */
88+ RenderCall getARenderCall ( ) { result .getParent + ( ) = this }
89+
90+ // TODO: model the implicit render call when a path through the method does
91+ // not end at an explicit render or redirect
92+ /** Gets the controller class containing this method. */
93+ ActionControllerControllerClass getControllerClass ( ) { result = controllerClass }
94+ }
95+
96+ // A method call with a `self` receiver from within a controller class
97+ private class ActionControllerContextCall extends MethodCall {
6498 private ActionControllerControllerClass controllerClass ;
6599
66- ActionControllerParamsCall ( ) {
67- this .getMethodName ( ) = "params" and
100+ ActionControllerContextCall ( ) {
68101 this .getReceiver ( ) instanceof Self and
69102 this .getEnclosingModule ( ) = controllerClass
70103 }
@@ -73,14 +106,77 @@ class ActionControllerParamsCall extends MethodCall {
73106}
74107
75108/**
76- * A `RemoteFlowSource::Range` to represent accessing the Action Controller
77- * parameters available to a controller via the `params` method.
109+ * A call to the `params` method to fetch the request parameters.
110+ */
111+ abstract class ParamsCall extends MethodCall {
112+ ParamsCall ( ) { this .getMethodName ( ) = "params" }
113+ }
114+
115+ /**
116+ * A `RemoteFlowSource::Range` to represent accessing the
117+ * ActionController parameters available via the `params` method.
78118 */
79- class ActionControllerParamsSource extends RemoteFlowSource:: Range {
80- ActionControllerParamsCall call ;
119+ class ParamsSource extends RemoteFlowSource:: Range {
120+ ParamsCall call ;
81121
82- ActionControllerParamsSource ( ) { this .asExpr ( ) .getExpr ( ) = call }
122+ ParamsSource ( ) { this .asExpr ( ) .getExpr ( ) = call }
83123
84- // TODO: what to use here?
85124 override string getSourceType ( ) { result = "ActionController::Metal#params" }
86125}
126+
127+ // A call to `params` from within a controller.
128+ private class ActionControllerParamsCall extends ActionControllerContextCall , ParamsCall { }
129+
130+ // A call to `render_to` from within a controller.
131+ private class ActionControllerRenderToCall extends ActionControllerContextCall , RenderToCall { }
132+
133+ // A call to `html_safe` from within a controller.
134+ private class ActionControllerHtmlSafeCall extends HtmlSafeCall {
135+ ActionControllerHtmlSafeCall ( ) { this .getEnclosingModule ( ) instanceof ActionControllerControllerClass }
136+ }
137+
138+ /**
139+ * A call to the `redirect_to` method, used in an action to redirect to a
140+ * specific URL/path or to a different action in this controller.
141+ */
142+ class RedirectToCall extends ActionControllerContextCall {
143+ RedirectToCall ( ) { this .getMethodName ( ) = "redirect_to" }
144+
145+ /** Gets the `Expr` representing the URL to redirect to, if any */
146+ Expr getRedirectUrl ( ) { result = this .getArgument ( 0 ) }
147+
148+ /** Gets the `ActionControllerActionMethod` to redirect to, if any */
149+ ActionControllerActionMethod getRedirectActionMethod ( ) {
150+ exists ( string methodName |
151+ methodName = this .getKeywordArgument ( "action" ) .( StringlikeLiteral ) .getValueText ( ) and
152+ methodName = result .getName ( ) and
153+ result .getEnclosingModule ( ) = this .getControllerClass ( )
154+ )
155+ }
156+ }
157+
158+ /**
159+ * A `SetterMethodCall` that assigns a value to the `response_body`.
160+ */
161+ class ResponseBodySetterCall extends SetterMethodCall {
162+ ResponseBodySetterCall ( ) { this .getMethodName ( ) = "response_body=" }
163+ }
164+
165+ /**
166+ * A method in an `ActionController` class that is accessible from within a view as a helper method.
167+ */
168+ class ActionControllerHelperMethod extends Method {
169+ private ActionControllerControllerClass controllerClass ;
170+
171+ ActionControllerHelperMethod ( ) {
172+ this .getEnclosingModule ( ) = controllerClass and
173+ exists ( MethodCall helperMethodMarker |
174+ helperMethodMarker .getMethodName ( ) = "helper_method" and
175+ helperMethodMarker .getAnArgument ( ) .( StringlikeLiteral ) .getValueText ( ) = this .getName ( ) and
176+ helperMethodMarker .getEnclosingModule ( ) = controllerClass
177+ )
178+ }
179+
180+ /** Gets the class containing this helper method. */
181+ ActionControllerControllerClass getControllerClass ( ) { result = controllerClass }
182+ }
0 commit comments