Commit 45d0e238 authored by anonym's avatar anonym
Browse files

Merge remote-tracking branch 'origin/master' into stable

parents 0a5397f3 d449c3c8
[[!meta title="Porting Tails to Debian Stretch"]]
This is about the effort to create [Tails
3.0](https://labs.riseup.net/code/projects/tails/issues?query_id=198),
based on Debian Stretch.
[[!toc levels=2]]
# Big picture
When porting to Wheezy, our main problem has been that we started the
work too late, which made us discover Debian bugs too late (after the
Debian Wheezy freeze, or even after its release), and in the end we
had to workaround lots of problems on our side.
So we started much earlier the porting work to Jessie, which indeed
essentially avoided the aforementioned problem. But we didn't allocate
enough focused resources to this effort, and as a result the total
duration of the porting to Jessie work is lasting too much, and we're
spending too much time just keeping our feature/jessie branch
up-to-date wrt. the changes we were making in our Wheezy
production branches.
For Stretch we'd like to avoid both problems. We want to start early,
in order to fix problems directly in Debian Stretch before it's
released. And, we want the porting work to fit into a shorter time
span, so as soon as we start we'll allocate more resources to it, and
in a better organized, team-based and focused way.
Additionally, we would like to use this process as an opportunity to
evaluate the idea of basing Tails on snapshots of Debian testing.
# Schedule
* 2016Q1 — Tails 2.0 is out
* April or May 2016 — start working on Tails 3.0 (1 week sprint with
all involved people) :intrigeri:anonym:kytv:
- get feature/stretch to build and boot
- update the automated test suite to test Tails/Stretch ISO images
* May 2016 to April 2017 — have one dedicated half-time, 1-week sprint
every 6 weeks.
- Schedule these sprints in advance, announce them
publicly, and invite other contributors (e.g. doc writers).
- Most of these sprints will probably be attended remotely, but at
least some could happen face-to-face.
- At the beginning of each Stretch sprint, we import a new snapshot
of Debian testing into our freezable APT repository, so that:
* during the sprint we update our stuff as required by changes
that happened in Debian since the last sprint;
* our stuff is not broken by changes in Debian neither during
sprints, nor between them;
* we get a feeling of how "being based on snapshots of Debian
testing" would work.
* December 5 2016 — Debian Stretch freeze starts
* April 2017 (???) — Debian Stretch is released
* April-June 2017 — Tails 3.0 is released
# Let's go rolling
Let's use this porting cycle to evaluate how being based on snapshots
of Debian testing would feel like. During the entire cycle:
* Keep the automated test suite up-to-date on feature/stretch :kytv:
* Keep the documentation up-to-date on feature/stretch :doc_writer:
* Take notes of issues we see from the perspective of "how would it go
if we were based on testing already?". E.g.:
- How to deal with ongoing transitions that block migration of
security updates from sid to testing?
Note that during half of the cycle, we'll be based on a frozen Debian
testing, so the changes rate coming from Debian won't be crazy.
Of course there will be changes coming from our own porting efforts.
And then, once Tails 3.0 is out: we're not lagging behind anymore, and
are thus in a position to decide whether we want to base Tails on
snapshots of Debian testing.
......@@ -11,6 +11,9 @@
a desktop file whose base name matches the application id, then your
notification will not show up". We'll see.
* intrigeri has a working Perl example with `add_button`. Next step is
to pass parameters to the notification.
* If it's deemed overkill, or just too painful, to port every single
script that needs to send notifications with actions to
"GApplication + D-Bus activation + actions support" properly,
......@@ -40,7 +43,6 @@
use Gtk3;
use Glib::Object::Introspection;
use Try::Tiny;
Glib::Object::Introspection->setup(
basename => 'Gio',
......@@ -58,8 +60,7 @@
# If gedit is already running, this fails with:
# GLib-GIO-CRITICAL **: g_application_send_notification:
# assertion '!g_application_get_is_remote (application)' failed
$app->send_notification("my-notification-id", $notification)
or die "Could not send notification";
$app->send_notification("my-notification-id", $notification);
* private D-Bus API (`org.gtk.Notifications`):
<https://wiki.gnome.org/Projects/GLib/GNotification> ... maybe an
......@@ -87,3 +88,10 @@
{ label => "New document", action => "app.new-document"},
],
});
* GNOME Shell 3.16: non-default action buttons are only displayed when
the notification pops up initially, _not_ in the [Message
List](https://wiki.gnome.org/Design/OS/Notifications/#Message_List).
- Is it the same on Jessie?
- Can we get away with only a default action that opens the URL we
want in the use cases we have in practice?
......@@ -9,9 +9,40 @@ If I had to mention the ideal design goals for such changes, I would say
that the more straightforward would be the better for implementation and
also for maintainability.
[[!toc levels=2]]
[[!toc levels=3]]
# Using DNS
# The plan
## Big picture
We decided to implement a two-way strategy for this feature:
* Use JavaScript to modify the link on the download page, so that each
user is pointed to random mirror.
- Vanilla JS (no frameworks)
- Store the JS code and its configuration file in two dedicated
ikiwiki overlays, for finer-grained access control possibilities
to it (e.g. we may want to let people who don't have commit access
to Git maintain the mirrors pool).
- Configuration for the JS is loaded from JSON file. It attaches
a weight to each mirror. Weight 0 means that the mirror is
currently disabled, and will never be redirected to. We're using
JSON and not YAML to avoid the need to use a third-party parser.
* Keep using DNS to point to 3-5 fast and reliable mirrors. This will
be the fallback for people who do not use JS. So we still need a DNS
dynamic update system; we can simply re-purpose the one we already
have (`dl.amnesia.boum.org`).
* The ISO verification extension also needs to use mirrors. So, we'll
be providing library code for it to do the same, internally, as
a web browser would do when visiting the Tails download page, that
is replacing the hostname, in a ISO download URL, with a suitable
mirror's hostname (using the JSON mirror pool configuration file).
# Initial research
## Using DNS
Using DNS seems to be an easy way to do some round robin in low level. It
allows some kind of transparency to the upper layers protocols and
......@@ -24,7 +55,7 @@ The following ways are available to implement it:
* NS Hacks
* Modified DNS servers
## CNAME Hacks
### CNAME Hacks
As mention by ToBeFree something that can be done is to have different
pools of servers like:
......@@ -55,7 +86,7 @@ that has not been ported to bind 9. Neither NSD nor PowerDNS seem to
support it, and their is no actual data about how resolvers would
handle this case, so I don't think it is the best option.
## NS Hacks
### NS Hacks
Following the same idea the dl amnesia.boum.org could be delegated to a
few different DNS servers, and those servers may have different versions
......@@ -82,7 +113,7 @@ CNAME hacks, almost as the NS servers will not receive 50% of requests
because of [[!rfc 5452]]). However, I am not sure that playing with DNS
inconsistency will be a so good idea, for example for maintainability :)
## Using modified DNS servers
### Using modified DNS servers
Interestingly Tails is not the first project to be looking how to use DNS
for load distribution. People already wrote some DNS software designed to
......@@ -102,7 +133,7 @@ Deploying such software would solve the problem in a more elegant way than
CNAME or NS hacks. It would require a bit of system administration that
maybe can be done using some puppet templates in a few Virtal Machines.
# Using HTTP(s)
## Using HTTP(s)
DNS is not the only way to do some load balancing. It is mostly used for
low level protocols that don't allow redirects (for example: NTP). As
......@@ -147,13 +178,13 @@ Thus, if I may, I would like to recommend considering the HTTP(s) option,
even if it means that I have to write the PHP script by myself or to create
an easy task entry on the ticket tracker and follow it :)
# Proof of concept: JavaScript + multiple DNS pools / named mirrors
## Proof of concept: JavaScript + multiple DNS pools / named mirrors
This method can either be used with multiple DNS pools (dl1.amnesia.boum.org, dl2.amnesia.boum.org etc.) or with named mirrors (freiwuppertal.dl.amnesia.boum.org, othermirror.dl.amnesia.boum.org, ...). Using named mirrors allows you to use a huge, unlimited list of completely equally used mirrors; using multiple DNS pools leads to effects described under "CNAME hacks".
These POCs should be 1:1 usable on the Tails [[download]] page. All that would be needed is setting up the DNS pools and/or named mirrors, and telling the mirror owners to configure their servers to respond to \*.amnesia.boum.org (the wildcard is important).
## JavaScript POC (multiple DNS pools)
### JavaScript POC (multiple DNS pools)
<script src="//code.jquery.com/jquery.min.js"></script>
<script type="text/javascript">//<![CDATA[
......@@ -171,12 +202,12 @@ For this to work and to be flexible, mirrors need to respond to \*.amnesia.boum.
At least nginx is unable to use a wildcard like dl\*.amnesia.boum.org, so \*.amnesia.boum.org has to be used. This is more flexible anyway.
### Example webpage (see the webpage source there too)
#### Example webpage (see the webpage source there too)
<http://freiwuppertal.de/tails-mirror-example-dns.htm>
## JavaScript POC (named mirrors)
### JavaScript POC (named mirrors)
<script src="//code.jquery.com/jquery.min.js"></script>
<script type="text/javascript">//<![CDATA[
......@@ -192,16 +223,108 @@ At least nginx is unable to use a wildcard like dl\*.amnesia.boum.org, so \*.amn
For this to work and to be flexible, mirrors need to respond to \*.amnesia.boum.org. Just responding to a fixed name would make this an unflexible solution, so the wildcard is needed.
### Example webpage (see the webpage source there too)
#### Example webpage (see the webpage source there too)
<http://freiwuppertal.de/tails-mirror-example-named.htm>
### Giving mirrors higher or lower weight
#### Giving mirrors higher or lower weight
Using this approach, giving one mirror more weight than others is very easy: Simply add it's name multiple times to the array of mirrors. :D
### Vanilla JavaScript POC and JSON
<a href="http://dl.amnesia.boum.org/tails/stable/tails-i386-1.6/tails-i386-1.6.iso" id="dllink">download link</a>
<script type="text/javascript">
function fetchJSONdata(path, callback) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200 || xhr.status === 0) {
var data = JSON.parse(xhr.responseText);
if (callback) callback(data);
} else {
console.log( "Error: " + xhr.statusText);
}
}
};
xhr.open('GET', path, true);
xhr.send();
}
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min +1)) + min;
}
function isJSON(str) {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
}
function replaceDownloadURL(updatedURL) {
var URLMarker = "/tails/stable";
// todo check that url is a correct url
var linkDOMElem = document.getElementById('dllink');
var linkHREF = linkDOMElem.href.split( '//' );
var linkToISO = linkHREF[1].split( URLMarker );
// fixme http or https
linkDOMElem.href = '//' + updatedURL + URLMarker + linkToISO[1];
return true;
}
fetchJSONdata('./mirrors.json', function(data){
//console.log(data);
if( data == "undefined" ) {
console.log( "Error: mirror data not loaded.");
} else if( !isJSON( JSON.stringify(data) ) ) {
console.log( "Error: mirror data is not JSON.");
} else {
//console.log(data.mirrors);
// todo delete all mirrors with weight 0 before choosing one
if(data.mirrors.length > 0 ) {
var activeMirrors = new Array();
for ( i = 0; i < data.mirrors.length; i++ ) {
if ( data.mirrors[i].weight != 0 ) {
// add mirror as many times as its weight, max weight is 5
if ( parseInt(data.mirrors[i].weight ) > 5) {
var max_weight = 5;
} else {
var max_weight = parseInt( data.mirrors[i].weight );
}
for ( w = 0; w < max_weight; w++ ) {
activeMirrors.push( data.mirrors[i] );
}
}
}
console.log(activeMirrors);
var randomMirror = getRandomInt(0, activeMirrors.length-1);
//console.log(randomMirror);
//console.log(data.mirrors[randomMirror]);
replaceDownloadURL(activeMirrors[randomMirror].url);
}
}
});
</script>
The mirrors.json file contains:
<pre>
{
"mirrors": [
{ "url": "1.dl.amnesia.boum.org", "weight": "10" },
{ "url": "5.dl.amnesia.boum.org", "weight": "5" },
{ "url": "6.dl.amnesia.boum.org", "weight": "6" },
{ "url": "3.dl.amnesia.boum.org", "weight": "0" }
]
}
</pre>
# PHP: first draft
## PHP: first draft
// http://stackoverflow.com/questions/4233407/get-random-item-from-array
......
......@@ -117,19 +117,18 @@ Basic configuration & integration
* Don't display the "Adblock Plus installation complete" tab.
* Don't prompt whether one wants to report usage and performance
information to Mozilla.
* Disable FoxyProxy.
* Enable "Only use secure protocols" by default (one may still
uncheck it when needed).
* Don't check updates for Add-ons.
* Add launcher to the GNOME panel.
* More generally: have a look at our Iceweasel prefs and copy all
* More generally: have a look at our Tor Browser prefs and copy all
those that exist and make sense for Icedove.
* The [[security/IP_address_leak_with_icedove]] can be fixed by
setting `mail.smtpserver.default.hello_argument` to "localhost".
See [this Tor wiki
entry](https://trac.torproject.org/projects/tor/wiki/TheOnionRouter/TorifyHOWTO/EMail#ExperimentalSuggestionsforpossiblymakingthunderbirdandorclawsstopleakinginfoExperimental)
for other goodies. By applying those configurations I think both
claws and icedove comes to an equal level security-wise.
claws and icedove comes to an equal level security-wise. (Note: This will be set by TorBirdy)
* Disable by default the indexer from
`Preferences -> Advanced -> General -> Enable Global Search and Indexer`.
Otherwise pinentry dialogs can appear while checking email in the
......
......@@ -137,9 +137,9 @@ decide to still use them, then we probably have to wait for
Proposal for a first iteration:
* For green test suite run: keep the test logs (Jenkins natively do
that) and video captures
* For red test suite run: keep the screen and video captures and the
logs.
that).
* For red test suite run: keep the screen and video captures, the
logs and the pcap files.
On the second iteration, we will keep video capture only for the red
tests.
......
......@@ -268,6 +268,45 @@ archived with the artifacts of the upstream job. Then the downstream job
can be configured with then EnvInject plugin we already use to set the
necessary variables in the job environment.
Define which $OLD_ISO to test against
-------------------------------------
It appeared in [[!tails_ticket 10117]] that this question is not so
obvious and easy to address.
The most obvious answer would be to use the previous release for all the
branches **but** feature/jessie, which would use the previously built
ISO of the same branch.
But in some occasions, an ISO can't be tested this way, because it
contains changes that affects the "set up an old Tails", like changes in
the Persistence Assistant, the Greeter, the Tails Installer or in
syslinux.
So we may need a way to encode in the Git repo that a given branch needs
to use the same value than $ISO rather than the last release as $OLD_ISO.
We could use the same kind of trick than for the APT_overlay feature:
having a file in `config/ci.d/` that if present shows that this is the
case. OTOH, we may need something a bit more complex than a simple
boolean flag. So we may rather want to check the content of a file.
But this brings concerns about the merge of the base branch in the
feature branch and how to handle conflicts. Note that at testing time,
we'll have to merge the base branch before we look at that config
setting (because for some reason the base branch might itself require
old ISO = same).
As a first baby step, we will by default use the same ISO for both
`--old-iso` and `--iso`, except for the branches used to prepare
releases (`devel` and `stable`), so that we
know if the upgrades are broken long before the next release.
Another option that could be considered, using existing code in the repo: use the
`OLD_TAILS_ISO` flag present in `config/default.yml`: when we release we
set its value to the released ISO, and for some branch that need it we
empty this variable so that the test use the same ISO for both
`--old-iso` and `--iso`.
Retrieving the ISOs for the test
--------------------------------
......
......@@ -10,7 +10,8 @@ What for:
Why is it complicated:
- Release every 6 weeks and maybe emergency security releases
- Release every 6 weeks, plus the occasional unscheduled emergency
security release
- Heavy quality assurance process (automated builds and tests)
- Complex infrastructure (upgrades)
- User trust (authenticated downloads, OpenPGP Web-of-Trust)
......@@ -30,7 +31,7 @@ Good ways of doing it:
- Help us build in Tails other mechanisms that you might need to adapt
it to your needs (for example to have persistent DConf settings or APT
sources).
- Talk with us to see how we can adapt our ISO images to make them
- Talk with us to see how we can adapt our ISO images and source code to make them
easier for your to reuse.
- If you want to include a piece of software into Tails, talk to us as
early as possible so we can provide feedback on how to integrate it.
......
......@@ -21,37 +21,30 @@ Please take this into account when you comment on current proposals. Improvement
# Flow
After working on a prototype and doing UX testing with some folks at NUMA, we arrived at
the idea of having two main experience flows:
After working on a prototype and doing UX testing with some folks at NUMA, we arrived at the idea of having two main experience flows:
- A quick setup for regular users, in which every option is easy to access in a few screens;
- A wizard to guide newcomers.
- Guided Configuration: A wizard to guide new users
- Self-guided Configuration: A quick setup for veteran users
The result of this step can be found in [[NUMA_flow]].
The result of this step can be found in this [[NUMA_flow]].
# Implementation phases
The implementation and release of this is scheduled in three
phases, so that we make actual progress we can deliver to users as
soon as things become reality:
The implementation and release of this is scheduled in three phases. The intention is to make progress that can be delivered as soon as things become reality:
- Phase 1: redesign the Greeter's 1st and 2nd screen. We then have
similar functionality to the current Greeter, but more clearly presented.
- PHASE 1: Redesign the Greeter's 1st screen. We then have similar functionality to the current Greeter but more clearly presented.
- Phase 2: add a Wizard to guide beginners ("Discover: Guided Configuration")
- PHASE 2: Add a wizard to guide beginners ("Discover: Guided Configuration")
- Phase 3: merge the persistence creation/configuration into the
greeter
- PHASE 3: Merge the persistence creation/configuration into the Greeter
We are proposing this because we have been debating a lot on the first screen(s) and we have reached something that is worth being tested and implemented. There is still work needed on the Guided Configuration wizard.
We are proposing this because we have been debating a lot on
the first screen(s) and we have reached something that is worth
being tested and implemented. On the other hand, there is more
work needed on the Guided Configuration wizard.
# Proposed design for the 1st screen
We refined this on the *tails-ux* mailing list to arrive at the following concrete proposal
for the 1st screen. Below in this document we explain every designation.
We refined this on the *tails-ux* mailing list to arrive at the following concrete proposal for the 1st screen. Below in this document we explain every designation.
## Intention
......@@ -61,27 +54,22 @@ Design a greeter dialog that:
- Accommodates for fast access to other advanced options
- Has a simple and easy to understand interface for both new and advanced users
- Uses as much tested data from previous design iterations as possible
- Is up-to-date with GNOME 3.14 standards
- Is up-to-date with GNOME 3.14 guidelines
## Proposed design
<img src="https://labs.riseup.net/code/attachments/download/937/Tails.Greeter.Explained.png" width="900px" />
## Proposed design
[full size bitmap](https://labs.riseup.net/code/attachments/download/937/Tails.Greeter.Explained.png)
[source](https://labs.riseup.net/code/attachments/download/936/Tails.Greeter.Explained.svgz)
A single welcome and settings screen, which is always displayed, that acts as a "Check & Go" screen, as well as a hub for editing settings.
<img src="https://mailman.boum.org/pipermail/tails-ux/attachments/20150910/550fa30e/attachment-0001.png" width="900px" />
<img src="https://labs.riseup.net/code/attachments/download/984/Greeter.Explained.png" width="100%" height="auto" />
[full size bitmap](https://mailman.boum.org/pipermail/tails-ux/attachments/20150910/550fa30e/attachment-0001.png)
[source](https://mailman.boum.org/pipermail/tails-ux/attachments/20150910/550fa30e/attachment-0001.bin)
[full size bitmap](https://labs.riseup.net/code/attachments/download/984/Greeter.Explained.png)
[source](https://labs.riseup.net/code/attachments/download/985/Greeter.Explained.svgz)
There is a single welcome and settings screen which is always displayed and acts as a "Check & Go" screen, as well as a hub for editing settings.
<img src="https://labs.riseup.net/code/attachments/download/979/Greeter.States.png" width="100%" height="auto" />
When a line is clicked, a popover ([[https://developer.gnome.org/hig/stable/popovers.html.en]]) opens with an explanation of the option and the controls to change its value.
As the values change their new value will replace the previous value in each respective location.
It is clear that the "Language" section can/should be saved, but not yet weather the "Settings" section can/should be saved.
[full size bitmap](https://labs.riseup.net/code/attachments/download/979/Greeter.States.png)
[source](https://labs.riseup.net/code/attachments/download/980/Greeter.States.svgz)
## Explanation of this design
......@@ -89,17 +77,19 @@ It is clear that the "Language" section can/should be saved, but not yet weather
Which content structure type is most appropriate for the Greeter?
[[!img Greeter.Decision.00-Structure.png link="Greeter.Decision.00-Structure.svg" size="800x"]]
<img src="https://labs.riseup.net/code/attachments/download/987/Content.Structure.Types.png" width="100%" height="auto" />
- Step-by-step - Guided walkthrough
- Show/Hide - Hidden off-screen or behind on-screen element
- **Openface - Full display**
[full size bitmap](https://labs.riseup.net/code/attachments/download/987/Content.Structure.Types.png)
[source](https://labs.riseup.net/code/attachments/download/988/Content.Structure.Types.svgz)
With the Step-by-step flow already established as the most appropriate guided configuration structure, the designation made was that, the Show/Hide structure most appropriately accommodates the two end-of-spectrum use cases (noob vs veteran). However, it doesn't align GNOME HIG and doesn't feedback to the user which options are selected (when diverging from defaults). We thus choosed to:
- Step-by-step: Guided walkthrough
- Show/Hide: Hidden off-screen or behind on-screen element
- **Openface: Full display**
- add a + button to add setting, as commonly found in GNOME lists
- display settings that diverge from defaults
With the Step-by-step flow already established as the most appropriate guided configuration structure, the designation made was that the Show/Hide structure most appropriately accommodates the two end-of-spectrum use cases (noob and veteran). However, this does not align with the GNOME HIG or provide feedback to the user which options are selected (when diverging from defaults). We thus chose to:
- Add a "+" button to add a customizable setting, as commonly found in GNOME lists
- Only display privacy settings that diverge from defaults
### Options Available On The 1st Screen
......@@ -113,7 +103,10 @@ In our situation, this is most effectively accomplished by displaying all settin
Where should the ‘Start Tails’ button be located?
[[!img Greeter.Decision.01-Start.png link="Greeter.Decision.01-Start.svg" size="800x"]]
<img src="https://labs.riseup.net/code/attachments/download/989/Start.Tails.Button.Location.png" width="100%" height="auto" />
[full size bitmap](https://labs.riseup.net/code/attachments/download/989/Start.Tails.Button.Location.png)
[source](https://labs.riseup.net/code/attachments/download/990/Start.Tails.Button.Location.svgz)
Height:
......@@ -140,11 +133,14 @@ How should the settings section be ordered?
- Importance: Storage, Language, Settings
- **Logical: Language, Storage, Settings**
An arbitrary order such as alphabetical is much less relevant than ordering by importance or logical steps. On top of that, to setup storage, one should select the appropriate language first to be able to read or write. Thus the choice of the Language, Storage, then Settings order.
An order such as alphabetical is much less helpful than ordering by importance or by logical steps. On top of that, to setup storage, one should select the appropriate language first to be able to read or write. Thus the choice of the Language, Storage, then Settings order.
Should the settings sections be labeled with either two or three labels?
Further, should the settings sections be labeled with either two or three labels?
<img src="https://labs.riseup.net/code/attachments/download/991/Settings.Labels.png" width="100%" height="auto" />
[[!img Greeter.Decision.03-Labels.png link="Greeter.Decision.03-Labels.svg" size="800x"]]
[full size bitmap](https://labs.riseup.net/code/attachments/download/991/Settings.Labels.png)
[source](https://labs.riseup.net/code/attachments/download/992/Settings.Labels.svgz)
- Two
- **Three**
......@@ -155,7 +151,10 @@ The designation was made that having three sections with three labels was the mo
Should icons accompany the Section or Line-item labels, none, or both?
[[!img Greeter.Decision.04-Icons.png link="Greeter.Decision.04-Icons.svg" size="800x"]]
<img src="https://labs.riseup.net/code/attachments/download/993/Label.Icons.png" width="100%" height="auto" />
[full size bitmap](https://labs.riseup.net/code/attachments/download/993/Label.Icons.png)
[source](https://labs.riseup.net/code/attachments/download/994/Label.Icons.svgz)
- Section
- **Line Item**
......@@ -175,7 +174,10 @@ The designation was made that icons should not accompany button labels. In addit
Should the Greeter have the option to be closed/restarted?
[[!img Greeter.Decision.05-Close.png link="Greeter.Decision.05-Close.svg" size="800x"]]
<img src="https://labs.riseup.net/code/attachments/download/995/Close.Greeter.png" width="100%" height="auto" />
[full size bitmap](https://labs.riseup.net/code/attachments/download/995/Close.Greeter.png)
[source](https://labs.riseup.net/code/attachments/download/996/Close.Greeter.svgz)
- **Close/Restart**
- No Close/Restart
......@@ -188,7 +190,11 @@ Since there are multiple boot modes to choose from for Tails, the designation wa
The language section is always visible. When a language is saved (in cleartext), it is automatically filled in with saved options.
Clicking on a language line will open a Popover with the available options and a search bar.