Polish flask_mail tests and code

This commit is contained in:
jorgectf
2021-06-23 00:38:58 +02:00
parent 48cd5062cf
commit 4d890ddeae
3 changed files with 116 additions and 0 deletions

View File

@@ -0,0 +1,34 @@
# https://pythonhosted.org/Flask-Mail/
# https://github.com/mattupstate/flask-mail/blob/1709c70d839a7cc7b1f7eeb97333b71cd420fe32/flask_mail.py#L239
# tmp: this test cover RFS to any part of the message, but can be shortened to a specific part (body&html) once we decide the objective of the query.
from flask_mail import Mail, Message
app = Flask(__name__)
mail = Mail(app)
@app.route("/send")
def send():
msg = Message(subject=request.args["subject"],
sender=request.args["sender"],
recipients=list(request.args["recipient"]),
body=request.args["body"],
html=request.args["html"])
# The message can contain a body and/or HTML:
msg.body = "test"
msg.html = "<b>test</b>"
mail.send(msg)
@app.route("/connect")
def connect():
"""
Minimal example to test mail.connect() usage
"""
with mail.connect() as conn:
msg = Message(subject=request.args["subject"],
sender=request.args["sender"],
recipients=list(request.args["recipient"]),
body=request.args["html"])
conn.send(msg)

View File

@@ -4,3 +4,4 @@
private import experimental.semmle.python.frameworks.Stdlib
private import experimental.semmle.python.frameworks.LDAP
private import experimental.semmle.python.frameworks.Flask

View File

@@ -0,0 +1,81 @@
/**
* Provides classes modeling security-relevant aspects of the `flask` PyPI package.
* See https://flask.palletsprojects.com/en/1.1.x/.
*/
private import python
private import semmle.python.dataflow.new.DataFlow
private import experimental.semmle.python.Concepts
private import semmle.python.ApiGraphs
private module Flask {
private API::Node flaskMail() { result = API::moduleImport("flask_mail") }
private API::Node flaskMailInstance() { result = flaskMail().getMember("Mail").getReturn() }
private DataFlow::CallCfgNode flaskMessageCall() {
result = flaskMail().getMember("Message").getACall()
}
private class FlaskMail extends DataFlow::CallCfgNode, EmailSender {
/** A message variable to avoid multiple results in case consequential results are needed */
DataFlow::CallCfgNode message;
FlaskMail() {
this =
[flaskMailInstance(), flaskMailInstance().getMember("connect").getReturn()]
.getMember("send")
.getACall()
}
override DataFlow::Node getPlainTextBody() {
result in [flaskMessageCall().getArg(2), flaskMessageCall().getArgByName("body")]
or
exists(DataFlow::AttrWrite bodyWrite |
bodyWrite.getObject().getALocalSource() = flaskMessageCall() and
bodyWrite.getAttributeName() = "body" and
result = bodyWrite.getValue()
)
}
override DataFlow::Node getHtmlBody() {
result in [flaskMessageCall().getArg(3), flaskMessageCall().getArgByName("html")]
or
exists(DataFlow::AttrWrite bodyWrite |
bodyWrite.getObject().getALocalSource() = flaskMessageCall() and
bodyWrite.getAttributeName() = "html" and
result = bodyWrite.getValue()
)
}
override DataFlow::Node getTo() {
result in [flaskMessageCall().getArg(1), flaskMessageCall().getArgByName("recipients")]
or
exists(DataFlow::AttrWrite bodyWrite |
bodyWrite.getObject().getALocalSource() = flaskMessageCall() and
bodyWrite.getAttributeName() = "recipients" and
result = bodyWrite.getValue()
)
}
override DataFlow::Node getFrom() {
result in [flaskMessageCall().getArg(5), flaskMessageCall().getArgByName("sender")]
or
exists(DataFlow::AttrWrite bodyWrite |
bodyWrite.getObject().getALocalSource() = flaskMessageCall() and
bodyWrite.getAttributeName() = "sender" and
result = bodyWrite.getValue()
)
}
override DataFlow::Node getSubject() {
result in [flaskMessageCall().getArg(0), flaskMessageCall().getArgByName("subject")]
or
exists(DataFlow::AttrWrite bodyWrite |
bodyWrite.getObject().getALocalSource() = flaskMessageCall() and
bodyWrite.getAttributeName() = "subject" and
result = bodyWrite.getValue()
)
}
}
}