6 $veracrypt_passphrase = 'asdf'
7 $veracrypt_hidden_passphrase = 'fdsa'
8 $veracrypt_volume_name = 'veracrypt'
10 def veracrypt_volume_size_in_GNOME(is_hidden)
11 is_hidden ? '52 MB' : '105 MB'
14 def create_veracrypt_keyfile()
15 keyfile = Tempfile.new('veracrypt-keyfile', $config["TMPDIR"])
21 def reply_prompt(r_f, w_f, prompt_re, answer)
22 r_f.expect(prompt_re) do
23 debug_log "got prompt, typing #{answer}"
24 sleep 1 # tcplay takes some time before it's ready to read our input
29 def create_veracrypt_volume(type, with_keyfile)
30 @veracrypt_is_hidden = (type == 'hidden')
31 @veracrypt_needs_keyfile = with_keyfile
32 step "I temporarily create a 100 MiB raw disk named \"#{$veracrypt_volume_name}\""
33 disk_path = $vm.storage.disk_path($veracrypt_volume_name)
34 keyfile = create_veracrypt_keyfile()
35 fatal_system "losetup -f '#{disk_path}'"
36 loop_dev = `losetup -j '#{disk_path}'`.split(':').first
37 tcplay_create_cmd = "tcplay --create --device='#{loop_dev}'" \
38 + " --weak-keys --insecure-erase"
39 tcplay_create_cmd += " --hidden" if @veracrypt_is_hidden
40 tcplay_create_cmd += " --keyfile='#{keyfile}'" if @veracrypt_needs_keyfile
41 debug_log "tcplay create command: #{tcplay_create_cmd}"
42 PTY.spawn(tcplay_create_cmd) do |r_f, w_f, pid|
45 reply_prompt(r_f, w_f, /^Passphrase:\s/, $veracrypt_passphrase)
46 reply_prompt(r_f, w_f, /^Repeat passphrase:\s/, $veracrypt_passphrase)
47 if @veracrypt_is_hidden
48 reply_prompt(r_f, w_f, /^Passphrase for hidden volume:\s/,
49 $veracrypt_hidden_passphrase)
50 reply_prompt(r_f, w_f, /^Repeat passphrase:\s/,
51 $veracrypt_hidden_passphrase)
52 reply_prompt(r_f, w_f, /^Size of hidden volume.*:\s/, '50M')
54 reply_prompt(r_f, w_f, /^\s*Are you sure you want to proceed/, 'y')
55 r_f.expect(/^All done!/)
60 $?.exitstatus == 0 or raise "#{tcplay_create_cmd} exited with #{$?.exitstatus}"
62 tcplay_map_cmd = "tcplay --map=veracrypt --device='#{loop_dev}'"
63 tcplay_map_cmd += " --keyfile='#{keyfile}'" if @veracrypt_needs_keyfile
64 debug_log "tcplay map command: #{tcplay_map_cmd}"
65 PTY.spawn(tcplay_map_cmd) do |r_f, w_f, pid|
68 reply_prompt(r_f, w_f, /^Passphrase:\s/,
69 @veracrypt_is_hidden ? $veracrypt_hidden_passphrase : $veracrypt_passphrase)
70 r_f.expect(/^All ok!/)
75 $?.exitstatus == 0 or raise "#{tcplay_map_cmd} exited with #{$?.exitstatus}"
77 fatal_system "mkfs.vfat '/dev/mapper/veracrypt' >/dev/null"
78 Dir.mktmpdir('veracrypt-mountpoint', $config["TMPDIR"]) { |mountpoint|
79 fatal_system "mount -t vfat '/dev/mapper/veracrypt' '#{mountpoint}'"
80 # must match SecretFileOnVeraCryptVolume.png when displayed in GNOME Files
81 FileUtils.cp('/usr/share/common-licenses/GPL-3', "#{mountpoint}/SecretFile")
82 fatal_system "umount '#{mountpoint}'"
84 fatal_system "tcplay --unmap=veracrypt"
85 fatal_system "losetup -d '#{loop_dev}'"
89 When /^I plug a USB drive containing a (.+) VeraCrypt volume( with a keyfile)?$/ do |type, with_keyfile|
90 create_veracrypt_volume(type, with_keyfile)
91 step "I plug USB drive \"#{$veracrypt_volume_name}\""
94 When /^I plug and mount a USB drive containing a (.+) VeraCrypt file container( with a keyfile)?$/ do |type, with_keyfile|
95 create_veracrypt_volume(type, with_keyfile)
96 @veracrypt_shared_dir_in_guest = share_host_files($vm.storage.disk_path($veracrypt_volume_name))
97 $vm.execute_successfully(
98 "chown #{LIVE_USER}:#{LIVE_USER} '#{@veracrypt_shared_dir_in_guest}/#{$veracrypt_volume_name}'"
102 When /^I unlock and mount this VeraCrypt (volume|file container) with Unlock VeraCrypt Volumes$/ do |support|
103 step 'I start "Unlock VeraCrypt Volumes" via GNOME Activities Overview'
106 @screen.wait_and_click('Gtk3UnlockButton.png', 10)
107 when 'file container'
108 @screen.wait_and_click('UnlockVeraCryptVolumesAddButton.png', 10)
109 @screen.wait('Gtk3FileChooserDesktopButton.png', 10)
110 @screen.type(@veracrypt_shared_dir_in_guest + '/' + $veracrypt_volume_name + Sikuli::Key.ENTER)
112 @screen.wait('VeraCryptUnlockDialog.png', 10)
114 @veracrypt_is_hidden ? $veracrypt_hidden_passphrase : $veracrypt_passphrase
116 @screen.click('VeraCryptUnlockDialogHiddenVolumeLabel.png') if @veracrypt_is_hidden
117 @screen.type(Sikuli::Key.ENTER)
118 @screen.waitVanish('VeraCryptUnlockDialog.png', 10)
120 $vm.execute_successfully('ls /media/amnesia/*/SecretFile')
124 When /^I unlock and mount this VeraCrypt (volume|file container) with GNOME Disks$/ do |support|
125 step 'I start "Disks" via GNOME Activities Overview'
126 disks = Dogtail::Application.new('gnome-disks')
129 disks.children(roleName: 'table cell').find { |row|
130 /^105 MB Drive/.match(row.name)
132 when 'file container'
133 gnome_shell = Dogtail::Application.new('gnome-shell')
134 menu = gnome_shell.menu('Disks')
136 @screen.wait_and_click('GnomeDisksAttachDiskImageMenuEntry.png', 10)
137 # Once we use a more recent Dogtail that can deal with UTF-8 (#12185),
139 # gnome_shell.child('Attach Disk Imageā¦', roleName: 'label').click
140 # Otherwise Disks is sometimes minimized, for some reason I don't understand
142 attach_dialog = disks.child('Select Disk Image to Attach', roleName: 'file chooser', showingOnly: true)
143 attach_dialog.child('Set up read-only loop device', roleName: 'check box').click
144 filter = attach_dialog.child('Disk Images (*.img, *.iso)', roleName: 'combo box')
148 filter.child('All Files', roleName: 'menu item').click
151 # we probably clicked too early, which triggered an "Attempting
152 # to generate a mouse event at negative coordinates" Dogtail error
156 @screen.type(@veracrypt_shared_dir_in_guest + '/' + $veracrypt_volume_name)
157 sleep 2 # avoid ENTER being eaten by the auto-completion system
158 @screen.type(Sikuli::Key.ENTER)
161 disks.children(roleName: 'table cell').find { |row|
162 /^105 MB Loop Device/.match(row.name)
170 disks.child('', roleName: 'panel', description: 'Unlock selected encrypted partition').click
171 unlock_dialog = disks.dialog('Set options to unlock')
172 passphrase_field = unlock_dialog.child('', roleName: 'password text')
173 passphrase_field.grabFocus()
174 passphrase_field.typeText(
175 @veracrypt_is_hidden ? $veracrypt_hidden_passphrase : $veracrypt_passphrase
177 if @veracrypt_needs_keyfile
178 # not accessible and unreachable with the keyboard (#15952)
179 @screen.click('GnomeDisksUnlockDialogKeyfileComboBox.png')
180 @screen.wait('Gtk3FileChooserDesktopButton.png', 10)
181 $vm.file_overwrite('/tmp/keyfile', 'asdf')
182 @screen.type('/tmp/keyfile' + Sikuli::Key.ENTER)
183 @screen.waitVanish('Gtk3FileChooserDesktopButton.png', 10)
185 @screen.wait_and_click('GnomeDisksUnlockDialogHiddenVolumeLabel.png', 10) if @veracrypt_is_hidden
186 # Clicking is robust neither with Dogtail (no visible effect) nor with Sikuli
187 # (that sometimes clicks just a little bit outside of the button)
188 @screen.wait('Gtk3UnlockButton.png', 10)
189 @screen.type('u', Sikuli::KeyModifier.ALT) # "Unlock" button
190 try_for(10, :msg => "Failed to mount the unlocked volume") do
192 unlocked_volume = disks.child('105 MB VeraCrypt/TrueCrypt', roleName: 'panel', showingOnly: true)
193 unlocked_volume.click
194 # Move the focus down to the "Filesystem\n107 MB FAT" item (that Dogtail
195 # is not able to find) using the 'Down' arrow, in order to display
196 # the "Mount selected partition" button.
197 unlocked_volume.grabFocus()
198 sleep 0.5 # otherwise the following key press is sometimes lost
199 disks.pressKey('Down')
200 disks.child('', roleName: 'panel', description: 'Mount selected partition', showingOnly: true).click
203 # we probably did something too early, which triggered a Dogtail error
204 # such as "Attempting to generate a mouse event at negative coordinates"
208 try_for(10, :msg => "/media/amnesia/*/SecretFile does not exist") do
209 $vm.execute_successfully('ls /media/amnesia/*/SecretFile')
213 When /^I open this VeraCrypt volume in GNOME Files$/ do
214 $vm.spawn('nautilus /media/amnesia/*', user: LIVE_USER)
215 Dogtail::Application.new('nautilus').window(
216 veracrypt_volume_size_in_GNOME(@veracrypt_is_hidden) + ' Volume'
220 When /^I lock the currently opened VeraCrypt (volume|file container)$/ do |support|
221 $vm.execute_successfully(
222 'udisksctl unmount --block-device /dev/mapper/tcrypt-*',
225 device = support == 'volume' ? '/dev/sda' : '/dev/loop1'
226 $vm.execute_successfully(
227 "udisksctl lock --block-device #{device}",
232 Then /^the VeraCrypt (volume|file container) has been unmounted and locked$/ do |support|
233 assert(! $vm.execute('ls /media/amnesia/*/SecretFile').success?)
234 assert(! $vm.execute('ls /dev/mapper/tcrypt-*').success?)