@@ -8,6 +8,7 @@ private import semmle.python.dataflow.new.DataFlow
8
8
private import semmle.python.dataflow.new.RemoteFlowSources
9
9
private import semmle.python.dataflow.new.TaintTracking
10
10
private import semmle.python.Concepts
11
+ private import semmle.python.ApiGraphs
11
12
private import semmle.python.frameworks.PEP249
12
13
private import semmle.python.regex
13
14
@@ -1975,6 +1976,205 @@ private module Django {
1975
1976
}
1976
1977
}
1977
1978
1979
+ /** Provides models for django forms (defined in the `django.forms` module) */
1980
+ module Forms {
1981
+ /**
1982
+ * Provides models for the `django.forms.forms.BaseForm` class and subclasses. This
1983
+ * is usually used by the `django.forms.forms.Form` class, which is also available
1984
+ * under the more commonly used alias `django.forms.Form`.
1985
+ *
1986
+ * See https://docs.djangoproject.com/en/3.1/ref/forms/api/
1987
+ */
1988
+ module Form {
1989
+ /** Gets a reference to the `django.forms.forms.BaseForm` class or any subclass. */
1990
+ API:: Node subclassRef ( ) {
1991
+ // canonical definition
1992
+ result =
1993
+ API:: moduleImport ( "django" )
1994
+ .getMember ( "forms" )
1995
+ .getMember ( "forms" )
1996
+ .getMember ( [ "BaseForm" , "Form" ] )
1997
+ .getASubclass * ( )
1998
+ or
1999
+ result =
2000
+ API:: moduleImport ( "django" )
2001
+ .getMember ( "forms" )
2002
+ .getMember ( "models" )
2003
+ .getMember ( [ "BaseModelForm" , "ModelForm" ] )
2004
+ .getASubclass * ( )
2005
+ or
2006
+ // aliases from `django.forms`
2007
+ result =
2008
+ API:: moduleImport ( "django" )
2009
+ .getMember ( "forms" )
2010
+ .getMember ( [ "BaseForm" , "Form" , "BaseModelForm" , "ModelForm" ] )
2011
+ .getASubclass * ( )
2012
+ or
2013
+ // other Form subclasses defined in Django
2014
+ result =
2015
+ API:: moduleImport ( "django" )
2016
+ .getMember ( "contrib" )
2017
+ .getMember ( "admin" )
2018
+ .getMember ( "forms" )
2019
+ .getMember ( [ "AdminAuthenticationForm" , "AdminPasswordChangeForm" ] )
2020
+ .getASubclass * ( )
2021
+ or
2022
+ result =
2023
+ API:: moduleImport ( "django" )
2024
+ .getMember ( "contrib" )
2025
+ .getMember ( "admin" )
2026
+ .getMember ( "helpers" )
2027
+ .getMember ( "ActionForm" )
2028
+ .getASubclass * ( )
2029
+ or
2030
+ result =
2031
+ API:: moduleImport ( "django" )
2032
+ .getMember ( "contrib" )
2033
+ .getMember ( "admin" )
2034
+ .getMember ( "views" )
2035
+ .getMember ( "main" )
2036
+ .getMember ( "ChangeListSearchForm" )
2037
+ .getASubclass * ( )
2038
+ or
2039
+ result =
2040
+ API:: moduleImport ( "django" )
2041
+ .getMember ( "contrib" )
2042
+ .getMember ( "auth" )
2043
+ .getMember ( "forms" )
2044
+ .getMember ( [
2045
+ "PasswordResetForm" , "UserChangeForm" , "SetPasswordForm" ,
2046
+ "AdminPasswordChangeForm" , "PasswordChangeForm" , "AuthenticationForm" ,
2047
+ "UserCreationForm"
2048
+ ] )
2049
+ .getASubclass * ( )
2050
+ or
2051
+ result =
2052
+ API:: moduleImport ( "django" )
2053
+ .getMember ( "contrib" )
2054
+ .getMember ( "flatpages" )
2055
+ .getMember ( "forms" )
2056
+ .getMember ( "FlatpageForm" )
2057
+ .getASubclass * ( )
2058
+ or
2059
+ result =
2060
+ API:: moduleImport ( "django" )
2061
+ .getMember ( "forms" )
2062
+ .getMember ( "formsets" )
2063
+ .getMember ( "ManagementForm" )
2064
+ .getASubclass * ( )
2065
+ or
2066
+ result =
2067
+ API:: moduleImport ( "django" )
2068
+ .getMember ( "forms" )
2069
+ .getMember ( "models" )
2070
+ .getMember ( [ "ModelForm" , "BaseModelForm" ] )
2071
+ .getASubclass * ( )
2072
+ }
2073
+ }
2074
+
2075
+ /**
2076
+ * Provides models for the `django.forms.fields.Field` class and subclasses. This is
2077
+ * also available under the more commonly used alias `django.forms.Field`.
2078
+ *
2079
+ * See https://docs.djangoproject.com/en/3.1/ref/forms/fields/
2080
+ */
2081
+ module Field {
2082
+ /** Gets a reference to the `django.forms.fields.Field` class or any subclass. */
2083
+ API:: Node subclassRef ( ) {
2084
+ exists ( string modName , string clsName |
2085
+ // canonical definition
2086
+ result =
2087
+ API:: moduleImport ( "django" )
2088
+ .getMember ( "forms" )
2089
+ .getMember ( modName )
2090
+ .getMember ( clsName )
2091
+ .getASubclass * ( )
2092
+ or
2093
+ // alias from `django.forms`
2094
+ result = API:: moduleImport ( "django" ) .getMember ( "forms" ) .getMember ( clsName ) .getASubclass * ( )
2095
+ |
2096
+ modName = "fields" and
2097
+ clsName in [
2098
+ "Field" ,
2099
+ // Known subclasses
2100
+ "BooleanField" , "IntegerField" , "CharField" , "SlugField" , "DateTimeField" ,
2101
+ "EmailField" , "DateField" , "TimeField" , "DurationField" , "DecimalField" , "FloatField" ,
2102
+ "GenericIPAddressField" , "UUIDField" , "JSONField" , "FilePathField" ,
2103
+ "NullBooleanField" , "URLField" , "TypedChoiceField" , "FileField" , "ImageField" ,
2104
+ "RegexField" , "ChoiceField" , "MultipleChoiceField" , "ComboField" , "MultiValueField" ,
2105
+ "SplitDateTimeField" , "TypedMultipleChoiceField" , "BaseTemporalField"
2106
+ ]
2107
+ or
2108
+ // Known subclasses from `django.forms.models`
2109
+ modName = "models" and
2110
+ clsName in [ "ModelChoiceField" , "ModelMultipleChoiceField" , "InlineForeignKeyField" ]
2111
+ )
2112
+ or
2113
+ // other Field subclasses defined in Django
2114
+ result =
2115
+ API:: moduleImport ( "django" )
2116
+ .getMember ( "contrib" )
2117
+ .getMember ( "auth" )
2118
+ .getMember ( "forms" )
2119
+ .getMember ( [ "ReadOnlyPasswordHashField" , "UsernameField" ] )
2120
+ .getASubclass * ( )
2121
+ or
2122
+ result =
2123
+ API:: moduleImport ( "django" )
2124
+ .getMember ( "contrib" )
2125
+ .getMember ( "gis" )
2126
+ .getMember ( "forms" )
2127
+ .getMember ( "fields" )
2128
+ .getMember ( [
2129
+ "GeometryCollectionField" , "GeometryField" , "LineStringField" ,
2130
+ "MultiLineStringField" , "MultiPointField" , "MultiPolygonField" , "PointField" ,
2131
+ "PolygonField"
2132
+ ] )
2133
+ .getASubclass * ( )
2134
+ or
2135
+ result =
2136
+ API:: moduleImport ( "django" )
2137
+ .getMember ( "contrib" )
2138
+ .getMember ( "postgres" )
2139
+ .getMember ( "forms" )
2140
+ .getMember ( "array" )
2141
+ .getMember ( [ "SimpleArrayField" , "SplitArrayField" ] )
2142
+ .getASubclass * ( )
2143
+ or
2144
+ result =
2145
+ API:: moduleImport ( "django" )
2146
+ .getMember ( "contrib" )
2147
+ .getMember ( "postgres" )
2148
+ .getMember ( "forms" )
2149
+ .getMember ( "hstore" )
2150
+ .getMember ( "HStoreField" )
2151
+ .getASubclass * ( )
2152
+ or
2153
+ result =
2154
+ API:: moduleImport ( "django" )
2155
+ .getMember ( "contrib" )
2156
+ .getMember ( "postgres" )
2157
+ .getMember ( "forms" )
2158
+ .getMember ( "ranges" )
2159
+ .getMember ( [
2160
+ "BaseRangeField" , "DateRangeField" , "DateTimeRangeField" , "DecimalRangeField" ,
2161
+ "IntegerRangeField"
2162
+ ] )
2163
+ .getASubclass * ( )
2164
+ or
2165
+ result =
2166
+ API:: moduleImport ( "django" )
2167
+ .getMember ( "forms" )
2168
+ .getMember ( "models" )
2169
+ .getMember ( [ "InlineForeignKeyField" , "ModelChoiceField" , "ModelMultipleChoiceField" ] )
2170
+ .getASubclass * ( )
2171
+ }
2172
+ }
2173
+ }
2174
+
2175
+ // ---------------------------------------------------------------------------
2176
+ // Helpers
2177
+ // ---------------------------------------------------------------------------
1978
2178
/**
1979
2179
* Gets the last decorator call for the function `func`, if `func` has decorators.
1980
2180
*/
@@ -1983,6 +2183,96 @@ private module Django {
1983
2183
not exists ( Call other_decorator | other_decorator .getArg ( 0 ) = result )
1984
2184
}
1985
2185
2186
+ /** Adds the `getASelfRef` member predicate when modeling a class. */
2187
+ abstract private class SelfRefMixin extends Class {
2188
+ /**
2189
+ * Gets a reference to instances of this class, originating from a self parameter of
2190
+ * a method defined on this class.
2191
+ *
2192
+ * Note: TODO: This doesn't take MRO into account
2193
+ * Note: TODO: This doesn't take staticmethod/classmethod into account
2194
+ */
2195
+ private DataFlow:: Node getASelfRef ( DataFlow:: TypeTracker t ) {
2196
+ t .start ( ) and
2197
+ result .( DataFlow:: ParameterNode ) .getParameter ( ) = this .getAMethod ( ) .getArg ( 0 )
2198
+ or
2199
+ exists ( DataFlow:: TypeTracker t2 | result = this .getASelfRef ( t2 ) .track ( t2 , t ) )
2200
+ }
2201
+
2202
+ /**
2203
+ * Gets a reference to instances of this class, originating from a self parameter of
2204
+ * a method defined on this class.
2205
+ *
2206
+ * Note: TODO: This doesn't take MRO into account
2207
+ * Note: TODO: This doesn't take staticmethod/classmethod into account
2208
+ */
2209
+ DataFlow:: Node getASelfRef ( ) { result = this .getASelfRef ( DataFlow:: TypeTracker:: end ( ) ) }
2210
+ }
2211
+
2212
+ // ---------------------------------------------------------------------------
2213
+ // Form and form field modeling
2214
+ // ---------------------------------------------------------------------------
2215
+ /**
2216
+ * A class that is a subclass of the `django.forms.Form` class,
2217
+ * thereby handling user input.
2218
+ */
2219
+ class DjangoFormClass extends Class , SelfRefMixin {
2220
+ DjangoFormClass ( ) { this .getABase ( ) = Django:: Forms:: Form:: subclassRef ( ) .getAUse ( ) .asExpr ( ) }
2221
+ }
2222
+
2223
+ /**
2224
+ * A source of cleaned_data (either the return value from `super().clean()`, or a reference to `self.cleaned_data`)
2225
+ *
2226
+ * See https://docs.djangoproject.com/en/3.1/ref/forms/validation/#form-and-field-validation
2227
+ */
2228
+ private class DjangoFormCleanedData extends RemoteFlowSource:: Range , DataFlow:: Node {
2229
+ DjangoFormCleanedData ( ) {
2230
+ exists ( DjangoFormClass cls , Function meth |
2231
+ cls .getAMethod ( ) = meth and
2232
+ (
2233
+ this = API:: builtin ( "super" ) .getReturn ( ) .getMember ( "clean" ) .getACall ( ) and
2234
+ this .getScope ( ) = meth
2235
+ or
2236
+ this .( DataFlow:: AttrRead ) .getAttributeName ( ) = "cleaned_data" and
2237
+ this .( DataFlow:: AttrRead ) .getObject ( ) = cls .getASelfRef ( )
2238
+ )
2239
+ )
2240
+ }
2241
+
2242
+ override string getSourceType ( ) {
2243
+ result = "django.forms.Field subclass, value parameter in method"
2244
+ }
2245
+ }
2246
+
2247
+ /**
2248
+ * A class that is a subclass of the `django.forms.Field` class,
2249
+ * thereby handling user input.
2250
+ */
2251
+ class DjangoFormFieldClass extends Class {
2252
+ DjangoFormFieldClass ( ) {
2253
+ this .getABase ( ) = Django:: Forms:: Field:: subclassRef ( ) .getAUse ( ) .asExpr ( )
2254
+ }
2255
+ }
2256
+
2257
+ /**
2258
+ * A parameter in a method on a `DjangoFormFieldClass` that receives the user-supplied value for this field.
2259
+ *
2260
+ * See https://docs.djangoproject.com/en/3.1/ref/forms/validation/#form-and-field-validation
2261
+ */
2262
+ private class DjangoFormFieldValueParam extends RemoteFlowSource:: Range , DataFlow:: ParameterNode {
2263
+ DjangoFormFieldValueParam ( ) {
2264
+ exists ( DjangoFormFieldClass cls , Function meth |
2265
+ cls .getAMethod ( ) = meth and
2266
+ meth .getName ( ) in [ "to_python" , "validate" , "run_validators" , "clean" ] and
2267
+ this .getParameter ( ) = meth .getArg ( 1 )
2268
+ )
2269
+ }
2270
+
2271
+ override string getSourceType ( ) {
2272
+ result = "django.forms.Field subclass, value parameter in method"
2273
+ }
2274
+ }
2275
+
1986
2276
// ---------------------------------------------------------------------------
1987
2277
// routing modeling
1988
2278
// ---------------------------------------------------------------------------
@@ -2068,7 +2358,7 @@ private module Django {
2068
2358
}
2069
2359
2070
2360
/** A class that we consider a django View class. */
2071
- abstract class DjangoViewClass extends DjangoViewClassHelper {
2361
+ abstract class DjangoViewClass extends DjangoViewClassHelper , SelfRefMixin {
2072
2362
/** Gets a function that could handle incoming requests, if any. */
2073
2363
Function getARequestHandler ( ) {
2074
2364
// TODO: This doesn't handle attribute assignment. Should be OK, but analysis is not as complete as with
@@ -2080,29 +2370,6 @@ private module Django {
2080
2370
result .getName ( ) = "get_redirect_url"
2081
2371
)
2082
2372
}
2083
-
2084
- /**
2085
- * Gets a reference to instances of this class, originating from a self parameter of
2086
- * a method defined on this class.
2087
- *
2088
- * Note: TODO: This doesn't take MRO into account
2089
- * Note: TODO: This doesn't take staticmethod/classmethod into account
2090
- */
2091
- private DataFlow:: Node getASelfRef ( DataFlow:: TypeTracker t ) {
2092
- t .start ( ) and
2093
- result .( DataFlow:: ParameterNode ) .getParameter ( ) = this .getAMethod ( ) .getArg ( 0 )
2094
- or
2095
- exists ( DataFlow:: TypeTracker t2 | result = this .getASelfRef ( t2 ) .track ( t2 , t ) )
2096
- }
2097
-
2098
- /**
2099
- * Gets a reference to instances of this class, originating from a self parameter of
2100
- * a method defined on this class.
2101
- *
2102
- * Note: TODO: This doesn't take MRO into account
2103
- * Note: TODO: This doesn't take staticmethod/classmethod into account
2104
- */
2105
- DataFlow:: Node getASelfRef ( ) { result = this .getASelfRef ( DataFlow:: TypeTracker:: end ( ) ) }
2106
2373
}
2107
2374
2108
2375
/**
0 commit comments