Page 1 of 1
Read-only user variables?
Posted: 04 Feb 2013, 23:27
by MultiplayerCoder
In my game, there is a user variable that contains the current color of the user's avatar. I have an extension set up that will modify the user variable from server-side. By using the extension, I can check if the request is valid (e.g. user has the color in their inventory). However, I am worried a modded client could bypass the extension and directly update the user vars.
Is there anyway that I am able to make a user variable which is read-only to the client but is writable by the server?
Re: Read-only user variables?
Posted: 05 Feb 2013, 09:35
by Lapo
The easy way is to inhibit the UserVariables update from the client side, if you don't need it for other tasks.
This is done by configuring the User profile under the
AdminTool >
ZoneConfigurator >
PrivilegeManager
See the details here:
http://docs2x.smartfoxserver.com/Advanc ... ge-manager
Re: Read-only user variables?
Posted: 05 Feb 2013, 23:49
by MultiplayerCoder
Hmm.. that could certainly work. Unfortunately, there are also user-variables that I don't particularly care about & the user needs write-access to.
I can see 2 obvious solutions:
1) Replace user variable calls to an extension wrapper and use the user permissions method
2) Handle the user var updated event on the server extension and check whether the extension called or the user called it.
Both seem fairly tedious, and I was hoping there would be a more reasonable alternative. By any chance do you know how other games deal with this problem?
Re: Read-only user variables?
Posted: 06 Feb 2013, 08:37
by Lapo
There is a third way, using a SystemController filter:
http://docs2x.smartfoxserver.com/Advanc ... er-filters
In a nutshell the filter allows you to pre-process a request before it gets processed by the Server's main controller (SystemController).
You can check if a variable update is requested for a variable that is read-only and drop the request.
Thinking about this, gave me me an idea for an all-purpose variable filter that allows the developer to handle read-only variables pretty easily. It can be configured with the names of the read-only variables and it will filter out all requests to modify them.
I will do an experiment later today and post here how it can be done, it should be pretty easy

Re: Read-only user variables?
Posted: 06 Feb 2013, 11:45
by Lapo
Here is the
ReadOnlyUserVariablesFilter class, it is a simple filter that can be added via your Extension and it allows to provide a list of User Variables names that cannot be updated by the client.
This is the class code:
Code: Select all
public class ReadOnlyUserVariablesFilter extends SysControllerFilter
{
private final Set<String> readOnlyVars;
private final Zone zone;
private final Logger log;
public ReadOnlyUserVariablesFilter(Zone zone)
{
this(zone, null);
}
public ReadOnlyUserVariablesFilter(Zone zone, List<String> varNames)
{
this.log = LoggerFactory.getLogger(this.getClass());
this.zone = zone;
readOnlyVars = varNames == null ? new CopyOnWriteArraySet<String>() : new CopyOnWriteArraySet<String>(varNames);
}
public void addVariable(String varName)
{
readOnlyVars.add(varName);
}
public void removeVariable(String varName)
{
readOnlyVars.remove(varName);
}
public List<String> getFilteredVariables()
{
return new ArrayList<String>(readOnlyVars);
}
public void clearFilter()
{
readOnlyVars.clear();
}
@Override
public FilterAction handleClientRequest(User sender, ISFSObject params) throws SFSException
{
// Not this Zone, continue
if (sender.getZone() != this.zone)
return FilterAction.CONTINUE;
ISFSArray vars = params.getSFSArray(SetUserVariables.KEY_VAR_LIST);
if (vars != null && vars.size() > 0)
{
ISFSArray filteredVars = null;
if (vars.size() == 1)
filteredVars = filterSingleVariableUpdate(vars);
else
filteredVars = filterMultiVariableUpdate(vars);
if (filteredVars.size() < 1)
return FilterAction.HALT;
params.putSFSArray(SetUserVariables.KEY_VAR_LIST, filteredVars);
}
return FilterAction.CONTINUE;
}
private ISFSArray filterSingleVariableUpdate(ISFSArray vars)
{
ISFSArray var = (ISFSArray) vars.getElementAt(0);
return isReadOnly(var.getUtfString(0)) ? new SFSArray() : vars;
}
private ISFSArray filterMultiVariableUpdate(ISFSArray vars)
{
ISFSArray filteredVars = new SFSArray();
for (int i = 0; i < vars.size(); i++)
{
ISFSArray var = (ISFSArray) vars.getElementAt(i);
if (!isReadOnly(var.getUtfString(0)))
filteredVars.addSFSArray(var);
}
return filteredVars;
}
private boolean isReadOnly(String varName)
{
boolean readOnly = readOnlyVars.contains(varName);
if (log.isDebugEnabled() && readOnly)
log.debug("Filtering read-only variable: " + varName);
return readOnly;
}
}
This is how you can
activate the filter in your Extension's init() method:
Code: Select all
public class MyExtension extends SFSExtension
{
@Override
public void init()
{
// Reset filter chain to clean previous filters
getParentZone().resetSystemFilterChain();
ISystemFilterChain filterChain = new SysControllerFilterChain();
ReadOnlyUserVariablesFilter filter = new ReadOnlyUserVariablesFilter(getParentZone(), Arrays.asList("alpha", "beta"));
filterChain.addFilter("ReadOnlyUserVars", filter);
// Plug the filter chain
getParentZone().setFilterChain(SystemRequest.SetUserVariables, filterChain);
}
@Override
public void destroy()
{
super.destroy();
}
}
The Filter works on a per-Zone basis, so it will not filter other variables if you have other games running in other Zones.
In the above example the Filter will prevent the client from altering any UserVariable called "alpha" or "beta". Of course you will still able to access/delete those variables from server-side.
We plan to include this filter in the next SFS2X release so that it can be easily added to any existing application.
Hope it helps
Re: Read-only user variables?
Posted: 06 Feb 2013, 12:06
by MultiplayerCoder
Thanks so much! I'll post later when I try this out
