How do I make aliases for already existing commands? - java

So, I'm making a Minecraft mod that allows make aliases for exising commands, like /tp, /spawnpoint, /setblock, etc.., as well as making many commands in one that will be executed by the order, like so:
/alias add sun "time set day" "weather clear"
I've already made the base of /alias command itself, but I still have no idea, how to make the functionality of it.
public class CommandAlias extends CommandBase {
private final List<String> aliases = Lists.newArrayList(Reference.MODID, "alias", "al");
#Override
public String getName() {
return "alias";
}
#Override
public String getUsage(ICommandSender sender) {
return "/alias add|remove|edit <alias> <command(s)>";
}
#Override
public List<String> getAliases() {
return aliases;
}
#Override
public boolean checkPermission(MinecraftServer server, ICommandSender sender) {
return true;
}
#Override
public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException {
// sender.sendMessage(new TextComponentString("Hi " + sender.getName() + "!"));
if (args.length < 1) {
sender.sendMessage(new TextComponentString(TextFormatting.RED + "Invalid arguments!"));
return;
}
String alias = args[0];
String cmd = args[1];
if (args[0] == "add"){
// something
} else if (args[0] == "remove" || args[0] == "delete"){
// something
} else if (args[0] == "edit"){
// something
}
}
}

You'll need a couple of things:
A list of all aliases that are registered
An alias executor that will execute the aliased command when it is typed
Register the alias commands to bukkit
Here's a bit of a sample of this:
A list of aliases
HashMap<String, String> aliasList = new HashMap<String>;
When you add an alias you will need to add it to the command it is aliasing:
aliasList.put(myAliasString, commandToReplace);
An alias executor that will execute the aliased command when it is typed
executeAlias(String alias, ICommandSender sender, String[] args) {
if(aliasList.contains(alias) {
String aliasedCommand = aliastList.get(alias);
// Here you will need to convert the args array to a spaced string (if needed).
// Then send the command:
Bukkit.getServer().dispatchCommand(sender, commandString);
}
}
Register the commands when they come in:
if (args[0] == "add"){
// Make the AliasListener have the code from part 2
Bukkit.getCommand(args[1]).setExecutor(aliasListener)
// Store the alias and the command it replaces in the list.
this.aliasList.put(args[1], args[2])
}

Related

How to determine if account running java application is 'SYSTEM'

How can I check whether my Java application is running as "SYSTEM"/"Local System" (as seen on Windows Service list)?
I tried using this:
System.out.println("Running with user: " + System.getenv().get("USERDOMAIN") + "\\" + System.getenv().get("USERNAME"));
... but it seems to return DOMAIN\COMPUTERNAME according where the program is run. So it can be like DOMAIN1\COMPUTER1 and somewhere else it is FOO\SERVER451 and both still means "SYSTEM" account.
For background information, my Java application is wrapped to a Windows Service with 'Apache Commons Daemon Service Runner' and by default it will run as "Local System" (same way as in example image).
I really would want to simplify my code to print either SYSTEM or MYDOMAIN\JackTheUser depending on user type... Is there a way to do it with Java?
EDIT 20/12/02:
This is what I have done meanwhile the SO army working to find the correct answer:
Main:
String username = System.getenv().get("USERNAME");
String userdomain = System.getenv().get("USERDOMAIN");
String servername = getComputerName();
if (username.equalsIgnoreCase((servername + "$"))) {
System.out.println("Running with user: 'Local System'("
+ userdomain + "\\" + username + ")");
} else {
System.out.println("Running with user: '" + userdomain + "\\"
+ username + "'");
}
Methods:
private static String getComputerName() {
Map<String, String> env = System.getenv();
if (env.containsKey("COMPUTERNAME"))
return env.get("COMPUTERNAME");
else if (env.containsKey("HOSTNAME"))
return env.get("HOSTNAME");
else
return "Unknown Host name";
}
Prints:
Running with user: 'MYDOMAIN\jokkeri' or Running with user: 'Local System'(MYSERVER\SERVER_1$)
(not a perfect solution and I'm sure there are many occasions where it won't work but it's a starting point)
EDIT2 20/12/02:
Some good information about SYSTEM account was found from this thread from superuser: https://superuser.com/questions/265216/windows-account-ending-with
That’s the best I can come up so far
private static final String APP_NAME = "Some App";
private static final Configuration CONFIG = new Configuration() {
public #Override AppConfigurationEntry[] getAppConfigurationEntry(String name) {
return name.equals(APP_NAME)?
new AppConfigurationEntry[] { new AppConfigurationEntry(
"com.sun.security.auth.module.NTLoginModule",
LoginModuleControlFlag.REQUIRED, Collections.emptyMap())}:
null;
}
};
static final boolean DEBUG = true;
public static void main(String[] args) throws LoginException {
LoginContext lc = new LoginContext(APP_NAME, null, null, CONFIG);
lc.login();
final Subject subject=lc.getSubject();
boolean isSystem = false;
try {
for(Principal p: subject.getPrincipals()) {
if(DEBUG) System.out.println(p);
if(p.toString().equals("NTSidUserPrincipal: S-1-5-18")) {
isSystem = true;
if(DEBUG) System.out.println("\tit's SYSTEM");
}
}
}
finally { lc.logout(); }
}
As explained in this answer, SYSTEM is a set of permissions that can be attached to different accounts. The code iterates over all principals associated with the current account and tests for the well known SYSTEM.
But if you’re only interested in a printable user name, you may check for the NTUserPrincipal.
LoginContext lc = new LoginContext(APP_NAME, null, null, CONFIG);
lc.login();
final Subject subject=lc.getSubject();
try {
String name = System.getProperty("user.name"); // just a fall-back
for(Principal p: subject.getPrincipals()) {
if(p.toString().startsWith("NTUserPrincipal: ")) {
name = p.getName();
break;
}
}
System.out.println("Hello " + name);
}
finally { lc.logout(); }
If you can live with a direct dependency to the com.sun.security.auth package (or jdk.security.auth module in Java 9+), you can use the specific principal types directly
LoginContext lc = new LoginContext(APP_NAME, null, null, CONFIG);
lc.login();
final Subject subject=lc.getSubject();
try {
boolean system = false;
for(NTSidUserPrincipal p: subject.getPrincipals(NTSidUserPrincipal.class)) {
if(p.getName().equals("S-1-5-18")) {
system = true;
break;
}
}
Set<NTUserPrincipal> up = subject.getPrincipals(NTUserPrincipal.class);
String name = up.isEmpty()?
System.getProperty("user.name"): up.iterator().next().getName();
System.out.println("Hello " + name+(system? " *": ""));
}
finally { lc.logout(); }

passing parameters through hashmap to function in java

i was trying to build a command line tool alike in java, for example, if i write down in console "dir c:/....", it will activate my Dir class and will get the "c:/...." path as a parameter to the Dir class, and doing so with hashmap.
i dont know how to pass parameters through the commandline and hashmap,
is it even possible?
every command has it's own class, which implements the main "Command" interface, with a doCommand() function.
after running the start() function in the CLI class, it should take commands and do the requested command.
Command Interface:
public interface Command {
public void doCommand();
}
my CLI class:
public class CLI {
BufferedReader in;
PrintWriter out;
HashMap<String, Command> hashMap;
Controller controller;
public CLI(Controller controller, BufferedReader in, PrintWriter out,
HashMap<String, Command> hashMap) {
this.in = in;
this.out = out;
this.hashMap = hashMap;
}
public void start() {
new Thread(new Runnable() {
#Override
public void run() {
try {
out.println("Enter a command please:");
String string = in.readLine();
while (!string.equals("exit")) {
Command command = hashMap.get(string);
command.doCommand();
string = in.readLine();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
}
lets take for example my DirCommmand, as i said before, which should recognize the "dir" string through my hashMap configuration, and should pass the next word as a string parameter for the path
public class DirCommand implements Command {
#Override
public void doCommand() {
System.out.println("doing dir command...");
}
}
and my hashmap configuration:
hashMap.put("dir", new DirCommand());
which sets in a diffrent class the hashMap configuration and pass it to the CLI class's hashMap object at the start of the project.
i would love for some help because i have no idea how to do so.
First of all, in order to pass the parameters to doCommand, what I would do is use a variable param list, like:
public interface Command {
public void doCommand(String... params);
}
Second, I would split the input string on spaces as:
String[] result = command.split(" ");
Finally, the command would be the result[0] and the rest you would pass to the doCommand method.

What security issues come from calling methods with reflection?

I'm working on a project that has hosts and clients, and where hosts can send commands to clients (via sockets).
I'm determined that using JSON to communicate works the best.
For example:
{
"method" : "toasty",
"params" : ["hello world", true]
}
In this example, when this JSON string is sent to the client, it will be processed and a suitable method within the client will be run as such:
public abstract class ClientProcessor {
public abstract void toasty(String s, boolean bool);
public abstract void shutdown(int timer);
private Method[] methods = getClass().getDeclaredMethods();
public void process(String data) {
try {
JSONObject json = new JSONObject(data);
String methodName = (String) json.get("method");
if (methodName.equals("process"))
return;
for (int i = 0; i < methods.length; i++)
if (methods[i].getName().equals(methodName)) {
JSONArray arr = json.getJSONArray("params");
int length = arr.length();
Object[] args = new Object[length];
for (int i2 = 0; i2 < length; i2++)
args[i2] = arr.get(i2);
methods[i].invoke(this, args);
return;
}
} catch (Exception e) {}
}
}
And using the ClientProcessor:
public class Client extends ClientProcessor {
#Override
public void toasty(String s, boolean bool) {
//make toast here
}
#Override
public void shutdown(int timer) {
//shutdown system within timer
}
public void processJSON(String json) {
process(json);
}
}
The JSON is sent by the server to the client, but the server could be modified to send different JSONs.
My questions are:
Is this a safe way of running methods by processing JSON?
Is there a better way to do this? I'm thinking that using reflection is terribly slow.
There's a 100 and 1 ways you can process a JSON message so that some processing occurs, but they'll all boil down to:
parse message
map message to method
invoke method
send response
While you could use a reflective call (performance-wise it would be fine for most cases) to invoke a method, that, imho, would be a little too open - a malicious client could for example crash your system by issuing wait calls.
Reflection also opens you up to having to correctly map the parameters, which is more complicated than the code you've shown in your question.
So don't use Reflection.
Would you could do is define a simple interface, implementations of which would understand how to process the parameters and have your processor (more commonly referred to as a Controller) invoke that, something like this:
public interface ServiceCall
{
public JsonObject invoke(JsonArray params) throws ServiceCallException;
}
public class ServiceProcessor
{
private static final Map<String, ServiceCall> SERVICE_CALLS = new HashMap<>();
static
{
SERVICE_CALLS.put("toasty", new ToastCall());
}
public String process(String messageStr)
{
try
{
JsonObject message = Json.createReader(new StringReader(messageStr)).readObject();
if (message.containsKey("method"))
{
String method = message.getString("method");
ServiceCall serviceCall = SERVICE_CALLS.get(method);
if (serviceCall != null)
{
return serviceCall.invoke(message.getJsonArray("params")).toString();
}
else
{
return fail("Unknown method: " + method);
}
}
else
{
return fail("Invalid message: no method specified");
}
}
catch (Exception e)
{
return fail(e.message);
}
}
private String fail(String message)
{
return Json.createObjectBuilder()
.add("status", "failed")
.add("message", message)
.build()
.toString();
}
private static class ToastCall implements ServiceCall
{
public JsonObject invoke(JsonArray params) throws ServiceCallException
{
//make toast here
}
}
}
Map method names to int constants and just switch(case) on these constants to invoke appropriate method.
"toasty" : 1
"shutdown": 2
switch()
case 1: toasty()
case 2: shutdown()
I believe you are trying to convert JSON string to Java object and vice versa... if that is the requirement then this would not be the right approach...
Try any open source API like Gson...
it is the API by Google for conversin of Java to JSON and vice versa.
Please check ...
https://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/Gson.html
Let me know if you have any further questions...

Some informations of how handle the main() args in Java [duplicate]

This question already has answers here:
How to make IntelliJ prompt me for command line arguments
(3 answers)
Closed 8 years ago.
I have to develop a command line Java application in which the main() method accept 2 String parameters named respetivelly partitaIVA and nomePDF.
So, as starting point, I created this simple Main class:
public class Main {
public static void main(String[] args) {
System.out.println("Hello World !!!");
}
}
I think that I can perform this minimalistic application from the Windows console and that I can perform my application passion these parameters to it doing something like this in the Windows console (or in the Linux shell):
java Main 123456789 myDocument.pdf
and I think that I can retrieve it inside my application modifying the original code in this way:
public class Main {
public static void main(String[] args) {
System.out.println("Hello World !!!");
String partitaIVA = args[0];
String nomePDF = args[1];
}
}
So now I have 2 doubts about this topic:
1) I know that I can perform this application specifying my 2 parameters using the Windows command line or the Linux shell but can I do the same thing into my IDE console? Specifically in the Run tab of IntelliJ?
2) Can I specify in some way that the parameters that the user can specify are only 2?
1) There is something called run/debug configuration https://www.jetbrains.com/idea/help/creating-and-editing-run-debug-configurations.html (here are also sone details about the specific options you have: https://www.jetbrains.com/idea/help/creating-and-editing-run-debug-configurations.html#d1628194e152)
2) No, you can only print an error and guide the user
You should invest the time in learning a modern CLI argument parser:
I prefer JewelCli
<dependency>
<groupId>com.lexicalscope.jewelcli</groupId>
<artifactId>jewelcli</artifactId>
<version>0.8.9</version>
</dependency>
Here is an example that can be used as a base class:
public class Main
{
private static final Logger LOG;
static
{
LOG = LoggerFactory.getLogger(Main.class);
}
private static Args init(#Nonnull final String[] args)
{
final Cli<Args> cli = CliFactory.createCli(Args.class);
try
{
return cli.parseArguments(args);
}
catch (final ArgumentValidationException e)
{
for (final ValidationFailure vf : e.getValidationFailures())
{
LOG.error(vf.getMessage());
}
LOG.info(cli.getHelpMessage());
System.exit(2); // Bash standard for arg parsing errors
return null; // This is to make the compiler happy!
}
}
private static List<String> parseKey(#Nonnull final String key)
{
return new ArrayList<String>(Arrays.asList(key.toLowerCase().split("\\.")));
}
#SuppressWarnings("unchecked")
private static Map<String, Object> addNode(#Nonnull Map<String, Object> node, #Nonnull final List<String> keys, #Nonnull final String value)
{
if (keys.isEmpty())
{
return node;
}
else if (keys.size() == 1)
{
node.put(keys.remove(0), value.trim());
return node;
}
else if (node.containsKey(keys.get(0)))
{
return addNode((Map<String, Object>) node.get(keys.remove(0)), keys, value);
}
else
{
final Map<String, Object> map = new HashMap<String, Object>();
node.put(keys.remove(0), map);
return addNode(map, keys, value);
}
}
public static void main(final String[] args)
{
try
{
final Args a = init(args);
final Properties p = new Properties();
p.load(new FileInputStream(a.getInputFile()));
final HashMap<String, Object> root = new HashMap<String, Object>();
for (final String key : p.stringPropertyNames())
{
addNode(root, parseKey(key), p.getProperty(key));
}
switch (a.getFormat().toLowerCase().charAt(0))
{
case 'j': LOG.info(mapToJson(root)); break;
case 'b' : LOG.info(Strings.bytesToHex(mapToCbor(root))); break;
case 'x' : LOG.error("XML not implemented at this time!"); break;
default : LOG.error("Invalid format {}", a.getFormat());
}
}
catch (IOException e)
{
throw new RuntimeException(e);
}
}
interface Args
{
#Option(shortName = "i", longName = "input", description = "Properties file to read from.")
File getInputFile();
#Option(shortName = "o", longName = "output", description = "JSON file to output to.")
File getOutputFile();
#Option(shortName = "f", longName = "format", description = "Format of output Json|Binary|Xml")
String getFormat();
#Option(helpRequest = true, description = "Display Help", shortName = "h")
boolean getHelp();
}
}
In Intellij (Linux) you do:
Press Alt + Shift + F10 (the run shortcut)
Press right key
Go down to Edit
Then press Tab to go to "Program arguments".
This is where you pass the arugments in IntelliJ. After that just hit run.

Java Properties Save Temporary

I have some issues using properties in java. I have this software that uses properties.
What i want to do is run some code right before the Java software open so i have the following
MessageBox.infoBox("Are you ready to be amazed?", "XXX");
String macAdress = MCSystem.getMacAd();
MessageBox.infoBox(macAdress, "This is your MacAddress");
String sAct = config.getProperty("user.activationkey");
MessageBox.infoBox("You have no Activation or invalid Key","first ACT");
if(sAct != null)
{
MessageBox.infoBox(sAct,"second ACT");
}
else
{
String retAct = MessageBox.messageDialog("Please Enter Your Activation Key : ");
MessageBox.infoBox(retAct, "third ACT");
config.setProperty("user.activationkey", retAct);
String testin = config.getProperty("user.activationkey");
MessageBox.infoBox(testin, "fourth ACT");
}
As far as this goes everything works fine, outputs are good and right after that the software opens fine.
Now i would like to display the "user.activationkey" inside the software.
I'm trying to do it like below but i see no result. It's empty.
ActivationKey.setText(config.getProperty("user.activationkey"));
Any help would be appreciated.
EDIT:
private void init(File configfile) {
this.configfile = configfile;
m_propsconfig = new Properties();
logger.log(Level.INFO, "Reading configuration file: {0}", configfile.getAbsolutePath());
}
...
public String getProperty(String sKey) {
return m_propsconfig.getProperty(sKey);
}
...
public void setProperty(String sKey, String sValue) {
if (sValue == null) {
m_propsconfig.remove(sKey);
} else {
m_propsconfig.setProperty(sKey, sValue);
}
}

Categories

Resources