Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions python/change-notes/2021-04-13-werkzeug-api-graphs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
lgtm,codescanning
* The Werkzeug model has been changed to use API graphs. When defining new models for classes based
on the `MultiDict` and `FileStorage` classes in `werkzeug.datastructures`, the relevant extension
points are now the two `InstanceSourceApiNode` classes in the `semmle.python.frameworks.Werkzeug`
module, instead of `InstanceSource`. The latter classes have now been deprecated.
6 changes: 4 additions & 2 deletions python/ql/src/semmle/python/frameworks/Flask.qll
Original file line number Diff line number Diff line change
Expand Up @@ -401,13 +401,15 @@ module Flask {
}
}

private class RequestAttrMultiDict extends Werkzeug::werkzeug::datastructures::MultiDict::InstanceSource {
private class RequestAttrMultiDict extends Werkzeug::werkzeug::datastructures::MultiDict::InstanceSourceApiNode {
string attr_name;

RequestAttrMultiDict() {
attr_name in ["args", "values", "form", "files"] and
this = request().getMember(attr_name).getAnImmediateUse()
this = request().getMember(attr_name)
}

override string toString() { result = this.(API::Node).toString() }
}

private class RequestAttrFiles extends RequestAttrMultiDict {
Expand Down
46 changes: 12 additions & 34 deletions python/ql/src/semmle/python/frameworks/Werkzeug.qll
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
private import python
private import semmle.python.dataflow.new.DataFlow
private import semmle.python.dataflow.new.TaintTracking
private import semmle.python.ApiGraphs

/**
* Provides models for the `Werkzeug` PyPI package.
Expand All @@ -23,6 +24,9 @@ module Werkzeug {
* See https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.MultiDict.
*/
module MultiDict {
/** DEPRECATED. Use `InstanceSourceApiNode` instead. */
abstract deprecated class InstanceSource extends DataFlow::Node { }

/**
* A source of instances of `werkzeug.datastructures.MultiDict`, extend this class to model new instances.
*
Expand All @@ -32,37 +36,16 @@ module Werkzeug {
*
* Use the predicate `MultiDict::instance()` to get references to instances of `werkzeug.datastructures.MultiDict`.
*/
abstract class InstanceSource extends DataFlow::Node { }

/** Gets a reference to an instance of `werkzeug.datastructures.MultiDict`. */
private DataFlow::Node instance(DataFlow::TypeTracker t) {
t.start() and
result instanceof InstanceSource
or
exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
}

/** Gets a reference to an instance of `werkzeug.datastructures.MultiDict`. */
DataFlow::Node instance() { result = instance(DataFlow::TypeTracker::end()) }
abstract class InstanceSourceApiNode extends API::Node { }

/**
* Gets a reference to the `getlist` method on an instance of `werkzeug.datastructures.MultiDict`.
*
* See https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.Headers.getlist
*/
private DataFlow::Node getlist(DataFlow::TypeTracker t) {
t.startInAttr("getlist") and
result = instance()
or
exists(DataFlow::TypeTracker t2 | result = getlist(t2).track(t2, t))
DataFlow::Node getlist() {
result = any(InstanceSourceApiNode a).getMember("getlist").getAUse()
}

/**
* Gets a reference to the `getlist` method on an instance of `werkzeug.datastructures.MultiDict`.
*
* See https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.Headers.getlist
*/
DataFlow::Node getlist() { result = getlist(DataFlow::TypeTracker::end()) }
}

/**
Expand All @@ -71,6 +54,9 @@ module Werkzeug {
* See https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.FileStorage.
*/
module FileStorage {
/** DEPRECATED. Use `InstanceSourceApiNode` instead. */
abstract deprecated class InstanceSource extends DataFlow::Node { }

/**
* A source of instances of `werkzeug.datastructures.FileStorage`, extend this class to model new instances.
*
Expand All @@ -80,18 +66,10 @@ module Werkzeug {
*
* Use the predicate `FileStorage::instance()` to get references to instances of `werkzeug.datastructures.FileStorage`.
*/
abstract class InstanceSource extends DataFlow::Node { }

/** Gets a reference to an instance of `werkzeug.datastructures.FileStorage`. */
private DataFlow::Node instance(DataFlow::TypeTracker t) {
t.start() and
result instanceof InstanceSource
or
exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
}
abstract class InstanceSourceApiNode extends API::Node { }

/** Gets a reference to an instance of `werkzeug.datastructures.FileStorage`. */
DataFlow::Node instance() { result = instance(DataFlow::TypeTracker::end()) }
DataFlow::Node instance() { result = any(InstanceSourceApiNode a).getAUse() }
}
}
}
Expand Down