@@ -1498,6 +1498,147 @@ private module Django {
14981498 }
14991499 }
15001500 }
1501+
1502+ // -------------------------------------------------------------------------
1503+ // django.views
1504+ // -------------------------------------------------------------------------
1505+ /** Gets a reference to the `django.views` module. */
1506+ DataFlow:: Node views ( ) { result = django_attr ( "views" ) }
1507+
1508+ /** Provides models for the `django.views` module */
1509+ module views {
1510+ /**
1511+ * Gets a reference to the attribute `attr_name` of the `django.views` module.
1512+ * WARNING: Only holds for a few predefined attributes.
1513+ */
1514+ private DataFlow:: Node views_attr ( DataFlow:: TypeTracker t , string attr_name ) {
1515+ // for 1.11.x, see: https://github.com/django/django/blob/stable/1.11.x/django/views/__init__.py
1516+ attr_name in [ "generic" , "View" ] and
1517+ (
1518+ t .start ( ) and
1519+ result = DataFlow:: importNode ( "django.views" + "." + attr_name )
1520+ or
1521+ t .startInAttr ( attr_name ) and
1522+ result = views ( )
1523+ )
1524+ or
1525+ // Due to bad performance when using normal setup with `views_attr(t2, attr_name).track(t2, t)`
1526+ // we have inlined that code and forced a join
1527+ exists ( DataFlow:: TypeTracker t2 |
1528+ exists ( DataFlow:: StepSummary summary |
1529+ views_attr_first_join ( t2 , attr_name , result , summary ) and
1530+ t = t2 .append ( summary )
1531+ )
1532+ )
1533+ }
1534+
1535+ pragma [ nomagic]
1536+ private predicate views_attr_first_join (
1537+ DataFlow:: TypeTracker t2 , string attr_name , DataFlow:: Node res ,
1538+ DataFlow:: StepSummary summary
1539+ ) {
1540+ DataFlow:: StepSummary:: step ( views_attr ( t2 , attr_name ) , res , summary )
1541+ }
1542+
1543+ /**
1544+ * Gets a reference to the attribute `attr_name` of the `django.views` module.
1545+ * WARNING: Only holds for a few predefined attributes.
1546+ */
1547+ private DataFlow:: Node views_attr ( string attr_name ) {
1548+ result = views_attr ( DataFlow:: TypeTracker:: end ( ) , attr_name )
1549+ }
1550+
1551+ // -------------------------------------------------------------------------
1552+ // django.views.generic
1553+ // -------------------------------------------------------------------------
1554+ /** Gets a reference to the `django.views.generic` module. */
1555+ DataFlow:: Node generic ( ) { result = views_attr ( "generic" ) }
1556+
1557+ /** Provides models for the `django.views.generic` module */
1558+ module generic {
1559+ /**
1560+ * Gets a reference to the attribute `attr_name` of the `django.views.generic` module.
1561+ * WARNING: Only holds for a few predefined attributes.
1562+ */
1563+ private DataFlow:: Node generic_attr ( DataFlow:: TypeTracker t , string attr_name ) {
1564+ // for 3.1.x see: https://github.com/django/django/blob/stable/3.1.x/django/views/generic/__init__.py
1565+ // same for 1.11.x see: https://github.com/django/django/blob/stable/1.11.x/django/views/generic/__init__.py
1566+ attr_name in [
1567+ "View" , "TemplateView" , "RedirectView" , "ArchiveIndexView" , "YearArchiveView" ,
1568+ "MonthArchiveView" , "WeekArchiveView" , "DayArchiveView" , "TodayArchiveView" ,
1569+ "DateDetailView" , "DetailView" , "FormView" , "CreateView" , "UpdateView" , "DeleteView" ,
1570+ "ListView" , "GenericViewError"
1571+ ] and
1572+ (
1573+ t .start ( ) and
1574+ result = DataFlow:: importNode ( "django.views.generic" + "." + attr_name )
1575+ or
1576+ t .startInAttr ( attr_name ) and
1577+ result = generic ( )
1578+ )
1579+ or
1580+ // Due to bad performance when using normal setup with `generic_attr(t2, attr_name).track(t2, t)`
1581+ // we have inlined that code and forced a join
1582+ exists ( DataFlow:: TypeTracker t2 |
1583+ exists ( DataFlow:: StepSummary summary |
1584+ generic_attr_first_join ( t2 , attr_name , result , summary ) and
1585+ t = t2 .append ( summary )
1586+ )
1587+ )
1588+ }
1589+
1590+ pragma [ nomagic]
1591+ private predicate generic_attr_first_join (
1592+ DataFlow:: TypeTracker t2 , string attr_name , DataFlow:: Node res ,
1593+ DataFlow:: StepSummary summary
1594+ ) {
1595+ DataFlow:: StepSummary:: step ( generic_attr ( t2 , attr_name ) , res , summary )
1596+ }
1597+
1598+ /**
1599+ * Gets a reference to the attribute `attr_name` of the `django.views.generic` module.
1600+ * WARNING: Only holds for a few predefined attributes.
1601+ */
1602+ private DataFlow:: Node generic_attr ( string attr_name ) {
1603+ result = generic_attr ( DataFlow:: TypeTracker:: end ( ) , attr_name )
1604+ }
1605+
1606+ /**
1607+ * Provides models for the `django.views.generic.View` class and subclasses.
1608+ *
1609+ * See
1610+ * - https://docs.djangoproject.com/en/3.1/topics/class-based-views/
1611+ * - https://docs.djangoproject.com/en/3.1/ref/class-based-views/
1612+ */
1613+ module View {
1614+ /** Gets a reference to the `django.views.generic.View` class or any subclass. */
1615+ private DataFlow:: Node subclassRef ( DataFlow:: TypeTracker t ) {
1616+ t .start ( ) and
1617+ result =
1618+ generic_attr ( [
1619+ "View" ,
1620+ // Known Views
1621+ "TemplateView" , "RedirectView" , "ArchiveIndexView" , "YearArchiveView" ,
1622+ "MonthArchiveView" , "WeekArchiveView" , "DayArchiveView" , "TodayArchiveView" ,
1623+ "DateDetailView" , "DetailView" , "FormView" , "CreateView" , "UpdateView" ,
1624+ "DeleteView" , "ListView"
1625+ ] )
1626+ or
1627+ // `django.views.View` alias
1628+ t .start ( ) and
1629+ result = views_attr ( "View" )
1630+ or
1631+ // subclasses in project code
1632+ result .asExpr ( ) .( ClassExpr ) .getABase ( ) = subclassRef ( t .continue ( ) ) .asExpr ( )
1633+ or
1634+ exists ( DataFlow:: TypeTracker t2 | result = subclassRef ( t2 ) .track ( t2 , t ) )
1635+ }
1636+
1637+ /** Gets a reference to the `django.views.generic.View` class or any subclass. */
1638+ DataFlow:: Node subclassRef ( ) { result = subclassRef ( DataFlow:: TypeTracker:: end ( ) ) }
1639+ }
1640+ }
1641+ }
15011642 }
15021643
15031644 // ---------------------------------------------------------------------------
@@ -1530,11 +1671,62 @@ private module Django {
15301671 result = djangoRouteHandlerFunctionTracker ( DataFlow:: TypeTracker:: end ( ) , func )
15311672 }
15321673
1674+ /** A django View class defined in project code. */
1675+ class DjangoViewClassDef extends Class {
1676+ DjangoViewClassDef ( ) { this .getABase ( ) = django:: views:: generic:: View:: subclassRef ( ) .asExpr ( ) }
1677+
1678+ /** Gets a function that could handle incoming requests, if any. */
1679+ DjangoRouteHandler getARouteHandler ( ) {
1680+ // TODO: This doesn't handle attribute assignment. Should be OK, but analysis is not as complete as with
1681+ // points-to and `.lookup`, which would handle `post = my_post_handler` inside class def
1682+ result = this .getAMethod ( ) and
1683+ result .getName ( ) = HTTP:: httpVerbLower ( )
1684+ }
1685+
1686+ /** Gets a reference to this class. */
1687+ private DataFlow:: Node getARef ( DataFlow:: TypeTracker t ) {
1688+ t .start ( ) and
1689+ result .asExpr ( ) .( ClassExpr ) = this .getParent ( )
1690+ or
1691+ exists ( DataFlow:: TypeTracker t2 | result = this .getARef ( t2 ) .track ( t2 , t ) )
1692+ }
1693+
1694+ /** Gets a reference to this class. */
1695+ DataFlow:: Node getARef ( ) { result = this .getARef ( DataFlow:: TypeTracker:: end ( ) ) }
1696+
1697+ /** Gets a reference to the `as_view` classmethod of this class. */
1698+ private DataFlow:: Node asViewRef ( DataFlow:: TypeTracker t ) {
1699+ t .startInAttr ( "as_view" ) and
1700+ result = this .getARef ( )
1701+ or
1702+ exists ( DataFlow:: TypeTracker t2 | result = this .asViewRef ( t2 ) .track ( t2 , t ) )
1703+ }
1704+
1705+ /** Gets a reference to the `as_view` classmethod of this class. */
1706+ DataFlow:: Node asViewRef ( ) { result = this .asViewRef ( DataFlow:: TypeTracker:: end ( ) ) }
1707+
1708+ /** Gets a reference to the result of calling the `as_view` classmethod of this class. */
1709+ private DataFlow:: Node asViewResult ( DataFlow:: TypeTracker t ) {
1710+ t .start ( ) and
1711+ result .asCfgNode ( ) .( CallNode ) .getFunction ( ) = this .asViewRef ( ) .asCfgNode ( )
1712+ or
1713+ exists ( DataFlow:: TypeTracker t2 | result = asViewResult ( t2 ) .track ( t2 , t ) )
1714+ }
1715+
1716+ /** Gets a reference to the result of calling the `as_view` classmethod of this class. */
1717+ DataFlow:: Node asViewResult ( ) { result = asViewResult ( DataFlow:: TypeTracker:: end ( ) ) }
1718+ }
1719+
15331720 /**
1534- * A function that is used as a django route handler.
1721+ * A function that is a django route handler, meaning it handles incoming requests
1722+ * with the django framework.
15351723 */
15361724 private class DjangoRouteHandler extends Function {
1537- DjangoRouteHandler ( ) { exists ( djangoRouteHandlerFunctionTracker ( this ) ) }
1725+ DjangoRouteHandler ( ) {
1726+ exists ( djangoRouteHandlerFunctionTracker ( this ) )
1727+ or
1728+ any ( DjangoViewClassDef vc ) .getARouteHandler ( ) = this
1729+ }
15381730
15391731 /** Gets the index of the request parameter. */
15401732 int getRequestParamIndex ( ) {
@@ -1549,8 +1741,19 @@ private module Django {
15491741 Parameter getRequestParam ( ) { result = this .getArg ( this .getRequestParamIndex ( ) ) }
15501742 }
15511743
1744+ /** A data-flow node that sets up a route on a server, using the django framework. */
15521745 abstract private class DjangoRouteSetup extends HTTP:: Server:: RouteSetup:: Range , DataFlow:: CfgNode {
1553- abstract override DjangoRouteHandler getARouteHandler ( ) ;
1746+ /** Gets the data-flow node that is used as the argument for the view handler. */
1747+ abstract DataFlow:: Node getViewArg ( ) ;
1748+
1749+ final override DjangoRouteHandler getARouteHandler ( ) {
1750+ djangoRouteHandlerFunctionTracker ( result ) = getViewArg ( )
1751+ or
1752+ exists ( DjangoViewClassDef vc |
1753+ getViewArg ( ) = vc .asViewResult ( ) and
1754+ result = vc .getARouteHandler ( )
1755+ )
1756+ }
15541757 }
15551758
15561759 /**
@@ -1576,11 +1779,8 @@ private module Django {
15761779 result .asCfgNode ( ) = [ node .getArg ( 0 ) , node .getArgByName ( "route" ) ]
15771780 }
15781781
1579- override DjangoRouteHandler getARouteHandler ( ) {
1580- exists ( DataFlow:: Node viewArg |
1581- viewArg .asCfgNode ( ) in [ node .getArg ( 1 ) , node .getArgByName ( "view" ) ] and
1582- djangoRouteHandlerFunctionTracker ( result ) = viewArg
1583- )
1782+ override DataFlow:: Node getViewArg ( ) {
1783+ result .asCfgNode ( ) in [ node .getArg ( 1 ) , node .getArgByName ( "view" ) ]
15841784 }
15851785
15861786 override Parameter getARoutedParameter ( ) {
@@ -1661,11 +1861,8 @@ private module Django {
16611861 result .asCfgNode ( ) = [ node .getArg ( 0 ) , node .getArgByName ( "route" ) ]
16621862 }
16631863
1664- override DjangoRouteHandler getARouteHandler ( ) {
1665- exists ( DataFlow:: Node viewArg |
1666- viewArg .asCfgNode ( ) in [ node .getArg ( 1 ) , node .getArgByName ( "view" ) ] and
1667- djangoRouteHandlerFunctionTracker ( result ) = viewArg
1668- )
1864+ override DataFlow:: Node getViewArg ( ) {
1865+ result .asCfgNode ( ) in [ node .getArg ( 1 ) , node .getArgByName ( "view" ) ]
16691866 }
16701867 }
16711868
@@ -1683,11 +1880,8 @@ private module Django {
16831880 result .asCfgNode ( ) = [ node .getArg ( 0 ) , node .getArgByName ( "regex" ) ]
16841881 }
16851882
1686- override DjangoRouteHandler getARouteHandler ( ) {
1687- exists ( DataFlow:: Node viewArg |
1688- viewArg .asCfgNode ( ) in [ node .getArg ( 1 ) , node .getArgByName ( "view" ) ] and
1689- djangoRouteHandlerFunctionTracker ( result ) = viewArg
1690- )
1883+ override DataFlow:: Node getViewArg ( ) {
1884+ result .asCfgNode ( ) in [ node .getArg ( 1 ) , node .getArgByName ( "view" ) ]
16911885 }
16921886 }
16931887
0 commit comments