package org.fdroid.fdroid.data; import java.io.File; /** * File guaranteed to have a santitized name (though not a sanitized path to the parent dir). * Useful so that we can use Java's type system to enforce that the file we are accessing * doesn't contain illegal characters. * Sanitized names are those which only have the following characters: [A-Za-z0-9.-_] */ @SuppressWarnings("serial") public class SanitizedFile extends File { /** * The "name" argument is assumed to be a file name, _not including any path separators_. * If it is a relative path to be appended to "parent", such as "/blah/sneh.txt", then * the forward slashes will be removed and it will be assumed you meant "blahsneh.txt". */ public SanitizedFile(File parent, String name) { super(parent, name.replaceAll("[^A-Za-z0-9-._]", "")); } /** * Used by the {@link org.fdroid.fdroid.data.SanitizedFile#knownSanitized(java.io.File)} * method, but intentionally kept private so people don't think that any sanitization * will occur by passing a file in - because it wont. */ private SanitizedFile(File file) { super(file.getAbsolutePath()); } /** * This is dangerous, but there will be some cases when all we have is an absolute file * path that wasn't given to us from user input. One example would be asking Android for * the path to an installed .apk on disk. In such situations, we can't meaningfully * sanitize it, but will still need to pass to a function which only allows SanitizedFile's * as arguments (because they interact with, e.g. shells). * * To illustrate, imagine perfectly valid file path: "/tmp/../secret/file.txt", * one cannot distinguish between: * * "/tmp/" (known safe directory) + "../secret/file.txt" (suspicious looking file name) * * and * * "/tmp/../secret/" (known safe directory) + "file.txt" (known safe file name) * * I guess the best this method offers us is the ability to uniquely trace the different * ways in which files are created and handled. It should make it easier to find and * prevent suspect usages of methods which only expect SanitizedFile's, but are given * a SanitizedFile returned from this method that really originated from user input. */ public static SanitizedFile knownSanitized(String path) { return new SanitizedFile(new File(path)); } /** * @see {@link org.fdroid.fdroid.data.SanitizedFile#knownSanitized(String)} */ public static SanitizedFile knownSanitized(File file) { return new SanitizedFile(file); } }