diff --git a/.README.md.swp b/.README.md.swp deleted file mode 100644 index 86d3767..0000000 Binary files a/.README.md.swp and /dev/null differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1fb093e --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ + +#Swap files +*.swp + +design +testfile +testbed.py +randoms + +*.lock +*.pyc +*.pyo +*.toml diff --git a/.update.py.swp b/.update.py.swp deleted file mode 100644 index 127d383..0000000 Binary files a/.update.py.swp and /dev/null differ diff --git a/.upnot.swp b/.upnot.swp deleted file mode 100644 index 5624021..0000000 Binary files a/.upnot.swp and /dev/null differ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..437c010 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Hussar + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 6b6d256..266dc3a 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,23 @@ # Debian Update Notifier -Update Notifier is a simple and easy-to-use application that uses chronjobs for scheduling package updates. It takes a password and runs ``sudo apt update`` in a subprocess. It stores no passwords in any files. +Update Notifier is a simple and easy-to-use application that uses chronjobs for scheduling package updates. It pipes a password stored in memory to sudo subprocesses and stores no passwords in any plain text files. -// [Insert picture of notification popup] +![screenshot](/assets/gui-screenshot.png) -## Usage -`` ./setup.py 15`` +## Requirements +PySide2, trio, and sudo. -Sets the chronjob to run the update.py script at the current location every 15 days. Setup expects an integer representing the update interval. +``pip3 install PySide2 trio`` + +``$ apt install sudo`` + +## Install +`` ./ChronInstall.sh [n]`` + +Sets the chronjob to run the update.py script at the current location every n days. The default is 30 if nothing is entered. The update script can also be run manually. + +## TODO +* Handle subprocess termination after cancel button is pressed +* Handle ctrl-c terminal press +* Handle Cancel and other errors +* Add chronjob install script +* Add icon diff --git a/assets/gui-screenshot.png b/assets/gui-screenshot.png new file mode 100644 index 0000000..9d2a36f Binary files /dev/null and b/assets/gui-screenshot.png differ diff --git a/cronInstall.sh b/cronInstall.sh new file mode 100755 index 0000000..890d742 --- /dev/null +++ b/cronInstall.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +distResult=$(grep "PRETTY_NAME=" < /etc/*-release) +echo "$distResult" +updateInterval="$1" +updatePath="$(pwd)/update.py" + +if [ -z "$updateInterval" ]; then + updateInterval=30 + echo $updateInterval +fi +#Check that the running distro is debian and update.py exists +if [[ "$distResult" != *"Debian"* ]]; then + echo 'Identified distribution is not debian. Quiting...' + exit 1 +fi + +if [ ! -f "$updatePath" ]; then + echo 'update.py not found. Quitting...' + exit 1 +fi + +#Check if there is too many arguments +if [ "$#" -gt "1" ]; then + echo "Too many arguments. There are $#." + exit 1 +fi + +retes='^[0-9]+$' +if ! [[ $updateInterval =~ $retes ]]; then + echo 'interval has non int value. Quiting.' + exit 1 +fi + +echo 'Starting' + +#inTime = '17 * * * * root cd / && run-parts --report /etc/cron.hourly' +insert="$updateInterval 5 pkg.updates $updatePath" +currentLine=$(cat /etc/anacrontab | grep 'pkg.updates') + +if [ "$currentLine" = "" ]; then + echo "$insert" >> /etc/anacrontab +else + sed -i "/pkg.updates/ c\\$insert" /etc/anacrontab +fi diff --git a/update.py b/update.py index b645294..7dfe8df 100755 --- a/update.py +++ b/update.py @@ -23,9 +23,9 @@ class UpdatePrompt(QDialog): layout = QVBoxLayout() btnLayout = QHBoxLayout() self.centStack = QStackedWidget() - updateButton = QPushButton('Update') - cancelButton = QPushButton('Cancel') - notifyLabel = QLabel('There are updates scheduled') + self.updateButton = QPushButton('Update') + self.cancelButton = QPushButton('Cancel') + notifyLabel = QLabel('There are upgrades scheduled') self.inputBox = QLineEdit() self.outputBox = QTextBrowser() #refreshIcon = QIcon.fromTheme('process-working') @@ -36,8 +36,8 @@ class UpdatePrompt(QDialog): layout.addWidget(self.centStack) layout.addWidget(self.inputBox) layout.addLayout(btnLayout) - btnLayout.addWidget(cancelButton) - btnLayout.addWidget(updateButton) + btnLayout.addWidget(self.cancelButton) + btnLayout.addWidget(self.updateButton) self.centStack.addWidget(refreshAnimation) self.centStack.addWidget(self.outputBox) @@ -48,14 +48,15 @@ class UpdatePrompt(QDialog): self.inputBox.setEchoMode(QLineEdit.Password) self.inputBox.setFocus() self.inputBox.returnPressed.connect(self.pkgUpdates) - updateButton.clicked.connect(self.pkgUpdates) - cancelButton.clicked.connect(self.cancelUpdates) + self.updateButton.clicked.connect(self.pkgUpdates) + self.cancelButton.clicked.connect(self.cancelUpdates) + self.updateButton.setDefault(True) self.centStack.setCurrentIndex(1) notifyLabel.setAlignment(Qt.AlignTop) self.outputBox.setReadOnly(True) #self.outputBox.setAlignment(Qt.AlignTop) - self.setWindowTitle('Package Updates') + self.setWindowTitle('Package Upgrades') self.setLayout(layout) self.resize(450, 250) return @@ -123,9 +124,14 @@ class UpdatePrompt(QDialog): self.passError('The password field cannot be empty') return + self.inputBox.clear() + self.inputBox.setDisabled(True) + self.updateButton.setDisabled(True) trio.run(self.asetup, password) self.centStack.setCurrentIndex(1) self.refreshIcon.stop() + self.updateButton.setDisabled(False) + self.inputBox.setDisabled(False) return def passError(self, s): @@ -143,6 +149,7 @@ class UpdatePrompt(QDialog): return def cancelUpdates(self): + #Needs way of closing subprocess during async run self.reject() return