-
Notifications
You must be signed in to change notification settings - Fork 2.3k
[Push AV]: Add url validation as per RFC3986 #41502
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -30,6 +30,7 @@ | |
| #include <lib/support/DefaultStorageKeyAllocator.h> | ||
| #include <protocols/interaction_model/StatusCode.h> | ||
| #include <set> | ||
| #include <uriparser/Uri.h> | ||
|
|
||
| static constexpr uint16_t kMaxConnectionId = 65535; // This is also invalid connectionID | ||
| static constexpr uint16_t kMaxEndpointId = 65534; | ||
|
|
@@ -43,6 +44,34 @@ using namespace chip::app::Clusters::PushAvStreamTransport::Attributes; | |
| using namespace Protocols::InteractionModel; | ||
| using chip::Protocols::InteractionModel::Status; | ||
|
|
||
| namespace { | ||
| bool hasHttpsScheme(const UriUriA & uri) | ||
| { | ||
| if (!uri.scheme.first || !uri.scheme.afterLast) | ||
| return false; | ||
|
|
||
| std::string scheme(uri.scheme.first, uri.scheme.afterLast); | ||
| return scheme == "https"; | ||
| } | ||
|
|
||
| bool isValidRFC3986Uri(const std::string & uriStr) | ||
| { | ||
| UriUriA uri; | ||
| const char * errorPos; | ||
|
|
||
| int result = uriParseSingleUriA(&uri, uriStr.c_str(), &errorPos); | ||
| if (result != URI_SUCCESS) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| bool isHttps = hasHttpsScheme(uri); | ||
|
|
||
| uriFreeUriMembersA(&uri); | ||
| return isHttps; | ||
| } | ||
|
Comment on lines
+57
to
+72
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To make the URL validation more efficient, you can extend this function to also check for the presence of a query or fragment, since bool isValidRFC3986Uri(const std::string & uriStr)
{
UriUriA uri;
const char * errorPos;
if (uriParseSingleUriA(&uri, uriStr.c_str(), &errorPos) != URI_SUCCESS)
{
return false;
}
bool isHttps = hasHttpsScheme(uri);
bool hasQuery = (uri.query.first != nullptr);
bool hasFragment = (uri.fragment.first != nullptr);
uriFreeUriMembersA(&uri);
return isHttps && !hasQuery && !hasFragment;
}
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This validation has to happen for all URIs, but the query/fragment bits only need to happen for CMAF URIs. So the bot's advice here would only work if this function had a way to configure whether query/fragment are allowed. |
||
| } // namespace | ||
|
|
||
| namespace chip { | ||
| namespace app { | ||
| namespace Clusters { | ||
|
|
@@ -234,14 +263,14 @@ void PushAvStreamTransportServerLogic::PushAVStreamTransportDeallocateCallback(S | |
|
|
||
| bool PushAvStreamTransportServerLogic::ValidateUrl(const std::string & url) | ||
| { | ||
| const std::string https = "https://"; | ||
|
|
||
| // Check minimum length and https prefix | ||
| if (url.size() <= https.size() || url.substr(0, https.size()) != https) | ||
| if (!isValidRFC3986Uri(url)) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These RFC Checks are for all Transports, while the following invalid character checks are CMAF-specific in the spec. Also, heads up - #41321 addresses other issues in this API and also call this only when |
||
| { | ||
| ChipLogError(Camera, "URL is not a valid RFC3986 URI: %s", url.c_str()); | ||
| return false; | ||
| } | ||
|
|
||
| const std::string https = "https://"; | ||
|
|
||
| // Check that URL does not contain fragment character '#' | ||
| if (url.find('#') != std::string::npos) | ||
| { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to RFC 3986, the scheme component is case-insensitive. The current implementation performs a case-sensitive comparison with "https". This should be changed to a case-insensitive comparison.
Additionally, creating a
std::stringfor comparison is inefficient as it can cause heap allocation. A direct character-by-character comparison can avoid this.You will need to include
<cctype>for thetolowerfunction.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code from Gemini above is cruddy, but the comment is correct.
Please: