@@ -1498,6 +1498,147 @@ private module Django {
1498
1498
}
1499
1499
}
1500
1500
}
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
+ }
1501
1642
}
1502
1643
1503
1644
// ---------------------------------------------------------------------------
@@ -1530,11 +1671,62 @@ private module Django {
1530
1671
result = djangoRouteHandlerFunctionTracker ( DataFlow:: TypeTracker:: end ( ) , func )
1531
1672
}
1532
1673
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
+
1533
1720
/**
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.
1535
1723
*/
1536
1724
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
+ }
1538
1730
1539
1731
/** Gets the index of the request parameter. */
1540
1732
int getRequestParamIndex ( ) {
@@ -1549,8 +1741,19 @@ private module Django {
1549
1741
Parameter getRequestParam ( ) { result = this .getArg ( this .getRequestParamIndex ( ) ) }
1550
1742
}
1551
1743
1744
+ /** A data-flow node that sets up a route on a server, using the django framework. */
1552
1745
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
+ }
1554
1757
}
1555
1758
1556
1759
/**
@@ -1576,11 +1779,8 @@ private module Django {
1576
1779
result .asCfgNode ( ) = [ node .getArg ( 0 ) , node .getArgByName ( "route" ) ]
1577
1780
}
1578
1781
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" ) ]
1584
1784
}
1585
1785
1586
1786
override Parameter getARoutedParameter ( ) {
@@ -1661,11 +1861,8 @@ private module Django {
1661
1861
result .asCfgNode ( ) = [ node .getArg ( 0 ) , node .getArgByName ( "route" ) ]
1662
1862
}
1663
1863
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" ) ]
1669
1866
}
1670
1867
}
1671
1868
@@ -1683,11 +1880,8 @@ private module Django {
1683
1880
result .asCfgNode ( ) = [ node .getArg ( 0 ) , node .getArgByName ( "regex" ) ]
1684
1881
}
1685
1882
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" ) ]
1691
1885
}
1692
1886
}
1693
1887
0 commit comments