Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add filename length checker to file obfuscator #191

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from
10 changes: 10 additions & 0 deletions app/src/main/java/deltazero/amarok/PrefMgr.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public static SharedPreferences getPrefs() {
public static final String FILE_HIDER_MODE = "fileHiderMode";
public static final String IS_ENABLE_AUTO_UPDATE = "isEnableAutoUpdate";
public static final String ENABLE_OBFUSCATE_FILE_HEADER = "enableObfuscateFileHeader";
public static final String ENABLE_TRUNCATE_FILE_NAMES = "enableTruncateFileName";
public static final String ENABLE_OBFUSCATE_TEXT_FILE = "enableObfuscateTextFile";
public static final String ENABLE_OBFUSCATE_TEXT_FILE_ENHANCED = "enableObfuscateTextFileEnhanced";
public static final String ENABLE_QUICK_HIDE_SERVICE = "enableQuickHideService";
Expand Down Expand Up @@ -139,6 +140,15 @@ public static BaseFileHider getFileHider(Context context) {
};
}

public static void setTruncate(boolean shouldTruncate) {
mPrefEditor.putBoolean(ENABLE_TRUNCATE_FILE_NAMES, shouldTruncate);
mPrefEditor.apply();
}

public static boolean getTruncate() {
return mPrefs.getBoolean(ENABLE_TRUNCATE_FILE_NAMES, false);
}

public static void setFileHiderMode(Class<? extends BaseFileHider> mode) {
int modeCode;
if (mode == NoneFileHider.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Set;
import java.nio.charset.StandardCharsets;

import deltazero.amarok.PrefMgr;
import deltazero.amarok.utils.FileHiderUtil;
Expand All @@ -28,6 +29,7 @@
public class ObfuscateFileHider extends BaseFileHider {
private final static String TAG = "FileHider";

private static final int MAX_FILENAME_LENGTH = 255;
private final static int MAX_PROCESS_WHOLE_FILE_SIZE_KB = 10 * 1024; // In KB.
private final static int MAX_PROCESS_ENHANCED_WHOLE_FILE_SIZE_KB = 30 * 1024;
private final static int BASE64_TAG = Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING;
Expand Down Expand Up @@ -104,7 +106,6 @@ public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) {
endingMark = FILENAME_FULL_PROCESS_MARK;

// Process filename
// TODO: 2023/1/9 Handle long filename that invalid to android after Base64 encode
Path newPath = processFilename(path, method, endingMark);

// Process file content
Expand Down Expand Up @@ -148,52 +149,26 @@ public FileVisitResult postVisitDirectory(Path dir, IOException e) {
*/
@Nullable
private Path processFilename(Path path, ProcessMethod method, String extraEndingMark) {
String filename = path.getFileName().toString();
String newFilename = null;
Path newPath;

boolean hasEncoded = FileHiderUtil.checkIsMarkInFilename(filename);

if (method == HIDE) {
if (hasEncoded) {
Log.d(TAG, "Found encoded name: " + filename + ", skip...");
return null;
String originalFilename = path.getFileName().toString();
String encodedFilename = Base64.encodeToString(originalFilename.getBytes(StandardCharsets.UTF_8), Base64.URL_SAFE | Base64.NO_WRAP);
if (encodedFilename.length() > MAX_FILENAME_LENGTH) {
String truncatedFilename = encodedFilename.substring(0, MAX_FILENAME_LENGTH - extraEndingMark.length()) + extraEndingMark;
String fileExtension = "";
int extIndex = originalFilename.lastIndexOf('.');
if (extIndex > 0) {
fileExtension = originalFilename.substring(extIndex);
}

newFilename = "." + Base64.encodeToString(filename.getBytes(UTF_8), BASE64_TAG) + extraEndingMark;
Log.d(TAG, "Encode: " + path + " -> " + newFilename);
Path parentDir = path.getParent();
Path newPath = parentDir.resolve(truncatedFilename + fileExtension);

} else if (method == UNHIDE) {
if (!hasEncoded) {
Log.w(TAG, "Found not coded name: " + filename + ", skip...");
return null;
}

try {
newFilename = new String(
Base64.decode(FileHiderUtil.stripFilenameExtras(filename), BASE64_TAG), UTF_8
);
} catch (IllegalArgumentException e) {
Log.w(TAG, "Unable to decode: " + filename);
return null;
}

Log.d(TAG, "Decode: " + path + " -> " + newFilename);
}

// Try to rename.

assert newFilename != null;
newPath = Paths.get(path.getParent().toString(), newFilename);

boolean is_succeeded = path.toFile().renameTo(newPath.toFile());

if (!is_succeeded) {
Log.w(TAG, "Error when renaming file: " + path + " -> " + newPath);
return null;
} else {
Log.i(TAG, "Filename exceeded limit, truncated to: " + newPath);
return newPath;
}

Path parentDir = path.getParent();
Path newPath = parentDir.resolve(encodedFilename + extraEndingMark);
return newPath;
}

private void processFileHeader(Path path) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

public class ObfuscateFileHiderSettingsActivity extends AmarokActivity {

private MaterialSwitch swObfuscateFileHeader, swObfuscateTextFile, swObfuscateTextFileEnhanced;
private MaterialSwitch swObfuscateFileHeader, swObfuscateTextFile, swObfuscateTextFileEnhanced, swTruncateFileNames;
private MaterialToolbar tbToolBar;

@Override
Expand All @@ -22,6 +22,7 @@ protected void onCreate(Bundle savedInstanceState) {
swObfuscateFileHeader = findViewById(R.id.switch_filehider_sw_obfuscate_header);
swObfuscateTextFile = findViewById(R.id.switch_filehider_sw_obfuscate_text);
swObfuscateTextFileEnhanced = findViewById(R.id.switch_filehider_sw_obfuscate_text_enhanced);
swTruncateFileNames = findViewById(R.id.filehider_truncate_long_names);
tbToolBar = findViewById(R.id.switch_filehider_tb_toolbar);

// Init UI
Expand All @@ -44,6 +45,11 @@ protected void onCreate(Bundle savedInstanceState) {
PrefMgr.setEnableObfuscateTextFileEnhanced(isChecked);
updateUI();
});
swTruncateFileNames.setOnCheckedChangeListener((buttonView, isChecked) -> {
PrefMgr.setTruncate(isChecked);
updateUI();
});


// Enable back button
tbToolBar.setNavigationOnClickListener(v -> finish());
Expand All @@ -62,8 +68,9 @@ private void updateUI() {
swObfuscateFileHeader.setChecked(PrefMgr.getEnableObfuscateFileHeader());
swObfuscateTextFile.setChecked(PrefMgr.getEnableObfuscateTextFile());
swObfuscateTextFileEnhanced.setChecked(PrefMgr.getEnableObfuscateTextFileEnhanced());
swTruncateFileNames.setChecked(PrefMgr.getTruncate());

swObfuscateTextFile.setEnabled(PrefMgr.getEnableObfuscateFileHeader());
swObfuscateTextFileEnhanced.setEnabled(PrefMgr.getEnableObfuscateFileHeader() && PrefMgr.getEnableObfuscateTextFile());
}
}
}
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@
<string name="filehider_chmod_description">Change file permissions to make them unreadable. Root access required. The procedure is immediate.</string>
<string name="filehider_nomedia">NoMedia Mode</string>
<string name="filehider_nomedia_description">Simply adds .nomedia to folders. No root access required.</string>
<string name="filehider_truncate_long_names">Truncates overly long file names for better filesystem compatibility. No root access required.</string>
<string name="welcome_title">Welcome</string>
<string name="welcome_msg">Amarok is a free and freedom tool for hiding private files &amp; applications.\n\nPlease note that Amarok is not an encryption software, but rather a tool for hiding things. We strongly advise against using Amarok to protect confidential files and applications.\n\n<u>Disclaimers: Amarok is provided without any warranties or conditions. The user is fully responsible for any harm or consequences that may arise from using Amarok.</u></string>
<string name="warning">WARNING</string>
Expand Down
Loading