-
Notifications
You must be signed in to change notification settings - Fork 0
/
keepass-rclone-lib.sh
executable file
·182 lines (145 loc) · 5.87 KB
/
keepass-rclone-lib.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#!/bin/bash
# Important note:
# If you don't synchronize but then edit the other file,
# the newer modification time on the second file edited
# will cause data to be overridden.
# The solution would be to merge manually
# (Database --> Merge from database).
#####################
## Configuration ##
#####################
# Name of your remote storage as defined in Rclone
DRIVE_NAME="google-drive"
# Name and locations of the passwords file
DB_FILE_NAME="keepass.kdbx"
LOCAL_LOCATION="$HOME/Documents/keepass"
MERGE_LOCATION="$LOCAL_LOCATION/merging"
REMOTE_LOCATION="keepass"
# Refresh time in second
REFRESH_TIME=1200
# Name of the last_mtime file
LAST_MTIME_FILENAME="last_mtime.txt"
# Notify urgency (low, normal, critical)
MERGE_NOTIFY_URGENCY="normal"
#####################
# Compose full path to local and remote database files
LOCAL_PATH="$LOCAL_LOCATION/$DB_FILE_NAME"
REMOTE_PATH="$REMOTE_LOCATION/$DB_FILE_NAME"
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
# Alias import and export commands and make them available within the functions
alias passwords_export="rclone copy $LOCAL_PATH $DRIVE_NAME:$REMOTE_LOCATION"
alias passwords_import="rclone copy $DRIVE_NAME:$REMOTE_PATH $LOCAL_LOCATION"
alias passwords_import_to_merge="rclone copy $DRIVE_NAME:$REMOTE_PATH $MERGE_LOCATION"
shopt -s expand_aliases
function format_datetime_from_string () {
echo `date -d "$1" +"%F %T.%3N"`
}
# Parse local passwords file modification time using the stat command
function get_local_passwords_mtime () {
local string=`stat -c %y $LOCAL_PATH | cut -d ' ' -f 1,2;`
echo `format_datetime_from_string "$string"`
}
# Parse remote passwords file modification time using Rclone's lsl command
# See: https://rclone.org/commands/rclone_lsl/
function get_remote_passwords_mtime () {
output=`rclone lsl $DRIVE_NAME:$REMOTE_PATH 2>/dev/null`
if [ $? -eq 3 ]; then
unset output
return 1
else
local string=`echo "$output" | tr -s ' ' | cut -d ' ' -f 3,4;`
echo `format_datetime_from_string "$string"`
unset output
return 0
fi
}
function save_local_passwords_last_mtime_file () {
# Create a file to log the last modification time of the local database
local mtime=$(get_local_passwords_mtime)
local output_file="$LOCAL_LOCATION/$LAST_MTIME_FILENAME"
# Write the modification time to the file
echo "$mtime" > "$output_file"
}
function read_last_mtime_log () {
local mtime_file="$LOCAL_LOCATION/$LAST_MTIME_FILENAME"
# Check if the log file exists
if [[ -e "$mtime_file" ]]; then
# Read the content of the log file
local mtime_string
mtime_string=$(<"$mtime_file")
echo "$(format_datetime_from_string "$mtime_string")"
else
echo "Error: mtime file does not exist at $mtime_file."
return 1
fi
}
function sync_passwords () {
printf "Checking local passwords database...\n"
if [[ ! -e "$LOCAL_PATH" ]]; then
printf "Local passwords file does not exist!\n"
printf "Importing from remote...\t"
passwords_import
save_local_passwords_last_mtime_file
printf "Done!\n"
return 0
fi
printf "Found local passwords database!\n\n"
# Storing the values so they can be used for printing and then conversion
local human_readable_local_mtime=`get_local_passwords_mtime`
local human_readable_last_mtime=`read_last_mtime_log`
printf "Checking remote passwords database...\n"
human_readable_remote_mtime=`get_remote_passwords_mtime 2>/dev/null` # Also storing but with exit status require for checking
if [ $? -ne 0 ]; then
printf "No remote passwords database found!\n"
printf "Exporting...\t"
passwords_export
printf "Done!\n"
return 0
fi
printf "Found remote passwords database!\n\n"
# Printing modification times to the user
printf "Local passwords file modification time:\t\t$human_readable_local_mtime\n"
printf "Remote passwords file modification time:\t$human_readable_remote_mtime\n"
printf "Last recorded modification time:\t\t$human_readable_last_mtime\n\n"
# The conversion is required for the comparison in the following if statement
local_mtime_in_seconds_since_epoch=$(date -d "$human_readable_local_mtime" +%s)
remote_mtime_in_seconds_since_epoch=$(date -d "$human_readable_remote_mtime" +%s)
last_mtime_in_seconds_since_epoch=$(date -d "$human_readable_last_mtime" +%s)
unset human_readable_remote_mtime
if [ "$last_mtime_in_seconds_since_epoch" -lt "$remote_mtime_in_seconds_since_epoch" -a "$last_mtime_in_seconds_since_epoch" -ne "$local_mtime_in_seconds_since_epoch" ]; then
passwords_import_to_merge
printf "Both local and remote passwords database had been changed and require merging!\n"
selection=$(notify-send -u $MERGE_NOTIFY_URGENCY "keepass-rclone-sync: Both local and remote passwords databases had been changed and require merging!" -A 0="Merge now" -A 1="Later")
if [ ! -n "$selection" ]; then
# Closing notify window
return 0
elif [ "$selection" -eq 1 ]; then
# Clicking "Later" in notify window
return 0
elif [ "$selection" -eq 0 ]; then
# Clicking "Merge now" in notify window
gnome-terminal -- bash $SCRIPT_DIR/keepass-merge.sh
return 0
fi
elif [ "$local_mtime_in_seconds_since_epoch" -gt "$remote_mtime_in_seconds_since_epoch" ]; then
# Handle local being newer than remote
printf "Local passwords file found to be newer than remote!\n"
printf "Exporting...\t"
passwords_export
save_local_passwords_last_mtime_file
printf "Done!\n"
return 0
elif [ "$local_mtime_in_seconds_since_epoch" -lt "$remote_mtime_in_seconds_since_epoch" ]; then
# Handle remote being newer than local
printf "Local passwords file found to be older than remote!\n"
printf "Importing...\t"
passwords_import
save_local_passwords_last_mtime_file
printf "Done!\n"
return 0
else
printf "Password files are synchronized.\n"
save_local_passwords_last_mtime_file
return 0
fi
}