@@ -34,7 +34,7 @@ private module Django {
3434 * WARNING: Only holds for a few predefined attributes.
3535 */
3636 private DataFlow:: Node django_attr ( DataFlow:: TypeTracker t , string attr_name ) {
37- attr_name in [ "db" , "urls" , "http" ] and
37+ attr_name in [ "db" , "urls" , "http" , "conf" ] and
3838 (
3939 t .start ( ) and
4040 result = DataFlow:: importNode ( "django" + "." + attr_name )
@@ -437,6 +437,55 @@ private module Django {
437437 DataFlow:: Node re_path ( ) { result = urls_attr ( "re_path" ) }
438438 }
439439
440+ // -------------------------------------------------------------------------
441+ // django.conf
442+ // -------------------------------------------------------------------------
443+ /** Gets a reference to the `django.conf` module. */
444+ DataFlow:: Node conf ( ) { result = django_attr ( "conf" ) }
445+
446+ /** Provides models for the `django.conf` module */
447+ module conf {
448+ // -------------------------------------------------------------------------
449+ // django.conf.urls
450+ // -------------------------------------------------------------------------
451+ /** Gets a reference to the `django.conf.urls` module. */
452+ private DataFlow:: Node urls ( DataFlow:: TypeTracker t ) {
453+ t .start ( ) and
454+ result = DataFlow:: importNode ( "django.conf.urls" )
455+ or
456+ t .startInAttr ( "urls" ) and
457+ result = conf ( )
458+ or
459+ exists ( DataFlow:: TypeTracker t2 | result = urls ( t2 ) .track ( t2 , t ) )
460+ }
461+
462+ // NOTE: had to rename due to shadowing rules in QL
463+ /** Gets a reference to the `django.conf.urls` module. */
464+ DataFlow:: Node conf_urls ( ) { result = urls ( DataFlow:: TypeTracker:: end ( ) ) }
465+
466+ // NOTE: had to rename due to shadowing rules in QL
467+ /** Provides models for the `django.conf.urls` module */
468+ module conf_urls {
469+ /** Gets a reference to the `django.conf.urls.url` function. */
470+ private DataFlow:: Node url ( DataFlow:: TypeTracker t ) {
471+ t .start ( ) and
472+ result = DataFlow:: importNode ( "django.conf.urls.url" )
473+ or
474+ t .startInAttr ( "url" ) and
475+ result = conf_urls ( )
476+ or
477+ exists ( DataFlow:: TypeTracker t2 | result = url ( t2 ) .track ( t2 , t ) )
478+ }
479+
480+ /**
481+ * Gets a reference to the `django.conf.urls.url` function.
482+ *
483+ * See https://docs.djangoproject.com/en/1.11/ref/urls/#django.conf.urls.url
484+ */
485+ DataFlow:: Node url ( ) { result = url ( DataFlow:: TypeTracker:: end ( ) ) }
486+ }
487+ }
488+
440489 // -------------------------------------------------------------------------
441490 // django.http
442491 // -------------------------------------------------------------------------
@@ -684,28 +733,56 @@ private module Django {
684733 }
685734 }
686735
736+ /** A Django route setup that uses a Regex to specify route (and routed parameters). */
737+ abstract private class DjangoRegexRouteSetup extends DjangoRouteSetup {
738+ override Parameter getARoutedParameter ( ) {
739+ // If we don't know the URL pattern, we simply mark all parameters as a routed
740+ // parameter. This should give us more RemoteFlowSources but could also lead to
741+ // more FPs. If this turns out to be the wrong tradeoff, we can always change our mind.
742+ exists ( DjangoRouteHandler routeHandler | routeHandler = this .getARouteHandler ( ) |
743+ not exists ( this .getUrlPattern ( ) ) and
744+ result in [ routeHandler .getArg ( _) , routeHandler .getArgByName ( _) ] and
745+ not result = any ( int i | i <= routeHandler .getRequestParamIndex ( ) | routeHandler .getArg ( i ) )
746+ )
747+ or
748+ exists ( DjangoRouteHandler routeHandler , DjangoRouteRegex regex |
749+ routeHandler = this .getARouteHandler ( ) and
750+ regex .getRouteSetup ( ) = this
751+ |
752+ // either using named capture groups (passed as keyword arguments) or using
753+ // unnamed capture groups (passed as positional arguments)
754+ not exists ( regex .getGroupName ( _, _) ) and
755+ // first group will have group number 1
756+ result =
757+ routeHandler .getArg ( routeHandler .getRequestParamIndex ( ) + regex .getGroupNumber ( _, _) )
758+ or
759+ result = routeHandler .getArgByName ( regex .getGroupName ( _, _) )
760+ )
761+ }
762+ }
763+
687764 /**
688- * A regex that is used in a call to `django.urls.re_path` .
765+ * A regex that is used to set up a route .
689766 *
690767 * Needs this subclass to be considered a RegexString.
691768 */
692- private class DjangoUrlsRePathRegex extends RegexString {
693- DjangoUrlsRePathCall rePathCall ;
769+ private class DjangoRouteRegex extends RegexString {
770+ DjangoRegexRouteSetup rePathCall ;
694771
695- DjangoUrlsRePathRegex ( ) {
772+ DjangoRouteRegex ( ) {
696773 this instanceof StrConst and
697774 DataFlow:: localFlow ( DataFlow:: exprNode ( this ) , rePathCall .getUrlPatternArg ( ) )
698775 }
699776
700- DjangoUrlsRePathCall getRePathCall ( ) { result = rePathCall }
777+ DjangoRegexRouteSetup getRouteSetup ( ) { result = rePathCall }
701778 }
702779
703780 /**
704781 * A call to `django.urls.re_path`.
705782 *
706783 * See https://docs.djangoproject.com/en/3.0/ref/urls/#re_path
707784 */
708- private class DjangoUrlsRePathCall extends DjangoRouteSetup {
785+ private class DjangoUrlsRePathCall extends DjangoRegexRouteSetup {
709786 override CallNode node ;
710787
711788 DjangoUrlsRePathCall ( ) { node .getFunction ( ) = django:: urls:: re_path ( ) .asCfgNode ( ) }
@@ -720,29 +797,26 @@ private module Django {
720797 djangoRouteHandlerFunctionTracker ( result ) = viewArg
721798 )
722799 }
800+ }
723801
724- override Parameter getARoutedParameter ( ) {
725- // If we don't know the URL pattern, we simply mark all parameters as a routed
726- // parameter. This should give us more RemoteFlowSources but could also lead to
727- // more FPs. If this turns out to be the wrong tradeoff, we can always change our mind.
728- exists ( DjangoRouteHandler routeHandler | routeHandler = this .getARouteHandler ( ) |
729- not exists ( this .getUrlPattern ( ) ) and
730- result in [ routeHandler .getArg ( _) , routeHandler .getArgByName ( _) ] and
731- not result = any ( int i | i <= routeHandler .getRequestParamIndex ( ) | routeHandler .getArg ( i ) )
732- )
733- or
734- exists ( DjangoRouteHandler routeHandler , DjangoUrlsRePathRegex regex |
735- routeHandler = this .getARouteHandler ( ) and
736- regex .getRePathCall ( ) = this
737- |
738- // either using named capture groups (passed as keyword arguments) or using
739- // unnamed capture groups (passed as positional arguments)
740- not exists ( regex .getGroupName ( _, _) ) and
741- // first group will have group number 1
742- result =
743- routeHandler .getArg ( routeHandler .getRequestParamIndex ( ) + regex .getGroupNumber ( _, _) )
744- or
745- result = routeHandler .getArgByName ( regex .getGroupName ( _, _) )
802+ /**
803+ * A call to `django.conf.urls.url`.
804+ *
805+ * See https://docs.djangoproject.com/en/1.11/ref/urls/#django.conf.urls.url
806+ */
807+ private class DjangoConfUrlsUrlCall extends DjangoRegexRouteSetup {
808+ override CallNode node ;
809+
810+ DjangoConfUrlsUrlCall ( ) { node .getFunction ( ) = django:: conf:: conf_urls:: url ( ) .asCfgNode ( ) }
811+
812+ override DataFlow:: Node getUrlPatternArg ( ) {
813+ result .asCfgNode ( ) = [ node .getArg ( 0 ) , node .getArgByName ( "regex" ) ]
814+ }
815+
816+ override DjangoRouteHandler getARouteHandler ( ) {
817+ exists ( DataFlow:: Node viewArg |
818+ viewArg .asCfgNode ( ) in [ node .getArg ( 1 ) , node .getArgByName ( "view" ) ] and
819+ djangoRouteHandlerFunctionTracker ( result ) = viewArg
746820 )
747821 }
748822 }
0 commit comments