improved and tested both Mconf encryptor and decryptor
This commit is contained in:
parent
ee1bfee1fb
commit
25c495d123
@ -31,83 +31,92 @@ BigBlueButton.logger = Logger.new("/var/log/bigbluebutton/decrypt.log",'daily' )
|
||||
|
||||
bbb_props = YAML::load(File.open('../../core/scripts/bigbluebutton.yml'))
|
||||
mconf_props = YAML::load(File.open('mconf.yml'))
|
||||
privatekey_path = mconf_props['privatekey_path']
|
||||
xml_url = mconf_props['get_recordings_url']
|
||||
|
||||
private_key = mconf_props['private_key']
|
||||
get_recordings_url = mconf_props['get_recordings_url']
|
||||
recording_dir = bbb_props['recording_dir']
|
||||
rawdir = "#{recording_dir}/raw"
|
||||
raw_dir = "#{recording_dir}/raw"
|
||||
archived_dir = "#{recording_dir}/status/archived"
|
||||
|
||||
xml_data = Net::HTTP.get_response(URI.parse(xml_url)).body
|
||||
doc = REXML::Document.new(xml_data)
|
||||
|
||||
files_url = []
|
||||
types = []
|
||||
keys_url = []
|
||||
md5_server_side = []
|
||||
doc.elements.each('response/recordings/recording/download/format/type') do |type|
|
||||
types << type.text
|
||||
end
|
||||
doc.elements.each('response/recordings/recording/download/format/url') do |url|
|
||||
files_url << url.text
|
||||
end
|
||||
doc.elements.each('response/recordings/recording/download/format/md5') do |md5|
|
||||
md5_server_side << md5.text
|
||||
end
|
||||
doc.elements.each('response/recordings/recording/download/format/key') do |key|
|
||||
keys_url << key.text
|
||||
doc = Nokogiri::XML(Net::HTTP.get_response(URI.parse(get_recordings_url)).body)
|
||||
returncode = doc.xpath("//returncode")
|
||||
if returncode.empty? or returncode.text != "SUCCESS"
|
||||
raise "getRecordings didn't return success"
|
||||
end
|
||||
|
||||
types.each_with_index do |eachtype, idx|
|
||||
if (eachtype == "encrypted") then
|
||||
url = files_url[idx]
|
||||
k_url = keys_url[idx]
|
||||
encrypted_file = url.split("/").last
|
||||
match = /(.*).dat/.match encrypted_file
|
||||
meeting_id = match[1]
|
||||
if not File.exist?("#{archived_dir}/#{meeting_id}.done") then
|
||||
Dir.chdir(rawdir) do
|
||||
doc.xpath("//recording").each do |recording|
|
||||
record_id = recording.xpath("recordID").text
|
||||
recording.xpath("//download/format").each do |format|
|
||||
type = format.xpath("type").text
|
||||
BigBlueButton.logger.info("type = #{type}")
|
||||
if type == "encrypted"
|
||||
meeting_id = record_id
|
||||
file_url = format.xpath("url").text
|
||||
key_file_url = format.xpath("key").text
|
||||
md5_value = format.xpath("md5").text
|
||||
|
||||
writeOut = open(encrypted_file, "wb")
|
||||
writeOut.write(open(url).read)
|
||||
writeOut.close
|
||||
BigBlueButton.logger.info("recordID = #{record_id}")
|
||||
BigBlueButton.logger.info("file_url = #{file_url}")
|
||||
BigBlueButton.logger.info("key_file_url = #{key_file_url}")
|
||||
BigBlueButton.logger.info("md5_value = #{md5_value}")
|
||||
|
||||
md5sum = Digest::MD5.file(encrypted_file)
|
||||
encrypted_file = file_url.split("/").last
|
||||
decrypted_file = File.basename(encrypted_file, '.*') + ".zip"
|
||||
if not File.exist?("#{archived_dir}/#{meeting_id}.done") then
|
||||
Dir.chdir(raw_dir) do
|
||||
BigBlueButton.logger.info("Decrypting the recording #{meeting_id}")
|
||||
|
||||
if (md5sum == md5_server_side[idx]) then
|
||||
key_file = k_url.split("/").last
|
||||
writeOut = open(key_file, "wb")
|
||||
writeOut.write(open(k_url).read)
|
||||
writeOut.close
|
||||
BigBlueButton.logger.info("Downloading the encrypted file to #{encrypted_file}")
|
||||
writeOut = open(encrypted_file, "wb")
|
||||
writeOut.write(open(file_url).read)
|
||||
writeOut.close
|
||||
|
||||
command = "openssl rsautl -decrypt -inkey #{privatekey_path} < #{key_file} > key.txt"
|
||||
BigBlueButton.logger.info(command)
|
||||
Open3.popen3(command) do | stdin, stdout, stderr|
|
||||
BigBlueButton.logger.info("command= #{command}") #{$?.exitstatus}")
|
||||
end
|
||||
command = "openssl enc -aes-256-cbc -d -pass file:key.txt < #{encrypted_file} > #{meeting_id}.zip"
|
||||
BigBlueButton.logger.info(command)
|
||||
Open3.popen3(command) do | stdin, stdout, stderr|
|
||||
BigBlueButton.logger.info("command= #{command}") #{$?.exitstatus}")
|
||||
end
|
||||
md5_calculated = Digest::MD5.file(encrypted_file)
|
||||
|
||||
BigBlueButton::MconfProcessor.unzip(rawdir, "#{meeting_id}.zip")
|
||||
if md5_calculated == md5_value
|
||||
BigBlueButton.logger.info("The calculated MD5 matches the expected value")
|
||||
key_file = key_file_url.split("/").last
|
||||
decrypted_key_file = File.basename(key_file, '.*') + ".txt"
|
||||
|
||||
BigBlueButton.logger.info("Downloading the key file to #{key_file}")
|
||||
writeOut = open(key_file, "wb")
|
||||
writeOut.write(open(key_file_url).read)
|
||||
writeOut.close
|
||||
|
||||
archived_done = File.new("#{archived_dir}/#{meeting_id}.done", "w")
|
||||
archived_done.write("Archived #{meeting_id}")
|
||||
archived_done.close
|
||||
if key_file != decrypted_key_file
|
||||
command = "openssl rsautl -decrypt -inkey #{private_key} < #{key_file} > #{decrypted_key_file}"
|
||||
status = BigBlueButton.execute(command)
|
||||
if not status.success?
|
||||
raise "Couldn't decrypt the random key with the server private key"
|
||||
end
|
||||
FileUtils.rm_r "#{key_file}"
|
||||
else
|
||||
BigBlueButton.logger.info("No public key was used to encrypt the random key")
|
||||
end
|
||||
|
||||
BigBlueButton.logger.info("Removing files")
|
||||
ZIPFILE = "#{meeting_id}.zip"
|
||||
[encrypted_file, key_file, "key.txt", ZIPFILE].each { |file| FileUtils.rm_f(file)}
|
||||
else
|
||||
FileUtils.rm_f(encrypted_file)
|
||||
end
|
||||
command = "openssl enc -aes-256-cbc -d -pass file:#{decrypted_key_file} < #{encrypted_file} > #{decrypted_file}"
|
||||
status = BigBlueButton.execute(command)
|
||||
if not status.success?
|
||||
raise "Couldn't decrypt the recording file using the random key"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
BigBlueButton::MconfProcessor.unzip("#{raw_dir}/#{meeting_id}", decrypted_file)
|
||||
|
||||
end
|
||||
archived_done = File.new("#{archived_dir}/#{meeting_id}.done", "w")
|
||||
archived_done.write("Archived #{meeting_id}")
|
||||
archived_done.close
|
||||
|
||||
[ "#{encrypted_file}", "#{decrypted_file}", "#{decrypted_key_file}" ].each { |file|
|
||||
BigBlueButton.logger.info("Removing #{file}")
|
||||
FileUtils.rm_r "#{file}"
|
||||
}
|
||||
|
||||
else
|
||||
BigBlueButton.logger.error("The calculated MD5 doesn't match the expected value")
|
||||
FileUtils.rm_f(encrypted_file)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
@ -1,2 +1,2 @@
|
||||
get_recordings_url: http://143.54.10.141/bigbluebutton/api/getRecordings?checksum=890f03ce56424120dc467f3bbf310a54fd05b541
|
||||
privatekey_path: /home/mconf/key.pem
|
||||
get_recordings_url: http://143.54.10.52/bigbluebutton/api/getRecordings?checksum=39ebeadb772553a206d43857f6287b4536b1c32c
|
||||
private_key: /home/mconf/dev/bigbluebutton/record-and-playback/key.pem
|
||||
|
@ -45,12 +45,15 @@ meeting_raw_presentation_dir = "#{raw_presentation_src}/#{meeting_id}"
|
||||
meeting_process_dir = "#{recording_dir}/process/mconf/#{meeting_id}"
|
||||
|
||||
if not FileTest.directory?(meeting_process_dir)
|
||||
FileUtils.mkdir_p "#{meeting_process_dir}/presentation_raw"
|
||||
FileUtils.mkdir_p "#{meeting_process_dir}"
|
||||
# Create a copy of the raw archives
|
||||
BigBlueButton.logger.info("Copying the recording raw files from #{meeting_raw_dir} to #{meeting_process_dir}")
|
||||
FileUtils.cp_r Dir.glob("#{meeting_raw_dir}/*"), meeting_process_dir
|
||||
BigBlueButton.logger.info("Copying the recording presentation from #{meeting_raw_presentation_dir}/#{meeting_id} to #{meeting_process_dir}/presentation_raw")
|
||||
FileUtils.cp_r Dir.glob("#{meeting_raw_presentation_dir}/#{meeting_id}/*"), "#{meeting_process_dir}/presentation_raw"
|
||||
|
||||
# There's no need to backup the presentation raw folder now
|
||||
# FileUtils.mkdir_p "#{meeting_process_dir}/presentation_raw"
|
||||
# BigBlueButton.logger.info("Copying the recording presentation from #{meeting_raw_presentation_dir}/#{meeting_id} to #{meeting_process_dir}/presentation_raw")
|
||||
# FileUtils.cp_r Dir.glob("#{meeting_raw_presentation_dir}/#{meeting_id}/*"), "#{meeting_process_dir}/presentation_raw"
|
||||
|
||||
process_done = File.new("#{recording_dir}/status/processed/#{meeting_id}-mconf.done", "w")
|
||||
process_done.write("Processed #{meeting_id}")
|
||||
|
@ -62,20 +62,41 @@ done_files.each do |df|
|
||||
|
||||
# encrypt files
|
||||
command = "openssl enc -aes-256-cbc -pass file:#{meeting_id}.txt < #{meeting_id}.zip > #{meeting_id}.dat"
|
||||
BigBlueButton.execute(command)
|
||||
status = BigBlueButton.execute(command)
|
||||
if not status.success?
|
||||
raise "Couldn't encrypt the recording file using the random key"
|
||||
end
|
||||
|
||||
FileUtils.rm_f "#{meeting_id}.zip"
|
||||
|
||||
key_filename = ""
|
||||
if metadata.has_key?('public_key')
|
||||
if metadata.has_key?('public-key')
|
||||
key_filename = "#{meeting_id}.enc"
|
||||
BigBlueButton.logger.info("Unescaping public key")
|
||||
public_key_decoded = CGI::unescape("#{metadata[:public_key.to_s]}")
|
||||
public_key = File.new("public_key.pem","w")
|
||||
#BigBlueButton.logger.info("Unescaping public key")
|
||||
#public_key_decoded = CGI::unescape("#{metadata['public-key'].to_s}")
|
||||
# The key is already unescaped in the metadata!!
|
||||
public_key_decoded = "#{metadata['public-key'].to_s}"
|
||||
public_key_filename = "public-key.pem"
|
||||
public_key = File.new("#{public_key_filename}", "w")
|
||||
public_key.write "#{public_key_decoded}"
|
||||
public_key.close
|
||||
|
||||
command = "openssl rsautl -encrypt -pubin -inkey public-key.pem < #{meeting_id}.txt > #{meeting_id}.enc"
|
||||
BigBlueButton.execute(command)
|
||||
FileUtils.rm_f "#{meeting_id}.txt"
|
||||
public_key = File.new("#{public_key_filename}", "r")
|
||||
counter = 0
|
||||
while (line = public_key.gets)
|
||||
BigBlueButton.logger.info "#{counter}: #{line}"
|
||||
counter = counter + 1
|
||||
end
|
||||
public_key.close
|
||||
|
||||
command = "openssl rsautl -encrypt -pubin -inkey #{public_key_filename} < #{meeting_id}.txt > #{meeting_id}.enc"
|
||||
status = BigBlueButton.execute(command)
|
||||
if not status.success?
|
||||
raise "Couldn't encrypt the random key using the server public key passed as metadata"
|
||||
end
|
||||
|
||||
# Comment it for testing
|
||||
FileUtils.rm_f ["#{meeting_id}.txt", "#{public_key_filename}"]
|
||||
else
|
||||
key_filename = "#{meeting_id}.txt"
|
||||
BigBlueButton.logger.warn "No public key was found in the meeting's metadata"
|
||||
@ -86,9 +107,6 @@ done_files.each do |df|
|
||||
|
||||
BigBlueButton.logger.info("Creating metadata.xml")
|
||||
|
||||
# TODO: create a flag to indicate if the file .enc is encrypted or not
|
||||
# due to the presence the public key in the meeting's metadata
|
||||
|
||||
# Create metadata.xml
|
||||
b = Builder::XmlMarkup.new(:indent => 2)
|
||||
metaxml = b.recording {
|
||||
@ -128,6 +146,13 @@ done_files.each do |df|
|
||||
BigBlueButton.logger.info("Removing published files: #{meeting_publish_dir}")
|
||||
FileUtils.remove_entry_secure meeting_publish_dir, :force => true, :verbose => true
|
||||
|
||||
# Remove all the recording flags
|
||||
FileUtils.rm_f [ "#{recording_dir}/status/processed/#{meeting_id}-mconf.done",
|
||||
"#{recording_dir}/status/sanity/#{meeting_id}.done",
|
||||
"#{recording_dir}/status/recorded/#{meeting_id}.done",
|
||||
"#{recording_dir}/status/archived/#{meeting_id}.done" ]
|
||||
|
||||
# Comment it for testing
|
||||
BigBlueButton.logger.info("Removing the recording raw files: #{meeting_raw_dir}")
|
||||
FileUtils.remove_entry_secure meeting_raw_dir, :force => true, :verbose => true
|
||||
BigBlueButton.logger.info("Removing the recording presentation: #{meeting_raw_presentation_dir}")
|
||||
|
Loading…
Reference in New Issue
Block a user