From 010b1813fc5b95d759c8abad5b21b7eecc9f042e Mon Sep 17 00:00:00 2001 From: Nathan Dyer Date: Wed, 14 Dec 2022 10:44:46 -0500 Subject: [PATCH 01/25] First stab at adding a GNOME Shell Extension, and the necessary logic for Ansible to install and enable it. --- .../extension.js | 109 ++++++++++++++++++ .../metadata.json | 11 ++ .../stylesheet.css | 1 + .../tasks/install_shell_extension.yml | 37 ++++++ 4 files changed, 158 insertions(+) create mode 100644 install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js create mode 100644 install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/metadata.json create mode 100644 install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/stylesheet.css create mode 100644 install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml diff --git a/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js b/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js new file mode 100644 index 0000000000..61fdf9ddbb --- /dev/null +++ b/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js @@ -0,0 +1,109 @@ +/* exported init */ + +const GETTEXT_DOMAIN = 'securedrop'; + +const {Clutter, GObject, GLib, St } = imports.gi; + +const Util = imports.misc.util; +const ExtensionUtils = imports.misc.extensionUtils; +const Main = imports.ui.main; +const PanelMenu = imports.ui.panelMenu; +const PopupMenu = imports.ui.popupMenu; + +const _ = ExtensionUtils.gettext; + +const Indicator = GObject.registerClass( +class Indicator extends PanelMenu.Button { + _init() { + super._init(0.0, _('SecureDrop')); + + let icon = new St.Icon({ + icon_name: 'package-x-generic-symbolic', + style_class: 'system-status-icon', + }); + + let label = new St.Label({ + text: _('SecureDrop'), + y_expand: true, + y_align: Clutter.ActorAlign.CENTER, + }); + + let topBox = new St.BoxLayout({ + style_class: 'panel-status-menu-box' + }); + + topBox.add_child(icon); + topBox.add_child(label); + this.add_child(topBox); + + let source = new PopupMenu.PopupMenuItem(_('Launch Source Interface')); + source.connect('activate', () => { + Util.trySpawnCommandLine(`SADDR=\`cat ~/Persistent/securedrop/install_files/ansible-base/app-sourcev3-ths\` && tor-browser $SADDR`); + }); + + let journalist = new PopupMenu.PopupMenuItem(_('Launch Journalist Interface')); + journalist.connect('activate', () => { + Util.trySpawnCommandLine(`JADDR=\`cut -d: f1 ~/Persistent/securedrop/install_files/ansible-base/app-journalist.auth_private\` && tor-browser "${JADDR}.onion"`); + }); + + let admin_label = new St.Label({ + text: _('Admin Actions'), + y_expand: true, + y_align: Clutter.ActorAlign.START, + }); + + let updates = new PopupMenu.PopupMenuItem(_('Check for SecureDrop Updates')); + updates.connect('activate', () => { + Util.trySpawnCommandLine(``); + }); + + let app_server_ssh = new PopupMenu.PopupMenuItem(_('SSH into the App Server')); + app_server_ssh.connect('activate', () => { + Util.trySpawnCommandLine(`gnome-terminal -- ssh app`); + }); + + let mon_server_ssh = new PopupMenu.PopupMenuItem(_('SSH into the Monitor Server')); + mon_server_ssh.connect('activate', () => { + Util.trySpawnCommandLine(`gnome-terminal -- ssh mon`); + }); + + let keypass = new PopupMenu.PopupMenuItem(_('Open KeePassXC Password Vault')); + keypass.connect('activate', () => { + Util.trySpawnCommandLine(`keepassxc`); + }); + + this.menu.addMenuItem(source); + this.menu.addMenuItem(journalist); + this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); + this.menu.addMenuItem(updates); + this.menu.addMenuItem(app_server_ssh); + this.menu.addMenuItem(mon_server_ssh); + this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); + this.menu.addMenuItem(keypass); + } +}); + +class Extension { + constructor(uuid) { + this._uuid = uuid; + + ExtensionUtils.initTranslations(GETTEXT_DOMAIN); + } + + enable() { + this._indicator = new Indicator(); + let pos = Main.sessionMode.panel.left.indexOf('appMenu'); + if ('apps-menu' in Main.panel.statusArea) + pos++; + Main.panel.addToStatusArea(this._uuid, this._indicator, pos, 'left'); + } + + disable() { + this._indicator.destroy(); + this._indicator = null; + } +} + +function init(meta) { + return new Extension(meta.uuid); +} diff --git a/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/metadata.json b/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/metadata.json new file mode 100644 index 0000000000..e5988c6296 --- /dev/null +++ b/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/metadata.json @@ -0,0 +1,11 @@ +{ + "name": "SecureDrop", + "description": "SecureDrop Utility Menu", + "uuid": "securedrop@securedrop.freedom.press", + "shell-version": [ + "40", + "41", + "42", + "43" + ] +} diff --git a/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/stylesheet.css b/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/stylesheet.css new file mode 100644 index 0000000000..37b93f2191 --- /dev/null +++ b/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/stylesheet.css @@ -0,0 +1 @@ +/* Add your custom extension styling here */ diff --git a/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml b/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml new file mode 100644 index 0000000000..b497c65c24 --- /dev/null +++ b/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml @@ -0,0 +1,37 @@ +--- +- name: Create the SecureDrop GNOME Shell Extension directory + become: yes + file: + path: "{{ tails_config_live_dotfiles }}/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press" + state: directory + mode: "0755" + owner: amnesia + group: amnesia + +- name: Copy the extension metadata to the extension directory + become: yes + copy: + src: securedrop@securedrop.freedom.press/metadata.json + dest: "{{ tails_config_live_dotfiles }}/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/" + owner: amnesia + group: amnesia + +- name: Copy the extension CSS to the extension directory + become: yes + copy: + src: securedrop@securedrop.freedom.press/stylesheet.css + dest: "{{ tails_config_live_dotfiles }}/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/" + owner: amnesia + group: amnesia + +- name: Copy the extension itself to the extension directory + become: yes + copy: + src: securedrop@securedrop.freedom.press/extension.js + dest: "{{ tails_config_live_dotfiles }}/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press" + owner: amnesia + group: amnesia + +- name: Enable the new GNOME Shell extension + become: yes + command: gnome-extensions enable securedrop@securedrop.freedom.press From 5e1f0ff8b67f9a6b84bcd6d89143c2a19b02f75f Mon Sep 17 00:00:00 2001 From: Nathan Dyer Date: Thu, 15 Dec 2022 14:49:26 -0500 Subject: [PATCH 02/25] Fix broken commands, have Tails load extension with network hook, and make sure Ansible actually runs the new task. --- .../extension.js | 34 ++++++++++++------- .../tails-config/files/securedrop_init.py | 3 ++ .../roles/tails-config/tasks/main.yml | 2 ++ 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js b/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js index 61fdf9ddbb..57ec71d731 100644 --- a/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js +++ b/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js @@ -15,7 +15,7 @@ const _ = ExtensionUtils.gettext; const Indicator = GObject.registerClass( class Indicator extends PanelMenu.Button { _init() { - super._init(0.0, _('SecureDrop')); + super._init(0.0, 'SecureDrop'); let icon = new St.Icon({ icon_name: 'package-x-generic-symbolic', @@ -23,7 +23,7 @@ class Indicator extends PanelMenu.Button { }); let label = new St.Label({ - text: _('SecureDrop'), + text: 'SecureDrop', y_expand: true, y_align: Clutter.ActorAlign.CENTER, }); @@ -36,38 +36,48 @@ class Indicator extends PanelMenu.Button { topBox.add_child(label); this.add_child(topBox); - let source = new PopupMenu.PopupMenuItem(_('Launch Source Interface')); + let source = new PopupMenu.PopupMenuItem('Launch Source Interface'); source.connect('activate', () => { - Util.trySpawnCommandLine(`SADDR=\`cat ~/Persistent/securedrop/install_files/ansible-base/app-sourcev3-ths\` && tor-browser $SADDR`); + let [ok, out, err, exit] = GLib.spawn_command_line_sync('/bin/bash -c "cat ~/Persistent/securedrop/install_files/ansible-base/app-sourcev3-ths"'); + if (out.length > 0) { + Util.spawn(['tor-browser', out.toString()]); + } else { + Util.trySpawnCommandLine('notify-send "Unable to find Source Interface Onion Address"'); + } }); - let journalist = new PopupMenu.PopupMenuItem(_('Launch Journalist Interface')); + let journalist = new PopupMenu.PopupMenuItem('Launch Journalist Interface'); journalist.connect('activate', () => { - Util.trySpawnCommandLine(`JADDR=\`cut -d: f1 ~/Persistent/securedrop/install_files/ansible-base/app-journalist.auth_private\` && tor-browser "${JADDR}.onion"`); + let [ok, out, err, exit] = GLib.spawn_command_line_sync('/bin/bash -c "cut -d: -f1 ~/Persistent/securedrop/install_files/ansible-base/app-journalist.auth_private"'); + if (out.length > 0) { + Util.spawn(['tor-browser', out.toString() + '.onion']); + } else { + Util.trySpawnCommandLine('notify-send "Unable to find Journalist Interface Onion Address"'); + } }); let admin_label = new St.Label({ - text: _('Admin Actions'), + text: 'Admin Actions', y_expand: true, y_align: Clutter.ActorAlign.START, }); - let updates = new PopupMenu.PopupMenuItem(_('Check for SecureDrop Updates')); + let updates = new PopupMenu.PopupMenuItem('Check for SecureDrop Updates'); updates.connect('activate', () => { - Util.trySpawnCommandLine(``); + Util.spawn(['python3', '/home/amnesia/Persistent/securedrop/journalist_gui/SecureDropUpdater']); }); - let app_server_ssh = new PopupMenu.PopupMenuItem(_('SSH into the App Server')); + let app_server_ssh = new PopupMenu.PopupMenuItem('SSH into the App Server'); app_server_ssh.connect('activate', () => { Util.trySpawnCommandLine(`gnome-terminal -- ssh app`); }); - let mon_server_ssh = new PopupMenu.PopupMenuItem(_('SSH into the Monitor Server')); + let mon_server_ssh = new PopupMenu.PopupMenuItem('SSH into the Monitor Server'); mon_server_ssh.connect('activate', () => { Util.trySpawnCommandLine(`gnome-terminal -- ssh mon`); }); - let keypass = new PopupMenu.PopupMenuItem(_('Open KeePassXC Password Vault')); + let keypass = new PopupMenu.PopupMenuItem('Open KeePassXC Password Vault'); keypass.connect('activate', () => { Util.trySpawnCommandLine(`keepassxc`); }); diff --git a/install_files/ansible-base/roles/tails-config/files/securedrop_init.py b/install_files/ansible-base/roles/tails-config/files/securedrop_init.py index b78577837c..b8dcd9911b 100644 --- a/install_files/ansible-base/roles/tails-config/files/securedrop_init.py +++ b/install_files/ansible-base/roles/tails-config/files/securedrop_init.py @@ -128,6 +128,9 @@ if is_tails: subprocess.call(["gnome-shell-extension-tool", "-r", "desktop-icons@csoriano"], env=env) +# enable the GNOME Shell Extension +subprocess.call(["gnome-extensions", "enable", "securedrop@securedrop.freedom.press"], env=env) + # reacquire uid0 and notify the user os.setresuid(0, 0, -1) os.setresgid(0, 0, -1) diff --git a/install_files/ansible-base/roles/tails-config/tasks/main.yml b/install_files/ansible-base/roles/tails-config/tasks/main.yml index c4508a68ae..542ca910e3 100644 --- a/install_files/ansible-base/roles/tails-config/tasks/main.yml +++ b/install_files/ansible-base/roles/tails-config/tasks/main.yml @@ -8,6 +8,8 @@ - include: create_desktop_shortcuts.yml +- include: install_shell_extension.yml + - include: configure_network_hook.yml - name: Check that we are on an admin workstation From d2fb2f353babee76b9dfb4d8459c97256217c245 Mon Sep 17 00:00:00 2001 From: Nathan Dyer Date: Tue, 20 Dec 2022 11:28:56 -0500 Subject: [PATCH 03/25] Don't run gnome-extensions command with elevated privileges (without this, the task will fail) --- .../roles/tails-config/tasks/install_shell_extension.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml b/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml index b497c65c24..50fbde5efe 100644 --- a/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml +++ b/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml @@ -33,5 +33,5 @@ group: amnesia - name: Enable the new GNOME Shell extension - become: yes + become: no command: gnome-extensions enable securedrop@securedrop.freedom.press From 4c0368686702e01ced8410cc37beb534372a3027 Mon Sep 17 00:00:00 2001 From: Nathan Dyer Date: Thu, 22 Dec 2022 09:06:57 -0500 Subject: [PATCH 04/25] Remove trailing spaces to appease the linter --- .../roles/tails-config/tasks/install_shell_extension.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml b/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml index 50fbde5efe..0cf70fc660 100644 --- a/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml +++ b/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml @@ -15,7 +15,7 @@ dest: "{{ tails_config_live_dotfiles }}/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/" owner: amnesia group: amnesia - + - name: Copy the extension CSS to the extension directory become: yes copy: @@ -23,7 +23,7 @@ dest: "{{ tails_config_live_dotfiles }}/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/" owner: amnesia group: amnesia - + - name: Copy the extension itself to the extension directory become: yes copy: @@ -31,7 +31,7 @@ dest: "{{ tails_config_live_dotfiles }}/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press" owner: amnesia group: amnesia - + - name: Enable the new GNOME Shell extension become: no command: gnome-extensions enable securedrop@securedrop.freedom.press From 88e924135a132af2f910ed89dcb09e3476342d72 Mon Sep 17 00:00:00 2001 From: Nathan Dyer Date: Wed, 11 Jan 2023 15:02:06 -0500 Subject: [PATCH 05/25] Don't show admin-related menu items if it's on a journalist workstation. --- .../extension.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js b/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js index 57ec71d731..811adacb79 100644 --- a/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js +++ b/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js @@ -17,6 +17,14 @@ class Indicator extends PanelMenu.Button { _init() { super._init(0.0, 'SecureDrop'); + // Check for SSH keys - if they don't exist, this is a Journalist workstation + // (and therefore the admin options should remain hidden) + let is_admin = false; + let [ok, out, err, exit] = GLib.spawn_command_line_sync('/bin/bash -c "test -f ~/Persistent/securedrop/install_files/ansible-base/app-ssh.auth_private"'); + if (exit == 0) { + is_admin = true; + } + let icon = new St.Icon({ icon_name: 'package-x-generic-symbolic', style_class: 'system-status-icon', @@ -84,10 +92,12 @@ class Indicator extends PanelMenu.Button { this.menu.addMenuItem(source); this.menu.addMenuItem(journalist); - this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); - this.menu.addMenuItem(updates); - this.menu.addMenuItem(app_server_ssh); - this.menu.addMenuItem(mon_server_ssh); + if (is_admin) { + this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); + this.menu.addMenuItem(updates); + this.menu.addMenuItem(app_server_ssh); + this.menu.addMenuItem(mon_server_ssh); + } this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); this.menu.addMenuItem(keypass); } From b29573305ce8aeb8e1da514300b95a06dc7930c3 Mon Sep 17 00:00:00 2001 From: Nathan Dyer Date: Wed, 18 Jan 2023 14:45:54 -0500 Subject: [PATCH 06/25] Switch to checking for tor_v3_keys.json to determine between Journalist and Admin workstations. --- .../files/securedrop@securedrop.freedom.press/extension.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js b/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js index 811adacb79..827aa5825d 100644 --- a/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js +++ b/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js @@ -17,10 +17,11 @@ class Indicator extends PanelMenu.Button { _init() { super._init(0.0, 'SecureDrop'); - // Check for SSH keys - if they don't exist, this is a Journalist workstation + // Check for SSH onion service client authentication keys - + // if they don't exist, this is a Journalist workstation // (and therefore the admin options should remain hidden) let is_admin = false; - let [ok, out, err, exit] = GLib.spawn_command_line_sync('/bin/bash -c "test -f ~/Persistent/securedrop/install_files/ansible-base/app-ssh.auth_private"'); + let [ok, out, err, exit] = GLib.spawn_command_line_sync('/bin/bash -c "test -f ~/Persistent/securedrop/install_files/ansible-base/tor_v3_keys.json"'); if (exit == 0) { is_admin = true; } From 0896be7baa494fb656bcaa8ff4e68ac42fbd8a6d Mon Sep 17 00:00:00 2001 From: Nathan Dyer Date: Wed, 18 Jan 2023 15:05:09 -0500 Subject: [PATCH 07/25] Use explicit length checks and validate the URL contains .onion --- .../files/securedrop@securedrop.freedom.press/extension.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js b/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js index 827aa5825d..ab944a7573 100644 --- a/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js +++ b/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js @@ -48,7 +48,7 @@ class Indicator extends PanelMenu.Button { let source = new PopupMenu.PopupMenuItem('Launch Source Interface'); source.connect('activate', () => { let [ok, out, err, exit] = GLib.spawn_command_line_sync('/bin/bash -c "cat ~/Persistent/securedrop/install_files/ansible-base/app-sourcev3-ths"'); - if (out.length > 0) { + if (out.length == 62 && out.toString().endsWith(".onion")) { Util.spawn(['tor-browser', out.toString()]); } else { Util.trySpawnCommandLine('notify-send "Unable to find Source Interface Onion Address"'); @@ -58,7 +58,7 @@ class Indicator extends PanelMenu.Button { let journalist = new PopupMenu.PopupMenuItem('Launch Journalist Interface'); journalist.connect('activate', () => { let [ok, out, err, exit] = GLib.spawn_command_line_sync('/bin/bash -c "cut -d: -f1 ~/Persistent/securedrop/install_files/ansible-base/app-journalist.auth_private"'); - if (out.length > 0) { + if (out.length == 56) { Util.spawn(['tor-browser', out.toString() + '.onion']); } else { Util.trySpawnCommandLine('notify-send "Unable to find Journalist Interface Onion Address"'); From 4ac0c286fc070a1a980d07680a28bb9aaf0a2c21 Mon Sep 17 00:00:00 2001 From: Nathan Dyer Date: Wed, 18 Jan 2023 15:17:37 -0500 Subject: [PATCH 08/25] Show update option, even on Journalist workstation. --- .../files/securedrop@securedrop.freedom.press/extension.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js b/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js index ab944a7573..b4e7844d57 100644 --- a/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js +++ b/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js @@ -93,9 +93,9 @@ class Indicator extends PanelMenu.Button { this.menu.addMenuItem(source); this.menu.addMenuItem(journalist); + this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); + this.menu.addMenuItem(updates); if (is_admin) { - this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); - this.menu.addMenuItem(updates); this.menu.addMenuItem(app_server_ssh); this.menu.addMenuItem(mon_server_ssh); } From b0228714df79c40a747d42aa66934ab9844c60f8 Mon Sep 17 00:00:00 2001 From: Nathan Dyer Date: Fri, 20 Jan 2023 12:05:40 -0500 Subject: [PATCH 09/25] Copy files to running system in addition to Persistent volume --- .../tasks/install_shell_extension.yml | 57 +++++++++++++++++-- 1 file changed, 53 insertions(+), 4 deletions(-) diff --git a/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml b/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml index 0cf70fc660..2a3881234f 100644 --- a/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml +++ b/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml @@ -1,5 +1,5 @@ --- -- name: Create the SecureDrop GNOME Shell Extension directory +- name: Create the SecureDrop GNOME Shell Extension directory in Persistent Storage become: yes file: path: "{{ tails_config_live_dotfiles }}/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press" @@ -7,16 +7,49 @@ mode: "0755" owner: amnesia group: amnesia + +- name: Create the SecureDrop GNOME Shell Extension directory in the running system + become: yes + file: + path: "/home/amnesia/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press" + state: directory + mode: "0755" + owner: amnesia + group: amnesia -- name: Copy the extension metadata to the extension directory +- name: Copy the extension metadata to the extension directory in Persistent Storage + become: yes + copy: + src: securedrop@securedrop.freedom.press/metadata.json + dest: "{{ tails_config_live_dotfiles }}/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/" + owner: amnesia + group: amnesia + +- name: Copy the extension metadata to the extension directory in the running system + become: yes + copy: + src: securedrop@securedrop.freedom.press/metadata.json + dest: "/home/amnesia/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/" + owner: amnesia + group: amnesia + +- name: Copy the extension metadata to the extension directory in Persistent Storage become: yes copy: src: securedrop@securedrop.freedom.press/metadata.json dest: "{{ tails_config_live_dotfiles }}/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/" owner: amnesia group: amnesia + +- name: Copy the extension metadata to the extension directory in the running system + become: yes + copy: + src: securedrop@securedrop.freedom.press/metadata.json + dest: "/home/amnesia/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/" + owner: amnesia + group: amnesia -- name: Copy the extension CSS to the extension directory +- name: Copy the extension CSS to the extension directory in Persistent Storage become: yes copy: src: securedrop@securedrop.freedom.press/stylesheet.css @@ -24,13 +57,29 @@ owner: amnesia group: amnesia -- name: Copy the extension itself to the extension directory +- name: Copy the extension CSS to the extension directory in the running system + become: yes + copy: + src: securedrop@securedrop.freedom.press/stylesheet.css + dest: "/home/amnesia/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/" + owner: amnesia + group: amnesia + +- name: Copy the extension itself to the extension directory in Persistent Storage become: yes copy: src: securedrop@securedrop.freedom.press/extension.js dest: "{{ tails_config_live_dotfiles }}/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press" owner: amnesia group: amnesia + +- name: Copy the extension itself to the extension directory in the running system + become: yes + copy: + src: securedrop@securedrop.freedom.press/extension.js + dest: "/home/amnesia/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press" + owner: amnesia + group: amnesia - name: Enable the new GNOME Shell extension become: no From 5edcfc40bcc5b8537aaf0c5b1eef1426969d2d05 Mon Sep 17 00:00:00 2001 From: Nathan Dyer Date: Fri, 20 Jan 2023 12:26:17 -0500 Subject: [PATCH 10/25] Load app and mon hostnames dynamically --- .../securedrop@securedrop.freedom.press/extension.js | 10 ++++++++-- .../tails-config/tasks/install_shell_extension.yml | 12 ++++++------ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js b/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js index b4e7844d57..b527167b7d 100644 --- a/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js +++ b/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js @@ -78,12 +78,18 @@ class Indicator extends PanelMenu.Button { let app_server_ssh = new PopupMenu.PopupMenuItem('SSH into the App Server'); app_server_ssh.connect('activate', () => { - Util.trySpawnCommandLine(`gnome-terminal -- ssh app`); + let [ok, out, err, exit] = GLib.spawn_command_line_sync('/bin/bash -c "awk -v FS="app_hostname: " 'NF>1{print $2}' /home/amnesia/Persistent/securedrop/install_files/ansible-base/group_vars/all/site-specific"'); + if (out.length > 0) { + Util.trySpawnCommandLine(`gnome-terminal -- ssh ` + out); + } }); let mon_server_ssh = new PopupMenu.PopupMenuItem('SSH into the Monitor Server'); mon_server_ssh.connect('activate', () => { - Util.trySpawnCommandLine(`gnome-terminal -- ssh mon`); + let [ok, out, err, exit] = GLib.spawn_command_line_sync('/bin/bash -c "awk -v FS="monitor_hostname: " 'NF>1{print $2}' /home/amnesia/Persistent/securedrop/install_files/ansible-base/group_vars/all/site-specific"'); + if (out.length > 0) { + Util.trySpawnCommandLine(`gnome-terminal -- ssh ` + out); + } }); let keypass = new PopupMenu.PopupMenuItem('Open KeePassXC Password Vault'); diff --git a/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml b/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml index 2a3881234f..7b5087cc8d 100644 --- a/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml +++ b/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml @@ -7,7 +7,7 @@ mode: "0755" owner: amnesia group: amnesia - + - name: Create the SecureDrop GNOME Shell Extension directory in the running system become: yes file: @@ -24,7 +24,7 @@ dest: "{{ tails_config_live_dotfiles }}/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/" owner: amnesia group: amnesia - + - name: Copy the extension metadata to the extension directory in the running system become: yes copy: @@ -32,7 +32,7 @@ dest: "/home/amnesia/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/" owner: amnesia group: amnesia - + - name: Copy the extension metadata to the extension directory in Persistent Storage become: yes copy: @@ -40,7 +40,7 @@ dest: "{{ tails_config_live_dotfiles }}/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/" owner: amnesia group: amnesia - + - name: Copy the extension metadata to the extension directory in the running system become: yes copy: @@ -64,7 +64,7 @@ dest: "/home/amnesia/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/" owner: amnesia group: amnesia - + - name: Copy the extension itself to the extension directory in Persistent Storage become: yes copy: @@ -72,7 +72,7 @@ dest: "{{ tails_config_live_dotfiles }}/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press" owner: amnesia group: amnesia - + - name: Copy the extension itself to the extension directory in the running system become: yes copy: From 1220dbdfa6653299cac628cf3fd7b26320569d0e Mon Sep 17 00:00:00 2001 From: Nathan Dyer Date: Mon, 23 Jan 2023 16:03:50 -0500 Subject: [PATCH 11/25] Fix a couple bugs recently introduced that prevent the extension from loading. --- .../securedrop@securedrop.freedom.press/extension.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js b/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js index b527167b7d..4372bdd24a 100644 --- a/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js +++ b/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js @@ -48,6 +48,7 @@ class Indicator extends PanelMenu.Button { let source = new PopupMenu.PopupMenuItem('Launch Source Interface'); source.connect('activate', () => { let [ok, out, err, exit] = GLib.spawn_command_line_sync('/bin/bash -c "cat ~/Persistent/securedrop/install_files/ansible-base/app-sourcev3-ths"'); + out = out.trim(); if (out.length == 62 && out.toString().endsWith(".onion")) { Util.spawn(['tor-browser', out.toString()]); } else { @@ -58,6 +59,7 @@ class Indicator extends PanelMenu.Button { let journalist = new PopupMenu.PopupMenuItem('Launch Journalist Interface'); journalist.connect('activate', () => { let [ok, out, err, exit] = GLib.spawn_command_line_sync('/bin/bash -c "cut -d: -f1 ~/Persistent/securedrop/install_files/ansible-base/app-journalist.auth_private"'); + out = out.trim(); if (out.length == 56) { Util.spawn(['tor-browser', out.toString() + '.onion']); } else { @@ -78,7 +80,8 @@ class Indicator extends PanelMenu.Button { let app_server_ssh = new PopupMenu.PopupMenuItem('SSH into the App Server'); app_server_ssh.connect('activate', () => { - let [ok, out, err, exit] = GLib.spawn_command_line_sync('/bin/bash -c "awk -v FS="app_hostname: " 'NF>1{print $2}' /home/amnesia/Persistent/securedrop/install_files/ansible-base/group_vars/all/site-specific"'); + let command = "awk -v FS='app_hostname: ' 'NF>1{print $2}' /home/amnesia/Persistent/securedrop/install_files/ansible-base/group_vars/all/site-specific"; + let [ok, out, err, exit] = GLib.spawn_command_line_sync(command); if (out.length > 0) { Util.trySpawnCommandLine(`gnome-terminal -- ssh ` + out); } @@ -86,7 +89,8 @@ class Indicator extends PanelMenu.Button { let mon_server_ssh = new PopupMenu.PopupMenuItem('SSH into the Monitor Server'); mon_server_ssh.connect('activate', () => { - let [ok, out, err, exit] = GLib.spawn_command_line_sync('/bin/bash -c "awk -v FS="monitor_hostname: " 'NF>1{print $2}' /home/amnesia/Persistent/securedrop/install_files/ansible-base/group_vars/all/site-specific"'); + let command = "awk -v FS='monitor_hostname: ' 'NF>1{print $2}' /home/amnesia/Persistent/securedrop/install_files/ansible-base/group_vars/all/site-specific"; + let [ok, out, err, exit] = GLib.spawn_command_line_sync(command); if (out.length > 0) { Util.trySpawnCommandLine(`gnome-terminal -- ssh ` + out); } From c223858a5457f0517e6dcec56261525918db743e Mon Sep 17 00:00:00 2001 From: Zeke Hunter-Green Date: Mon, 5 Dec 2022 14:24:09 +0000 Subject: [PATCH 12/25] empty commit to rerun ci after setting up circle ci project for fork From 768943d0e91d8a2e964b6d5c4157d306e39e5028 Mon Sep 17 00:00:00 2001 From: Nathan Dyer Date: Wed, 25 Jan 2023 15:14:34 -0500 Subject: [PATCH 13/25] Switch to using an Ansible template. --- .../roles/tails-config/defaults/main.yml | 6 ++ .../tasks/install_shell_extension.yml | 100 ++++++++++++++---- .../extension.js.in} | 33 ++---- 3 files changed, 95 insertions(+), 44 deletions(-) rename install_files/ansible-base/roles/tails-config/{files/securedrop@securedrop.freedom.press/extension.js => templates/extension.js.in} (69%) diff --git a/install_files/ansible-base/roles/tails-config/defaults/main.yml b/install_files/ansible-base/roles/tails-config/defaults/main.yml index 3d468feecb..433f4b9c3c 100644 --- a/install_files/ansible-base/roles/tails-config/defaults/main.yml +++ b/install_files/ansible-base/roles/tails-config/defaults/main.yml @@ -24,6 +24,12 @@ tails_config_desktop_icon_directories: - "{{ tails_config_amnesia_home }}/.local/share/applications" - "{{ tails_config_live_dotfiles }}/.local/share/applications" +# Destination directories for storing the SecureDrop GNOME Shell +# extension +tails_config_extension_directories: + - "{{ tails_config_amnesia_home }}/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/" + - "{{ tails_config_live_dotfiles }}/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/" + # Path for storing site-specific ATHS info for connecting to Journalist Interface. tails_config_torrc_additions: "{{ tails_config_securedrop_dotfiles }}/torrc_additions" diff --git a/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml b/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml index 7b5087cc8d..42fc63d98c 100644 --- a/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml +++ b/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml @@ -1,21 +1,59 @@ --- -- name: Create the SecureDrop GNOME Shell Extension directory in Persistent Storage - become: yes +- name: Check for v3 Source Interface file + stat: + path: app-sourcev3-ths + register: v3_source_file + +- name: Check for v3 Journalist Interface file + stat: + path: app-journalist.auth_private + register: v3_journalist_file + +- name: Check for site specific file + stat: + path: group_vars/all/site-specific + register: site_specific_file + +- name: Look up v3 Source Interface URL. + command: grep -Po '.{56}\.onion' app-sourcev3-ths + changed_when: false + register: sourcev3_interface_lookup_result + when: v3_source_file.stat.exists == true + +- name: Look up v3 Journalist Interface URL. + command: awk -F ':' '{print $1 ".onion"}' app-journalist.auth_private + changed_when: false + register: journalistv3_interface_lookup_result + when: v3_source_file.stat.exists == true + +- name: Look up app server hostname + command: "awk -v FS='app_hostname: ' 'NF>1{print $2}' group_vars/all/site-specific" + changed_when: false + register: app_server_lookup_result + when: site_specific_file.stat.exists == true + +- name: Look up mon server hostname + command: "awk -v FS='monitor_hostname: ' 'NF>1{print $2}' /home/amnesia/Persistent/securedrop/install_files/ansible-base/group_vars/all/site-specific" + changed_when: false + register: mon_server_lookup_result + when: site_specific_file.stat.exists == true + +- name: Create the SecureDrop GNOME Shell Extension directories file: - path: "{{ tails_config_live_dotfiles }}/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press" state: directory - mode: "0755" - owner: amnesia - group: amnesia + path: "{{ item }}" + with_items: "{{ tails_config_extension_directories }}" -- name: Create the SecureDrop GNOME Shell Extension directory in the running system +- name: Set normal user ownership on subset of directories. become: yes file: - path: "/home/amnesia/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press" state: directory - mode: "0755" + path: "{{ item }}" owner: amnesia group: amnesia + # Only set normal user ownership for files in ~amnesia. + when: item.startswith(tails_config_amnesia_home) + with_items: "{{ tails_config_extension_directories }}" - name: Copy the extension metadata to the extension directory in Persistent Storage become: yes @@ -65,21 +103,43 @@ owner: amnesia group: amnesia -- name: Copy the extension itself to the extension directory in Persistent Storage - become: yes - copy: - src: securedrop@securedrop.freedom.press/extension.js - dest: "{{ tails_config_live_dotfiles }}/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press" - owner: amnesia - group: amnesia +- name: Set the right variable for source + set_fact: + source_iface: "{{ sourcev3_interface_lookup_result }}" + +- name: Set the right variable for journalist + set_fact: + journalist_iface: "{{ journalistv3_interface_lookup_result }}" -- name: Copy the extension itself to the extension directory in the running system +- name: Set the right variable for app server hostname + set_fact: + app_hostname: "{{ app_server_lookup_result }}" + +- name: Set the right variable for app server hostname + set_fact: + mon_hostname: "{{ mon_server_lookup_result }}" + +- name: Assemble interface information for extension + set_fact: + _securedrop_extension_info: + - src: extension.js.in + filename: extension.js + source_interface_address: "{{ source_iface.stdout }}" + journalist_interface_address: "{{ journalist_iface.stdout }}" + app_hostname: "{{ app_hostname.stdout }}" + mon_hostname: "{{ mon_hostname.stdout }}" + +- name: Create SecureDrop extension become: yes - copy: - src: securedrop@securedrop.freedom.press/extension.js - dest: "/home/amnesia/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press" + template: + src: "{{ item.0.src }}" + dest: "{{ item.1 }}/{{ item.0.filename }}" owner: amnesia group: amnesia + mode: "0700" + with_nested: + - "{{ _securedrop_extension_info }}" + - "{{ tails_config_extension_directories }}" - name: Enable the new GNOME Shell extension become: no diff --git a/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js b/install_files/ansible-base/roles/tails-config/templates/extension.js.in similarity index 69% rename from install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js rename to install_files/ansible-base/roles/tails-config/templates/extension.js.in index 4372bdd24a..034146ec28 100644 --- a/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/extension.js +++ b/install_files/ansible-base/roles/tails-config/templates/extension.js.in @@ -10,6 +10,11 @@ const Main = imports.ui.main; const PanelMenu = imports.ui.panelMenu; const PopupMenu = imports.ui.popupMenu; +const source_interface_address = "{{ item.0.source_interface_address }}"; +const journalist_interface_address = "{{ item.0.journalist_interface_address }}"; +const app_server_hostname = "{{ item.0.app_hostname }}"; +const mon_server_hostname = "{{ item.0.mon_hostname }}"; + const _ = ExtensionUtils.gettext; const Indicator = GObject.registerClass( @@ -47,24 +52,12 @@ class Indicator extends PanelMenu.Button { let source = new PopupMenu.PopupMenuItem('Launch Source Interface'); source.connect('activate', () => { - let [ok, out, err, exit] = GLib.spawn_command_line_sync('/bin/bash -c "cat ~/Persistent/securedrop/install_files/ansible-base/app-sourcev3-ths"'); - out = out.trim(); - if (out.length == 62 && out.toString().endsWith(".onion")) { - Util.spawn(['tor-browser', out.toString()]); - } else { - Util.trySpawnCommandLine('notify-send "Unable to find Source Interface Onion Address"'); - } + Util.spawn(['tor-browser', source_interface_address]); }); let journalist = new PopupMenu.PopupMenuItem('Launch Journalist Interface'); journalist.connect('activate', () => { - let [ok, out, err, exit] = GLib.spawn_command_line_sync('/bin/bash -c "cut -d: -f1 ~/Persistent/securedrop/install_files/ansible-base/app-journalist.auth_private"'); - out = out.trim(); - if (out.length == 56) { - Util.spawn(['tor-browser', out.toString() + '.onion']); - } else { - Util.trySpawnCommandLine('notify-send "Unable to find Journalist Interface Onion Address"'); - } + Util.spawn(['tor-browser', source_interface_address]); }); let admin_label = new St.Label({ @@ -80,20 +73,12 @@ class Indicator extends PanelMenu.Button { let app_server_ssh = new PopupMenu.PopupMenuItem('SSH into the App Server'); app_server_ssh.connect('activate', () => { - let command = "awk -v FS='app_hostname: ' 'NF>1{print $2}' /home/amnesia/Persistent/securedrop/install_files/ansible-base/group_vars/all/site-specific"; - let [ok, out, err, exit] = GLib.spawn_command_line_sync(command); - if (out.length > 0) { - Util.trySpawnCommandLine(`gnome-terminal -- ssh ` + out); - } + Util.trySpawnCommandLine(`gnome-terminal -- ssh ` + app_server_hostname); }); let mon_server_ssh = new PopupMenu.PopupMenuItem('SSH into the Monitor Server'); mon_server_ssh.connect('activate', () => { - let command = "awk -v FS='monitor_hostname: ' 'NF>1{print $2}' /home/amnesia/Persistent/securedrop/install_files/ansible-base/group_vars/all/site-specific"; - let [ok, out, err, exit] = GLib.spawn_command_line_sync(command); - if (out.length > 0) { - Util.trySpawnCommandLine(`gnome-terminal -- ssh ` + out); - } + Util.trySpawnCommandLine(`gnome-terminal -- ssh ` + mon_server_hostname); }); let keypass = new PopupMenu.PopupMenuItem('Open KeePassXC Password Vault'); From 0a01b411c422567874253eb8ead9823a1c8513cb Mon Sep 17 00:00:00 2001 From: Nathan Dyer Date: Mon, 27 Feb 2023 14:33:40 -0500 Subject: [PATCH 14/25] Use a SecureDrop icon in the Shell extension --- .../tails-config/files/securedrop-symbolic.png | Bin 0 -> 2563 bytes .../tasks/install_shell_extension.yml | 16 ++++++++++++++++ .../tails-config/templates/extension.js.in | 2 +- 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 install_files/ansible-base/roles/tails-config/files/securedrop-symbolic.png diff --git a/install_files/ansible-base/roles/tails-config/files/securedrop-symbolic.png b/install_files/ansible-base/roles/tails-config/files/securedrop-symbolic.png new file mode 100644 index 0000000000000000000000000000000000000000..e75b33219a0c670462bc9462cd0e66ba31a9e874 GIT binary patch literal 2563 zcmV+e3jFnnP)pF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H136M!d zK~#90-JM;GRn--MzeV|xK@kE*L>tj60{%1tQqUmQQf)+hs-{gFn%ESdsy3~awn;;q zw6PDhrHxG_*dO|vY5Gt{P2*rK78|LE!~$WkO({q%76wqEFvzSvtbLe0ckbMK_TJ~* zbBCR*2j-r$*E-+XXP>p!Ui%=bN;@_YSpa+s7!Q0^RbQysr20)&+e&~rKqt@-s3+aP z^;O$9#NMh6@W5RG{1Q0rfE@z9?BtO9+i7>q6;<2YHUNQ3fHlAg2kBkl5nz&c%(=kB zz!7&$AFv*{taAG+1UJQjI_{vH1Re*b6?x8C2e63IlxNhQbpU}5-~r%(H=lI^S0?m% zsT+asdGqFK;JmX2ATS143G6THjaui;{gxZ$<3=n%U=(mS@VW8GaW}EYv+qUVmdXJF*SN_$Gi;v&H@a$Yb!^S%%;vQmAaIrQ z-LkOjzwWJfPQoae44mHrkYn9V{f0wAY25dIYyZcPu2odEIGNl_E|63kg;ww{;nXH3j7E7Iq+%V!h-D`gXJ=h*66GY zFq79QIPh*@-~?bgaG|@)e@TSdk7a|tlsYo8gv8Ea^fUyR$#azKgAD_8V*Ap|NcUF=@)d;`5c*azI`l z!2mPa1>Dgl5VMzF^!f*IE0(|rxmZNjV@s=x%Ft2t2=wJRmPvZfz?r~PiAqlc>nJc|f+Zo=5x3sr z%O8NRVJm_MavUE9&@=dUhR;ysm7`cLFFGv5(qa!WG|dz$uTryw3S7Y8vXJ5cIt5vd zEG12^SPXkt1iZT#T=^9vZ_%Ix1-PL!fS!`6z>gSMe2JB3$&p3D)+nA$)YS)kmnIdh z*jmxsr2_Pn%>tfDys%T)O4yLJ8J1>xg!C6#cb*&N>21WPIDnqQ2K)5B;t z3RV!7W~wKMb&zMp7M(ryg1!T$+GB4 z?ou;=WyHc~nyS93s`p`m{H8K>)wGS6!@fdQ50t5>RDfAi)vc$0E)=1d5%-nF3b)2CYH=BsvQHq4$M^5_3ECzW=%wH6OqS6WO0h}pBP)KoG;m&<#o&;1XQeL@ua8q$962T6VisdAMhw8)1Hom!4<6~vJ}{g zi*SnWzYu_`dPG%M0oP%3OV(xrPl-skh|DQMSKcNfGex8m3*D|QOHZM0jH>Qd)#X?r z`3~==rNA~3StBCn7pb#e6Oq{r?2;96~N9ufJh zh?MDrb~t^dx6q6D6|h-E7B)LjRr^%+QQ&gm2UutY1KHy(ss2|xw3tzF1Ms4VtQC=_ zld`Jzs_FyoJpa=r*8>|x{~U%wq##SRgbCaYHY8@Gu}^GHhPnY%um%* zaN7^uhixe8X>i=l%{nT~nN`&uRb7T{q}lELvOl|9na_5odJUH4&Kyd>jw002ovPDHLkV1jA{%+3G+ literal 0 HcmV?d00001 diff --git a/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml b/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml index 42fc63d98c..8f66ae3b5c 100644 --- a/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml +++ b/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml @@ -102,6 +102,22 @@ dest: "/home/amnesia/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/" owner: amnesia group: amnesia + +- name: Copy the symbolic icon used for the shell extension in Persistent Storage + become: yes + copy: + src: securedrop-symbolic.png + dest: "{{ tails_config_live_dotfiles }}/.local/share/icons/" + owner: amnesia + group: amnesia + +- name: Copy the symbolic icon used for the shell extension in the running system + become: yes + copy: + src: securedrop-symbolic.png + dest: "/home/amnesia/.local/share/icons/" + owner: amnesia + group: amnesia - name: Set the right variable for source set_fact: diff --git a/install_files/ansible-base/roles/tails-config/templates/extension.js.in b/install_files/ansible-base/roles/tails-config/templates/extension.js.in index 034146ec28..af7b95282e 100644 --- a/install_files/ansible-base/roles/tails-config/templates/extension.js.in +++ b/install_files/ansible-base/roles/tails-config/templates/extension.js.in @@ -32,7 +32,7 @@ class Indicator extends PanelMenu.Button { } let icon = new St.Icon({ - icon_name: 'package-x-generic-symbolic', + icon_name: 'securedrop-symbolic', style_class: 'system-status-icon', }); From d185eedc083fe4337b20b98261ab8f2b03d63d2a Mon Sep 17 00:00:00 2001 From: Nathan Dyer Date: Thu, 2 Mar 2023 15:55:41 -0500 Subject: [PATCH 15/25] Add a button to open a file browser. --- .../roles/tails-config/templates/extension.js.in | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/install_files/ansible-base/roles/tails-config/templates/extension.js.in b/install_files/ansible-base/roles/tails-config/templates/extension.js.in index af7b95282e..fe24eef07d 100644 --- a/install_files/ansible-base/roles/tails-config/templates/extension.js.in +++ b/install_files/ansible-base/roles/tails-config/templates/extension.js.in @@ -85,6 +85,11 @@ class Indicator extends PanelMenu.Button { keypass.connect('activate', () => { Util.trySpawnCommandLine(`keepassxc`); }); + + let filebrowser = new PopupMenu.PopupMenuItem(_('Open File Browser')); + filebrowser.connect('activate', () => { + Util.trySpawnCommandLine(`xdg-open /home/amnesia/Persistent`); + }); this.menu.addMenuItem(source); this.menu.addMenuItem(journalist); @@ -96,6 +101,7 @@ class Indicator extends PanelMenu.Button { } this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); this.menu.addMenuItem(keypass); + this.menu.addMenuItem(filebrowser); } }); From 7704a5a064d2d84107f668c912226badc390445a Mon Sep 17 00:00:00 2001 From: Nathan Dyer Date: Fri, 3 Mar 2023 11:41:46 -0500 Subject: [PATCH 16/25] Make symbolic icon white instead of black so it's visible in the menu. --- .../files/securedrop-symbolic.png | Bin 2563 -> 5475 bytes .../tasks/install_shell_extension.yml | 4 ++-- .../tails-config/templates/extension.js.in | 14 ++++++++------ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/install_files/ansible-base/roles/tails-config/files/securedrop-symbolic.png b/install_files/ansible-base/roles/tails-config/files/securedrop-symbolic.png index e75b33219a0c670462bc9462cd0e66ba31a9e874..3c78d8ec5ab709ae926aea999ddadc5ba782f4e0 100644 GIT binary patch literal 5475 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 aH{dMZnr18vtfD}r597Fcx|A&pUHxxQnMR}l delta 2554 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 Q5&!@I07*qoM6N<$g6`JS8vp Date: Tue, 14 Mar 2023 12:11:31 -0400 Subject: [PATCH 17/25] Enable translations for the SecureDrop Extension --- .../tails-config/tasks/install_shell_extension.yml | 10 ++++++++++ securedrop/babel.cfg | 3 +++ securedrop/i18n_tool.py | 4 +++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml b/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml index e592b33117..ec352caf3c 100644 --- a/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml +++ b/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml @@ -157,6 +157,16 @@ - "{{ _securedrop_extension_info }}" - "{{ tails_config_extension_directories }}" +- name: Add extension translations in Persistent Storage + synchronize: + src: "{{ tails_config_amnesia_persistent }}/securedrop/securedrop/translations/" + dest: "{{ tails_config_live_dotfiles }}/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/po/" + +- name: Add extension translations in the running system + synchronize: + src: "{{ tails_config_amnesia_persistent }}/securedrop/securedrop/translations/" + dest: "/home/amnesia/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/po/" + - name: Enable the new GNOME Shell extension become: no command: gnome-extensions enable securedrop@securedrop.freedom.press diff --git a/securedrop/babel.cfg b/securedrop/babel.cfg index 52ae100b04..061374b5b6 100644 --- a/securedrop/babel.cfg +++ b/securedrop/babel.cfg @@ -10,3 +10,6 @@ silent=False [jinja2: */*.html] silent=False extensions=jinja2.ext.autoescape,jinja2.ext.with_,jinja2.ext.do + +[javascript: **.js.in] +extract_messages = $._, jQuery._ diff --git a/securedrop/i18n_tool.py b/securedrop/i18n_tool.py index 95a4b46b73..3dc19ecbc6 100755 --- a/securedrop/i18n_tool.py +++ b/securedrop/i18n_tool.py @@ -27,6 +27,7 @@ LOCALE_DIR = { "securedrop": "securedrop/translations", "desktop": "install_files/ansible-base/roles/tails-config/templates", + "extension": "install_files/ansible-base/roles/tails-config/templates", } @@ -246,7 +247,8 @@ def set_translate_messages_parser(self, subps: _SubParsersAction) -> None: "translate-messages", help=("Update and compile " "source and template translations") ) translations_dir = join(dirname(realpath(__file__)), "translations") - sources = ".,source_templates,journalist_templates" + extension_location = join(dirname(realpath(__file__)), "..", LOCALE_DIR["extension"]) + sources = join(".,source_templates,journalist_templates,",extension_location) self.set_translate_parser(parser, translations_dir, sources) mapping = "babel.cfg" parser.add_argument( From eb4d0857bea186f54b8605ed8f09cd2cdeba3462 Mon Sep 17 00:00:00 2001 From: Nathan Dyer Date: Fri, 17 Mar 2023 15:00:14 -0400 Subject: [PATCH 18/25] Fix the icon appearance, set the position in the menu, and fix a bug with a button opening the wrong interface. --- .../roles/tails-config/templates/extension.js.in | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/install_files/ansible-base/roles/tails-config/templates/extension.js.in b/install_files/ansible-base/roles/tails-config/templates/extension.js.in index e102d72138..55f84292ca 100644 --- a/install_files/ansible-base/roles/tails-config/templates/extension.js.in +++ b/install_files/ansible-base/roles/tails-config/templates/extension.js.in @@ -37,10 +37,13 @@ class Indicator extends PanelMenu.Button { let gicon = Gio.icon_new_for_string(CurrentExtension.path + "/icons/securedrop-symbolic.png"); let icon = new St.Icon({ gicon }); + icon.icon_size = 18; + icon.height = 18; + icon.width = 18; let label = new St.Label({ text: 'SecureDrop', - y_expand: true, + y_expand: false, y_align: Clutter.ActorAlign.CENTER, }); @@ -59,7 +62,7 @@ class Indicator extends PanelMenu.Button { let journalist = new PopupMenu.PopupMenuItem('Launch Journalist Interface'); journalist.connect('activate', () => { - Util.spawn(['tor-browser', source_interface_address]); + Util.spawn(['tor-browser', journalist_interface_address]); }); let admin_label = new St.Label({ @@ -116,7 +119,11 @@ class Extension { enable() { this._indicator = new Indicator(); - let pos = Main.sessionMode.panel.left.indexOf('appMenu'); + + // Position is a zero-based index of where to put the extension + // in the status bar. Index 3, in Tails, would be to the right + // of the 'Places' Menu (Activites, Applicatons, Places, SD) + let pos = 3; if ('apps-menu' in Main.panel.statusArea) pos++; Main.panel.addToStatusArea(this._uuid, this._indicator, pos, 'left'); From 1ffac83c978ab8148ce6f2cae5ab00f28ffbcb31 Mon Sep 17 00:00:00 2001 From: Nathan Dyer Date: Tue, 21 Mar 2023 16:13:25 -0400 Subject: [PATCH 19/25] Appease the linter. --- .../roles/tails-config/tasks/install_shell_extension.yml | 4 ++-- securedrop/i18n_tool.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml b/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml index ec352caf3c..2705ebfac9 100644 --- a/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml +++ b/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml @@ -102,7 +102,7 @@ dest: "/home/amnesia/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/" owner: amnesia group: amnesia - + - name: Copy the symbolic icon used for the shell extension in Persistent Storage become: yes copy: @@ -110,7 +110,7 @@ dest: "{{ tails_config_live_dotfiles }}/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/icons/" owner: amnesia group: amnesia - + - name: Copy the symbolic icon used for the shell extension in the running system become: yes copy: diff --git a/securedrop/i18n_tool.py b/securedrop/i18n_tool.py index 3dc19ecbc6..81b2472f20 100755 --- a/securedrop/i18n_tool.py +++ b/securedrop/i18n_tool.py @@ -248,7 +248,7 @@ def set_translate_messages_parser(self, subps: _SubParsersAction) -> None: ) translations_dir = join(dirname(realpath(__file__)), "translations") extension_location = join(dirname(realpath(__file__)), "..", LOCALE_DIR["extension"]) - sources = join(".,source_templates,journalist_templates,",extension_location) + sources = join(".,source_templates,journalist_templates,", extension_location) self.set_translate_parser(parser, translations_dir, sources) mapping = "babel.cfg" parser.add_argument( From a68d4d417eddaeb4cf72234a3fa23b73b3d22331 Mon Sep 17 00:00:00 2001 From: Nathan Dyer Date: Wed, 24 May 2023 15:34:45 -0400 Subject: [PATCH 20/25] Add support for gnome-shell 3.38 and fix translations. This explicitly adds support for GNOME Shell 3.38, and corrects some issues with the gettext system to make translations work correctly. It also wraps the user-facing strings in gettext calls for said translations. --- .../metadata.json | 1 + .../tails-config/templates/extension.js.in | 17 ++++++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/metadata.json b/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/metadata.json index e5988c6296..385bd7c82b 100644 --- a/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/metadata.json +++ b/install_files/ansible-base/roles/tails-config/files/securedrop@securedrop.freedom.press/metadata.json @@ -3,6 +3,7 @@ "description": "SecureDrop Utility Menu", "uuid": "securedrop@securedrop.freedom.press", "shell-version": [ + "3.38", "40", "41", "42", diff --git a/install_files/ansible-base/roles/tails-config/templates/extension.js.in b/install_files/ansible-base/roles/tails-config/templates/extension.js.in index 55f84292ca..cd2296cda1 100644 --- a/install_files/ansible-base/roles/tails-config/templates/extension.js.in +++ b/install_files/ansible-base/roles/tails-config/templates/extension.js.in @@ -11,15 +11,18 @@ const PanelMenu = imports.ui.panelMenu; const PopupMenu = imports.ui.popupMenu; const St = imports.gi.St; +const Gettext = imports.gettext; const CurrentExtension = imports.misc.extensionUtils.getCurrentExtension(); const Gio = imports.gi.Gio; +const Domain = Gettext.domain(GETTEXT_DOMAIN) + const source_interface_address = "{{ item.0.source_interface_address }}"; const journalist_interface_address = "{{ item.0.journalist_interface_address }}"; const app_server_hostname = "{{ item.0.app_hostname }}"; const mon_server_hostname = "{{ item.0.mon_hostname }}"; -const _ = ExtensionUtils.gettext; +const _ = Domain.gettext; const Indicator = GObject.registerClass( class Indicator extends PanelMenu.Button { @@ -55,12 +58,12 @@ class Indicator extends PanelMenu.Button { topBox.add_child(label); this.add_child(topBox); - let source = new PopupMenu.PopupMenuItem('Launch Source Interface'); + let source = new PopupMenu.PopupMenuItem(_('Launch Source Interface')); source.connect('activate', () => { Util.spawn(['tor-browser', source_interface_address]); }); - let journalist = new PopupMenu.PopupMenuItem('Launch Journalist Interface'); + let journalist = new PopupMenu.PopupMenuItem(_('Launch Journalist Interface')); journalist.connect('activate', () => { Util.spawn(['tor-browser', journalist_interface_address]); }); @@ -71,22 +74,22 @@ class Indicator extends PanelMenu.Button { y_align: Clutter.ActorAlign.START, }); - let updates = new PopupMenu.PopupMenuItem('Check for SecureDrop Updates'); + let updates = new PopupMenu.PopupMenuItem(_('Check for SecureDrop Updates')); updates.connect('activate', () => { Util.spawn(['python3', '/home/amnesia/Persistent/securedrop/journalist_gui/SecureDropUpdater']); }); - let app_server_ssh = new PopupMenu.PopupMenuItem('SSH into the App Server'); + let app_server_ssh = new PopupMenu.PopupMenuItem(_('SSH into the App Server')); app_server_ssh.connect('activate', () => { Util.trySpawnCommandLine(`gnome-terminal -- ssh ` + app_server_hostname); }); - let mon_server_ssh = new PopupMenu.PopupMenuItem('SSH into the Monitor Server'); + let mon_server_ssh = new PopupMenu.PopupMenuItem(_('SSH into the Monitor Server')); mon_server_ssh.connect('activate', () => { Util.trySpawnCommandLine(`gnome-terminal -- ssh ` + mon_server_hostname); }); - let keypass = new PopupMenu.PopupMenuItem('Open KeePassXC Password Vault'); + let keypass = new PopupMenu.PopupMenuItem(_('Open KeePassXC Password Vault')); keypass.connect('activate', () => { Util.trySpawnCommandLine(`keepassxc`); }); From 5db2cb4513a8beb287b7440c2b6c9aa6a51b0d42 Mon Sep 17 00:00:00 2001 From: Nathan Dyer Date: Thu, 25 May 2023 14:01:01 -0400 Subject: [PATCH 21/25] Prompt user for a reboot and remove logic to install to running system --- .../roles/tails-config/defaults/main.yml | 4 +- .../tasks/install_shell_extension.yml | 49 ------------------- .../roles/tails-config/tasks/main.yml | 4 ++ 3 files changed, 5 insertions(+), 52 deletions(-) diff --git a/install_files/ansible-base/roles/tails-config/defaults/main.yml b/install_files/ansible-base/roles/tails-config/defaults/main.yml index 433f4b9c3c..4c37d1f5c4 100644 --- a/install_files/ansible-base/roles/tails-config/defaults/main.yml +++ b/install_files/ansible-base/roles/tails-config/defaults/main.yml @@ -24,10 +24,8 @@ tails_config_desktop_icon_directories: - "{{ tails_config_amnesia_home }}/.local/share/applications" - "{{ tails_config_live_dotfiles }}/.local/share/applications" -# Destination directories for storing the SecureDrop GNOME Shell -# extension +# Destination directories for storing the SecureDrop GNOME Shell extension tails_config_extension_directories: - - "{{ tails_config_amnesia_home }}/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/" - "{{ tails_config_live_dotfiles }}/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/" # Path for storing site-specific ATHS info for connecting to Journalist Interface. diff --git a/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml b/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml index 2705ebfac9..2931a7d500 100644 --- a/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml +++ b/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml @@ -63,30 +63,6 @@ owner: amnesia group: amnesia -- name: Copy the extension metadata to the extension directory in the running system - become: yes - copy: - src: securedrop@securedrop.freedom.press/metadata.json - dest: "/home/amnesia/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/" - owner: amnesia - group: amnesia - -- name: Copy the extension metadata to the extension directory in Persistent Storage - become: yes - copy: - src: securedrop@securedrop.freedom.press/metadata.json - dest: "{{ tails_config_live_dotfiles }}/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/" - owner: amnesia - group: amnesia - -- name: Copy the extension metadata to the extension directory in the running system - become: yes - copy: - src: securedrop@securedrop.freedom.press/metadata.json - dest: "/home/amnesia/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/" - owner: amnesia - group: amnesia - - name: Copy the extension CSS to the extension directory in Persistent Storage become: yes copy: @@ -95,14 +71,6 @@ owner: amnesia group: amnesia -- name: Copy the extension CSS to the extension directory in the running system - become: yes - copy: - src: securedrop@securedrop.freedom.press/stylesheet.css - dest: "/home/amnesia/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/" - owner: amnesia - group: amnesia - - name: Copy the symbolic icon used for the shell extension in Persistent Storage become: yes copy: @@ -111,14 +79,6 @@ owner: amnesia group: amnesia -- name: Copy the symbolic icon used for the shell extension in the running system - become: yes - copy: - src: securedrop-symbolic.png - dest: "/home/amnesia/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/icons/" - owner: amnesia - group: amnesia - - name: Set the right variable for source set_fact: source_iface: "{{ sourcev3_interface_lookup_result }}" @@ -161,12 +121,3 @@ synchronize: src: "{{ tails_config_amnesia_persistent }}/securedrop/securedrop/translations/" dest: "{{ tails_config_live_dotfiles }}/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/po/" - -- name: Add extension translations in the running system - synchronize: - src: "{{ tails_config_amnesia_persistent }}/securedrop/securedrop/translations/" - dest: "/home/amnesia/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/po/" - -- name: Enable the new GNOME Shell extension - become: no - command: gnome-extensions enable securedrop@securedrop.freedom.press diff --git a/install_files/ansible-base/roles/tails-config/tasks/main.yml b/install_files/ansible-base/roles/tails-config/tasks/main.yml index 542ca910e3..a39ccb01ba 100644 --- a/install_files/ansible-base/roles/tails-config/tasks/main.yml +++ b/install_files/ansible-base/roles/tails-config/tasks/main.yml @@ -19,3 +19,7 @@ - include: create_ssh_aliases.yml when: site_specific_result.stat.exists + +- name: Remind user to reboot + debug: + msg: "Please reboot your Workstation to take advantage of the SecureDrop Extension." From 821a2c70e480aa03cd09429acc629707f3a5615a Mon Sep 17 00:00:00 2001 From: Nathan Dyer Date: Tue, 30 May 2023 16:11:58 -0400 Subject: [PATCH 22/25] Only show one message to the user at end of the run, and refer to the extension as the SecureDrop Menu. --- install_files/ansible-base/roles/tails-config/tasks/main.yml | 4 ---- install_files/ansible-base/securedrop-tails.yml | 1 + 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/install_files/ansible-base/roles/tails-config/tasks/main.yml b/install_files/ansible-base/roles/tails-config/tasks/main.yml index a39ccb01ba..542ca910e3 100644 --- a/install_files/ansible-base/roles/tails-config/tasks/main.yml +++ b/install_files/ansible-base/roles/tails-config/tasks/main.yml @@ -19,7 +19,3 @@ - include: create_ssh_aliases.yml when: site_specific_result.stat.exists - -- name: Remind user to reboot - debug: - msg: "Please reboot your Workstation to take advantage of the SecureDrop Extension." diff --git a/install_files/ansible-base/securedrop-tails.yml b/install_files/ansible-base/securedrop-tails.yml index 07909a939f..6f192c3199 100755 --- a/install_files/ansible-base/securedrop-tails.yml +++ b/install_files/ansible-base/securedrop-tails.yml @@ -19,6 +19,7 @@ msg: >- Successfully configured Tor and set up desktop bookmarks for SecureDrop! You will see a notification appear on your screen when Tor is ready. + Please reboot your Workstation to take advantage of the SecureDrop Menu. The Journalist Interface's Tor onion URL is: http://{{ journalist_iface.stdout }} The Source Interfaces's Tor onion URL is: http://{{ source_iface.stdout }} From 76f3adeed90f4aaadbf0685e09dec6314367d5c0 Mon Sep 17 00:00:00 2001 From: Cory Francis Myers Date: Tue, 30 May 2023 16:44:56 -0700 Subject: [PATCH 23/25] build(gettext): extend the "translate-desktop" command to cover the GNOME Shell extension In the original (since lost) 1cfd35b, we tried to treat the GNOME Shell extension as a separate "securedrop/extension" Weblate component with its own "translate-extension" command, replicating both "--extract-update" and "--compile" modes. In f3d3f04, we tried to treat the GNOME Shell extension as an extension (sorry) of the main "securedrop/securedrop" component, taking advantage of Babel's mapping feature to parse the ".js.in" file as JavaScript. Here we harmonize the two approaches. "translate-desktop --extract-update" is now a two-step process, first via Babel over the ".js.in" JavaScript file, then as usual via xgettext over the ".j2.in" desktop templates. (This is logically reversed, but Babel appears to have no equivalent of xgettext's appending "--join-existing" mode.) "translate-desktop --compile" similarly does two passes with msgfmt, first to create the standard gettext directory layout and then to update the desktop templates. NB. We also add "msgmerge --no-fuzzy-matching" after #6772, which required rebasing from "develop". --- .gitignore | 4 +- securedrop/i18n_tool.py | 88 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 83 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 113fdca04d..60fbd34427 100644 --- a/.gitignore +++ b/.gitignore @@ -94,8 +94,8 @@ coverage.xml .hypothesis/ .mypy_cache/ -# Translations -*.mo +# Translations compiled during packaging: +securedrop/translations/**/*.mo # Flask stuff: instance/ diff --git a/securedrop/i18n_tool.py b/securedrop/i18n_tool.py index 81b2472f20..89e5bed536 100755 --- a/securedrop/i18n_tool.py +++ b/securedrop/i18n_tool.py @@ -27,7 +27,6 @@ LOCALE_DIR = { "securedrop": "securedrop/translations", "desktop": "install_files/ansible-base/roles/tails-config/templates", - "extension": "install_files/ansible-base/roles/tails-config/templates", } @@ -142,9 +141,44 @@ def translate_desktop(self, args: argparse.Namespace) -> None: if args.extract_update: sources = args.sources.split(",") + xgettext_flags = [] + + # First extract from JavaScript sources via Babel ("xgettext + # --language=JavaScript" can't parse gettext as exposed by GNOME + # JavaScript): + js_sources = [source for source in sources if ".js" in source] + if js_sources: + xgettext_flags.append("--join-existing") + subprocess.check_call( + [ + "pybabel", + "extract", + "--charset=utf-8", + "--mapping", + args.mapping, + "--output", + "desktop.pot", + "--project=SecureDrop", + "--version", + args.version, + "--msgid-bugs-address=securedrop@freedom.press", + "--copyright-holder=Freedom of the Press Foundation", + "--add-comments=Translators:", + "--strip-comments", + "--add-location=never", + "--no-wrap", + *js_sources, + ], + cwd=args.translations_dir, + ) + + # Then extract from desktop templates via xgettext in appending + # "--join-existing" mode: + desktop_sources = [source for source in sources if ".js" not in source] subprocess.check_call( [ "xgettext", + *xgettext_flags, "--output=desktop.pot", "--language=Desktop", "--keyword", @@ -153,7 +187,7 @@ def translate_desktop(self, args: argparse.Namespace) -> None: args.version, "--msgid-bugs-address=securedrop@freedom.press", "--copyright-holder=Freedom of the Press Foundation", - *sources, + *desktop_sources, ], cwd=args.translations_dir, ) @@ -168,7 +202,9 @@ def translate_desktop(self, args: argparse.Namespace) -> None: if not f.endswith(".po"): continue po_file = os.path.join(args.translations_dir, f) - subprocess.check_call(["msgmerge", "--update", po_file, messages_file]) + subprocess.check_call( + ["msgmerge", "--no-fuzzy-matching", "--update", po_file, messages_file] + ) log.warning(f"messages translations updated in {messages_file}") else: log.warning("desktop translations are already up to date") @@ -181,7 +217,34 @@ def translate_desktop(self, args: argparse.Namespace) -> None: try: open(linguas_file, "w").write(content) - for source in args.sources.split(","): + # First, compile each message catalog for normal gettext use. + # We have to iterate over them, rather than using "pybabel + # compile --directory", in order to replicate gettext's + # standard "{locale}/LC_MESSAGES/{domain}.mo" structure (like + # "securedrop/translations"). + locale_dir = os.path.join(args.translations_dir, "locale") + for po in pos: + locale = po.replace(".po", "") + output_dir = os.path.join(locale_dir, locale, "LC_MESSAGES") + subprocess.run(["mkdir", "--parents", output_dir], check=True) + subprocess.run( + [ + "msgfmt", + "--output-file", + os.path.join(output_dir, "messages.mo"), + po, + ], + check=True, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + cwd=args.translations_dir, + ) + + # Then use msgfmt to update the desktop files as usual. + desktop_sources = [ + source for source in args.sources.split(",") if ".js" not in source + ] + for source in desktop_sources: target = source.rstrip(".in") subprocess.check_call( [ @@ -247,8 +310,7 @@ def set_translate_messages_parser(self, subps: _SubParsersAction) -> None: "translate-messages", help=("Update and compile " "source and template translations") ) translations_dir = join(dirname(realpath(__file__)), "translations") - extension_location = join(dirname(realpath(__file__)), "..", LOCALE_DIR["extension"]) - sources = join(".,source_templates,journalist_templates,", extension_location) + sources = ".,source_templates,journalist_templates" self.set_translate_parser(parser, translations_dir, sources) mapping = "babel.cfg" parser.add_argument( @@ -267,7 +329,19 @@ def set_translate_desktop_parser(self, subps: _SubParsersAction) -> None: "..", LOCALE_DIR["desktop"], ) - sources = "desktop-journalist-icon.j2.in,desktop-source-icon.j2.in" + sources = ",".join( + [ + "desktop-journalist-icon.j2.in", + "desktop-source-icon.j2.in", + "extension.js.in", + ] + ) + mapping = join(dirname(realpath(__file__)), "babel.cfg") + parser.add_argument( + "--mapping", + default=mapping, + help=f"Mapping of files to consider (default {mapping})", + ) self.set_translate_parser(parser, translations_dir, sources) parser.set_defaults(func=self.translate_desktop) From ab015f1e337f7f110b9c422f8474798e139e1243 Mon Sep 17 00:00:00 2001 From: Cory Francis Myers Date: Tue, 30 May 2023 18:27:57 -0700 Subject: [PATCH 24/25] deploy(tails-config): expect "messages" domain in "locale" directory In Ansible idiom, the "locale" tree should come from the role's files rather than its template, which would simplify the path reference. However, it's generated by "i18n_tool.py", which shouldn't be concerned with the surrounding Ansible layout. --- .../roles/tails-config/tasks/install_shell_extension.yml | 4 ++-- .../ansible-base/roles/tails-config/templates/extension.js.in | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml b/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml index 2931a7d500..fb5327bf5b 100644 --- a/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml +++ b/install_files/ansible-base/roles/tails-config/tasks/install_shell_extension.yml @@ -119,5 +119,5 @@ - name: Add extension translations in Persistent Storage synchronize: - src: "{{ tails_config_amnesia_persistent }}/securedrop/securedrop/translations/" - dest: "{{ tails_config_live_dotfiles }}/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/po/" + src: roles/tails-config/templates/locale/ + dest: "{{ tails_config_live_dotfiles }}/.local/share/gnome-shell/extensions/securedrop@securedrop.freedom.press/locale/" diff --git a/install_files/ansible-base/roles/tails-config/templates/extension.js.in b/install_files/ansible-base/roles/tails-config/templates/extension.js.in index cd2296cda1..91253dd426 100644 --- a/install_files/ansible-base/roles/tails-config/templates/extension.js.in +++ b/install_files/ansible-base/roles/tails-config/templates/extension.js.in @@ -1,6 +1,6 @@ /* exported init */ -const GETTEXT_DOMAIN = 'securedrop'; +const GETTEXT_DOMAIN = 'messages'; const {Clutter, GObject, GLib } = imports.gi; From 85b722c6a30c22cf93bde4b624aaa7a9fca0ad83 Mon Sep 17 00:00:00 2001 From: Kevin O'Gorman Date: Mon, 5 Jun 2023 18:18:23 -0400 Subject: [PATCH 25/25] Adding placeholder locale files --- .../roles/tails-config/templates/ar.po | 21 ++++++++++++++++ .../roles/tails-config/templates/ca.po | 21 ++++++++++++++++ .../roles/tails-config/templates/cs.po | 21 ++++++++++++++++ .../roles/tails-config/templates/de_DE.po | 21 ++++++++++++++++ .../roles/tails-config/templates/desktop.pot | 23 +++++++++++++++++- .../roles/tails-config/templates/el.po | 21 ++++++++++++++++ .../roles/tails-config/templates/es_ES.po | 21 ++++++++++++++++ .../roles/tails-config/templates/fr.po | 21 ++++++++++++++++ .../roles/tails-config/templates/hi.po | 21 ++++++++++++++++ .../roles/tails-config/templates/is.po | 21 ++++++++++++++++ .../roles/tails-config/templates/it.po | 21 ++++++++++++++++ .../locale/ar/LC_MESSAGES/messages.mo | Bin 0 -> 729 bytes .../locale/ca/LC_MESSAGES/messages.mo | Bin 0 -> 664 bytes .../locale/cs/LC_MESSAGES/messages.mo | Bin 0 -> 680 bytes .../locale/de_DE/LC_MESSAGES/messages.mo | Bin 0 -> 677 bytes .../locale/el/LC_MESSAGES/messages.mo | Bin 0 -> 690 bytes .../locale/es_ES/LC_MESSAGES/messages.mo | Bin 0 -> 673 bytes .../locale/fr/LC_MESSAGES/messages.mo | Bin 0 -> 663 bytes .../locale/hi/LC_MESSAGES/messages.mo | Bin 0 -> 703 bytes .../locale/is/LC_MESSAGES/messages.mo | Bin 0 -> 675 bytes .../locale/it/LC_MESSAGES/messages.mo | Bin 0 -> 669 bytes .../locale/nb_NO/LC_MESSAGES/messages.mo | Bin 0 -> 683 bytes .../locale/nl/LC_MESSAGES/messages.mo | Bin 0 -> 671 bytes .../locale/pt_BR/LC_MESSAGES/messages.mo | Bin 0 -> 680 bytes .../locale/pt_PT/LC_MESSAGES/messages.mo | Bin 0 -> 684 bytes .../locale/ro/LC_MESSAGES/messages.mo | Bin 0 -> 715 bytes .../locale/ru/LC_MESSAGES/messages.mo | Bin 0 -> 767 bytes .../locale/sk/LC_MESSAGES/messages.mo | Bin 0 -> 680 bytes .../locale/sv/LC_MESSAGES/messages.mo | Bin 0 -> 649 bytes .../locale/tr/LC_MESSAGES/messages.mo | Bin 0 -> 645 bytes .../locale/zh_Hans/LC_MESSAGES/messages.mo | Bin 0 -> 650 bytes .../locale/zh_Hant/LC_MESSAGES/messages.mo | Bin 0 -> 674 bytes .../roles/tails-config/templates/nb_NO.po | 21 ++++++++++++++++ .../roles/tails-config/templates/nl.po | 21 ++++++++++++++++ .../roles/tails-config/templates/pt_BR.po | 21 ++++++++++++++++ .../roles/tails-config/templates/pt_PT.po | 21 ++++++++++++++++ .../roles/tails-config/templates/ro.po | 21 ++++++++++++++++ .../roles/tails-config/templates/ru.po | 21 ++++++++++++++++ .../roles/tails-config/templates/sk.po | 21 ++++++++++++++++ .../roles/tails-config/templates/sv.po | 21 ++++++++++++++++ .../roles/tails-config/templates/tr.po | 21 ++++++++++++++++ .../roles/tails-config/templates/zh_Hans.po | 21 ++++++++++++++++ .../roles/tails-config/templates/zh_Hant.po | 21 ++++++++++++++++ 43 files changed, 463 insertions(+), 1 deletion(-) create mode 100644 install_files/ansible-base/roles/tails-config/templates/locale/ar/LC_MESSAGES/messages.mo create mode 100644 install_files/ansible-base/roles/tails-config/templates/locale/ca/LC_MESSAGES/messages.mo create mode 100644 install_files/ansible-base/roles/tails-config/templates/locale/cs/LC_MESSAGES/messages.mo create mode 100644 install_files/ansible-base/roles/tails-config/templates/locale/de_DE/LC_MESSAGES/messages.mo create mode 100644 install_files/ansible-base/roles/tails-config/templates/locale/el/LC_MESSAGES/messages.mo create mode 100644 install_files/ansible-base/roles/tails-config/templates/locale/es_ES/LC_MESSAGES/messages.mo create mode 100644 install_files/ansible-base/roles/tails-config/templates/locale/fr/LC_MESSAGES/messages.mo create mode 100644 install_files/ansible-base/roles/tails-config/templates/locale/hi/LC_MESSAGES/messages.mo create mode 100644 install_files/ansible-base/roles/tails-config/templates/locale/is/LC_MESSAGES/messages.mo create mode 100644 install_files/ansible-base/roles/tails-config/templates/locale/it/LC_MESSAGES/messages.mo create mode 100644 install_files/ansible-base/roles/tails-config/templates/locale/nb_NO/LC_MESSAGES/messages.mo create mode 100644 install_files/ansible-base/roles/tails-config/templates/locale/nl/LC_MESSAGES/messages.mo create mode 100644 install_files/ansible-base/roles/tails-config/templates/locale/pt_BR/LC_MESSAGES/messages.mo create mode 100644 install_files/ansible-base/roles/tails-config/templates/locale/pt_PT/LC_MESSAGES/messages.mo create mode 100644 install_files/ansible-base/roles/tails-config/templates/locale/ro/LC_MESSAGES/messages.mo create mode 100644 install_files/ansible-base/roles/tails-config/templates/locale/ru/LC_MESSAGES/messages.mo create mode 100644 install_files/ansible-base/roles/tails-config/templates/locale/sk/LC_MESSAGES/messages.mo create mode 100644 install_files/ansible-base/roles/tails-config/templates/locale/sv/LC_MESSAGES/messages.mo create mode 100644 install_files/ansible-base/roles/tails-config/templates/locale/tr/LC_MESSAGES/messages.mo create mode 100644 install_files/ansible-base/roles/tails-config/templates/locale/zh_Hans/LC_MESSAGES/messages.mo create mode 100644 install_files/ansible-base/roles/tails-config/templates/locale/zh_Hant/LC_MESSAGES/messages.mo diff --git a/install_files/ansible-base/roles/tails-config/templates/ar.po b/install_files/ansible-base/roles/tails-config/templates/ar.po index 2899a36cfc..ded47b45d4 100644 --- a/install_files/ansible-base/roles/tails-config/templates/ar.po +++ b/install_files/ansible-base/roles/tails-config/templates/ar.po @@ -19,6 +19,27 @@ msgstr "" "&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n" "X-Generator: Weblate 2.20\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "واجهة SecureDrop للصحفيين" diff --git a/install_files/ansible-base/roles/tails-config/templates/ca.po b/install_files/ansible-base/roles/tails-config/templates/ca.po index 85a9bfb564..9bbf8fcf4c 100644 --- a/install_files/ansible-base/roles/tails-config/templates/ca.po +++ b/install_files/ansible-base/roles/tails-config/templates/ca.po @@ -18,6 +18,27 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 3.4\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "Interfície de periodista del SecureDrop" diff --git a/install_files/ansible-base/roles/tails-config/templates/cs.po b/install_files/ansible-base/roles/tails-config/templates/cs.po index 537171104d..c4ccca05c1 100644 --- a/install_files/ansible-base/roles/tails-config/templates/cs.po +++ b/install_files/ansible-base/roles/tails-config/templates/cs.po @@ -18,6 +18,27 @@ msgstr "" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" "X-Generator: Weblate 3.7.1\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "SecureDrop rozhraní novináře" diff --git a/install_files/ansible-base/roles/tails-config/templates/de_DE.po b/install_files/ansible-base/roles/tails-config/templates/de_DE.po index afc5fb2ebb..df4f87deb9 100644 --- a/install_files/ansible-base/roles/tails-config/templates/de_DE.po +++ b/install_files/ansible-base/roles/tails-config/templates/de_DE.po @@ -18,6 +18,27 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 2.17.1\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "Journalistenschnittstelle für SecureDrop" diff --git a/install_files/ansible-base/roles/tails-config/templates/desktop.pot b/install_files/ansible-base/roles/tails-config/templates/desktop.pot index 524987d447..c1ee0f43fe 100644 --- a/install_files/ansible-base/roles/tails-config/templates/desktop.pot +++ b/install_files/ansible-base/roles/tails-config/templates/desktop.pot @@ -13,9 +13,30 @@ msgstr "" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=CHARSET\n" +"Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "" diff --git a/install_files/ansible-base/roles/tails-config/templates/el.po b/install_files/ansible-base/roles/tails-config/templates/el.po index 2e90927a9e..0fb7fce83e 100644 --- a/install_files/ansible-base/roles/tails-config/templates/el.po +++ b/install_files/ansible-base/roles/tails-config/templates/el.po @@ -18,6 +18,27 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 2.20\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "Διεπαφή δημοσιογράφου του SecureDrop" diff --git a/install_files/ansible-base/roles/tails-config/templates/es_ES.po b/install_files/ansible-base/roles/tails-config/templates/es_ES.po index ccb841eb22..accdb186a9 100644 --- a/install_files/ansible-base/roles/tails-config/templates/es_ES.po +++ b/install_files/ansible-base/roles/tails-config/templates/es_ES.po @@ -18,6 +18,27 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 2.20\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "Interfaz de periodista de SecureDrop" diff --git a/install_files/ansible-base/roles/tails-config/templates/fr.po b/install_files/ansible-base/roles/tails-config/templates/fr.po index 6aad8d6935..8589fb1f38 100644 --- a/install_files/ansible-base/roles/tails-config/templates/fr.po +++ b/install_files/ansible-base/roles/tails-config/templates/fr.po @@ -19,6 +19,27 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n > 1;\n" "X-Generator: Weblate 2.14.1\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "SecureDrop - Interface des journalistes" diff --git a/install_files/ansible-base/roles/tails-config/templates/hi.po b/install_files/ansible-base/roles/tails-config/templates/hi.po index 8697f96d74..142c2c407b 100644 --- a/install_files/ansible-base/roles/tails-config/templates/hi.po +++ b/install_files/ansible-base/roles/tails-config/templates/hi.po @@ -18,6 +18,27 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 2.18\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "SecureDrop पत्रकार अंतराफलक" diff --git a/install_files/ansible-base/roles/tails-config/templates/is.po b/install_files/ansible-base/roles/tails-config/templates/is.po index c60c0b84ee..1124bd35a8 100644 --- a/install_files/ansible-base/roles/tails-config/templates/is.po +++ b/install_files/ansible-base/roles/tails-config/templates/is.po @@ -18,6 +18,27 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n % 10 != 1 || n % 100 == 11;\n" "X-Generator: Weblate 3.4\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "Blaðamannaviðmót SecureDrop" diff --git a/install_files/ansible-base/roles/tails-config/templates/it.po b/install_files/ansible-base/roles/tails-config/templates/it.po index c186161961..bca9c254cb 100644 --- a/install_files/ansible-base/roles/tails-config/templates/it.po +++ b/install_files/ansible-base/roles/tails-config/templates/it.po @@ -18,6 +18,27 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 2.18\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "Interfaccia Giornalista di SecureDrop" diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/ar/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/ar/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000000000000000000000000000000000..93d17468941382933d96cc53cee6cb9085d379fa GIT binary patch literal 729 zcmaJ_mEiM48|VvzYQ{sf*8F4g zhq&e&D)|gU!}<|BMWqudd>D53A9Rm;aM~M<`zH_W5vEcZHqdbrvAt!i*+lxFSFc9& z>h4S-MsiV46>4n{PuK`wBtxIi zm52p&Rr%x#6fEK;kC9D~FMQ}KK21XCoEej9-*H~zl!{=zYN|+c(sDZO zRQFDV`ni#*!!@wEqHa;-j}pQL0!I1X$*s}jFZlJBH9q1ai!4&k0yt# zRmBz4%uunO2xXLr*oW3MG4^o2RD8}3rCMkoM7lcaV7m>a3`7vPa1UG{ZxDDSy;3$v zHVS#$bKRYw3AI|OJAqeZG%KH1q;1l9t8G7FN3=gx?)7oG9B9-Vu5IP-voG1V{9X1H e)_#oqBEQIfW#9Aj`~!V&{}YzKp}-&6PwO9OC+402 literal 0 HcmV?d00001 diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/ca/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/ca/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000000000000000000000000000000000..bba4100cec06ddaa18399d40d9839ebfbe043946 GIT binary patch literal 664 zcmZ9J&2AGh5P+Az%O1Ic#J~v&c{d5I6r84NNz*Ej&?pIoBUA5WyJcfrwzq{N55bWK z-~cbt_uyHW>>jr2NT0^z`M3W)e)uzDdB8knc9=)Zl-bG`<{5*`6Xpl=_g)nJV*Qet z-jAXetSi=h9kHrqTd$TSsmjrjGZx;N%4sYMA7G*bxiu<^Zuyt&S9Hracjl5*5R*)t zk@JPo66S}a_lGBAI2$jPlhY6Jf~;{t%zR#C;%$|Cu`&{T-8JK`2Wv-^nN4CHc^}VD z#e%MiZ7p$xfh6=g-8Z7MD|&tC_GNGPRfi>>q7P!_Q2P>tagv8e4Kt$y>YLxNcgg0# zrZy>281^|s=N0B8R)iY~BMew_%HBl?*2^@#rgJVuNjq9%T%OuyN1wL$X-58QFg8_~ zwsj>ajAxVCxP6Om(uqer18JW1yX9p9eG92AvCsoh7w9~N;m6gn=(lm(oz~>USSyni zI+xHtFG4&oD~F{xHg4l3Xj_|p*c(7|9BOzzgzg~zEKW$1YhLA3vlP5ecH*e{)SEx5 ZAjk+Txq>_RfNYh}e)QeIHLq|tJ|v*l07k8#TzX|=%E zvO&VGQJY*z4x`iF>(h%qT=&P5!POggjHS|+4NaOS>}8c2HdP$Vde?+@J(+97L@m8i zqcQI2ijDC$uXC|8VUa^C2oG66PYB^YZy&x02=1jYmQA&grVv(X4k4)_t?4d=^fE1P z)QKU-WO*TG#*5YRh<=i3B~oNl6iW`h6~-BKGiyu3eg7lQC>MH7ZJyGpUv8Q-exv&d znj5Q1KQ?}ol|yXY;b7Qrh7o#!+fy`4NyUCHsT+%*tX~!)mmP>Rp$*#T?ev@-H0$c7 z=BQa;#wy8W%Hd#^TX$4cS`_SD>80Ty%k`&;+8x-uM!PbK!sl=d0dUxrM^OuQc0hKc zy;=-OY<1lC>;fg~&CK3yI)=8l?}hI6QERozsE)f|Ak}Ry?|%ON{@+z-{1qMI0-b-} CMa?S! literal 0 HcmV?d00001 diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/de_DE/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/de_DE/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000000000000000000000000000000000..52bb5575aae0032f193a8f2e1ff6f4433d556b34 GIT binary patch literal 677 zcmaix&2G~`5Xa5e#Ye6nF-TkxT02fbtu_s6Y1}BKp&q@QMYW_EV}vwt7nzX{mxF^`#-%me0>Y3vL0gi*{R<_GiZP7wTL z|D0Le4T5Lvzq99Xz;0trzm3f>s|g2WD>$(=8C7cMVPrhgQe_z2%Fj5T;jP?+>{raZ z80BJttg zgQ^lLs6s-@8+hMaI63m%hEck5ZV-y;XT@no?7+#Q1y%Fvu?jdrTWTRgCL`8KGj*O;ye~ z*^o?1rdhq)%u1FQULwjTc!6hgmI0jtD`V2fs>fvG$QY?(-+u>(mxFINp} zzw!Gi=wli0*~Gs?O{M1{T$4QhlnW`T2kEVv=in LWiP7_|2g{?`w{Hy literal 0 HcmV?d00001 diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/es_ES/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/es_ES/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000000000000000000000000000000000..d1f26c7c804246306cf6e36a81db0b349e46964b GIT binary patch literal 673 zcmZ9J&2H2%5XZyUB}cABVvx8Y=Sv_(*)Hm~O{*jk-x<@=Bo)Zsom@>yGFBB>R+j zf7kPX>^HJ>?2*~3&$rbQi_YM&Q5w!vXC!Zgbug6gGnh|~UQJGOxXc&J>BVb*fm#{IX0{e3JM3!9Rw@I#eYK=l4=RILsy5IDt@Y;@ zY=NIepNk!HhZ!VMoU%A!(F=&uEKZ+AB>$XS$5w_*+i<5$29r`Xm4Y*V(;_?M#t4*7 zS=g_HQ&;PQZrw@O1%+x~(q&n9yhgS{-e$1WTnf8^{f%?lW?}dR*OV25p~^s+I@G&% zZ8)5VCE8C;=@4x=hkWVJrn7vQOdLf1k)pv$s{BS%YYwkns2eWi2#O6i7Tx&G z>V&03T;E}ZhUKzQrI2+7=~_5{-gJgH>_nN?W+3%;Ysbk5cFVDZCu4|5{yTPx63uQ# lZ+Cq`5+srD{r%&wP$FnFg7RC(``z&8{{&SXm5%=f`~kD~&0zol literal 0 HcmV?d00001 diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/fr/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/fr/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000000000000000000000000000000000..0ab3f8158b87c41e51235ff038a41b5363d34638 GIT binary patch literal 663 zcmaKq&2G~`5Xa5e#Ye6nG2+4jtv^DgmQ7PNv`H06NR))ak&QieT%28Nc1_zO55bXF z;E{M1#*Tz@Vx*sDJu{x&|Lp#G`uL~E_K11T95GLrDbv_j<^`jeXUq@g_XE%S#r_pD zedu{F**o?e_Sm)7^lNQ}Nlkc3rh@mTCaucCI+$pOl&J*0gZzr~2_EDYWNt8VVv>q$ zBwH9QVKKb;FuWSU^=P@8%s=`|tPD9Zvw4wD?wN7rycbAuwM=|oI%|8zlbZ;Nc)j|-fMzh5FZ7xe|VLmyG39< RaP#l#(f+T_wokx%e*uDY$qWDh literal 0 HcmV?d00001 diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/hi/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/hi/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000000000000000000000000000000000..94f32a8a3699dc117573f7ae4963bee994229266 GIT binary patch literal 703 zcmZ{hO>fgc5Qfdy#Ye6nF`UubP6CqaG^nLbOQ4}4Nef4|_S9amcdgwuA4iZlRUCWd z=3d}};KGTYg8Wk$CrAkgMtU^kd3R=a#=oy$J$J~i5I2dt#5Ll8Xzc}Yi{Qi!;yv-> zlH+_Pzd<~`>^MF0XXGjEkXu;WZ(%cxD~-EamGDSaTJl^N3nOV!pYj-;HGM{UjBDCN ztCtvCHcHqrY9o}4V6wgQczb^c$HVDtboj)bVyU!cW0Q)6J*ZN{<|+cSxHX|$w@x); zq6)9nXpB2KWK(=C+FopzTa2I^bV3&NSP(*|7u^f)1Z3_3H{=?KPE#*2a{ zaAXQDVY8^Rq-w*Ba4Rji$h}w<_o+^%6;F}Pkrxp>6fzO8nOR$!$oJpi3AICS^*m4M z)GwEF8h@4d6Ev@^D*a6OtF94b!X1ys!__`IUf}L1TBoG$HLXQcCJ&@Y$#)u2$@C@o(Sts@=EiZ?I~TD2xPhVG=pv*mf=9c?E!T9?sK+} z67_O3&z3_$*XxAt`u}X|FHK!H7oVE?TT`Dm^)CvbsXsRLhgN8_l=|A#-%0+r^5@^O Ki!(a;|C&FJKJ>Bx literal 0 HcmV?d00001 diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/is/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/is/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000000000000000000000000000000000..15ba8a0c7b26199be63d26e7be2d30970c707c89 GIT binary patch literal 675 zcmZ{h&2G~`5Xa5e#Ye6nm>xKx^+%|n-PEXGX)!b;NDxKpQF#hI61f%{?bq5`PkW=@!iwMzdh0;;yJNNJRweqR^N%2gdm;~zlhrhp7)3B z3u6Az^ETQzSqgh(R%-jLG{vkjcxZGDA9Z7tD5Z6fDu-qvGW71{rwhw_isj|3p~FW=1Gm3a1T+(S;M2QoxQr*UIMF zIcavK!K*-<;yu-?q7enM8H$QSnqetaE;HCUbFQ{L41eI9T4B&Vtvwmm>ltm>#lsx! zh0}E?ZP<0@Agw=4hl6exaS-_jnpUaktv_oT#^IF<>rzP7hwMxki!S*xJ7Qa1T|3hP z4I8LT=Ta3Mw&v3LHSu1$J@~ literal 0 HcmV?d00001 diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/it/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/it/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000000000000000000000000000000000..877c79831b802bad14b418c26842c80e48d9cf6e GIT binary patch literal 669 zcmZ9J&2G~`5Xa5e#Ye6nF&sFd^+za@wP{d8nnZ?%MoDNnvau)b7H8MmT?0Mzz(a84 zL3o)yOUE|Ig}?OEcy`va^KtX|;ZKkBfOtwA5RZrxqS0sK86k)##1G>4J~rg(;TVoRehF>@@<*%=xu zwc@ZGPu`E`Q#hNh*6Ha7e}$DcjxB52&jEzMl;V|p`K(zi* zy{(n2gG}$=(7&pvMS*OCV$UIU)U!})O#^2;JvM!SfNsL;n+-qe9co=e%nQ20@(o-rxOZ XQovm5KWi6|OXwH=&#hTg{eSUWW=PB) literal 0 HcmV?d00001 diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/nb_NO/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/nb_NO/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000000000000000000000000000000000..3d5cee314a8a67e945b78b31bff7703ab35249cd GIT binary patch literal 683 zcmaKpJ9E=O5XZ%>0!bU$%Rs}Grw8g{%?1+dw(C^|KYLSV;(bm%me0vsqGWFKtP04)5)QMpx zE|IJ3F+hbuzN%qA!at@Wo9 zF~cvat|d;S!vs1}{7OWxMI1vMB`;n+kJ$VRX`NV*)V7e$Py+p;kQ&B@vh~gHEgW!L z>kg$hZjB^!)af?R<_#z6yyCN1pxh*N!ZqfKQ;*Em=H^!c2W#g_n}p#tF1a=a?Y{?=O<@{+;ku1cip^fEkWplK>P8W8cJq=HL5O@6# q;tVx!qFL7a-DuDW;=LgDz4qmELT%A%vE7;M?6Y|n7ZHYRh4nHR%c zTp&4RbPD6cqtnBa0bC3w)8YB2aDvv57b91wTzsesCuSxEx6Yb#)`JBh=4KUHLg&Kq zxtQR!s$+@1^q4}smF$V6Em{dA@6z4Q+ZIcBCY={ElG>Hh8%p8oMsheUD-Zk4`hfRb zkIGbJsCduUbWzCy#SG;tg?{C;CG0P~w=Rw28=P}AjGEWgw_>{~)5XnsoTIz)#>Tpg zo2V)1G8_#@gQgux)C!LbcT@9oZ!Op3@w<<0DV6R*wv^=1_dd^#MW^wr%UU3bfzC{> zbdf@5u6#HyE0U!+Hneh_%C5Jr*Y3h*+0*c<2T3>lDo#)%Z5s1sQxvqLWG_m>?STqV bf9DL>#t>Zo`vIu`IMy?Q{~YJsYRx_mn|aN6 literal 0 HcmV?d00001 diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/pt_BR/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/pt_BR/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000000000000000000000000000000000..56130695b448536f8e173702debe8dbbe66b145b GIT binary patch literal 680 zcmZ9KOK;Oa5P;3=;v-j(7!F7vw0^0e$Z4uJZBhjq8YQ7{qg#98Zn1Y)``~rs!av~1 zpW%n_TNpbC7e@Xx_Re^o`|IxQ?*Yjz;y$rM+#ybgR?dkB1SjqhUx}YLg5U?~N5uKf zAb3dn8)-TYNOjW2>tuz6H+W=}h8M~k$!lR9%%nrJ;ROcQ>?^Vtc+Ivj>Iw_TW+gjA zV}+7AEDjD|9vn~LY_eRo z>+l#n3uC9kg^@nZcy>I0yT9+={^7CQV(v3z<_>ehbn=0Dz)0pE^Nsm+!}ET!e#8_v zJ?|mw@2uJFvFfGE*UK97mhgzQftR`^CF{yMSSW|IkvV$T&ewdNot_rf`2lQ6u*b54!H&}yKm3^{2xvkeD- zSfKsnvg{$i i7za@l#J>0UvU!R82(I3MghIn``~ODGyZ-He5q|)$3elVZ literal 0 HcmV?d00001 diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/ro/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/ro/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000000000000000000000000000000000..b8afb7a50fe19d7688f3c1750873f2e3c23d0da6 GIT binary patch literal 715 zcmaiy&2AGh5P+Az%O1Ic#2lb%LEfJfP~>DwOPf}KhDJ#!9C3ChTZdhHWqS*VUU&!& z2yx|E`V#OgOtOc~jgdahcxE)78T;?u+uuEsTf}|hDRGB5C06o*ct8l^9`TL%bHnp~ zk$y~kz3F)mN&hBIZjaPjR`u30#k4kfWON0ubZwLR zsbj;8oujc*D-Pp>!`BBV12`W{ro*#0{sb#+92?nOX6$91TQ<`i?E2P>ZrxuP#7vh# zWzbrGe8whtDOa`Fk#NYN6UAK??XozA_&JZBJ&8#CQ(+yO8KG<;oHm@ApNmTY{pDI0 zaisS1Qph4mb-73BDz8P3Y=)xbFwvz@QYh$OI9FL7hM#awg)nFv3$)3@s+rJ+tv}4r zessDDjSkzw9E|oy!_lDKL>xr^p{7MD>hw!Rqd5HR!m1Eb^&q_v#-dB!&W>5P&09^h zK*I(q)tOW|hwfZDe_Yf?6zo`=(sEGM`e>8g9yDg6k|c%~5CMm6vLm>F4rRua+3ET3*$FB%%?{r+OMp%gcm2(mXCRvoas5+3MFW`{md$6m{^8{R KQf*D6dj9}gRo5o~ literal 0 HcmV?d00001 diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/ru/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/ru/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000000000000000000000000000000000..71cbbd05b2b5030c3e01453cfcc1ae0c9db33e38 GIT binary patch literal 767 zcma)4&2AGh5MKT+d*lid!-1*@Ir~GXs%^G3v}qM+Xq1G)5hv@U3yHn5z0gWMB!I*j z368u&g;W$k?U|$Z1vu~uya2OVq2$O&pJwd&z8TNRzph^XWT9O`Tt}1ivUwvcN|@q+auh0grOh{nUNI4lV{SVuA+q;$YYhtW|0tyHO)a;O|=ov6TZUb8M%VWs)2 za-EYD<0)r;??gdfl~AXB?hZ`9^%@Jg<|DR7G%pLvwv9GV?!CmGV1uR-sC zO2u^eq_a&{=e&HJK9i)zdm@VYAb{0wtnKD7m2^n9g&e5>crrVx@a`HEVaRWJZWwy7 zv;=wR-V8kt?t=@+#`AjU|4UWEavmIFrR{pBC$Z za%sh0{13m!AHht`S@y=9X5;LgIW^z137D_h+iYyk%!&D7rr8A3C;uZWsOQ;xlupfe Jb8fy^e*tX-0ImQ4 literal 0 HcmV?d00001 diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/sk/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/sk/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000000000000000000000000000000000..e0fb30b2ec1b52434f213accfaa345e1aee1146b GIT binary patch literal 680 zcmZvZy>in)5XZ$=qmmW|w#p>KoW7hHY}pD4iIXwJ#ABO4$yr)UvZOoB-Pu4odRj^f zo`nbC4R{vTRv{Pc%x_lu|E0a%y}yqi{;((>5KoC?;t_F8Y~vI0oZ!S0;v4bjo@M={ z{EVpXH~M$VBwLhrv8}g@8OCdc7fROfMy{3MWv&g3gh93BF=u>Ir3hhicK-J4Y6!Q(>1=fK&Yof|m0@F@<_UYfPBoj$5cKZUgibwOD#S!qPOVUD zdve33xXHJ**abHjLg4v5=5<-ngTN0vy%!#Zea*FDbH#-&xsfUapH$!TVX)%D$&@JM zsU}BfdC3>riDh*{KZ$hBQ)F}GRS2_EZg>HM%$Qn-uKO7mR1BTAIY+A0t(z&e+v;wD zx-hbKb>X&UX{^E?kH*7x8@}V&=aQBwsN1hKjbreOaqE)jq7QM#l|~c2pI@?W``vb` zB`P))u}pH2hR|K)#-5aG#Y=W6Ri#4^_3l+iojx>=(V>VU{|H`z2O%7alPG|L0}zAg ycq{rO27UV@yF!7gS=xtYV(2(89pB!+YbEb8>LW)Ga+8bSzZCz!eMgtL;?_U?{L6~~ literal 0 HcmV?d00001 diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/sv/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/sv/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000000000000000000000000000000000..8d780725d814edc7ea3cd988395e714b5d67fb84 GIT binary patch literal 649 zcmYk3&2rN)5Xa5e#Ye6%!*XU6$EJsj(=aV<+6g2ylZ3(%)!sO6ZAqh*Q*z`XdhD%d zUZU^8v#^c_?ElPfR@z;yw5vZapWk_`XUuEnfO)}8nOZ-XH;iOnF~6AKPdx9QEiluk zjlX2eZja4gb-lfom{b-|tv2vUS60a)CkGSd(5_{IUMIffc!HhS-0EvgoS3BI5-sIg z#V|iU`FwmnhRg9{Il1`aFVJY~#Eh~$6(6gN#7f6N`&(1K^=NGoQ(g9qMIwKGAr`pJ z>ssPeI*cLehXc`%L=-`I5Wf%K^;!N@k`pT{6&2EH8-r9@?Mht{94c+m6uYBayy77C zw9P*70hLuUL$N|x#<0A_G^Y(5Zk#g|2f@GO_GR_Cz%(sV(E5WE>Beaj&^Bo6a!*@- zHkpmvQG~s|f1-Jkil4eO+>67XE-;16)ew@6w1jT-b#*2NZC>5d8m$7nS4WU_%6ucclIP|}Zb5v-Xp?qs508uX-_}#C({{PjPeSAOu#$xm*gjKo$B3SFsulNFP z)S(tXmktE$cA_5dL_CUE^j>s7yzP+uOKBaCQEHn@XHc+}$+uFolbbqbum?QN3aRoS zF~vtZud_;Kz+;ewU~z?8WjE|(<6LP)82*B5Dg;6Mu)tszmQ9B?Z1Z6XcI!+TIt<&o zf;seOli8@9L=<%VGed*a^wM2PtvLAY!ZMdi_gS)$Xu%D>#uvQTo;!532IM21m{jRZ zu->(D{yeWx=KR87VFlA=y|sgGpEb*YW^V>8>iggM7&KrrlW$E^tQ$l<|M(}zat{s? V#fB(%ceney+hcbscUo?bya!sJ#!&zO literal 0 HcmV?d00001 diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/zh_Hans/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/zh_Hans/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000000000000000000000000000000000..faae4bbad1cd94fa1fa60a645cbd932ec4f3edbb GIT binary patch literal 650 zcmYk3OK;Oa5XZyo;v<(HKw^&|w6@bgm2R4$;+t?nYWWsS;z-V4`_rsvR`c?oo7c}8sB6e=J3DW4q|!&#tJ1F8SVC->>l>XNq;;U96$BOpp|iSXj2i>y)w0Qsu;10sxemGNen=& z3SS$r)*BtuF}xG=Ty&p1U}Qa94{7)i4+%F}xN$#3c}LtjIyGF{oI7P0Ns`UB%{bXw zUUr%rEk9DlHa?YU$y1zKWTfRcL%-#%{@BYOKQBLjy*T^!@BI6!|6=z0?`*d8{|BEo%eDXj literal 0 HcmV?d00001 diff --git a/install_files/ansible-base/roles/tails-config/templates/locale/zh_Hant/LC_MESSAGES/messages.mo b/install_files/ansible-base/roles/tails-config/templates/locale/zh_Hant/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000000000000000000000000000000000..0272019ce33ee55b578262aca2b38c54d37ff03c GIT binary patch literal 674 zcmY+BOK;Oa5Xa5y;v-i;>=A_4kBCFGX;4d=wtM1F z$Xn#sImbCde+`+RZ~Qy-n0CX$ zY7?yvA+~gs(0$NGD9OlVV{m_Cdr0<&)7fb6fjfm#X-mf@6$!mtrG`d|5mQf1aO(P8 z10<^ON)5)ilRY|x=VIB5ZgLBZbb_!;gOG*+2?Ev$Zv|-XE;p7&noE;&t285nOwb)u zNfH?@$Xc9<3?t8Cw4N4RE5n1Owy-wn~J>sXV_))-r2L!+ie* z9AJC!+Ut5sr+(S!Hh!D;6EM%LD*e~llN~Ot-;QGBU(Owm#=~|~p%=IVg^QM`6X%kVMLa7X!>D~ zG@t#T=RT&}AVD|ldekT*9WU& 1;\n" "X-Generator: Weblate 2.20\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "Interface de Jornalista do SecureDrop" diff --git a/install_files/ansible-base/roles/tails-config/templates/pt_PT.po b/install_files/ansible-base/roles/tails-config/templates/pt_PT.po index 8b07b30124..0ccfd71404 100644 --- a/install_files/ansible-base/roles/tails-config/templates/pt_PT.po +++ b/install_files/ansible-base/roles/tails-config/templates/pt_PT.po @@ -18,6 +18,27 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n > 1;\n" "X-Generator: Weblate 4.11.2\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "Interface de Jornalista do SecureDrop" diff --git a/install_files/ansible-base/roles/tails-config/templates/ro.po b/install_files/ansible-base/roles/tails-config/templates/ro.po index 5d1abfc90e..ac3fde426d 100644 --- a/install_files/ansible-base/roles/tails-config/templates/ro.po +++ b/install_files/ansible-base/roles/tails-config/templates/ro.po @@ -19,6 +19,27 @@ msgstr "" "20)) ? 1 : 2;\n" "X-Generator: Weblate 2.18\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "SecureDrop - interfața pentru jurnaliști" diff --git a/install_files/ansible-base/roles/tails-config/templates/ru.po b/install_files/ansible-base/roles/tails-config/templates/ru.po index 0dce7c4e61..5a56d97909 100644 --- a/install_files/ansible-base/roles/tails-config/templates/ru.po +++ b/install_files/ansible-base/roles/tails-config/templates/ru.po @@ -19,6 +19,27 @@ msgstr "" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" "X-Generator: Weblate 4.6\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "SecureDrop — интерфейс журналиста" diff --git a/install_files/ansible-base/roles/tails-config/templates/sk.po b/install_files/ansible-base/roles/tails-config/templates/sk.po index 727d50f238..74a084dd08 100644 --- a/install_files/ansible-base/roles/tails-config/templates/sk.po +++ b/install_files/ansible-base/roles/tails-config/templates/sk.po @@ -18,6 +18,27 @@ msgstr "" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" "X-Generator: Weblate 3.7.1\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "SecureDrop rozhranie novinára" diff --git a/install_files/ansible-base/roles/tails-config/templates/sv.po b/install_files/ansible-base/roles/tails-config/templates/sv.po index 2747a26c64..032c670ab6 100644 --- a/install_files/ansible-base/roles/tails-config/templates/sv.po +++ b/install_files/ansible-base/roles/tails-config/templates/sv.po @@ -18,6 +18,27 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 2.18\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "SecureDrop journalistgränssnitt" diff --git a/install_files/ansible-base/roles/tails-config/templates/tr.po b/install_files/ansible-base/roles/tails-config/templates/tr.po index dd37bde8ae..f7755086a4 100644 --- a/install_files/ansible-base/roles/tails-config/templates/tr.po +++ b/install_files/ansible-base/roles/tails-config/templates/tr.po @@ -18,6 +18,27 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 2.18\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "SecureDrop Gazeteci Arayüzü" diff --git a/install_files/ansible-base/roles/tails-config/templates/zh_Hans.po b/install_files/ansible-base/roles/tails-config/templates/zh_Hans.po index ea1f4694fb..be26afcf85 100644 --- a/install_files/ansible-base/roles/tails-config/templates/zh_Hans.po +++ b/install_files/ansible-base/roles/tails-config/templates/zh_Hans.po @@ -18,6 +18,27 @@ msgstr "" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Weblate 3.10.3\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "SecureDrop 记者界面" diff --git a/install_files/ansible-base/roles/tails-config/templates/zh_Hant.po b/install_files/ansible-base/roles/tails-config/templates/zh_Hant.po index 8dec7ce973..c9d7bfcd29 100644 --- a/install_files/ansible-base/roles/tails-config/templates/zh_Hant.po +++ b/install_files/ansible-base/roles/tails-config/templates/zh_Hant.po @@ -18,6 +18,27 @@ msgstr "" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Weblate 2.18\n" +msgid "Launch Source Interface" +msgstr "" + +msgid "Launch Journalist Interface" +msgstr "" + +msgid "Check for SecureDrop Updates" +msgstr "" + +msgid "SSH into the App Server" +msgstr "" + +msgid "SSH into the Monitor Server" +msgstr "" + +msgid "Open KeePassXC Password Vault" +msgstr "" + +msgid "Open File Browser" +msgstr "" + #: desktop-journalist-icon.j2.in:10 msgid "SecureDrop Journalist Interface" msgstr "SecureDrop 記者使用介面"