Make new "Show Passphrase" label translatable (#15102)
[tails-persistence-setup.git] / lib / Tails / Persistence / Step / Bootstrap.pm
blobe94f2664238862777df2bdcf3ffe496373719f2e
1 =head1 NAME
3 Tails::Persistence::Step::Bootstrap - bootstrap persistent storage
5 =cut
7 package Tails::Persistence::Step::Bootstrap;
9 use 5.10.1;
10 use strictures 2;
12 use Function::Parameters;
13 use Glib qw{TRUE FALSE};
15 use IPC::System::Simple qw{systemx};
16 use Number::Format qw(:subs);
17 use Types::Standard qw(HashRef);
19 use Locale::gettext;
20 use POSIX;
21 setlocale(LC_MESSAGES, "");
22 textdomain("tails-persistence-setup");
24 use Moo;
25 use MooX::late;
26 use namespace::clean;
29 =head1 ATTRIBUTES
31 =cut
33 foreach (qw{intro label verify_label warning_label}) {
34 has $_ => (
35 lazy_build => 1,
36 is => 'rw',
37 isa => 'Gtk3::Label',
41 foreach (qw{passphrase_entry verify_passphrase_entry}) {
42 has $_ => (
43 lazy_build => 1,
44 is => 'rw',
45 isa => 'Gtk3::Entry',
46 builder => '_build_passphrase_entry',
50 has 'table_alignment' => (
51 lazy_build => 1,
52 is => 'rw',
53 isa => 'Gtk3::Alignment',
55 has 'table' => (
56 lazy_build => 1,
57 is => 'rw',
58 isa => 'Gtk3::Table',
60 has 'warning_area' => (
61 lazy_build => 1,
62 is => 'rw',
63 isa => 'Gtk3::HBox',
65 has 'warning_image' => (
66 lazy_build => 1,
67 is => 'rw',
68 isa => 'Gtk3::Image',
70 has 'size_of_free_space' => (
71 required => 1,
72 is => 'ro',
73 isa => 'Int',
75 foreach (qw{mount_persistence_partition_cb create_configuration_cb}) {
76 has $_ => (
77 required => 1,
78 is => 'ro',
79 isa => 'CodeRef',
83 has 'passphrase_check_button' => (
84 lazy_build => 1,
85 is => 'rw',
86 isa => 'Gtk3::CheckButton',
90 =head1 CONSTRUCTORS
92 =cut
94 method BUILD (@args) {
95 $self->title->set_text($self->encoding->decode(gettext(
96 q{Persistence wizard - Persistent volume creation}
97 )));
98 $self->subtitle->set_text($self->encoding->decode(gettext(
99 q{Choose a passphrase to protect the persistent volume}
100 )));
101 $self->description->set_markup($self->encoding->decode(sprintf(
102 # TRANSLATORS: size, device vendor, device model
103 gettext(q{A %s persistent volume will be created on the <b>%s %s</b> device. Data on this volume will be stored in an encrypted form protected by a passphrase.}),
104 format_bytes($self->size_of_free_space, mode => "iec"),
105 $self->drive_vendor,
106 $self->drive_model,
107 )));
108 $self->go_button->set_label($self->encoding->decode(gettext(q{Create})));
111 method _build_main_widget () {
112 my $box = Gtk3::VBox->new();
113 $box->set_spacing(6);
114 $box->pack_start($self->title, FALSE, FALSE, 0);
115 $box->pack_start($self->intro, FALSE, FALSE, 0);
116 $box->pack_start($self->subtitle, FALSE, FALSE, 0);
117 $box->pack_start($self->description, FALSE, FALSE, 0);
119 my $show_passphrase_box = Gtk3::Box->new("horizontal", 0);
120 $show_passphrase_box->pack_end($self->passphrase_check_button, FALSE, FALSE, 0);
121 $box->add($show_passphrase_box);
122 my $passphrase_box = Gtk3::VBox->new(FALSE, 6);
123 $passphrase_box->set_spacing(6);
124 $passphrase_box->pack_start($self->table_alignment, FALSE, FALSE, 0);
125 $passphrase_box->pack_start($self->warning_area, FALSE, FALSE, 0);
127 $box->pack_start($passphrase_box, FALSE, FALSE, 0);
129 $self->verify_passphrase_entry->set_activates_default(TRUE);
131 $box->pack_start($self->status_area, FALSE, FALSE, 0);
133 my $button_alignment = Gtk3::Alignment->new(1.0, 0, 0.2, 1.0);
134 $button_alignment->set_padding(0, 0, 10, 10);
135 $button_alignment->add($self->go_button);
136 $box->pack_start($button_alignment, FALSE, FALSE, 0);
137 $self->passphrase_entry->grab_focus();
139 return $box;
142 method _build_intro () {
143 my $intro = Gtk3::Label->new('');
144 $intro->set_alignment(0.0, 0.5);
145 $intro->set_padding(10, 10);
146 $intro->set_line_wrap(TRUE);
147 $intro->set_line_wrap_mode('word');
148 $intro->set_single_line_mode(FALSE);
149 $intro->set_max_width_chars(72);
150 $intro->set_markup($self->encoding->decode(gettext(
151 q{<b>Beware!</b> Using persistence has consequences that must be well understood. Tails can't help you if you use it wrong! See the <i>Encrypted persistence</i> page of the Tails documentation to learn more.}
152 )));
154 return $intro;
157 method _build_warning_image () {
158 Gtk3::Image->new_from_stock('gtk-dialog-info', 'menu');
161 method _build_warning_area () {
162 my $ext_hbox = Gtk3::HBox->new(FALSE, 0);
163 $ext_hbox->set_border_width(10);
164 $ext_hbox->set_spacing(6);
166 my $box = Gtk3::HBox->new(FALSE, 12);
167 $box->set_spacing(6);
168 $box->pack_start($self->warning_image, FALSE, FALSE, 0);
169 $box->pack_start($self->warning_label, FALSE, FALSE, 0);
171 $ext_hbox->pack_start($box, FALSE, FALSE, 0);
172 $ext_hbox->pack_start(Gtk3::Label->new(' '), FALSE, FALSE, 0);
174 return $ext_hbox;
177 method _build_label () {
178 my $label = Gtk3::Label->new($self->encoding->decode(gettext(
179 q{Passphrase:}
180 )));
181 $label->set_alignment(0.0, 0.5);
182 return $label;
185 method _build_verify_label () {
186 my $label = Gtk3::Label->new($self->encoding->decode(gettext(
187 q{Verify Passphrase:}
188 )));
189 $label->set_alignment(0.0, 0.5);
190 return $label;
193 method _build_warning_label () {
194 my $label = Gtk3::Label->new('');
195 $label->set_padding(10, 0);
196 $label->set_markup(
197 "<i>"
198 . $self->encoding->decode(gettext(q{Passphrase can't be empty}))
199 . "</i>"
201 return $label;
204 method _build_passphrase_entry () {
205 my $entry = Gtk3::Entry->new;
206 $entry->set_visibility(FALSE);
207 $entry->signal_connect("changed" => sub { $self->passphrase_entry_changed });
209 return $entry;
212 method _build_table_alignment () {
213 my $table_alignment = Gtk3::Alignment->new(0.0, 0.0, 1.0, 1.0);
214 $table_alignment->add($self->table);
215 return $table_alignment;
218 method _build_table () {
219 my $table = Gtk3::Table->new(1, 2, FALSE);
220 $table->set_border_width(10);
221 $table->set_col_spacings(12);
222 $table->set_row_spacings(6);
223 $table->attach($self->label, 0, 1, 0, 1, 'fill', [qw{expand fill}], 0, 0);
224 $table->attach_defaults($self->passphrase_entry, 1, 2, 0, 1);
225 $table->attach($self->verify_label, 0, 1, 1, 2, 'fill', [qw{expand fill}], 0, 0);
226 $table->attach_defaults($self->verify_passphrase_entry, 1, 2, 1, 2);
228 return $table;
231 method _build_passphrase_check_button () {
232 my $check_button = Gtk3::CheckButton->new_with_label(
233 $self->encoding->decode(gettext(q{Show Passphrase}))
235 $check_button->set_active(FALSE);
236 $check_button->signal_connect(toggled => sub { $self->passphrase_check_button_toggled });
238 return $check_button;
242 =head1 METHODS
244 =cut
246 method update_passphrase_ui () {
247 my $passphrase = $self->passphrase_entry->get_text;
248 my $passphrase_verify = $self->verify_passphrase_entry->get_text;
250 # TODO: check passphrase strength (#7002)
252 if ($passphrase ne $passphrase_verify) {
253 $self->warning_label->set_markup(
254 "<i>"
255 . $self->encoding->decode(gettext(q{Passphrases do not match}))
256 . "</i>"
258 $self->warning_image->show;
259 $self->go_button->set_sensitive(FALSE);
261 elsif (length($passphrase) == 0) {
262 $self->warning_label->set_markup(
263 "<i>"
264 . $self->encoding->decode(gettext(q{Passphrase can't be empty}))
265 . "</i>"
267 $self->warning_image->show;
268 $self->go_button->set_sensitive(FALSE);
270 else {
271 $self->warning_image->hide;
272 $self->warning_label->set_text(' ');
273 $self->go_button->set_sensitive(TRUE);
277 method passphrase_entry_changed () {
278 $self->update_passphrase_ui;
281 method passphrase_check_button_toggled () {
282 my $show_passphrase_op = $self->passphrase_check_button->get_active;
283 foreach my $entry ($self->passphrase_entry, $self->verify_passphrase_entry) {
284 $entry->set_visibility($show_passphrase_op);
288 method operation_finished (HashRef $replies) {
289 my ($created_device, $error);
291 say STDERR "Entering Bootstrap::operation_finished";
293 if (exists($replies->{created_device}) && defined($replies->{created_device})) {
294 $created_device = $replies->{created_device};
295 # For some reason, we cannot get the exception when Try::Tiny is used,
296 # so let's do it by hand.
298 local $@;
299 eval { $replies->{format_reply}->get_result };
300 $error = $@;
303 else {
304 $error = $replies->{create_partition_error};
307 if ($error) {
308 $self->working(0);
309 say STDERR "$error";
310 $self->subtitle->set_text($self->encoding->decode(gettext(q{Failed})));
311 $self->description->set_text($error);
313 else {
314 say STDERR "created ${created_device}.";
315 $self->working(0);
317 $self->subtitle->set_text($self->encoding->decode(gettext(
318 q{Mounting Tails persistence partition.}
319 )));
320 $self->description->set_text($self->encoding->decode(gettext(
321 q{The Tails persistence partition will be mounted.}
322 )));
323 $self->working(1);
324 systemx(qw{/sbin/udevadm settle});
325 my $mountpoint = $self->mount_persistence_partition_cb->();
326 $self->working(0);
327 say STDERR "mounted persistence partition on $mountpoint";
329 $self->subtitle->set_text($self->encoding->decode(gettext(
330 q{Correcting permissions of the persistent volume.}
331 )));
332 $self->description->set_text($self->encoding->decode(gettext(
333 q{The permissions of the persistent volume will be corrected.}
334 )));
335 $self->working(1);
336 systemx(qw{sudo -n /usr/bin/tails-fix-persistent-volume-permissions});
337 $self->working(0);
338 say STDERR "fixed permissions.";
340 $self->subtitle->set_text($self->encoding->decode(gettext(
341 q{Creating default persistence configuration.}
342 )));
343 $self->description->set_text($self->encoding->decode(gettext(
344 q{The default persistence configuration will be created.}
345 )));
346 $self->working(1);
347 $self->create_configuration_cb->();
348 $self->working(0);
349 say STDERR "created default persistence configuration.";
351 $self->success_callback->();
355 method go_button_pressed () {
356 $_->hide foreach ($self->intro, $self->warning_area, $self->table,$self->passphrase_check_button);
357 $self->working(1);
358 $self->subtitle->set_text(
359 $self->encoding->decode(gettext(q{Creating...})),
361 $self->description->set_text(
362 $self->encoding->decode(gettext(q{Creating the persistent volume...})),
365 $self->go_callback->(
366 passphrase => $self->passphrase_entry->get_text,
367 end_cb => sub { $self->operation_finished(@_) },
371 with 'Tails::Persistence::Role::StatusArea';
372 with 'Tails::Persistence::Role::SetupStep';
374 no Moo;