Skip to content

Commit

Permalink
Added plugin validation
Browse files Browse the repository at this point in the history
Plugins can now set explicit access to state which plugins can read /
write which settings.

With this change, raw access methods have been removed from public
access.  They aren't safe anyways, since we can possibly recompile with
support for other databases.
  • Loading branch information
nosoop committed Mar 26, 2015
1 parent d8deaa9 commit 407f594
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 144 deletions.
145 changes: 82 additions & 63 deletions scripting/downloadprefs.sp
Expand Up @@ -9,7 +9,7 @@
#pragma semicolon 1
#include <sourcemod>

#define PLUGIN_VERSION "0.7.2"
#define PLUGIN_VERSION "0.8.0"
public Plugin:myinfo = {
name = "Download Preferences",
author = "nosoop",
Expand All @@ -23,6 +23,8 @@ public Plugin:myinfo = {
#define MAX_SQL_QUERY_LENGTH 512
#define MAX_URL_LENGTH 256

#define NATIVEERROR_NOPERMISSION 1

enum DownloadPrefsAccess {
DownloadPrefsAccess_Public,
DownloadPrefsAccess_Protected,
Expand Down Expand Up @@ -75,20 +77,15 @@ public APLRes:AskPluginLoad2(Handle:hMySelf, bool:bLate, String:strError[], iMax
RegPluginLibrary("downloadprefs");

CreateNative("RegClientDownloadCategory", Native_RegClientDownloadCategory);
CreateNative("UnregClientDownloadCategories", Native_UnregClientDownloadCategories);

CreateNative("RegClientDownloadFile", Native_RegClientDownloadFile);
CreateNative("SetClientDownloadPreference", Native_SetClientDownloadPreference);
CreateNative("GetClientDownloadPreference", Native_GetClientDownloadPreference);
CreateNative("ClientHasDownloadPreference", Native_ClientHasDownloadPreference);

// Raw access methods
CreateNative("SetRawDownloadPreference", Native_SetRawDownloadPreference);
CreateNative("GetRawDownloadPreference", Native_GetRawDownloadPreference);
CreateNative("HasRawDownloadPreference", Native_HasRawDownloadPreference);

// Unstable methods
CreateNative("RawCategoryInfo", Native_RawCategoryInfo);
CreateNative("GetActiveCategories", Native_GetActiveCategories);
CreateNative("CategoryToIdentifier", Native_CategoryToIdentifier);
CreateNative("GetCategoryInfo", Native_GetCategoryInfo);
CreateNative("GetAccessibleCategories", Native_GetAccessibleCategories);

g_hDatabase = GetDatabase();

Expand Down Expand Up @@ -179,9 +176,32 @@ public Native_RegClientDownloadCategory(Handle:hPlugin, nParams) {

GetNativeString(1, category, sizeof(category));
GetNativeString(2, description, sizeof(description));
new bool:bDefault = GetNativeCell(3);
new bool:bDefault = GetNativeCell(3),
DownloadPrefsAccess:access = nParams > 3 ? GetNativeCell(4) : DownloadPrefsAccess_Public;

new id = RegClientDownloadCategory(category, description, bDefault);

if (id == INVALID_DPREFS_ID) {
return INVALID_DPREFS_ID;
} else if (GetCategoryAccess(id) == DownloadPrefsAccess_Public) {
return id;
} else if (GetCategoryOwner(id) == INVALID_HANDLE) {
// Uninitialized category
SetCategoryOwner(id, hPlugin);
SetCategoryAccess(id, access);
return id;
}

return RegClientDownloadCategory(category, description, bDefault);
// Non-public with a different owner
return INVALID_DPREFS_ID;
}

public Native_UnregClientDownloadCategories(Handle:hPlugin, nParams) {
for (new i = 0; i < g_nDownloadPrefs; i++) {
if (GetCategoryOwner(i) == hPlugin) {
ClearCategory(i);
}
}
}

/**
Expand All @@ -194,7 +214,7 @@ RegClientDownloadFile(id, const String:filepath[]) {
decl String:sQuery[MAX_SQL_QUERY_LENGTH];
Format(sQuery, sizeof(sQuery),
"INSERT OR REPLACE INTO files (categoryid, filepath) VALUES (%d, '%s')",
g_rgiCategories[id], filepath);
GetCategoryIdentifier(id), filepath);
SQL_FastQuery(g_hDatabase, sQuery);
}

Expand All @@ -219,8 +239,11 @@ SetClientDownloadPreference(client, id, bool:enabled) {
public Native_SetClientDownloadPreference(Handle:hPlugin, nParams) {
new client = GetNativeCell(1), id = GetNativeCell(2), bool:enabled = GetNativeCell(3);

// TODO perform plugin validation
SetClientDownloadPreference(client, id, enabled);
if (PluginHasWriteAccess(hPlugin, id)) {
SetClientDownloadPreference(client, id, enabled);
} else {
ThrowNativeError(NATIVEERROR_NOPERMISSION, "Plugin %d is not allowed to write preference to category identifier %d", hPlugin, id);
}
}

/**
Expand All @@ -238,8 +261,13 @@ bool:GetClientDownloadPreference(client, id) {
public Native_GetClientDownloadPreference(Handle:hPlugin, nParams) {
new client = GetNativeCell(1), id = GetNativeCell(2);

// TODO perform plugin validation
return GetClientDownloadPreference(client, id);
if (PluginHasReadAccess(hPlugin, id)) {
return GetClientDownloadPreference(client, id);
} else {
// Category is private access.
ThrowNativeError(NATIVEERROR_NOPERMISSION, "Plugin %d is not allowed to read preferences from category identifier %d", hPlugin, id);
return false;
}
}

/**
Expand All @@ -254,13 +282,20 @@ bool:ClientHasDownloadPreference(client, id, &any:result = 0) {

public Native_ClientHasDownloadPreference(Handle:hPlugin, nParams) {
new client = GetNativeCell(1), id = GetNativeCell(2), result = GetNativeCellRef(3);
return ClientHasDownloadPreference(client, id, result);

if (PluginHasReadAccess(hPlugin, id)) {
return ClientHasDownloadPreference(client, id, result);
} else {
// Category is private access.
ThrowNativeError(NATIVEERROR_NOPERMISSION, "Plugin %d is not allowed to read preferences from category identifier %d", hPlugin, id);
return false;
}
}

/**
* Gets the description of the download category.
*/
bool:RawCategoryInfo(categoryid, String:title[], maxTitleLength, String:description[], maxDescLength) {
bool:GetCategoryInfo(categoryid, String:title[], maxTitleLength, String:description[], maxDescLength) {
decl String:sQuery[MAX_SQL_QUERY_LENGTH];
new Handle:hQuery = INVALID_HANDLE;
new bool:bHasRows;
Expand All @@ -279,11 +314,11 @@ bool:RawCategoryInfo(categoryid, String:title[], maxTitleLength, String:descript
return bHasRows;
}

public Native_RawCategoryInfo(Handle:hPlugin, nParams) {
new categoryid = GetNativeCell(1), maxTitleLength = GetNativeCell(3), maxDescLength = GetNativeCell(5);
public Native_GetCategoryInfo(Handle:hPlugin, nParams) {
new id = GetNativeCell(1), maxTitleLength = GetNativeCell(3), maxDescLength = GetNativeCell(5);
new String:title[maxTitleLength], String:description[maxDescLength];

new bool:bResult = RawCategoryInfo(categoryid, title, maxTitleLength, description, maxDescLength);
new bool:bResult = GetCategoryInfo(GetCategoryIdentifier(id), title, maxTitleLength, description, maxDescLength);

SetNativeString(2, title, maxTitleLength);
SetNativeString(3, description, maxDescLength);
Expand All @@ -295,19 +330,28 @@ public Native_RawCategoryInfo(Handle:hPlugin, nParams) {
* Adds the specified category to the active category list.
*/
_:DownloadCategoryAdded(categoryid) {
new bool:bFound = false;
new bool:bFound = false,
iFree = MAX_DOWNLOAD_PREFERENCES;

for (new i = 0; i < g_nDownloadPrefs; i++) {
bFound |= (categoryid == GetCategoryIdentifier(i));
if (bFound) {
// Category already exists
return i;
}
if (GetCategoryIdentifier(i) == INVALID_DOWNLOAD_CATEGORY) {
iFree = i < iFree ? i : iFree;
}
}

if (g_nDownloadPrefs < MAX_DOWNLOAD_PREFERENCES) {
SetCategoryIdentifier(g_nDownloadPrefs, categoryid);
return g_nDownloadPrefs++;
if (iFree < MAX_DOWNLOAD_PREFERENCES) {
SetCategoryIdentifier(iFree, categoryid);
return iFree;
} else {
SetCategoryIdentifier(g_nDownloadPrefs, categoryid);
return g_nDownloadPrefs++;
}
}
return INVALID_DPREFS_ID;
}
Expand All @@ -319,13 +363,13 @@ bool:IsValidDownloadCategory(id) {
return GetCategoryIdentifier(id) != INVALID_DOWNLOAD_CATEGORY;
}

public Native_GetActiveCategories(Handle:hPlugin, nParams) {
public Native_GetAccessibleCategories(Handle:hPlugin, nParams) {
new size = GetNativeCell(2), start = GetNativeCell(3), nCategories;
new categoryids[size];

for (new i = start; i < g_nDownloadPrefs; i++) {
if (IsValidDownloadCategory(i)) {
categoryids[nCategories++] = GetCategoryIdentifier(i);
if (IsValidDownloadCategory(i) && GetCategoryAccess(i) == DownloadPrefsAccess_Public) {
categoryids[nCategories++] = i;
}
}

Expand All @@ -352,11 +396,6 @@ SetRawDownloadPreference(steamid, categoryid, bool:enabled) {
SQL_FastQuery(g_hDatabase, sQuery);
}

public Native_SetRawDownloadPreference(Handle:hPlugin, nParams) {
new steamid = GetNativeCell(1), categoryid = GetNativeCell(2), bool:enabled = GetNativeCell(3);
SetRawDownloadPreference(steamid, categoryid, enabled);
}

/**
* Grants raw access to retrieve the download preference for the specified SteamID and category.
*/
Expand All @@ -374,11 +413,6 @@ bool:GetRawDownloadPreference(steamid, categoryid) {
return bPreferenceEnabled;
}

public Native_GetRawDownloadPreference(Handle:hPlugin, nParams) {
new steamid = GetNativeCell(1), categoryid = GetNativeCell(2);
return GetRawDownloadPreference(steamid, categoryid);
}

/**
* Checks if a SteamID has a preference set for a category.
*/
Expand All @@ -400,29 +434,6 @@ bool:HasRawDownloadPreference(steamid, categoryid, &any:result = 0) {
return bHasRows;
}

public Native_HasRawDownloadPreference(Handle:hPlugin, nParams) {
new steamid = GetNativeCell(1), categoryid = GetNativeCell(2), bool:result;

new bool:response = HasRawDownloadPreference(steamid, categoryid, result);
SetNativeCellRef(3, result);

return response;
}

/**
* Converts a categoryid to an id.
*/
public Native_CategoryToIdentifier(Handle:hPlugin, nParams) {
new categoryid = GetNativeCell(1);
for (new i = 0; i < g_nDownloadPrefs; i++) {
if (categoryid == GetCategoryIdentifier(i)) {
// Category already exists
return i;
}
}
return INVALID_DPREFS_ID;
}

/**
* Runs a query, returning the first integer from the first row.
*/
Expand Down Expand Up @@ -452,15 +463,15 @@ SetCategoryOwner(slot, Handle:hPlugin) {
}

Handle:GetCategoryOwner(slot) {
return g_rgiCategories[slot][DCS_Owner];
return Handle:g_rgiCategories[slot][DCS_Owner];
}

SetCategoryAccess(slot, DownloadPrefsAccess:access) {
g_rgiCategories[slot][DCS_AccessLevel] = _:access;
}

DownloadPrefsAccess:GetCategoryAccess(slot) {
return g_rgiCategories[slot][DCS_AccessLevel];
return DownloadPrefsAccess:g_rgiCategories[slot][DCS_AccessLevel];
}

ClearCategory(slot) {
Expand All @@ -469,6 +480,14 @@ ClearCategory(slot) {
SetCategoryAccess(slot, DownloadPrefsAccess_Private);
}

bool:PluginHasReadAccess(Handle:hPlugin, slot) {
return GetCategoryOwner(slot) == hPlugin || GetCategoryAccess(slot) != DownloadPrefsAccess_Private;
}

bool:PluginHasWriteAccess(Handle:hPlugin, slot) {
return GetCategoryOwner(slot) == hPlugin || GetCategoryAccess(slot) == DownloadPrefsAccess_Public;
}

/**
* Reads the database configuration.
*/
Expand Down
25 changes: 0 additions & 25 deletions scripting/downloadprefs/natives.sp

This file was deleted.

8 changes: 7 additions & 1 deletion scripting/downloadprefs_loader.sp
Expand Up @@ -12,7 +12,7 @@
#include <downloadprefs>
#define REQUIRE_EXTENSIONS

#define PLUGIN_VERSION "0.0.2" // Plugin version.
#define PLUGIN_VERSION "0.1.0" // Plugin version.
public Plugin:myinfo = {
name = "Download Preferences Loader",
author = "nosoop",
Expand All @@ -30,6 +30,12 @@ public OnPluginStart() {
RegAdminCmd("sm_dprefs_loader_refresh", ConCmd_ReloadCategories, ADMFLAG_ROOT, "Reparses the download preference file.");
}

public OnPluginEnd() {
if (g_bDPrefsLoaded) {
UnregClientDownloadCategories();
}
}

public Action:ConCmd_ReloadCategories(client, nArgs) {
LoadCategories();
PrintToChat(client, "[SM] The download preference file has been reloaded.");
Expand Down
14 changes: 7 additions & 7 deletions scripting/downloadprefs_menu.sp
Expand Up @@ -12,7 +12,7 @@
#undef REQUIRE_PLUGIN
#include <downloadprefs>

#define PLUGIN_VERSION "0.2.0" // Plugin version.
#define PLUGIN_VERSION "0.3.0" // Plugin version.

public Plugin:myinfo = {
name = "Download Preferences Client Menu",
Expand All @@ -39,15 +39,15 @@ public Action:ConCmd_OpenDownloadPrefMenu(iClient, nArgs) {
}

new category[128];
new size = GetActiveCategories(category, sizeof(category));
new size = GetAccessibleCategories(category, sizeof(category));

new Handle:hMenu = CreateMenu(MenuHandler_DownloadPref, MENU_ACTIONS_ALL);
SetMenuTitle(hMenu, "Download Preferences");

new String:title[128], String:desc[1], String:id[4], String:display[64];
for (new i = 0; i < size; i++) {
if (RawCategoryInfo(category[i], title, sizeof(title), desc, sizeof(desc))) {
new bool:bPreference = GetClientDownloadPreference(iClient, CategoryToIdentifier(category[i]));
if (GetCategoryInfo(category[i], title, sizeof(title), desc, sizeof(desc))) {
new bool:bPreference = GetClientDownloadPreference(iClient, category[i]);

Format(display, sizeof(display), "[%s] %s", bPreference ? "x" : " ", title);
IntToString(category[i], id, sizeof(id));
Expand Down Expand Up @@ -75,7 +75,7 @@ public MenuHandler_DownloadPref(Handle:hMenu, MenuAction:iAction, param1, param2
case MenuAction_Select: {
new iClient = param1, item = param2;
GetMenuItem(hMenu, item, sCategory, sizeof(sCategory));
new cid = CategoryToIdentifier(StringToInt(sCategory));
new cid = StringToInt(sCategory);

new bool:bPreference = GetClientDownloadPreference(iClient, cid);
SetClientDownloadPreference(iClient, cid, !bPreference);
Expand All @@ -87,8 +87,8 @@ public MenuHandler_DownloadPref(Handle:hMenu, MenuAction:iAction, param1, param2
GetMenuItem(hMenu, item, sCategory, sizeof(sCategory));
new category = StringToInt(sCategory);

if (RawCategoryInfo(category, title, sizeof(title), desc, sizeof(desc))) {
new bool:bPreference = GetClientDownloadPreference(iClient, CategoryToIdentifier(category));
if (GetCategoryInfo(category, title, sizeof(title), desc, sizeof(desc))) {
new bool:bPreference = GetClientDownloadPreference(iClient, category);
Format(display, sizeof(display), "[%s] %s", bPreference ? "x" : " ", title);

return RedrawMenuItem(display);
Expand Down

0 comments on commit 407f594

Please sign in to comment.