Open DrewNaylor opened 3 years ago
I'm thinking the command-line program that'll be run as administrator to save the sources will also have two other switches: /lock
and /unlock
. These will be used to lock and unlock the folder where the sources list will be stored.
The way they'll be used is guinget will call /lock
as admin when it starts up to prevent any other compliant programs from modifying the sources when it's running. (To easily unlock the sources, the command-line app will stay open until guinget exits; this is described later). This allows the GUI sources manager to run and modify the sources list (as admin; just viewing sources doesn't need admin) without needing to ask the user for a password when it starts. When guinget exits, the command-line app will detect that its parent process has exited and will run the code that /unlock
runs. If the GUI sources manager is run on its own, it'll do the locking itself, using the CLI app the same way guinget does. It's important that neither guinget nor the sources manager are run as admin directly, due to winget not working correctly if you try to run it as admin from a standard user account, as both programs involve running winget in some way.
When running the GUI sources manager, guinget will pass the "lock code" (the lock code is just the name of the process, the current time in UTC, and a pseudorandom set of numbers, all to ensure only one specific instance of a program is allowed to access the files and folders at one time) along so that the sources manager will know that it's ok to run and access the files and folders because guinget is in a safe state. Then, the sources manager will either pass that "lock code" along to the CLI app so it can do its thing, or it'll create its own "lock code" if it didn't get one from guinget. And finally, if for some reason the CLI app is run directly (super not recommended), it won't create or store a lock code, but will refuse to do anything if the lock file is already there. /unlock
can be used in emergencies if something breaks, but that forcibly removes the lock file, and thus may break things unless you're certain it's in a safe state.
This is stated in another issue regarding the lock file (or maybe the to-do list, not sure), but the lock file contains the "lock code" as a string that a program will compare to the "lock code" it was either given or created itself when it started. If there's a mismatch, it's up to the author to say what to do beyond hopefully refusing to do anything with that folder the lock file is in, but guinget and the sources manager will probably say that the path is locked and they'll display the "lock code" in the file (likely the CLI app will also display the file's "lock code" before exiting if it doesn't match what it was given). There are two different lock file locations: the sources list area, and the package list cache area. Checking each of these files will need to be done to be safe. When they're checked is up to how the program works.
A workaround for limited command-line argument length would be to calculate the SHA-256 sum of the sources list after figuring out what the file will be, then saving the temporary sources list file to the AppData
folder for the user. We'll pass both the SHA-256 sum and the filepath along to the command-line app, and it'll make sure that the file has the same checksum as we tell it. If it matches, it'll replace the currently-existing sources list in ProgramData
with what it already has loaded (to ensure the file doesn't get replaced after having the checksum verified, which is a potential exploitation point), otherwise it'll show a messagebox that says that the checksum of the temporary sources list doesn't match the expected value and to try again. In either case, it'll delete the temporary sources list file, just in case that's being used by malware if the checksums don't match, or because the file doesn't need to continue to exist if it's successful. Maybe there should be a way to have it be only with command-line output (/nogui
, perhaps) in case it's not being run from a GUI.
This shouldn't be too difficult to add when implementing #49, we'll just have to see if a sources file exists and use it or use the built-in one if it doesn't, along with having a way to create an editable sources file so it's easier for the user to modify. There should also be a button to delete and/or reset the sources file in case it gets messed up by accident. Not sure how admin permissions would be required to modify the file, as that's a really good idea and winget itself does that.
Edit: probably could just store the sources file in
ProgramData
and require admin permissions to run the sources editor program. That way it's easy to just save the sources list to a text file. The only thing is this doesn't allow for just viewing sources without a password. Another problem is that this doesn't allow for doing cache maintenance on the user's AppData, so it might be a better idea to have the part that edits be another program that pops up when clicking a button in the main sources editor. I'd prefer to not have it like that, but this is Windows.Storing the file in ProgramData will also make it easy for someone to log into an Administrator account if they need to use it to install something from a source that was set while in their standard/non-administrator account.
Actually, I think what may be a good idea is if the sources manager GUI uses a command-line program to add, edit, or remove sources. That would allow the sources to be viewed without admin permissions, as well as the ability to delete the user cache if desired. Perhaps a button to clear the admin user's cache will also be a good idea, as people may have a separate user account for admin purposes. Not too sure about command-line length limitations, though, as the best way to reduce how many times the user is asked to type in their password would be to have a button that saves the newly-edited sources list, with all the possible options for each source. To make things easy, I'll probably just use JSON to send to the CLI app, then convert it to YAML.