mirror of
https://github.com/rwinkhart/sshyp.git
synced 2026-08-28 12:56:28 -04:00
171 lines
7.1 KiB
Python
Executable File
171 lines
7.1 KiB
Python
Executable File
#!/usr/bin/python3
|
|
|
|
# Main Targets:
|
|
# TODO allow proper uploading of files (currently broken)
|
|
# TODO Truncate mod times for sftp compatibility
|
|
# TODO Make it so that when a new folder is created in sshyp, it is automatically created on the remote server
|
|
# TODO Replace references to rpass/sshyp directory with a changeable variable
|
|
|
|
# sshync 2021.10.27.unreleased2
|
|
# sshync was created to solve a problem with rpass/sshyp, and as such, sshync will be bundled with sshyp until it is
|
|
# polished enough for a standalone release
|
|
|
|
# sshync is a wrapper around sftp that allows easy remote directory synchronization via Python
|
|
# openssh (on POSIX compliant Unix) is required
|
|
|
|
# sshync will always overwrite the older files with the newer files, regardless of all other conditions
|
|
# ^the age is determined by the date and time of the last modification to the files
|
|
|
|
# syncing via sshync is always done recursively
|
|
|
|
# external modules
|
|
|
|
from os import walk
|
|
from os import system as term
|
|
from os.path import getmtime
|
|
from os.path import join as path_join
|
|
|
|
|
|
# internal modules
|
|
|
|
|
|
# recursively scans a local directory for all files and saves file paths and mod times to lists
|
|
def get_file_paths_mod(directory, name_database, time_database):
|
|
file_paths = []
|
|
temp_mod_times = []
|
|
mod_times = []
|
|
for root, directories, files in walk(directory):
|
|
for filename in files:
|
|
filepath = path_join(root, filename)
|
|
file_paths.append(filepath)
|
|
temp_mod_times.append(str(getmtime(filepath)))
|
|
for time in temp_mod_times:
|
|
mod_times.append(round(float(time), 2))
|
|
open(name_database, 'w').write(str(file_paths))
|
|
open(time_database, 'w').write(str(mod_times))
|
|
return file_paths, mod_times
|
|
|
|
|
|
# recursively scans a remote directory for all files and saves file paths and mod times to lists
|
|
def get_file_paths_mod_remote(profile_dir):
|
|
# import profile data
|
|
profile_data = get_profile(profile_dir)
|
|
user = profile_data[0].replace('\n', '')
|
|
ip = profile_data[1].replace('\n', '')
|
|
port = profile_data[2].replace('\n', '')
|
|
remote_dir = profile_data[4].replace('\n', '')
|
|
identity = profile_data[5].replace('\n', '')
|
|
term("ssh -i " + "'" + identity + "'" + " -p " + port + " " + user + "@" + ip + " \"python -c \'import sshync; "
|
|
"sshync.get_file_paths_mod(" +
|
|
"\"'\"" + remote_dir + "/\"'\", " + "\"'\"/var/lib/rpass/sshyncdatabase_names\"'\", " +
|
|
"\"'\"/var/lib/rpass/sshyncdatabase_times\"'\")\'\"")
|
|
term(
|
|
'sftp -P ' + port + ' ' + user + '@' + ip + ':/var/lib/rpass/sshyncdatabase_names ' + '/var/lib/rpass/sshyncdatabase_names')
|
|
term(
|
|
'sftp -P ' + port + ' ' + user + '@' + ip + ':/var/lib/rpass/sshyncdatabase_times ' + '/var/lib/rpass/sshyncdatabase_times')
|
|
remote_mod_names = (open('/var/lib/rpass/sshyncdatabase_names').read()).replace('[', '').replace(']', '').replace(
|
|
' ', '').replace("'", '').split(',')
|
|
remote_mod_times = (open('/var/lib/rpass/sshyncdatabase_times').read()).replace('[', '').replace(']', '').replace(
|
|
' ', '').replace("'", '').split(',')
|
|
return remote_mod_names, remote_mod_times
|
|
|
|
|
|
# regular profiles check the mod time of every individual file in the directory, making them slow but versatile
|
|
def make_profile(profile_dir, local_dir, remote_dir, identity, ip, port, user):
|
|
open(profile_dir, 'w').write(user + '\n' + ip + '\n' + port + '\n' + local_dir + '\n' + remote_dir + '\n' + identity
|
|
+ '\n')
|
|
|
|
|
|
# returns the settings for a specified profile
|
|
def get_profile(profile_dir):
|
|
try:
|
|
profile_data = open(profile_dir).readlines()
|
|
except (FileNotFoundError, IndexError):
|
|
profile_data = 0
|
|
return profile_data
|
|
|
|
|
|
# sorts name lists so that local and remote are in the same order
|
|
def name_sort(local_names, remote_names):
|
|
remote_names_new = []
|
|
for ele in local_names:
|
|
if ele in remote_names:
|
|
remote_names_new.append(ele)
|
|
for ele in remote_names:
|
|
if ele not in remote_names_new:
|
|
remote_names_new.append(ele)
|
|
return remote_names_new
|
|
|
|
|
|
# sorts time lists to compensate for name list re-ordering
|
|
def time_sort(old_names, new_names, old_times):
|
|
remote_mod_times_new = []
|
|
new_pos = -1
|
|
for title in new_names:
|
|
new_pos += 1
|
|
if title in old_names:
|
|
old_pos = old_names.index(title)
|
|
remote_mod_times_new.append(old_times[old_pos])
|
|
return remote_mod_times_new
|
|
|
|
|
|
def run_profile(profile_dir):
|
|
# import profile data
|
|
profile_data = get_profile(profile_dir)
|
|
user = profile_data[0].replace('\n', '')
|
|
ip = profile_data[1].replace('\n', '')
|
|
port = profile_data[2].replace('\n', '')
|
|
local_dir = profile_data[3].replace('\n', '')
|
|
remote_dir = profile_data[4].replace('\n', '')
|
|
identity = profile_data[5].replace('\n', '')
|
|
# get file modification times
|
|
local_mod_names, local_mod_times = get_file_paths_mod(local_dir + '/', '/var/lib/rpass/sshyncdatabase_names',
|
|
'/var/lib/rpass/sshyncdatabase_times')
|
|
remote_mod_times = []
|
|
remote_mod_names, remote_mod_times_temp = get_file_paths_mod_remote('/var/lib/rpass/rpass.sshync')
|
|
for time in remote_mod_times_temp: # remove quotes from remote_mod_times
|
|
remote_mod_times.append(float(time))
|
|
lmod_short = []
|
|
rmod_short = []
|
|
matching_names = []
|
|
matching_times_local = []
|
|
matching_times_remote = []
|
|
for lmod in local_mod_names:
|
|
lmod_short.append(lmod.replace(local_dir, ''))
|
|
for rmod in remote_mod_names:
|
|
rmod_short.append(rmod.replace(remote_dir, ''))
|
|
rmod_short_old = rmod_short
|
|
rmod_short = name_sort(lmod_short, rmod_short)
|
|
remote_mod_times = time_sort(rmod_short_old, rmod_short, remote_mod_times)
|
|
i = -1
|
|
for lshort in lmod_short:
|
|
i += 1
|
|
if lshort in rmod_short:
|
|
matching_names.append(lshort)
|
|
matching_times_local.append(local_mod_times[i])
|
|
else:
|
|
print('Uploading ' + lshort)
|
|
term('sftp -p -P ' + port + ' ' + user + '@' + ip + ':' + remote_dir + lshort.replace('/', '', 1) + " <<< $'put " + local_dir + lshort.replace('/', '', 1) + "'")
|
|
i = -1
|
|
for rshort in rmod_short:
|
|
i += 1
|
|
if rshort in lmod_short:
|
|
matching_times_remote.append(float(remote_mod_times[i]))
|
|
else:
|
|
print('Downloading ' + rshort)
|
|
term('sftp -p -P ' + port + ' ' + user + '@' + ip + ':' + remote_dir + rshort.replace('/', '', 1) + ' ' + local_dir + rshort.replace('/', '', 1))
|
|
i = -1
|
|
for ltime in matching_times_local:
|
|
i += 1
|
|
if float(ltime) == matching_times_remote[i]:
|
|
print('Local ' + matching_names[i] + ' is up to date, not syncing.')
|
|
elif float(ltime) > matching_times_remote[i]:
|
|
print('Local ' + matching_names[i] + ' is newer, uploading.')
|
|
# TODO SYNC UPLOAD lmod
|
|
elif float(ltime) < matching_times_remote[i]:
|
|
print('Local ' + matching_names[i] + ' is older, downloading.')
|
|
# TODO SYNC DOWNLOAD rmod
|
|
|
|
|
|
run_profile('/var/lib/rpass/rpass.sshync')
|