Self-destructing application

2019-01-15 13:26发布

问题:

Along the lines of "This tape will self-destruct in five seconds. Good luck, Jim"...

Would it be possible for an application to delete itself (or it's executable wrapper form) once a preset time of use or other condition has been reached?

Alternatively, what other approaches could be used to make the application useless?

The aim here is to have a beta expire, inviting users to get a more up-to-date version.

回答1:

It is possible. To get around the lock on the JAR file, your application may need to spawn a background process that waits until the JVM has exited before deleting stuff.

However, this isn't bomb-proof. Someone could install the application and then make the installed files and directories read-only so that your application can't delete itself. The user (or their administrator) via the OS'es access control system has the final say on what files are created and deleted.



回答2:

If you control where testers download your application, you could use an automated build system (e.g. Jenkins) that you could create a new beta versions every night that has a hard-coded expiry date:

private static final Date EXPIRY_DATE = <90 days in the future from build date>;

the above date is automatically inserted by the build process

if (EXPIRY_DATE.before(new Date()) {
    System.out.println("Get a new beta version, please");
    System.exit(1);
}

Mix that with signed and sealed jars, to put obstacles in the way of decompiling the bytecode and providing an alternative implementation that doesn't include that code, you can hand out a time-expiring beta of the code.

The automated build system could be configured to automatically upload the beta version to the server hosting the download version.



回答3:

Since Windows locks the JAR file while it is running, you cannot delete it from your own Java code hence you need a Batch file:

private static void selfDestructWindowsJARFile() throws Exception
{
    String resourceName = "self-destruct.bat";
    File scriptFile = File.createTempFile(FilenameUtils.getBaseName(resourceName), "." + FilenameUtils.getExtension(resourceName));

    try (FileWriter fileWriter = new FileWriter(scriptFile);
         PrintWriter printWriter = new PrintWriter(fileWriter))
    {
        printWriter.println("taskkill /F /IM \"java.exe\"");
        printWriter.println("DEL /F \"" + ProgramDirectoryUtilities.getCurrentJARFilePath() + "\"");
        printWriter.println("start /b \"\" cmd /c del \"%~f0\"&exit /b");
    }

    Desktop.getDesktop().open(scriptFile);
}

public static void selfDestructJARFile() throws Exception
{
    if (SystemUtils.IS_OS_WINDOWS)
    {
        selfDestructWindowsJARFile();
    } else
    {
        // Unix does not lock the JAR file so we can just delete it
        File directoryFilePath = ProgramDirectoryUtilities.getCurrentJARFilePath();
        Files.delete(directoryFilePath.toPath());
    }

    System.exit(0);
}

ProgramDirectoryUtilities class:

public class ProgramDirectoryUtilities
{
    private static String getJarName()
    {
        return new File(ProgramDirectoryUtilities.class.getProtectionDomain()
                .getCodeSource()
                .getLocation()
                .getPath())
                .getName();
    }

    public static boolean isRunningFromJAR()
    {
        String jarName = getJarName();
        return jarName.contains(".jar");
    }

    public static String getProgramDirectory()
    {
        if (isRunningFromJAR())
        {
            return getCurrentJARDirectory();
        } else
        {
            return getCurrentProjectDirectory();
        }
    }

    private static String getCurrentProjectDirectory()
    {
        return new File("").getAbsolutePath();
    }

    public static String getCurrentJARDirectory()
    {
        try
        {
            return getCurrentJARFilePath().getParent();
        } catch (URISyntaxException exception)
        {
            exception.printStackTrace();
        }

        throw new IllegalStateException("Unexpected null JAR path");
    }

    public static File getCurrentJARFilePath() throws URISyntaxException
    {
        return new File(ProgramDirectoryUtilities.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath());
    }
}

Solution inspired by this question.


Here is a better method for Windows:

private static void selfDestructWindowsJARFile() throws Exception
{
    String currentJARFilePath = ProgramDirectoryUtilities.getCurrentJARFilePath().toString();
    Runtime runtime = Runtime.getRuntime();
    runtime.exec("cmd /c ping localhost -n 2 > nul && del \"" + currentJARFilePath + "\"");
}

Here is the original answer.



回答4:

it is pretty possible i guess. maybe you can delete the jar like this and make sure the application vanishes given that you have the rights.

File jar = new File(".\\app.jar");
jar.deleteOnExit();
System.exit(0);

also using something like Nullsoft Scriptable Install System which enables you to write your own installed/uninstaller should help.