-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfilefunc.rb
More file actions
129 lines (113 loc) · 4.9 KB
/
filefunc.rb
File metadata and controls
129 lines (113 loc) · 4.9 KB
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
require 'aesfunc'
def write_file(filename, content)
output = File.new(filename,'w')
output.write(content)
output.flush
output.close
end
def encrypt_file(filename, password)
content = IO.read(filename)
content_hash = Digest::SHA256.digest(content)
file_cipher = aes256_encrypt(content_hash, content).unpack('H*')[0]
hash_cipher = aes256_encrypt(password, content_hash).unpack('H*')[0]
return {:file=> file_cipher, :hash=> hash_cipher}
end
def encrypt_dir_file(password)
filename = '.dir.yaml'
content = IO.read(filename)
file_cipher = aes256_encrypt(password, content).unpack('H*')[0]
cipher_hash = Digest::SHA256.digest(file_cipher)
hash_cipher = aes256_encrypt(password, cipher_hash).unpack('H*')[0]
return {:file=> file_cipher, :hash=> hash_cipher}
end
def get_file_hash(path)
Digest::SHA256.digest(IO.read(path)).to_s.unpack('H*')[0]
end
def get_encrypted_file_hash(path, password)
aes256_encrypt(password, get_file_hash(path))
end
def build_dir_structure(root, path, dir_hash, password)
current = Dir.new(path)
current.each do |file|
next if file=='.' or file=='..'
file_path = File.join(path, file)
if File.directory? file_path
build_dir_structure(root, file_path,dir_hash,password)
else
dir_key = file_path.split(root)[1]
dir_hash[dir_key] = {}
encrypted = encrypt_file(file_path,password)
dir_hash[dir_key][File.mtime(dir_key).to_i] = {:cipher_hash=>Digest::SHA256.digest(encrypted[:file]).unpack('H*')[0],:key=>encrypted[:hash]}
end
end
end
def update_dir(dir_path, dir_hash,password)
dir_hash.each do |k,v|
puts "Updating #{k}"
latest_rev = dir_hash[k].to_a.last[0]
if File.exists? k
encrypted = encrypt_file(k,password)
encrypted_cipher_hash = Digest::SHA256.digest(encrypted[:file]).unpack('H*')[0]
params = {}
params[:file] = encrypted[:file]
params[:cipher_hash] = Digest::SHA256.digest(encrypted[:file]).to_s.unpack('H*')[0]
remote_existence = RestClient.get("#{PICKBOX_SERVER_URL}/exists/" + encrypted_cipher_hash)
if remote_existence.empty?
# Upload local file if it hasn't been synced to remote
dir_hash[k][File.mtime(k).to_i] = {:cipher_hash=>encrypted_cipher_hash, :key=>encrypted[:hash]}
RestClient.post("#{PICKBOX_SERVER_URL}/upload",params)
else
# Update local file if remote revision is newer
unless encrypted_cipher_hash == v[latest_rev][:key]
remote_file_cipher = [RestClient.get("#{PICKBOX_SERVER_URL}/#{v[latest_rev][:cipher_hash]}")].pack('H*')
decrypt_key = aes256_decrypt(password,[v[latest_rev][:key]].pack('H*'))
decrypted_file = aes256_decrypt(decrypt_key,remote_file_cipher)
write_file(k, decrypted_file)
File.utime(Time.now, Time.at(latest_rev), k)
end
end
else
# Download remote file if such file doesn't exist locally
remote_file_cipher = [RestClient.get("#{PICKBOX_SERVER_URL}/#{v[latest_rev][:cipher_hash]}")].pack('H*')
decrypt_key = aes256_decrypt(password,[v[latest_rev][:key]].pack('H*'))
decrypted_file = aes256_decrypt(decrypt_key,remote_file_cipher)
FileUtils.mkpath(k.split(k.split(File::SEPARATOR).last)[0]) if k.include? File::SEPARATOR
write_file(k, decrypted_file)
File.utime(Time.now, Time.at(latest_rev), k)
end
end
write_file(dir_path, dir_hash.to_yaml)
end
def list_revisions(filename, dir_hash, password)
current_hash = encrypt_file(filename, password)[:file]
current_hash = Digest::SHA256.digest(current_hash).unpack('H*')[0]
revs = dir_hash[filename].to_a.reverse
indication = false
revs.each do |rev|
if current_hash == rev[1][:cipher_hash] and not indication
print ' *'
indication = true
end
puts "\t#{rev[1][:cipher_hash][0..7]}\t#{Time.at(rev[0])}"
end
end
def revert(filename, revision, dir_hash, dir_path, password)
revs = dir_hash[filename]
timestamp = nil
revs.each do |k,v|
if v[:cipher_hash][0..7]==revision
timestamp = k
break
end
end
if timestamp.nil?
puts 'Revision does not exist'
exit 14
end
remote_file_cipher = [RestClient.get("#{PICKBOX_SERVER_URL}/#{revs[timestamp][:cipher_hash]}")].pack('H*')
decrypt_key = aes256_decrypt(password,[revs[timestamp][:key]].pack('H*'))
decrypted_file = aes256_decrypt(decrypt_key,remote_file_cipher)
write_file(ARGV[1], decrypted_file)
revs[File.mtime(filename).to_i] = {:cipher_hash=>revs[timestamp][:cipher_hash], :key=>revs[timestamp][:key]}
write_file(dir_path, dir_hash.to_yaml)
end