Skip to content

Commit e4ea5f2

Browse files
committed
Python: Flask: Moderize app and blueprint
1 parent 7de488b commit e4ea5f2

1 file changed

Lines changed: 36 additions & 67 deletions

File tree

  • python/ql/src/semmle/python/frameworks

python/ql/src/semmle/python/frameworks/Flask.qll

Lines changed: 36 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,32 @@ private module FlaskModel {
4848
}
4949
}
5050

51+
/**
52+
* Provides models for flask applications (instances of the `flask.Flask` class).
53+
*
54+
* See https://flask.palletsprojects.com/en/1.1.x/api/#flask.Flask.
55+
*/
56+
module FlaskApp {
57+
/** Gets a reference to the `flask.Flask` class. */
58+
API::Node classRef() { result = API::moduleImport("flask").getMember("Flask") }
59+
60+
/** Gets a reference to an instance of `flask.Flask` (a flask application). */
61+
API::Node instance() { result = classRef().getReturn() }
62+
}
63+
64+
/**
65+
* Provides models for flask blueprints (instances of the `flask.Blueprint` class).
66+
*
67+
* See https://flask.palletsprojects.com/en/1.1.x/api/#flask.Blueprint.
68+
*/
69+
module Blueprint {
70+
/** Gets a reference to the `flask.Blueprint` class. */
71+
API::Node classRef() { result = flask().getMember("Blueprint") }
72+
73+
/** Gets a reference to an instance of `flask.Blueprint`. */
74+
API::Node instance() { result = classRef().getReturn() }
75+
}
76+
5177
// ---------------------------------------------------------------------------
5278
// flask
5379
// ---------------------------------------------------------------------------
@@ -66,67 +92,6 @@ private module FlaskModel {
6692

6793
/** Gets a reference to the `flask.make_response` function. */
6894
API::Node make_response() { result = flask_attr("make_response") }
69-
70-
/**
71-
* Provides models for the `flask.Flask` class
72-
*
73-
* See https://flask.palletsprojects.com/en/1.1.x/api/#flask.Flask.
74-
*/
75-
module Flask {
76-
/** Gets a reference to the `flask.Flask` class. */
77-
API::Node classRef() { result = flask().getMember("Flask") }
78-
79-
/** Gets a reference to an instance of `flask.Flask` (a flask application). */
80-
API::Node instance() { result = classRef().getReturn() }
81-
82-
/**
83-
* Gets a reference to the attribute `attr_name` of an instance of `flask.Flask` (a flask application).
84-
*/
85-
private API::Node instance_attr(string attr_name) { result = instance().getMember(attr_name) }
86-
87-
/** Gets a reference to the `route` method on an instance of `flask.Flask`. */
88-
API::Node route() { result = instance_attr("route") }
89-
90-
/** Gets a reference to the `add_url_rule` method on an instance of `flask.Flask`. */
91-
API::Node add_url_rule() { result = instance_attr("add_url_rule") }
92-
93-
/** Gets a reference to the `make_response` method on an instance of `flask.Flask`. */
94-
// HACK: We can't call this predicate `make_response` since shadowing is
95-
// completely disallowed in QL. I added an underscore to move things forward for
96-
// now :(
97-
API::Node make_response_() { result = instance_attr("make_response") }
98-
99-
/**
100-
* Gets a reference to the `response_class` attribute on the `flask.Flask` class or an instance.
101-
*
102-
* See https://flask.palletsprojects.com/en/1.1.x/api/#flask.Flask.response_class
103-
*/
104-
API::Node response_class() { result = [classRef(), instance()].getMember("response_class") }
105-
}
106-
107-
/**
108-
* Provides models for the `flask.Blueprint` class
109-
*
110-
* See https://flask.palletsprojects.com/en/1.1.x/api/#flask.Blueprint.
111-
*/
112-
module Blueprint {
113-
/** Gets a reference to the `flask.Blueprint` class. */
114-
API::Node classRef() { result = flask().getMember("Blueprint") }
115-
116-
/** Gets a reference to an instance of `flask.Blueprint`. */
117-
API::Node instance() { result = classRef().getReturn() }
118-
119-
/**
120-
* Gets a reference to the attribute `attr_name` of an instance of `flask.Blueprint`.
121-
*/
122-
private API::Node instance_attr(string attr_name) { result = instance().getMember(attr_name) }
123-
124-
/** Gets a reference to the `route` method on an instance of `flask.Blueprint`. */
125-
API::Node route() { result = instance_attr("route") }
126-
127-
/** Gets a reference to the `add_url_rule` method on an instance of `flask.Blueprint`. */
128-
API::Node add_url_rule() { result = instance_attr("add_url_rule") }
129-
}
13095
}
13196

13297
/**
@@ -136,7 +101,11 @@ private module FlaskModel {
136101
*/
137102
module Response {
138103
/** Gets a reference to the `flask.Response` class. */
139-
API::Node classRef() { result = [flask_attr("Response"), flask::Flask::response_class()] }
104+
API::Node classRef() {
105+
result = flask_attr("Response")
106+
or
107+
result = [FlaskApp::classRef(), FlaskApp::instance()].getMember("response_class")
108+
}
140109

141110
/**
142111
* A source of instances of `flask.Response`, extend this class to model new instances.
@@ -255,9 +224,9 @@ private module FlaskModel {
255224
*/
256225
private class FlaskAppRouteCall extends FlaskRouteSetup, DataFlow::CallCfgNode {
257226
FlaskAppRouteCall() {
258-
this = flask::Flask::route().getACall()
227+
this = FlaskApp::instance().getMember("route").getACall()
259228
or
260-
this = flask::Blueprint::route().getACall()
229+
this = Blueprint::instance().getMember("route").getACall()
261230
}
262231

263232
override DataFlow::Node getUrlPatternArg() {
@@ -274,9 +243,9 @@ private module FlaskModel {
274243
*/
275244
private class FlaskAppAddUrlRuleCall extends FlaskRouteSetup, DataFlow::CallCfgNode {
276245
FlaskAppAddUrlRuleCall() {
277-
this = flask::Flask::add_url_rule().getACall()
246+
this = FlaskApp::instance().getMember("add_url_rule").getACall()
278247
or
279-
this = flask::Blueprint::add_url_rule().getACall()
248+
this = Blueprint::instance().getMember("add_url_rule").getACall()
280249
}
281250

282251
override DataFlow::Node getUrlPatternArg() {
@@ -431,7 +400,7 @@ private module FlaskModel {
431400
FlaskMakeResponseCall() {
432401
this = flask::make_response().getACall()
433402
or
434-
this = flask::Flask::make_response_().getACall()
403+
this = FlaskApp::instance().getMember("make_response").getACall()
435404
}
436405

437406
override DataFlow::Node getBody() { result = this.getArg(0) }

0 commit comments

Comments
 (0)