Skip to content
Open
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
52 changes: 43 additions & 9 deletions server/plat/gdial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
#include <unistd.h>
#include <pthread.h>
#include <glib.h>
#include <sstream>
#include <vector>

#include "Module.h"
#include <core.h>
Expand Down Expand Up @@ -59,6 +61,8 @@ static gdial_modelname_cb g_modelname_cb = NULL;
#define DIAL_MAX_NUM_OF_APP_PREFIXES (64)
#define DIAL_MAX_NUM_OF_APP_CORS (64)

static std::vector<std::string> splitCorsOrigins(const std::string& corsValue);

class GDialCastObject
{
public:
Expand Down Expand Up @@ -124,12 +128,21 @@ class GDialCastObject
break;
}
GDIAL_LOGINFO("Application:[%d]", i);
GDIAL_LOGINFO("registerApplications: appName[%s] prefixes[%s] cors[%s] allowStop[%d]",
appEntry->Names.c_str(),
appEntry->prefixes.c_str(),
appEntry->cors.c_str(),
appEntry->allowStop);
gAppPrefxes = g_list_prepend (gAppPrefxes, g_strdup(appEntry->prefixes.c_str()));
GDIAL_LOGINFO("%s, ", appEntry->prefixes.c_str());
GDIAL_LOGINFO("");

allowed_origins = g_list_prepend (allowed_origins, g_strdup(appEntry->cors.c_str()));
GDIAL_LOGINFO("%s, ", appEntry->cors.c_str());
const std::vector<std::string> corsOrigins = splitCorsOrigins(appEntry->cors.c_str());
GDIAL_LOGINFO("registerApplications: splitCorsOrigins app[%s] count[%zu]", appEntry->Names.c_str(), corsOrigins.size());
for (const auto& origin : corsOrigins) {
allowed_origins = g_list_prepend(allowed_origins, g_strdup(origin.c_str()));
GDIAL_LOGINFO("registerApplications: allowed_origin[%s] for app[%s]", origin.c_str(), appEntry->Names.c_str());
}
GDIAL_LOGINFO("");

GHashTable *gProperties = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
Expand Down Expand Up @@ -229,7 +242,7 @@ class GDialCastObject
GDIAL_LOGTRACE("Exiting ...");
return error;
}

GDialErrorCode launchApplication(const char* appName, const char* args)
{
GDIAL_LOGTRACE("Entering ...");
Expand Down Expand Up @@ -275,8 +288,8 @@ class GDialCastObject
}

GDIAL_LOGINFO("App[%s] payload[%s] query_string[%s] additional_data_url[%s]observer[%p]",
applicationName.c_str(),
payLoad.c_str(),
applicationName.c_str(),
payLoad.c_str(),
queryString.c_str(),
additionalDataUrl.c_str(),
m_observer);
Expand Down Expand Up @@ -667,7 +680,7 @@ int gdial_os_application_stop(const char *app_name, int instance_id) {
GDIAL_LOGTRACE("Exiting ...");
return GDIAL_APP_ERROR_INTERNAL;
}
GDialErrorCode ret = GDialObjHandle->stopApplication(app_name,std::to_string(instance_id).c_str());
GDialErrorCode ret = GDialObjHandle->stopApplication(app_name,std::to_string(instance_id).c_str());
if (ret != GDIAL_CAST_ERROR_NONE) {
GDIAL_LOGINFO("GDialObjHandle.stopApplication failed!!! Error=%x",ret);
GDIAL_LOGTRACE("Exiting ...");
Expand Down Expand Up @@ -709,7 +722,7 @@ int gdial_os_application_hide(const char *app_name, int instance_id)
GDIAL_LOGTRACE("Exiting ...");
return GDIAL_APP_ERROR_BAD_REQUEST;
}

if (nullptr == GDialObjHandle)
{
GDIAL_LOGERROR("GDialObjHandle NULL!!! ");
Expand Down Expand Up @@ -816,8 +829,8 @@ int gdial_os_application_state(const char *app_name, int instance_id, GDialAppSt
GDIAL_LOGINFO("app [%s] state converted to [%d]", app_name, *state);
}
else {
*state = GDIAL_APP_STATE_RUNNING;
}
*state = GDIAL_APP_STATE_RUNNING;
}
}
}
GDIAL_LOGTRACE("Exiting ...");
Expand Down Expand Up @@ -1007,3 +1020,24 @@ int gdial_os_application_service_notification(gboolean isNotifyRequired, void* n
GDIAL_LOGTRACE("Exiting ...");
return GDIAL_APP_ERROR_NONE;
}

static std::vector<std::string> splitCorsOrigins(const std::string& corsValue)
{
std::vector<std::string> origins;
std::stringstream ss(corsValue);
std::string origin;

while (std::getline(ss, origin, ' ')) {
const std::string::size_type start = origin.find_first_not_of(" \t\r\n");
if (start == std::string::npos) {
continue;
}
const std::string::size_type end = origin.find_last_not_of(" \t\r\n");
const std::string trimmed = origin.substr(start, end - start + 1);
if (!trimmed.empty()) {
origins.push_back(trimmed);
}
}

return origins;
}
140 changes: 129 additions & 11 deletions server/plat/gdial_app_registry.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
* limitations under the License.
*/

#include <string.h>
#include <uuid/uuid.h>
#include <gdial_app_registry.h>
#include "gdialservicelogging.h"
Expand All @@ -42,25 +43,142 @@ void gdial_app_regstry_dispose (GDialAppRegistry *app_registry) {
return;
}

// Helper function to extract host from an origin string without libsoup
static gchar *util_get_host_from_origin(const gchar *origin) {
if (!origin) return NULL;

const gchar *host_start = NULL;

if (g_str_has_prefix(origin, "https://")) {
host_start = origin + strlen("https://");
} else if (g_str_has_prefix(origin, "http://")) {
host_start = origin + strlen("http://");
} else {
host_start = origin;
}

const gchar *delim_port = strchr(host_start, ':');
const gchar *delim_path = strchr(host_start, '/');
const gchar *end = NULL;

if (delim_port && delim_path) {
end = (delim_port < delim_path) ? delim_port : delim_path;
} else if (delim_port) {
end = delim_port;
} else {
end = delim_path;
}

if (end) {
return g_strndup(host_start, end - host_start);
}

return g_strdup(host_start);
}

gboolean gdial_app_registry_is_allowed_origin(GDialAppRegistry *app_registry, const gchar *header_origin) {
gboolean is_allowed = FALSE;
if (app_registry) {
GList *allowed_origins = app_registry->allowed_origins;
if(allowed_origins == NULL){

if (!app_registry) {
GDIAL_LOGINFO("gdial_app_registry_is_allowed_origin: app_registry=NULL header_origin[%s]", header_origin ? header_origin : "(null)");
return FALSE;
}
if (header_origin == NULL) {
GDIAL_LOGINFO("gdial_app_registry_is_allowed_origin: app[%s] header_origin=NULL", app_registry->name ? app_registry->name : "(null)");
return FALSE;
}

GList *allowed_origins = app_registry->allowed_origins;
GDIAL_LOGINFO("gdial_app_registry_is_allowed_origin: app[%s] incoming_origin[%s] configured_count[%d]",
app_registry->name ? app_registry->name : "(null)",
header_origin,
g_list_length(allowed_origins));
if (allowed_origins == NULL) {
GDIAL_LOGINFO("gdial_app_registry_is_allowed_origin: app[%s] allowed list empty => allowing origin[%s]", app_registry->name ? app_registry->name : "(null)", header_origin);
return TRUE;
}

while (allowed_origins) {
gchar *origin = (gchar *)allowed_origins->data;
GDIAL_LOGINFO("gdial_app_registry_is_allowed_origin: app[%s] checking configured_origin[%s] against incoming[%s]",
app_registry->name ? app_registry->name : "(null)",
origin ? origin : "(null)",
header_origin);
if (origin == NULL) {
allowed_origins = allowed_origins->next;
continue;
}

if (g_strcmp0(origin, "*") == 0) {
GDIAL_LOGINFO("gdial_app_registry_is_allowed_origin: app[%s] matched wildcard '*'", app_registry->name ? app_registry->name : "(null)");
is_allowed = TRUE;
break;
}
else
{
while(allowed_origins) {
gchar *origin = (gchar *)allowed_origins->data;
if (GDIAL_STR_ENDS_WITH(header_origin, origin)) {

if (g_str_has_prefix(origin, "package:")) {
if (g_strcmp0(header_origin, origin) == 0) {
GDIAL_LOGINFO("gdial_app_registry_is_allowed_origin: app[%s] matched package origin exact match: configured[%s] incoming[%s]",
app_registry->name ? app_registry->name : "(null)",
origin,
header_origin);
is_allowed = TRUE;
break;
}
GDIAL_LOGINFO("gdial_app_registry_is_allowed_origin: app[%s] package mismatch: configured[%s] incoming[%s]",
app_registry->name ? app_registry->name : "(null)",
origin,
header_origin);
}
else if (g_str_has_prefix(origin, "https://*.")) {
gchar *wildcard_host = origin + strlen("https://*.");
gchar *header_host = util_get_host_from_origin(header_origin);
GDIAL_LOGINFO("gdial_app_registry_is_allowed_origin: app[%s] wildcard check: configured[%s] wildcard_host[%s] incoming_host[%s]",
app_registry->name ? app_registry->name : "(null)",
origin,
wildcard_host,
header_host ? header_host : "(null)");
if (header_host) {
if (g_strcmp0(header_host, wildcard_host) == 0 || g_str_has_suffix(header_host, wildcard_host)) {
size_t host_len = strlen(header_host);
size_t wild_len = strlen(wildcard_host);
if (host_len == wild_len || (host_len > wild_len && header_host[host_len - wild_len - 1] == '.')) {
GDIAL_LOGINFO("gdial_app_registry_is_allowed_origin: app[%s] matched wildcard host rule", app_registry->name ? app_registry->name : "(null)");
is_allowed = TRUE;
}
}
g_free(header_host);
}
if (is_allowed) break;
}
else {
gchar *configured_host = util_get_host_from_origin(origin);
gchar *header_host = util_get_host_from_origin(header_origin);
GDIAL_LOGINFO("gdial_app_registry_is_allowed_origin: app[%s] strict host check: configured_host[%s] header_host[%s] configured_scheme_secure[%d] incoming_scheme_secure[%d]",
app_registry->name ? app_registry->name : "(null)",
configured_host ? configured_host : "(null)",
header_host ? header_host : "(null)",
g_str_has_prefix(origin, "https://"),
g_str_has_prefix(header_origin, "https://"));
if (configured_host && header_host) {
if (g_strcmp0(header_host, configured_host) == 0 &&
g_str_has_prefix(header_origin, "https://") == g_str_has_prefix(origin, "https://")) {
GDIAL_LOGINFO("gdial_app_registry_is_allowed_origin: app[%s] matched strict host rule", app_registry->name ? app_registry->name : "(null)");
is_allowed = TRUE;
break;
}
allowed_origins = allowed_origins->next;
}
g_free(configured_host);
g_free(header_host);

if (is_allowed) break;
}

allowed_origins = allowed_origins->next;
}

GDIAL_LOGINFO("gdial_app_registry_is_allowed_origin: app[%s] final_result[%s] for incoming[%s]",
app_registry->name ? app_registry->name : "(null)",
is_allowed ? "ALLOW" : "DENY",
header_origin);
return is_allowed;
}

Expand Down Expand Up @@ -125,4 +243,4 @@ GDialAppRegistry* gdial_app_registry_new (const gchar *app_name, const GList *ap
GDIAL_LOGINFO("App:[%s] uuid:[%s] per Bootup", app_name, uuid_data);

return app_registry;
}
}
41 changes: 40 additions & 1 deletion tests/L1Tests/plat/test_gdialPlat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,46 @@ TEST_F(GDialAppRegistryTest, IsAllowedOrigin_NullOriginDenied) {
EXPECT_FALSE(gdial_app_registry_is_allowed_origin(registry, nullptr));
}

TEST_F(GDialAppRegistryTest, IsAllowedOrigin_PackageMatchPermitsMobileApp) {
GList *origins = g_list_append(nullptr, g_strdup("package:com.google.android.youtube"));
registry = gdial_app_registry_new("YouTube", nullptr, nullptr,
TRUE, FALSE, origins);
g_list_free_full(origins, g_free);
ASSERT_NE(registry, nullptr);
EXPECT_TRUE(gdial_app_registry_is_allowed_origin(
registry, "package:com.google.android.youtube"));
EXPECT_FALSE(gdial_app_registry_is_allowed_origin(
registry, "package:com.google.ios.youtube"));
}

TEST_F(GDialAppRegistryTest, IsAllowedOrigin_WildcardHostPermitsSubdomains) {
GList *origins = g_list_append(nullptr, g_strdup("https://*.youtube.com"));
registry = gdial_app_registry_new("YouTube", nullptr, nullptr,
TRUE, FALSE, origins);
g_list_free_full(origins, g_free);
ASSERT_NE(registry, nullptr);
EXPECT_TRUE(gdial_app_registry_is_allowed_origin(
registry, "https://www.youtube.com"));
EXPECT_TRUE(gdial_app_registry_is_allowed_origin(
registry, "https://m.youtube.com"));
EXPECT_FALSE(gdial_app_registry_is_allowed_origin(
registry, "https://youtube.com.evil.example"));
EXPECT_FALSE(gdial_app_registry_is_allowed_origin(
registry, "https://notyoutube.com"));
}

TEST_F(GDialAppRegistryTest, IsAllowedOrigin_StrictSchemeMismatchDenied) {
GList *origins = g_list_append(nullptr, g_strdup("https://www.youtube.com"));
registry = gdial_app_registry_new("YouTube", nullptr, nullptr,
TRUE, FALSE, origins);
g_list_free_full(origins, g_free);
ASSERT_NE(registry, nullptr);
EXPECT_TRUE(gdial_app_registry_is_allowed_origin(
registry, "https://www.youtube.com"));
EXPECT_FALSE(gdial_app_registry_is_allowed_origin(
registry, "http://www.youtube.com"));
}

/* ================================================================== */
/* gdial_app_regstry_dispose */
/* ================================================================== */
Expand All @@ -190,4 +230,3 @@ TEST(GDialAppRegistryDisposeTest, Dispose_WithPropertiesDoesNotCrash) {
ASSERT_NE(r, nullptr);
gdial_app_regstry_dispose(r);
}

Loading