I wrote the following code to create two shared preference files:
SETTINGS_NAME for normal business, and OAUTH_NAME
to hide oauth consumer keys, secrets, and access tokens.
[I've read many times on stackOverflow this is the best, though not great, way to hide them.]
protected void onStart() {
super.onStart();
sharedPreferences = getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
sharedPreferenceChangeListener.onSharedPreferenceChanged(null, null);
sharedPreferencesOauth = getSharedPreferences(Constants.OAUTH_NAME, Context.MODE_PRIVATE);
}
But file OAUTH_NAME is not at all private!
It may be true that it can't be programmatically read by other apps,
but on a rooted device it can be opened and examined in ES File Explorer;
It's in /data/data/{packageName}/share_prefs/SHARED_PREFS_OAUTH_NAME.xml .
Certainly not much of a challenge for a hacker.
File SETTINGS_NAME, on the other hand, does seem to be more private in that
it is NOT in folder /data/data/{packageName}/share_prefs/ .
My question: why is file SETTINGS_NAME not in folder .../shared_prefs while file OAUTH_NAME -- also created MODE_PRIVATE -- is in folder .../shared_prefs?
Private settings are saved in an application's private directory.
On a rooted device nothing is private. It's like leaving your house's door wide open and wondering how can you be safe against a thief.
Saving a file in a more hidden location doesn't give much security, because anyone can dump .apk, decompile it and find where that file was saved. The only way you can save secure data on a rooted phone is to use encryption without storing a password.
You are running on Rooted-device right ?
Once rooted, everything can be accessed even the system file. so MODE_PRIVATE is working in this case.
You can access them via any explorer app. Can't protect your file now !!!
Related
I currently have a Qt Application that writes to a log during use and saves the file locally to the device.
This is straightforward enough, I create a QFile with the local path and write to it.
It looks something like this:
QFile logFile;
QString logPath = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
logFile.setFileName(logPath.append("/MyLogFile.txt"));
logFile.open(QFile::WriteOnly | QFile::Append);
// Write to log file ...
This works fine but I'd like to also write this log file to a network drive -
E.g. //192.168.12.34/Drive-1/LogFile.txt
I've tried altering the path to //192.168.12.34/Drive-1
but see nothing new in the network folder when I navigate to the above on a desktop.
Is this something that's possible to do from an Android device?
It can't be done this way. You need to mount the network drive first using a samba client, and then copy the files.
You can use a samba client app like AndSMB thats allow folder synchronization for that.
My application will be used offline and I plan daily pull/push synchronizations via USB cable. My users are in a very primitive situation: no wifi, and no cell phone towers. My question is not about synchronization, but rather just getting access to the data so that I can synchronize.
I connect the cable, select USB for file transfer, and I can see Internal Shared Storage. But I cannot find my SqlLite database anywhere. I have tried using these paths for the database:
Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData);
Environment.GetFolderPath(Environment.SpecialFolder.Personal);
Android.App.Application.Context.FilesDir.AbsolutePath;
The app works fine with any of those paths, the data is stored and retrieved, but I cannot see the database from my PC.
I have also tried this but it blows up:
Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).AbsolutePath;
I have tried debugging with Xamarin Live but then I get this error:
"You need to call SQLitePCL.raw.SetProvider();"
I have tried adding console.writeline and Log.Error to add in some diagnostics but I can't find any log files in Internal Shared Storage.
I have WRITE_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE permissions in the manifest; even tho I think that is not necessary.
If I could store files in Internal Shared Storage then I could put the database there and access it to synchronize. And I could create a simple text logging facility to write a text log to the same place.
I have rarely asked for help in 40 years but I've been at this for days. Thanks!
To get files onto Internal Shared Storage accessible via USB took 3 steps:
1: Get runtime permissions
ActivityCompat.RequestPermissions(activity, new String[] { Manifest.Permission.WriteExternalStorage, Manifest.Permission.ReadExternalStorage }, 1);
2) use this path:
string extPath = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath;
extPath = Path.Combine(extPath, "RtTrace.txt");
File.AppendAllText(extPath, "new content" + System.Environment.NewLine);
3) Media scan the resulting file to make it visible:
MediaScannerConnection.ScanFile(Android.App.Application.Context, new String[] { extPath }, null, null);
The path on Environment.SpecialFolder.Personal refers to a private area where only the app (and the OS itself when you clear data from the app, for example) have access. I don't know about ApplicationData.
You can easily copy your app file (the protected one) to a public folder, like Downloads or create a new folder MyAppDirectory at the public storage space, that will allow access from other devices. Then, you can clear local data that you don't need anymore (after the sync process).
To create a new public folder on Android:
var folder = System.IO.Path.Combine(Android.OS.Environment.ExternalStorageDirectory.AbsolutePath, "MyAppDirectory");
System.IO.Directory.CreateDirectory(folder);
You'll get this:
Then, copy the file:
var newFile = Path.Combine(folder, "MySharedFile"); // The database, xml, json, text or any file you want to share
var sourceFullName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal),"MyOriginalFile");
System.IO.File.Copy(sourceFullName, newFile, true /* overwrite */);
I hope it helps.
SQLite db is stored in application private memory and can't be accessed over USB, try exporting contents of your DB to an external file in your internal memory or External memory to be able to access it via a USB chord.
Using the new GDAA, as I understand it, in order to access a folder and its contents you have to have the folder's DriveId - because this insures that an app can only access the content it has created itself.
Now, my app uploads files to the user's Google Drive account (pictures) in a custom folder. When this folder is first created I save the DriveId of the folder to Shared Preferences so I can access the folder later for more uploads. My problem is that I would like the user to be able to access the pictures from multiple devices (so he/she e.g. can look at pictures uploaded from his/her phone while being on a tablet and vice versa), but this I cannot do without having the folder's DriveId on both devices. The only solution I can think of is sharing the DriveId between user's devices via some cloud service, but this seems awfully inconvenient for the purpose.
Any thoughts?
Shamelessly promoting myself to Cheryl's sidekick, I can give you some specific points, since I've run through this gauntlet before. This is what I did:
Create a unique 'root' for my app in the system root - "MyStupidAppRoot'. Here you'll hit the main challenge since you are creating it by name and if you base the creation on it's non-existence, you may not reliably be able to check it. But it is getting better, see SO 22382099 and SO 22515028.
Once you have a reliable anchor 'MyStupidAppRoot', you can create AppFolder mentioned by Cheryl (not available yet) or create you own visible file (again, the unique creation challenge) that can keep anything you want. Like for instance all your PREFERENCE strings. I even got so brave as to store full SQLite DB file there. It is possible since you write a byte[] buffer to a file.
Than, any other device with you app can find 'MyStupidAppRoot', get the resource file from there and read it.
It should be noted that the main difference between you own folder/file and the AppFolder is, that user's can't read the contents of an AppFolder, but can still delete it.
Here's how you can write byte[] buffer to a file. It is the 'await' version to make it simple, but there is an async version 'createFileAsync()' here.
public DriveFile createFileWait(DriveFolder fldr, String name, String mime, byte[] buff) {
DriveFile drvFile = null;
if (isConnected()) try {
ContentsResult rslt = Drive.DriveApi.newContents(_gac).await();
if (rslt.getStatus().isSuccess()) {
Contents cont = rslt.getContents();
cont.getOutputStream().write(buff);
MetadataChangeSet meta = (mime == null) ?
new MetadataChangeSet.Builder().setTitle(name).build() :
new MetadataChangeSet.Builder().setTitle(name).setMimeType(mime).build();
drvFile = fldr.createFile(_gac, meta, cont).await().getDriveFile();
}
} catch (Exception e) {}
return drvFile;
}
About the IDs:
The DriveId you mention above is an object, that can be turned into 2 different strings as discussed in SO 21800257. It is up to you which one you choose. The long one from 'encodeToString()' is easier to turn back into DriveId by 'decodeFromString()', the shorter one can be easily recognized in the http address, but takes async / await method to get back the DriveId - fetchDriveId().
You don't necessarily have to have the DriveId, its just the most sure-fire way to do it since it uniquely identifies the folder. You can also query based on the title to try to find the same folder. Assuming that the web and Android app share an app id, both should be able to access the same files.
One easy option for sharing state between apps is to make use of the newly launched App Folders (called App Data Folders on the web.) This is a hidden folder where you can store files specific to your app. Its not yet in the Android docs, but it should show up there as soon as the rollout of Google Play Services 4.3 is released. See http://android-developers.blogspot.com/2014/03/google-play-services-43.html
I have developed a Import / Export feature for my app so uses can export the database and shared preferences to be used in another phone. This has worked fine up until I got myself a S3 and tried to do it.
After some work I got the database import / export to work (duel SCdards issue) but the shared preferences is still causing me trouble.
On a new install the import fails because there is no shared preferences file on the phone. Once I update an option the File is created (added in a check to see if the file on the phone exists)
This to create it
this.sharedprefs = context.getSharedPreferences("sharedprefres.xml", Activity.MODE_PRIVATE);
This to check file is there
File sharedPrefencesFileOnPhone = new File(/data/data/PACKAGE_NAME/shared_prefs/, "sharedprefres.xml");
if (sharedPrefencesFileOnPhone.exists())
Log.d(DEBUG_TAG, "SP : Running Copy");
The Copy then seems to go though but none of the options are updated.
This all works on the emulator with no issues
The check only works once I have updated a option and the file is created which is given me to belive the shared preferences are saved.
Does the S3 hide the shared preferences somewhere else and if so is there some code for me to track it down that would work on multi phones
Thanks for your time
Try
/dbdata/databases/package.name/shared_prefs/package.name_preferences.xml (if it exists use it)
otherwise
new File(getFilesDir(), "../shared_prefs");
or
/data/data/package.name/shared_prefs/package.name_preferences.xml
Is there such thing on any Android based device as shared internal storage? I know you can use the SDCard as a shared file location between applications, but for a project I'm working on we dont want the ability for a SD Card to go missing (sensitive material).
The problem is as follows. App1 allows a user to browse (for example) some word documents and download them to the proposed shared storage, the user can then pass this file to Documents 2 Go editing them and saving the change. App 1 then allows an upload of the changed file.
I don't fancy building a document editor word/excel directly into app, unless thats easy?
EDIT:
The second app is "Documents 2 Go" I won't be able to edit its AndroidManifest
I faced a similar situation now for txt files and did this.
File downloadedFile= new File( context.getFilesDir(), "simple.txt" );
downloadedFile.setReadable( true, false );
downloadedFile.setWritable( true, false ); //set read/write for others
Uri downloadFileUri = Uri.fromFile( downloadedFile );
Intent intentToEditFile = new Intent( Intent.ACTION_EDIT );
intentToEditFile.setDataAndType( downloadFileUri, "text/plain" );
context.startActivity( intentToEditFile );
Now the 'Document 2 Go' editor will be launched to edit the file and
will be able to edit simple.txt
Note 1: Uri should be created from same file object that was set with
setReadable()/setWritable.
Note 2: Read/Write permission for other users might not be reflected in file
system. Some times I cannot see rw-rw-rw- in adb shell
I believe ContentProviders is your solution. Its the Android recommended method for sharing application data between different apps.
https://stackoverflow.com/a/6708681/804447
Sharing data between apps is what ContentProviders are for. Assuming that you know how to write a ContentProvider and access it, you can access files via ParcelFileDescriptor, which includes constants for the mode in which you create the files.
What you need now is to limit access so that not everybody can read the files through the content provider, and you do that via android permissions. In the manifest of one your apps, the one that will host the files and the content provider, write something like this:
<permission android:name="com.example.android.provider.ACCESS" android:protectionLevel="signature"/>
and in both apps add this:
<uses-permission android:name="com.example.android.provider.ACCESS" />
by using protectionLevel="signature", only apps signed by you can access your content provider, and thus your files.