@@ -8,13 +8,13 @@ private import codeql.ruby.dataflow.FlowSummary
88
99/** Provides modeling for the Sinatra library. */
1010module Sinatra {
11- private class App extends DataFlow:: ClassNode {
11+ class App extends DataFlow:: ClassNode {
1212 App ( ) { this = DataFlow:: getConstant ( "Sinatra" ) .getConstant ( "Base" ) .getADescendentModule ( ) }
1313
14- Route getRoute ( ) { result .getApp ( ) = this }
14+ Route getARoute ( ) { result .getApp ( ) = this }
1515 }
1616
17- private class Route extends DataFlow:: CallNode {
17+ class Route extends DataFlow:: CallNode {
1818 private App app ;
1919
2020 Route ( ) {
@@ -44,22 +44,26 @@ module Sinatra {
4444 }
4545 }
4646
47- private class ErbCall extends DataFlow:: CallNode {
47+ class ErbCall extends DataFlow:: CallNode {
4848 private Route route ;
4949
5050 ErbCall ( ) {
5151 this .asExpr ( ) .getExpr ( ) .getEnclosingCallable ( ) = route .getBody ( ) .asCallableAstNode ( ) and
5252 this .getMethodName ( ) = "erb"
5353 }
5454
55- ErbFile getTemplateFile ( ) {
56- result .getTemplateName ( ) =
57- this .getArgument ( 0 ) .asExpr ( ) .getConstantValue ( ) .getStringlikeValue ( ) and
58- result .getRelativePath ( ) .matches ( "%views/%" )
59- }
55+ /**
56+ * Gets the template file corresponding to this call.
57+ */
58+ ErbFile getTemplateFile ( ) { result = getTemplateFile ( this .asExpr ( ) .getExpr ( ) ) }
6059 }
6160
62- ErbFile getTemplateFile ( MethodCall erbCall ) {
61+ /**
62+ * Gets the template file referred to by `erbCall`.
63+ * This works on the AST level to avoid non-monotonic reecursion in `ErbLocalsHashSyntheticGlobal`.
64+ */
65+ private ErbFile getTemplateFile ( MethodCall erbCall ) {
66+ erbCall .getMethodName ( ) = "erb" and
6367 result .getTemplateName ( ) = erbCall .getArgument ( 0 ) .getConstantValue ( ) .getStringlikeValue ( ) and
6468 result .getRelativePath ( ) .matches ( "%views/%" )
6569 }
@@ -73,7 +77,7 @@ module Sinatra {
7377 loc .getEndLine ( ) + ":" + loc .getEndColumn ( )
7478 }
7579
76- private class ErbLocalsHashSyntheticGlobal extends SummaryComponent:: SyntheticGlobal {
80+ class ErbLocalsHashSyntheticGlobal extends SummaryComponent:: SyntheticGlobal {
7781 private string id ;
7882 private MethodCall erbCall ;
7983 private ErbFile erbFile ;
@@ -98,7 +102,9 @@ module Sinatra {
98102 override MethodCall getACall ( ) { result = any ( ErbCall c ) .asExpr ( ) .getExpr ( ) }
99103
100104 override predicate propagatesFlowExt ( string input , string output , boolean preservesValue ) {
101- input = "Argument[2]" and output = "SyntheticGlobal[" + global + "]" and preservesValue = true
105+ input = "Argument[locals:]" and
106+ output = "SyntheticGlobal[" + global + "]" and
107+ preservesValue = true
102108 }
103109 }
104110
@@ -124,4 +130,43 @@ module Sinatra {
124130 preservesValue = true
125131 }
126132 }
133+
134+ /**
135+ * Filters are run before or after the route handler. They can modify the
136+ * request and response, and share instance variables with the route handler.
137+ */
138+ class Filter extends DataFlow:: CallNode {
139+ private App app ;
140+
141+ Filter ( ) { this = app .getAModuleLevelCall ( [ "before" , "after" ] ) }
142+
143+ /**
144+ * Gets the pattern which constrains this route, if any. In the example below, the pattern is `/protected/*`.
145+ * Patterns are typically given as strings, and are interpreted by the `mustermann` gem (they are not regular expressions).
146+ * ```rb
147+ * before '/protected/*' do
148+ * authenticate!
149+ * end
150+ * ```
151+ */
152+ DataFlow:: ExprNode getPattern ( ) { result = this .getArgument ( 0 ) }
153+
154+ /**
155+ * Holds if this filter has a pattern.
156+ */
157+ predicate hasPattern ( ) { exists ( this .getPattern ( ) ) }
158+
159+ /**
160+ * Gets the body of this filter.
161+ */
162+ DataFlow:: BlockNode getBody ( ) { result = this .getBlock ( ) }
163+ }
164+
165+ class BeforeFilter extends Filter {
166+ BeforeFilter ( ) { this .getMethodName ( ) = "before" }
167+ }
168+
169+ class AfterFilter extends Filter {
170+ AfterFilter ( ) { this .getMethodName ( ) = "after" }
171+ }
127172}
0 commit comments