I'm writing a short C# program that will iterate over each user on a given Windows system, check in their local app data folder for a specific directory, and operating on it if it exists.
I'm looking for a good way to resolve the absolute file path to each users' local app data folder. I can use Environment.SpecialFolder.LocalApplicationData but that will only work for the user that is currently running the program.
I know I can cobble together a few different utilities and make a couple assumptions about where a user's local data is usually stored to make it work for 99% of the time (determine a list of all users, go through each one and find/guess where their app data is, etc.), but I was hoping there was a more elegant solution?
Related
Database File and Application that reads the db. The application has a registration component added. If the user doesn't want to register they can simply download the open source application, copy the database to the new folder, run a batch file and the database opens in the application, completely eliminating the registration and whatever extra features were added.
I want to keep the database file inhouse, even if it means adding the db file into the resources of the main application. The file does require data to be written to that file.
I've gone as far as converting the batch file to an exe file and loading the database file or even renaming the database file to something obscure like abc.exe (Even though its a db file it can be renamed to anything)
Database file is renamed to an exe file for the time being, I would prefer to either have it encrypted somehow or somehow placed into the resources of my main application and accessed that way, I am just trying to limit the way the software can be pirated.
Encryption:
You can encrypt SQLite databases using extensions such as SQLite Encryption Extension. The usefulness of such encryption depends on what you are trying to do. If your application can read the keys to decrypt it, so can a hacker that can run your application. You can use Windows Data Protection API to manage the keys so that if someone copied the database from one windows machine to another, the database would be unreadable; but again, if the hacker can access the source machine, they can obtain the keys just like your application (but it would protect against a "dumb" user from just copying the files over).
Putting it in your "main application resources": If you mean embedding the database within the EXE, you are out of luck if you have a requirement to write the data. Generally speaking, an EXE cannot modify itself (though depending on OS/version/user permission/absense of antimalware agents, etc, you might theoretically accomplish a self-modifying EXE; but, if you want your app to work most of the time in the wild, this strategy won't succeed). Even if you did succeed in an EXE that read itself, loaded the embedded blob as a database, modified that database in memory, then rewrote the entire EXE with database exported as a new blob (of different size than the original, wreaking havoc on the assembly), it wouldn't help. The attacker can do what your app does and access the data. Do yourself a favor and follow the operating system's guidelines for writing user data. For Windows, this is generally reading and writing files to your Local App Data folder.
Renaming a SQLite database to have an EXE extension. What are you trying to accomplish? Obscurity? Renaming it to EXE might fool some users (certainly not the motivated user I've described above), but it also might accidentally fool anti-malware / anti-virus software running on your legitimate user's operating systems into thinking your application is writing malformed executables (which would be suspicious) and shut your application down, or at least prevent it from working correctly. This will cause your users to not use your application or a mountain of support for you. What does it gain? It stops a "dumb" user from trying to open it in a SQLite query tool?
All that said, if you want to limit your user's abilities to read the data stored on their own storage devices, you really can't stop a determined user. You can stop the less savvy users. The majority of users cannot run a reflector on a C# assembly and figure out what it is doing, but many can. If you want to stop the less savvy users, encryption of the data will stop most of them, and it will be the least likely approach you've discussed to prevent your application from working "in the wild".
I've been trying to learn how to handle saving normal .txt files in UWP, and have realized that it's quite locked down compared to WPF, especially in the sense of what folders you can access without requesting the user to select a location. I have searched for various ways this might be possible but found no working answer.
Question Description:
I basically would love to know if this is possible, and preferably a point in the direction where I can learn how exactly to do this.
Application settings page requires user to select folder where files are saved.
Application remembers this between launches (unsure if this is possible, but I can't require the user to select the folder on every launch)
Application saves files to the specified folder.
In my understanding, this should be possible, as the user is the one specifying the location via filepicker, but is it possible to have this work between launches so that the user wont be required to re-select the save folder?
I need to figure this out, as I would like my application to support selecting attached network drives, cloud storage folders, etc.
Any help is very much appreciated, and if there are any questions I will answer them to the best of my ability.
Fow this purpose there are two access lists designed: FutureAccessList and MostRecentlyUsedList. Once the user has picked up the folder with the picker, you add it to such list and receive a token, which you save for future purpose in LocalSettings:
ApplicationData.Current.LocalSettings.Values["MyFolder"] = StorageApplicationPermissions.FutureAccessList.Add(pickedFolder);
Then later, once you want to access that folder, you can do it like this:
StorageFolder folder = await StorageApplicationPermissions.FutureAccessList.GetFolderAsync(ApplicationData.Current.LocalSettings.Values["MyFolder"].ToString());
You can't save a StorageFolder or a path to it in settings, hence the UWP app needs permissions to access the folder. Using above access lists solves this problem.
I believe you want to save user settings and keep it somewhere so that next time when they launch the application, they can use the same settings.
Please check out this tutorial from Microsoft, which describes how to do exactly that.
https://msdn.microsoft.com/en-us/library/bb397750(v=vs.110).aspx
I have a WPF program which deals with images on a canvas.
I am at the stage where I am trying to use serialization to be able to save the contents of my program and reload it at a later stage.
So At the moment when I am inserting any images into a control I am using absolute path values, I understand that this would be a bad idea for a program where I am wanting to save the state of the program and reload it at a later time.
So what is the best course of action to take in this situation.
Do I create a folder inside my WPF project for example called Images and then do I copy all Images I use in my program to this folder and then point the path to this?
Or am I completely on the wrong lines here?
If you are serializing the state data of your application, you would usually create a folder in one or more of the so-called system special folders, which you can get by a call to Environment.GetFolderPath.
You may for example store data with application scope (same for all users) in a folder below the special folder specified by the SpecialFolder.CommonApplicationData enum (which is C:\ProgramData on Windows 7 systems).
Data that is specific for the current roaming user (who works on multiple computers on a network), would be stored in a folder below SpecialFolder.ApplicationData. There is also SpecialFolder.LocalApplicationData for the non-roaming user.
You may take a look at the Environment.SpecialFolder enumeration to get an overview.
From my own experience, create a folder and save the images there. It will just make your life easier in the long run, and it makes it easy to see where the resources of the application are.
I have a file called middle.config that is deployed in the same directory as an exe, but I need to update values in this file. That means that I have to go to C:\Program Files (x86)\ directory to access the file. Although it is named as a .config file it does not follow the usual schema of a .config file. It looks like this:
<configuationSettings>
<middleSettings
groupName="XYZ"
forkName="SomeDbName"
dbServerName="123.123.123.123"
cnnTimeoutSeconds="30"
cmdDefaultTimeoutSeconds="30"
cmdMediumTimeoutSeconds="60"
cmdLongTimeoutSeconds="480"
/>
<userKeys>
<Assemblies value="C:\assemblies\" />
</userKeys>
<friendlyDbName value="NiceData"/>
</configuationSettings>
I'm able to read and manipulate the content with Xml, but when I try to save the file back, a "No Permissions" error is thrown. I cannot relocate the file. I'm stuck with this legacy schema so I'm not able to treat it like a normal .config file using ConfigurationManager.OpenExeConfiguration. I cannot define sections or groups on this schema (I've not been able to anyway). All my users are Administrators on their local machines.
How do I overwrite or delete and replace this file while it is in a protected directory(my assumption about the permissions error)? Failing that, is there a way to access this schema somehow with ConfigurationManager.OpenExeConfiguration.
{edit starts here}
There are three applications in this scenario, A, B, and mine C. Application A does not know about any other applications. It can connect to many, many databases, and it drops a single file 'middle.config' that contains pointer info to the last database location that was used by the last Application A session. Application B, let's call it an import/export application, only operates on the last Application A database location. Application B reads the 'middle.config' file for database pointer info and then executes console commands against that database. It performs bulk dumps or bulk imports for selected portions of the database.
This was the situation when I come along to build application C that uses the import/export application B to fetch, blocks of data and return them to the database. So, in order for application C to use Application B
against any database, application C must modify the 'middle.config' file so that application B will find the correct database. Application C is new and the other two are legacy. I either find a way to make this work, or I force the user to start Application A and point to the database of interest, then close Application A. This is VERY unhandy.
{edit ends here}
It is not advisable to write data files to the program files directory, as this requires elevated permissions. Giving a program elevated permissions just to update a config file clashes with the Principal of Least Privilege, which states that
a particular abstraction layer of a computing environment, every
module (such as a process, a user or a program depending on the
subject) must be able to access only the information and resources
that are necessary for its legitimate purpose
It's not a "legitimate purpose" to give the process elevated permissions (that can allow it to do many harmful things) just to update a config file. MS recommended practice is to write that type of data elsewhere.
Instead, consider storing the config file in a subfolder of the ApplicationData folder.
Suggested that your app is creating its own location under the AppData location folder for the current user instead of writing to files under location where the the app is installed (especially if under Program Files which is very strict.) Not suggested to force the user to run as Administrator for your application either.
Your assumption about protected directories is correct. Program Files has an Access Control List which prevents modification by processes running as standard users and, on Vista upwards, even by administrator processes which are not running elevated. Accessing the file using the standard configuration classes would not get around this.
If you absolutely can't move the file (Eric J. is right when says that writing to Program Files after installation is a bad idea), then you could embed a manifest in your config file-editing program which will try to force elevation with a UAC prompt at launch. Of course, the best solution would involve a) using standard config schema and b) keeping user data in user-writeable locations, but sometimes that isn't possible for legacy reasons.
I'm not aware of any way to persuade ConfigurationManager to read a non-standard schema, unfortunately.
Move the logic to a separate process and launch it with admin privileges from your current application.
From a different angle, look at this: Writing custom sections into app.config
I found the linked article to be very useful. Not sure it is going to answer all your questions though.
I currently store a serialized XML file in the application directory that contains all changes specific to the program operation (not typical system or user configuration). Weeks ago, we started running into problems where it would not save correctly (read my previous question about this).
Long story short, we finally discovered that Windows 7 (and sometimes Vista) has an issue with writing into the application directory (specifically anything under Program Files). Now, if this were a normal configuration file I would simply store it under the user's APPDATA folder, but it is not normal. We run this on our own instrumentation, and misconfigurations are 99% of the reason customers have issues running our software. So we need this file to be accessible such that they can easily find it and email it to us. Appdata is hard enough for experienced users to find, much less very non-technological people.
We've also tried running it as Administrator, and making folder permissions wide open (we have control over every computer it runs on; it will never run on some random person's machine). But, these sometimes work, and sometimes do not.
The worst part is that when I write the file back out, it doesn't even throw an error; it simply writes it to some temporary directory that expires at some unknown point in time. Weeks later, our user will have an issue, and the configuration file is all messed up.
So, my question is where should I be storing this file, if not in Program Files? Should I just put it in APPDATA anyway, and make a small utility that emails it to us automatically in case of a problem? Or can I leave it in Program Files, but change some specific permission or registry key to allow it to operate normally?
It depends on whether or not the user needs to edit the file directly. If not, you should put them in %APPDATA%, which you can access via:
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
Otherwise, you might put it in My Documents:
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
Either way, putting it in Program Files is not a good idea. As you discovered, there are permission issues, even if running as Administrator.
For those users, you could build a button in that would open this directory. You could put it in an inconspicuous place that you could later direct them to.
For users that have an email client on their box, you could have a button that would create a new email with subject and automatically attach the file to the email.