-
-
Notifications
You must be signed in to change notification settings - Fork 27
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
Trigger Selector #14
Comments
the issue here would be a pre requisite to this task. Will start development now. |
No need to overcomplicate things, do a simple OS call, done
others suggested For Windows: For Linux: or you can copy python code from here https://github.com/0xPoly/Centry |
… the appimage dir's python binary to execute the src/main.py file directly Also getting started on updating the cli to support multiple triggers * #14
The first part of this feature (limited to the cli only) for implementing a shutdown trigger on all three platforms is being tracked in a branch here: |
I made some progress on this, and I started implementing the shutdown function for Linux.
Executing this results in
That's actually because
Then it works. Well, at least for me. But this is problematic because:
The solution to [1] above by Centry (as linked-to by mrx23dot) is to just run the whole app as root. Well, there will come a time when we definitely need root privileges, but that's a really bad idea. I'm not sure yet how to do this, but probably what we should do is spawn a very minimal child process with root privliges. This child process should:
I don't know how to do that, but I'll be looking out fo other python programs that do something similar until we need it. @mrx23dot if you're aware of any apps that do this, I'd be happy to hear about them :) IMHO, the solution [2] is to figure out the path ASAP. Because of the time-sensitive nature of the trigger, we shouldn't wait until the trigger event to try to figure out the path to the binaries we need to shutdown. I'll add this to the init() of the buskill module. Long-term, we should probably have some sort of better way to inform the user if things don't look right. Like, when they hit the "arm" button, it should refuse to switch into "armed" mode if the app has reason to believe that it can't execute the trigger properly. |
I added the logic for a soft shudown on Windows after some breif tests just on a windows VM using the python shell. I could not get the ctypes solution with |
I tried my hand at manual tests of the existing Linux shutdown commands in MacOS, but none worked :( I couldn't find any commands named
I did find an additional command =
I tried this cute apple script, but that just triggers a popup on the GUI and asks the user to type their password. That's not going to work :'D
|
meanwhile, this Windows build finished successfully: I was able to download it on my Windows VM and run it. But there's this damn outstanding upstream issue that prevents the CLI from working on Windows There's a hack where you can just append
But Well, despite the fact that that I couldn't see what was going on, I gave it a try and started the above build of BusKill with the soft-shutdown trigger with the command
I attached a virtual USB drive ([1] Start -> Disk Management (Create and format hard disk partitions) [2] Action -> Attach VHD). And then I ejected that drive. I was successfully able to shutdown Windows 10 with the About 1 second after I ejected the disk, the screen locked. Then about 3 seconds later, it took away the input field for the password and said that Windows was shutting down. About 30 seconds later, the machine was off. Awesome!! |
As for MacOS, I can use
Note: you can test to see if
The above command won't actually shut down the system. It just scares all the users by telling them it will. Anyway, if it exits 0, within 1 second, then we know that the app will be able to shutdown. This could be added to
Actually, I think the best-case would be for the |
Oh, I didn't mention it above but I already finished fully testing the linux soft-shutdown logic (before Windows). All that remains is MacOS :/ |
Here's an example on how this was done in C++ https://stackoverflow.com/questions/58212418/how-to-have-a-non-root-parent-process-spawn-a-root-child-process-under-macos-x |
I think Apple's native Objective C solution to this has historically been |
ok, this seems really silly, but it seems the most common way people popup a GUI dialog asking for auth to get root permissions is using apple script I tried this over ssh and thought it was a dead-end because I couldn't get it to work
...but when I did it in a GUI terminal app over VNC, it actually worked
As described, it just popped-up a window that said
After I typed my password correctly into the GUI popup window, the terminal spat-out |
I just got the basic framework working for how to launch a new process as root from a non-root process via prompting the user for their password in MacOS. I created two simple files. One is a script named
Again, it fails if I execute it in ssh
But it works as desired if I execute it in the "Terminal" app in the GUI
TODO: make the root process actually a Thread or multiprocessing.Process that's running asynchronously, daemonized, and can shutdown the system immediately if called by the parent process. |
I'm not quite sure how to utilize this apple script (osascript) solution because:
I trust (assume) that creating a new But if I were to use |
I found some open-source code (part of the Here's the one for MacOS: |
Even the Immediate shutdownFirst, I was able to launch a subprocess as root that immediately shuts down. As long as the parent process is executed from the Terminal app in the GUI (as the normal user), then it will prompt the user for their password. Even though the parent has the non-root user's privileges, the subprocess has root permission (uid=0, I confirmed with This, of course, is not so useful. Rather, we want to be able to ask for the password early and then leave that root process in the background. But we need a way to communicate with the root child process to tell it if/when to shutdown. And the child process should only accept input from the parent, not other processes on the system. Parent (spawn_root.py)
Child (root_child.py)
Non-root child + communicationI was able to get a (parent) process to spawn a child process and to send it commands. The child is very skeptical of anything it receives. First the parent tries to tell it to do something nasty; the child refuses. Then the parent tries to tell it to do something it doesn't understand how to do; the child ignores the command. Finally, the parent tells the child to do a This is also not especially useful because we need the child to be root. Parent (spawn_child.py)
Child (child.py)
Example Execution
Note that the execution hangs at the end. The parent is waiting for the child to exit, but it won't because it's (intentionally) in an infinite loop. Root Child (Communication Fail)If I combine the above two, then execution stalls because there appears to be some communication breakdown between the two processes. And it's driving me insane. Parent (spawn_root.py)
Child (root_child.py)
Example Execution
It just stalls there after the parent attempts to send the message to the child. The parent is blocked while waiting for the response from the child. |
I was able to confirm that communication works between the parent & root child process when using sudo. This works on both Linux and MacOS. Parent (spawn_root.py)
Child (root_child.py)
Example Execution
Note that I'm using Anyway, you can see that it prints out that it's root and then immediately the session is killed because the machine rebooted. Success! However, if I take the exact same script but I replace the diff
Example Execution
|
* made the background of the settings screen grey by using canvas * switched from BoxView to GridView to get the list of items in the settings screen to appear as rows (still not 100% functional) * gave a temp green/red background to ^ these widgets to aid in getting their placements as-desired I'm committing this now because I want to change to expierimenting with (a possibly modified version of) Kivy's settings module, rather than re-invent the wheel * https://kivy.org/doc/stable/api-kivy.uix.settings.html Pros of using the settings module: 1. I don't have to re-invent the wheel; the code is already there and maintained by the kivy team 2. It has code re-use that automatically parses a config file and displays re-usable kivy elements Cons of using the settings module a. The documentation describes how to persist config options to a JSON file, but I want to use an ini-style format so it's easier to read & edit by-hand by advanced users. However, it appears that the Settings module just uses the kivy config object, which actually just extends the Python ConfigParser. And the default kivy config file (~/.kivy/config.ini) is in-fact an ini file. So this can likely be overcome * https://kivy.org/doc/stable/api-kivy.config.html#kivy.config.ConfigParser * https://docs.python.org/3/library/configparser.html b. I don't 100% like the way it looks. It doesn't match what I had expected following the Material Design spec, which may impact UX. But I could always add my own custom classes that extend or modify the api-kivy.uix.settings module to suit our needs.. * #14
I spent some time (see last commit above) trying to build a custom Settings screen, but I finally realized I'm just re-inventing the wheel. Kivy has a built-in settings module to handle this that dynamically renders a customizable settings screen from a json file. I didn't want to use this at first because I want to use ini instead of json, but once I realized it's built on-top of Python's ConfigParser, I think I can actually make it an INI (which is actually what kivy's config file format is by default) |
It took a horrible amount of time to work out all the kinks of the Settings screen (and therefore the Config File) in #16, but I think we're finally done with that, which was blocking this. As part of #16, I already implemented this feature too. The trigger setting and its two possible options ('lock-screen' and soft-shutdown) are defined in the Settings .json file. Then the user's choice is written to the buskill.ini config file, which has now also been merged with the built-in kivy settings (though in distinct sections of the .ini file). For the most part we're just kivy's built-in Settings modules: ...however, I chose not to us their panels that breaks the settings into sections as it's not consistent with Material Design. Also, for this particular ticket's When the user clicks the We also added some "confirmation" messages to the settings json for the I think this ticket is done, but I'll just do some tests of the build on all platforms before I merge this into dev and close this issue. |
I'm doing some tests of the most recent linux build, and I'm sad to say that it doesn't actually shutdown my Debian Linux AppVM
It detects that the USB drive has been removed. The |
I just tested the latest Windows build, and I confirmed that I was able to arm and lock the screen on the default settings. Then I went to the new Settings Screen, changed the trigger to |
I'm not really able to test a trigger of the app on my remote Mac Mini, but I did open the latest build of this GUI app, change the I found that the GUi was able to update the buskill.ini file, and the CLI used the same buskill.ini file -- but the buskil CLI still defaulted to using the Hmm..even if I open the GUI app and press the 'arm' button, it arms with the I confirmed that this bug is present in both Linux and Windows :( |
* #14 (comment) This commit fixes a bug where both the CLI and GUI version of this app would startup with the 'lock-screen' trigger, even if the config file was set to use the 'soft-shutdown' trigger. I added some logic to the buskill class to figure out what the setting was set-to in the config file, rather than just hard-coding it to lock-screen -- since we now have a config file
I fixed the buskill module to actually check the config file when first setting its That also required updating the CLI's ArgParser to not default-to (and call I confirmed that this build fixes the issue in Linux, MacOS, and Windows 10 |
regarding the shutdown bug on Linux, I found two distinct issues:
|
We have to call set_trigger(), else the paths to the binaries never gets set * #14 (comment)
I was able to test that [2] above was fixed by fixing only it first. After testing that fix, I just fixed [1] as well |
found another bug: my call to
|
The GUI defaulted to 'lock-screen', but the CLI did not. And it was crashing if 'trigger' wasn't defined in the config file when executed over the CLI. This fixes it * #14 (comment) INFO: using DATA_DIR:|/home/user/.local/share/.buskill| DEBUG: CONF_FILE:|/home/user/.local/share/.buskill/config.ini| Traceback (most recent call last): File "/tmp/.mount_buskilReWwl8/opt/python3.7/lib/python3.7/configparser.py", line 788, in get value = d[option] File "/tmp/.mount_buskilReWwl8/opt/python3.7/lib/python3.7/collections/__init__.py", line 916, in __getitem__ return self.__missing__(key) # support subclasses that define __missing__ File "/tmp/.mount_buskilReWwl8/opt/python3.7/lib/python3.7/collections/__init__.py", line 908, in __missing__ raise KeyError(key) KeyError: 'trigger' During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/tmp/.mount_buskilReWwl8/opt/src/main.py", line 129, in <module> bk = packages.buskill.BusKill() File "/tmp/.mount_buskilReWwl8/opt/src/packages/buskill/__init__.py", line 426, in __init__ self.set_trigger( self.config.get('buskill', 'trigger') ) File "/tmp/.mount_buskilReWwl8/opt/python3.7/lib/python3.7/configparser.py", line 791, in get raise NoOptionError(option, section) configparser.NoOptionError: No option 'trigger' in section: 'buskill' user@disp6142:~/buskill-lin--x86_64$ user@disp6142:~/buskill-lin--x86_64$ ./buskill-.AppImage --arm
I just tested the latest build in Linux, it appears to be full functional And it's fully functional on Windows I couldn't find any flaws in the latest MacOS build, but I can't test it fully. I noticed that if the I confirmed with WorkingThis is what it looks like when it's working (this happens when the GUI app is started when First we start the app
Then we arm it
Not workingFirst we start the app
Then we arm it
|
As before, it appears that the issue was that I was directly setting the instance field of |
this commit uses the set_trigger() function of the buskill object after the user changes the trigger in the Settings Screen. If we don't use the function, then the logic for the new trigger isn't followed -- such as finding the relevant `shutdown` binaries and spawning a root child process on MacOS, if needed * #14 (comment)
hmm...when testing on my Mac Mini by executing the However, I realized that (as I knew before), MacOS can't do this privilege escalation outside the GUI. I was getting errors if I tried it by executing it in an ssh session. Instead, I had to execute it in the But if that error occurs, it gets dumped to the DEBUG log and the GUI app continues along like nothing happened. The UI says that BusKill is armed, even though it probably won't work. TODO:
|
I just tried again with the latest BusKill build for MacOS, and it doesn't even appear to be trying to all
The first lines of
...but that line is clearly missing, which makes me think that |
I downloaded the latest version of the MacOS build, and it does appear to be fully functional I mounted the dmg. And then in the GUI The only thing that's a bit weird about this process is that the user may not understand why they're being prompted for their password when clicking the "back" arrow. It might make more sense to move the call of I'll leave it as-is for now. |
Alright, that's that. I'm merging this into |
This ticket is to track the development of a new feature permitting the user to choose the trigger that's executed.
Currently there is only one hard-coded trigger supported: lockscreen. When this feature is complete, there will be 1-3 triggers supported:
To achieve this, the following needs to be added
DATA_DIR
to persist settings between runs--list-triggers
option allowing the user to list all available triggers on their platform-t
=--trigger
option allowing the user to specify the trigger to be used at runtime. This is to be used in combination with the--arm
argument--set-default-trigger
option, which updates the config file's default trigger to be used after arming (affects both the CLI and the GUI).Note: this ticket should not attempt to handle auxiliary triggers (ie: self-destruct triggers or other custom triggers). This will be added later.
The text was updated successfully, but these errors were encountered: