blob: 261d0469c754bf2fc84c4893240548c28e1fcdf7 (
plain)
1 #!/usr/bin/env bash
2 # GPGSecure is a shell script that manages GPG encrypted archives
3 # Copyright (C) 2018 Aaron Ball <nullspoon@oper.io>
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18
19 export KEY=${KEY:-} # GPG key to encrypt the container with
20 export DIR # Directory path to present the gpg archive to
21 export TMP # Temp directory in memory to decrypt to
22
23 trap shutdown SIGINT SIGTERM SIGKILL SIGQUIT SIGHUP
24
25
26 shutdown() {
27 tar -C "${TMP}" -c . | gpg -e --recipient "${KEY}" > "${DIR}.tar.gpg"
28 # Shred all files in memory
29 find "${TMP}" -type f -exec shred -n 100 -f -u "{}" \;
30 # Delete the link
31 rm "${DIR}"
32 # Delete the temp dir from memory
33 rm -rf "${TMP}"
34 sync
35 exit
36 }
37
38
39 writeback() {
40 trap shutdown SIGINT SIGTERM SIGKILL SIGQUIT SIGHUP
41 # Sync back to disk every 10 seconds
42 while [ 0 ]; do
43 #printf '%s Syncing back to encrypted storage\n' "$(date '+%F %T')"
44 tar -C "${TMP}" -c . | gpg -e --recipient "${KEY}" > "${DIR}.tar.gpg"
45 if [ $? -gt 0 ]; then
46 printf 'WARNING: Something went wrong syncing back to encrypted storage\n'
47 printf 'Your data is likely in danger.\n'
48 printf 'If you see this message more than once, take a manual backup\n'
49 fi
50 sleep 20 &
51 wait $!
52 done
53 }
54
55
56 open() {
57 local archive="${1}"
58
59 # Convert DIR to absolute path to avoid cd issues
60 local dirname="$(cd $(dirname ${archive}) && pwd)"
61 local basename="$(basename ${archive})"
62 local dir="${dirname}/${basename}"
63 # Create a temp dir in memory to extract to for safety
64 export TMP=$(mktemp -d /tmp/dec-XXXXXXXXXXXXXX)
65 # Link!
66 ln -s "${TMP}" "${dir}"
67
68 if [ ! -f "${dir}.tar.gpg" ]; then
69 # Tell the user if that encrypted archive does not exist.
70 printf 'Encrypted archive does not exist. Creating.\n'
71 else
72 # Extract the encrypted tarchive if it exists
73 gpg -d "${dir}.tar.gpg" | tar -C "${TMP}" -x
74 fi
75
76 writeback &
77 echo $! > "${dirname}/.${basename}.pid"
78 }
79
80
81 status() {
82 local archive=${1}
83
84 local dirname="$(dirname ${archive})"
85 local basename="$(basename ${archive})"
86 local pidfile="${dirname}/.${basename}.pid"
87
88 # If no pidfile, assume closed
89 if [ ! -f "${pidfile}" ]; then
90 printf '%s is closed\n' "${archive}"
91 return 0
92 fi
93
94 local pid="$(cat ${pidfile})"
95
96 ps "${pid}" 2>/dev/null 1>/dev/null
97 if [ $? -eq 0 ]; then
98 printf '%s is open\n' "${archive}"
99 elif [ $? -gt 0 ]; then
100 printf '%s is closed but a stale pidfile was found. Removing\n' "${archive}"
101 rm -f "${pidfile}"
102 else
103 printf '%s is closed\n' "${archive}"
104 fi
105 }
106
107
108 close() {
109 local archive=${1}
110
111 local dirname="$(dirname ${archive})"
112 local basename="$(basename ${archive})"
113 local pidfile="${dirname}/.${basename}.pid"
114 local pid="$(cat ${pidfile})"
115
116 ps "${pid}" 2>/dev/null 1>/dev/null
117 if [ $? -gt 0 ]; then
118 printf "Stale pidfile detected but share is not open. Removing\n"
119 rm -f "${pidfile}"
120 return 1
121 else
122 # Send SIGTERM (15) to tell the process to exit cleanly
123 kill -15 "${pid}"
124 [ $? -eq 0 ] && rm "${pidfile}" && return 0
125
126 printf 'Error closing archive "%s"\n' "${archive}"
127 return 1
128 fi
129 }
130
131
132 main() {
133 local action="${1}"
134 local archive="${2}"
135
136 # Input validation
137 if [ -z "${action:-}" ]; then
138 printf 'Action (open, close, or status) required\n'
139 return 1
140 fi
141 if [ -z "${archive:-}" ]; then
142 printf 'Archive to decrypt required\n'
143 return 1
144 fi
145
146 if [ -z "${KEY}" ]; then
147 printf 'KEY variable unset. Cannot re-encrypt. Exiting.\n'
148 return 1
149 fi
150
151 gpg --list-keys ${KEY} 2>/dev/null 1>/dev/null
152 if [ $? -gt 0 ]; then
153 printf 'Unknown key "%s". Cannot proceed.\n' "${KEY}"
154 return 1
155 fi
156
157 local dirname="$(dirname ${archive})"
158 local basename="$(basename ${archive})"
159 export DIR="${dirname}/${basename}"
160
161 if [ "${action}" = 'open' ]; then
162 # Check if already open
163 if [ -f "${dirname}/.${basename}.pid" ]; then
164 printf 'ERROR: Archive "%s" is already open\n' "${archive}"
165 return 1
166 else
167 printf 'Opening!\n'
168 open "${archive}"
169 return $?
170 fi
171 elif [ "${action}" = 'close' ]; then
172 # Check if already closed
173 if [ ! -f "${dirname}/.${basename}.pid" ]; then
174 printf 'ERROR: Archive "%s" is not open\n' "${archive}"
175 exit 1
176 else
177 printf 'Closing!\n'
178 close "${archive}"
179 return $?
180 fi
181 elif [ "${action}" = 'status' ]; then
182 status "${archive}"
183 return $?
184 fi
185
186 # If we make it here, something went wrong.
187 printf 'ERROR: Unknown action "%s"\n' "${action}"
188 return 1
189 }
190
191 main ${@}
|