blog

git clone https://git.ce9e.org/blog.git

commit
91fcec2a1151d3ceb611747a64d99b5a3bb05af0
parent
b19647ead29ec3d12b90159068a351d5e5d27d6b
Author
Tobias Bengfort <tobias.bengfort@posteo.de>
Date
2024-10-04 13:11
add some posts

Diffstat

A _content/posts/2024-07-27-password-plan/index.md 183 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A _content/posts/2024-08-30-datetime/index.md 185 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A _content/posts/2024-09-04-clipboard/index.md 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A _content/posts/2024-10-03-not-the-only-place/index.md 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++

4 files changed, 531 insertions, 0 deletions


diff --git a/_content/posts/2024-07-27-password-plan/index.md b/_content/posts/2024-07-27-password-plan/index.md

@@ -0,0 +1,183 @@
   -1     1 ---
   -1     2 title: The plan to support per-app passwords on the linux desktop
   -1     3 date: 2024-07-27
   -1     4 tags: [code, linux, security]
   -1     5 description: "The secret service API has no provisions to isolate passwords that belong to app A from passwords that belong to app B. On a recent GNOME event I learned that a solution to this problem is in the works."
   -1     6 ---
   -1     7 
   -1     8 On the linux desktop we have the [secret
   -1     9 service](https://specifications.freedesktop.org/secret-service/) dbus API to
   -1    10 securely save passwords. This API is provided by services such as
   -1    11 gnome-keyring, KWallet, or KeePassXC. However, the exact threat model is often
   -1    12 [confusing for users](https://superuser.com/questions/969484):
   -1    13 unlinke similar APIs on iOS or Android, the secret service API has no
   -1    14 provisions to isolate passwords that belong to app A from passwords that belong
   -1    15 to app B.
   -1    16 
   -1    17 In an attempt to fix this I created an experimental implementation called
   -1    18 [xi-keyring](https://github.com/xi/xi-keyring/tree/2e51243) that used
   -1    19 `/proc/{pid}/exe` to identify the calling app. I quickly had to realize that
   -1    20 [this doesn't work](https://github.com/xi/xi-keyring/issues/3). For one, this
   -1    21 value often ended up being `python3.9` which both fails to effectively separate
   -1    22 apps and will also break on python updates. But more importantly, I learned
   -1    23 that it is possible to hijack binaries using `LD_PRELOAD`. So this was a dead
   -1    24 end.
   -1    25 
   -1    26 I recently visited a GNOME event and learned that a solution to this problem is
   -1    27 in the works. On the one hand I was delighted. On the other hand, I was a bit
   -1    28 disgruntled that they had not communicated their plans more clearly. I might
   -1    29 have saved quite some time if I had known that sooner.
   -1    30 
   -1    31 So in this post I will try to give an account of the plan as it was explained
   -1    32 to me so that others don't have to travel to some conference to learn about it.
   -1    33 
   -1    34 ## The app is the sandbox
   -1    35 
   -1    36 As explained before, we need to get an `app_id`. My experiments so far have not
   -1    37 yielded a reliable way to do this and a friend of mine who works in security
   -1    38 said that it is actually impossible with the classic UNIX process model.
   -1    39 However, nowadays we have sandboxing.
   -1    40 
   -1    41 The idea is that we use a separate dbus socket that is tagged with an
   -1    42 `app_id` for every sandbox. Flatpak currently does this by using
   -1    43 [xdg-dbus-proxy](https://github.com/flatpak/xdg-dbus-proxy) and storing the
   -1    44 `app_id` in `/.flatpak-info` in its namespace. However, there are also plans to
   -1    45 add this mechanism to dbus itself (the best explanation for this plan I could
   -1    46 find is in a [busd issue](https://github.com/dbus2/busd/issues/34)).
   -1    47 
   -1    48 Of course, this only solves the problem for sandboxed apps. It seems like
   -1    49 isolating unsandboxed apps is simply impossible. Still, there could be easier
   -1    50 ways to sandbox applications. I could imagine a tool that only provides the
   -1    51 tagged dbus socket without much other isolation.
   -1    52 
   -1    53 ## A new API
   -1    54 
   -1    55 With sandboxing we got a new set of dbus APIs called
   -1    56 [portals](https://flatpak.github.io/xdg-desktop-portal/docs/). They are
   -1    57 provided by [xdg-desktop-portal](https://github.com/flatpak/xdg-desktop-portal)
   -1    58 which does the `app_id` detection and then delegates to desktop specific
   -1    59 backends.
   -1    60 
   -1    61 There is a [secret
   -1    62 portal](https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Secret.html),
   -1    63 but it is very different from the old secret service: Instead of allowing to
   -1    64 store and retrieve passwords from the keyring, it only allows to retrieve a
   -1    65 single "master secret".
   -1    66 
   -1    67 When I saw this I was a bit confused and quickly decided that, whatever this
   -1    68 was, this was surely not related to the secret service. In a way it is even the
   -1    69 opposite: The secret service takes care of encrypting passwords at rest and
   -1    70 keeping them out of swappable memory, but does not isolate apps from each
   -1    71 other. The secret portal isolates apps from each other, but leaves all the
   -1    72 other stuff to the apps.
   -1    73 
   -1    74 The piece of the puzzle I was missing was
   -1    75 [libsecret](https://gitlab.gnome.org/GNOME/libsecret/), a library that has
   -1    76 traditionally been used to interact with the secret service, at least in the
   -1    77 GNOME/GTK/GLib world. Nowadays, when libsecret is being used inside of a
   -1    78 sandbox, it will automatically switch to using the portal and provide the
   -1    79 missing bits: It will use the master secret from the portal to store the
   -1    80 passwords in an encrypted file. This "file backend" has been added as far back
   -1    81 as [2018](https://gitlab.gnome.org/GNOME/libsecret/-/merge_requests/6).
   -1    82 
   -1    83 ## A new GUI for password management (?)
   -1    84 
   -1    85 Now, I don't really care if a feature is implemented in a service or a library.
   -1    86 There is really not that much of a difference. The much bigger change is that
   -1    87 the details of password management are no longer part of the *specification*.
   -1    88 
   -1    89 With the old secret service, I was able to manage, backup, sync, or lock my
   -1    90 passwords because they were all in one place. With this new system, the
   -1    91 passwords are scattered all over the place.
   -1    92 
   -1    93 There is a new GUI called [Key Rack](https://flathub.org/apps/app.drey.KeyRack)
   -1    94 that is aware of libsecret's file backed and can therefore provide centralized
   -1    95 password management, but only for applications that use libsecret (or something
   -1    96 that is compatible with it, we will get to that). Eventually, Key Rack might
   -1    97 also gain the ability to backup or sync passwords. However, the portal does not
   -1    98 allow to tell applications to forget about their master secret, so even Key
   -1    99 Rack will never be able to support locking the keyring.
   -1   100 
   -1   101 However, I am not completely sure if this is intentional or not. When the secret
   -1   102 portal was [first discussed](https://github.com/flatpak/xdg-desktop-portal/issues/14),
   -1   103 Stef Walter referenced a talk in which he claimed that users don't actually
   -1   104 want a password manager, they want applications to be able to store passwords
   -1   105 in a secure way (I am extrapolating a bit). Here is a quote from the confused
   -1   106 user I linked at the very start of this post that seems to support that claim:
   -1   107 
   -1   108 > I was really surprised when I discovered Gnome Keyring, a tool that I never
   -1   109 > heard about and that was saving all my passwords in PLAINTEXT without my
   -1   110 > consent.
   -1   111 
   -1   112 This discrepancy between Stef's talk and Key Rack only became clear to me after
   -1   113 the event, so I was not able to ask people about it. But to me it seems like
   -1   114 the original intent (to drop password management) was forgotten along the way.
   -1   115 If we put password management back into the mix, libsecret's file backend
   -1   116 doesn't make a lot of sense. The cleaner solution then would be to keep all
   -1   117 passwords in the secret service and add access control based on `app_id`.
   -1   118 
   -1   119 ## A new file format
   -1   120 
   -1   121 The file format that libsecret's file backed uses to store passwords is
   -1   122 different from the one that is being used by gnome-keyring. With gnome-keyring,
   -1   123 only the passwords themselves are encrypted. With libsecret's file backend, the
   -1   124 whole file is encrypted. This is generally a good thing.
   -1   125 
   -1   126 There is a small caveat: Sometimes it can be confusing for users to be asked to
   -1   127 unlock the keyring for an application that doesn't actually have any passwords
   -1   128 stored. If the metadata is not encrypted, we can first make sure that the
   -1   129 request is relevant before interrupting the users. When doing my own
   -1   130 implementation, I was going back and forth between these options. But in the
   -1   131 end I also decided on full encryption.
   -1   132 
   -1   133 ## A new implementation
   -1   134 
   -1   135 libsecret and especially gnome-keyring are both old and complex C codebases. So
   -1   136 naturally, someone rewrote the whole thing in rust.
   -1   137 
   -1   138 [oo7](https://github.com/bilelmoussaoui/oo7) started out as a rust library that
   -1   139 is more or less equivalent to libsecret. Crucially, it also implements a
   -1   140 compatible file backend. But later on it also gained an implementation of the
   -1   141 secret portal and there is an open pull request to also implement the [secret
   -1   142 service](https://github.com/bilelmoussaoui/oo7/pull/73). So oo7 will likely
   -1   143 replace gnome-keyring at some point.
   -1   144 
   -1   145 Just as with libsecret, you can let oo7 pick a suitable backend automatically.
   -1   146 But different from libsecret, you can also pick the backend explicitly. That
   -1   147 makes it possible to migrate existing passwords from one backend to the other.
   -1   148 
   -1   149 ## Conclusion
   -1   150 
   -1   151 I am honestly not sure how far along this whole thing is in practice. oo7 is
   -1   152 not quite ready yet, but seems to be the way forward. In theory, any
   -1   153 application that is using libsecret should automatically switch to the file
   -1   154 backend when sandboxed. Still, I could not find any traces of that on my
   -1   155 personal system.
   -1   156 
   -1   157 Even though it is good to know that there is a solid plan, there is a severe
   -1   158 lack of documentation. Until I [submitted a merge
   -1   159 request](https://gitlab.gnome.org/GNOME/libsecret/-/merge_requests/146),
   -1   160 libsecret's documentation didn't even mention the file backend. There is also
   -1   161 no clear governance process for the portals APIs. From the outside, it is very
   -1   162 hard to understand why the specs ended up like they have.
   -1   163 
   -1   164 And I believe this lack of information does not only affect developers like me.
   -1   165 When users are confused as to why all their passwords are stored in
   -1   166 gnome-keyring, that also points to a lack of information. We have two ways to
   -1   167 react: We could, as Stef Walter was proposing in 2013, remove any features
   -1   168 that users don't expect. That is valid approach.
   -1   169 
   -1   170 But the opposite approach is equally valid: We could proudly present to users
   -1   171 that the linux desktop comes with a built-in, secure, and trustworthy password
   -1   172 manager. We could have a persistent status indicator that shows whether the
   -1   173 keyring is currently unlocked. There could be notifications or prompts whenever
   -1   174 an applications tries to access a password. I am not sure, I am probably going
   -1   175 a bit too far here.
   -1   176 
   -1   177 The point is: In other areas we are trying to push things forwards. Why not
   -1   178 here?
   -1   179 
   -1   180 ---
   -1   181 
   -1   182 Thanks to Maximiliano, Niels De Graef, Zeeshan Ali Khan, and Janis König for
   -1   183 explaining all this stuff to me.

diff --git a/_content/posts/2024-08-30-datetime/index.md b/_content/posts/2024-08-30-datetime/index.md

@@ -0,0 +1,185 @@
   -1     1 ---
   -1     2 title: How to do arithmetic with dates and times
   -1     3 date: 2024-08-30
   -1     4 tags: [code]
   -1     5 description: Let's look into dates and times, timezones, leap years, daylight saving time, and how to do arithmetic with all of that.
   -1     6 ---
   -1     7 
   -1     8 As a programmer, you quickly learn that there are two things you should never
   -1     9 do yourself: cryptography and dealing with dates and times. The former because
   -1    10 it is easy to mess up security. For the latter, you would have to consider leap
   -1    11 years, leap seconds, daylight saving time, timezones, and a bunch of other
   -1    12 exceptions. As [Tom Scott](https://www.youtube.com/watch?v=-5wpm-gesOY) put it:
   -1    13 that way lays madness. Well, let's look into it anyway.
   -1    14 
   -1    15 ## Absolute time
   -1    16 
   -1    17 Unix time is a number that counts the seconds since 1970-01-01T00:00:00Z. I
   -1    18 have no clue how "1970-01-01T00:00:00Z" is defined exactly or how we can
   -1    19 measure seconds (something about atomic clocks?), but let's just assume that it
   -1    20 works.
   -1    21 
   -1    22 This gives us a solid base that we can build on. This number is the same, no
   -1    23 matter where we are or which language we speak. Crucially, it allows us to
   -1    24 measure durations as the difference between two points in time.
   -1    25 
   -1    26 There is a small caveat: Unix time ignores leap seconds. We still get the same
   -1    27 number everywhere, but some durations are just slightly off. All libraries that
   -1    28 I have looked into ignore this detail, which seems to be fine for most common
   -1    29 usecases.
   -1    30 
   -1    31 ## Absolute date
   -1    32 
   -1    33 Similar to how unix time counts the seconds since 1970-01-01, we can also count
   -1    34 the days since 0001-01-01. I am not sure if there is a catchy name for that
   -1    35 concept. Python's `datetime` calls it "ordinal", but that term is used
   -1    36 differently in other places. Rust's `chrono` calls it `days_from_ce`.
   -1    37 
   -1    38 However we want to call this, this gives us an absolute measure for dates. Here
   -1    39 again, we can measure distances between dates and all the good things.
   -1    40 
   -1    41 Compared to time, dates have much less physical grounding. It is somewhat
   -1    42 related to the rotation of the earth. But since the date changes at night and
   -1    43 night is at different times in different places, the date is not the same
   -1    44 everywhere. Still, a measure for absolute dates is useful for cultural reasons.
   -1    45 
   -1    46 ## Nominal date and time
   -1    47 
   -1    48 When we talk about date and time, we don't usually use huge integers. I have
   -1    49 grown up with a system based on the Gregorian calendar that has 60-second
   -1    50 minutes, 60-minute hours, 24-hour days, 7-day weeks, irregular months, and
   -1    51 12-month years. This system has very little physics and is mostly based on
   -1    52 culture. So it has all of that messy human stuff.
   -1    53 
   -1    54 For each absolute date, we can get the corresponding nominal date in a given
   -1    55 system (don't ask me how, but I am sure these mappings are well defined).
   -1    56 Similarly, we can map unix time to nominal datetimes for a given system and
   -1    57 timezone. For example, the timestamp 1725022800 can be converted to 2024-08-30
   -1    58 15:00 Europe/Berlin.
   -1    59 
   -1    60 Timezones define an offset from UTC. However, that offset often changes
   -1    61 (typically twice a year for daylight saving time). The list of all timezones
   -1    62 and their offsets at different times is maintained in the [IANA timezone
   -1    63 database](https://www.iana.org/time-zones).
   -1    64 
   -1    65 The mapping back from nominal dates and times to absolute ones is a bit more
   -1    66 complicated. With daylight saving time, many timezones regularly skip or repeat
   -1    67 hours. So an innocent-looking nominal value might have zero, one, or even
   -1    68 two corresponding absolute values.
   -1    69 
   -1    70 ## Nominal deltas
   -1    71 
   -1    72 Now this is the part I had the most fun with, so I am going to go into some
   -1    73 detail.
   -1    74 
   -1    75 As I explained before, for absolute dates and times it is pretty simple to
   -1    76 define a measure of duration. For nominal dates and times, this is much less
   -1    77 straight forwards. What does it mean to add a month to a date? What is the
   -1    78 duration between two datetimes? Let's look at some examples:
   -1    79 
   -1    80 ### Adding a delta
   -1    81 
   -1    82 Say I want to add one month to 1970-01-30. This is an issue because 1970-02-30
   -1    83 does not exist. There are several options that come to mind:
   -1    84 
   -1    85 -   **no API**: simply do not offer any API that would allow to do arithmetic
   -1    86     with such a squishy concept as "months"
   -1    87 -   **error**: raise an exception if the resulting date does not exist
   -1    88 -   **overflow**: normalize the result to 1970-03-02
   -1    89 -   **clip**: clip the result to 1970-02-28
   -1    90 -   **count from end**: since 1970-01-30 is the second-to-last day of January,
   -1    91     one month later should be the second-to-last day of February, 1970-02-27
   -1    92 
   -1    93 This is mostly an issue for months due to their irregularity. But similar
   -1    94 issues can also happen in other places, e.g. when naively adding a day would
   -1    95 fall into an hour that is skipped due to daylight saving time.
   -1    96 
   -1    97 Most libraries I have seen clip the result. JavaScript's `Date` object uses
   -1    98 overflow, and python's datetime library does not provide an API for adding
   -1    99 months.
   -1   100 
   -1   101 ### Adding a mixed delta
   -1   102 
   -1   103 How do you add one month and one day to 1970-04-30? Do you first add the month
   -1   104 (1970-05-30) and then the day (1970-05-31)? Or do you first add the day
   -1   105 (1970-05-01) and then the month (1970-06-01)?
   -1   106 
   -1   107 ### Comparing deltas
   -1   108 
   -1   109 Which duration is longer, 2 months or 60 days? In most cases, 2 month will have
   -1   110 61 days, so they will be longer. But when February is involved the two months
   -1   111 can be as short as 59 days. Again, we have different options.
   -1   112 
   -1   113 JavaScript's `Temporal` allows to compare these deltas, but only if you provide
   -1   114 a reference point that both deltas can be added to (which brings us back to the
   -1   115 previous issues). However, most libraries simply don't allow to compare deltas.
   -1   116 
   -1   117 ### Difference between dates/times
   -1   118 
   -1   119 What is the difference between 1970-01-01 and 1971-03-04? Again we have options:
   -1   120 
   -1   121 -   **no API**: as before
   -1   122 -   **top heavy**: add as many years as possible without overshooting, then
   -1   123     iterate with the next smaller unit until you have reached the target. In
   -1   124     this case this results in 1 year, 2 months, and 3 days
   -1   125 -   **absolute values**: convert the nominal values to absolute ones and use
   -1   126     the absolute difference: 427 days
   -1   127 -   **explicit**: let the user choose a unit. If the difference can not fully
   -1   128     be expressed in that unit, return either a fractional part (1.17 years) or
   -1   129     truncate (1 year)
   -1   130 
   -1   131 Python-dateutil's `relativedelta` uses the top-heavy approach. JavaScript's
   -1   132 `Temporal` also uses that approach, but also allows to choose a `largestUnit`.
   -1   133 Python's `timedelta` uses absolute values. `moment.js` uses the explicit
   -1   134 approach with fractions. Rust's `chrono` mostly uses the absolute values
   -1   135 approach, but also as a `years_since()` method.
   -1   136 
   -1   137 ## Other calendars
   -1   138 
   -1   139 I know that there are other systems than than the one described above. As far
   -1   140 as I understand, the Chinese calendar has eras and the Ethiopian calendar has
   -1   141 12 months, but also some days that do not belong to any month. These systems
   -1   142 seem so different to each other that I think that we should not try to shoehorn
   -1   143 them into a single implementation.
   -1   144 
   -1   145 Each system can have its own nominal data types, solving it's own unique
   -1   146 challenges. You can convert from one system to another by converting to and
   -1   147 from absolute values.
   -1   148 
   -1   149 ## Why is this relevant?
   -1   150 
   -1   151 If you look at all of these ambiguities, it is easy to give up and just live
   -1   152 without arithmetic for nominal dates and times.
   -1   153 
   -1   154 But still. In our human conversations it is completely normal to talk about
   -1   155 "two years ago" or "in two hours". We should be able to express these same
   -1   156 ideas in software.
   -1   157 
   -1   158 There is a silver lining: All of these ambiguities are only relevant in few
   -1   159 edge cases. The naive way to add a month does work in a lot of cases. For the
   -1   160 rest, we need APIs that are clear, simple, and avoid unexpected results.
   -1   161 
   -1   162 I am not sure whether any of the libraries I mentioned have already nailed that
   -1   163 part. Some get close. Here is my personal wish list:
   -1   164 
   -1   165 -   Make a clear distinction between absolute and nominal values
   -1   166 -   Make a clear distinction between dates and times
   -1   167 -   Clearly document how ambiguities are resolved
   -1   168 -   Do not assume that every day has 24 hours (most libraries get this wrong)
   -1   169 -   For adding deltas, most libraries seem to go with the clipping approach.
   -1   170     It might also be a good idea to offer different options to users.
   -1   171 -   I don't really care about comparing nominal deltas. Instead, users can
   -1   172     either compare absolute deltas or use a reference point.
   -1   173 -   For differences between dates and times, `Temporal`'s top heavy approach
   -1   174     with `largestUnit` looks pretty flexible. This or something like it is
   -1   175     probably the way to go.
   -1   176 
   -1   177 ## Links
   -1   178 
   -1   179 -   [Chrono](https://docs.rs/chrono/latest/chrono/index.html)
   -1   180 -   [python's `datetime`](https://docs.python.org/3/library/datetime.html)
   -1   181 -   [python-dateutil](https://github.com/dateutil/dateutil/)
   -1   182 -   [JavaScipt's `Date`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date)
   -1   183 -   [JavaScript's `Temporal`](https://tc39.es/proposal-temporal/docs/)
   -1   184 -   [Moment.js](https://momentjs.com/docs/)
   -1   185 -   New: my own [nominaldelta](https://github.com/xi/nominaldelta)

diff --git a/_content/posts/2024-09-04-clipboard/index.md b/_content/posts/2024-09-04-clipboard/index.md

@@ -0,0 +1,106 @@
   -1     1 ---
   -1     2 title: Keeping the clipboard alive
   -1     3 date: 2024-09-04
   -1     4 tags: [design, wayland]
   -1     5 description: Copied data is lost when you close the application that you wanted to copy from. I find this deeply confusing. I believe we can do better.
   -1     6 ---
   -1     7 
   -1     8 It frequently happens to me that I want to paste something, but nothing
   -1     9 happens. This is because on wayland (and many other systems, but I will
   -1    10 focus on wayland) the copied data is lost when you close the application
   -1    11 that you wanted to copy from. I find this deeply confusing. The official
   -1    12 solution seems to be to setup a clipboard manager. However, I found out
   -1    13 that clipboard managers are not a solution, they just make different
   -1    14 trade offs. I believe we can do better.
   -1    15 
   -1    16 ## The Problem
   -1    17 
   -1    18 I first thought that the clipboard contains the actual bits that are
   -1    19 being copied. But that is not the case. When you hit Ctrl-C, no data is
   -1    20 actually copied. Instead the data can be offered in multiple mime types
   -1    21 at the same time, so that the receiving end can pick which mime type it
   -1    22 prefers. For example, text copied from the web browser could be offered
   -1    23 as both `text/html` and `text/plain`.
   -1    24 
   -1    25 Of course, this mechanism only works as long as the application that is
   -1    26 offering the data does not quit. After that, there is no one left to
   -1    27 answer the request.
   -1    28 
   -1    29 ## Clipboard managers
   -1    30 
   -1    31 A common workaround for that problem is to use a clipboard manager like
   -1    32 this:
   -1    33 
   -1    34     wl-paste --watch cliphist store
   -1    35 
   -1    36 In this case, `wl-paste` will call `cliphist store` whenever something
   -1    37 is copied. It passes the copied data in one of the available mime types.
   -1    38 `cliphist` will then replace the original offer with its own
   -1    39 (`text/plain`). This means that the clipboard contents will not be lost
   -1    40 when the original source goes away. But it also has some drawbacks:
   -1    41 
   -1    42 -   Most mime type information is lost
   -1    43 -   The data needs to be transferred even if it is never actually pasted
   -1    44 
   -1    45 [`clipmon`](https://git.sr.ht/~whynothugo/clipmon) is another clipboard
   -1    46 manager that makes slightly different trade offs: It also replaces the
   -1    47 original offer with its own, but it preserves all mime types. This
   -1    48 solves the first drawback, but amplifies the second one: the same image
   -1    49 might have to be stored in multiple different formats. The author of
   -1    50 `clipmon` wrote a [great blog post about these trade
   -1    51 offs](https://whynothugo.nl/journal/2022/10/21/how-the-clipboard-works/).
   -1    52 
   -1    53 So in summary, the following goals are in conflict:
   -1    54 
   -1    55 -   offer content in different mime types
   -1    56 -   keep the clipboard alive when an application quits
   -1    57 -   avoid unnecessary data transfer and storage
   -1    58 
   -1    59 ## Finding balance
   -1    60 
   -1    61 Many clipboard managers have features beyond just keeping the clipboard
   -1    62 alive. But I only care about find a better default behavior.
   -1    63 
   -1    64 It would be nice if we could keep the original offer intact, and only
   -1    65 replace it with a fallback if the application actually quits. The
   -1    66 fallback could be restricted (e.g. only offer `text/plain`) to avoid
   -1    67 wasting resources. Still, I think this would be a more balanced solution
   -1    68 than what is currently available.
   -1    69 
   -1    70 I came up with the following script which can be used with
   -1    71 `wl-paste --watch`:
   -1    72 
   -1    73 ``` sh
   -1    74 #!/bin/sh -e
   -1    75 path="/tmp/clipboard-$USER-$XDG_SEAT.txt"
   -1    76 input=$(cat)
   -1    77 
   -1    78 if [ -n "$input" ]; then
   -1    79     umask 077
   -1    80     printf '%s' "$input" > "$path"
   -1    81 elif [ -f "$path" ] && ! wl-paste -l >/dev/null 2>&1; then
   -1    82     wl-copy < "$path"
   -1    83 fi
   -1    84 ```
   -1    85 
   -1    86 ## Moving it into the compositor
   -1    87 
   -1    88 I think the behavior I described above should be implemented in
   -1    89 compositors for three reasons:
   -1    90 
   -1    91 -   It should be the default behavior
   -1    92 
   -1    93 -   The above script has a race condition if an application creates a
   -1    94     new offer right before the call to `wl-copy`. Compositors have more
   -1    95     information and might be able to avoid that (not sure about it, this
   -1    96     might be an issue on the protocol level).
   -1    97 
   -1    98 -   By default, the wayland protocol only allows the currently active
   -1    99     window to access the clipboard for security reasons. Clipboard
   -1   100     managers only work if the compositor supports the [wlr data
   -1   101     control](https://wayland.app/protocols/wlr-data-control-unstable-v1)
   -1   102     extension protocol. Not relying on that protocol is the more secure
   -1   103     option.
   -1   104 
   -1   105 *Much of this post is based on discussions in
   -1   106 <https://github.com/labwc/labwc/issues/2042>.*

diff --git a/_content/posts/2024-10-03-not-the-only-place/index.md b/_content/posts/2024-10-03-not-the-only-place/index.md

@@ -0,0 +1,57 @@
   -1     1 ---
   -1     2 title: You are not the only place
   -1     3 date: 2024-10-03
   -1     4 tags: [design]
   -1     5 description: We can ultimately provide more meaningful services if we realize that our users can and will use other systems.
   -1     6 ---
   -1     7 
   -1     8 When working on a project, it's easy to become absorbed. We sometimes fail to
   -1     9 realize that our users are not as single-minded: They can and will use other
   -1    10 systems. If we want to build anything of value, we must look beyond our own
   -1    11 systems and understand the broader context in which our users operate.
   -1    12 
   -1    13 Here are three cases in which I should have realized that sooner:
   -1    14 
   -1    15 ## Design like your users spend most of their time elsewhere
   -1    16 
   -1    17 In the world of design, we often emphasize the importance of consistency.
   -1    18 However, unless you are Google or Facebook, and probably even then, you should
   -1    19 expect that your users spend far more time on other people's websites then on
   -1    20 yours. We should therefore think beyond our own design guidelines and consider
   -1    21 how our users experience the web as a whole.
   -1    22 
   -1    23 ## Be open for external references
   -1    24 
   -1    25 During my time at an organization that provided online forums for political
   -1    26 discussion, we made a critical oversight: we assumed that conversations were
   -1    27 confined to our platform. We failed to acknowledge that discussions were
   -1    28 happening everywhere — on social media, in news articles, and in everyday
   -1    29 conversations. Instead of merely hosting discussions, we should have focused on
   -1    30 summarizing the broader discourse and providing useful references to other
   -1    31 platforms. By doing so, we could have positioned ourselves as a valuable
   -1    32 resource in the larger conversation. Instead, we quickly vanished into
   -1    33 irrelevance as discussions where happening elsewhere.
   -1    34 
   -1    35 ## Know your niche
   -1    36 
   -1    37 At a conference focused on systems for scientific libraries, I witnessed a
   -1    38 fascinating discussion: Many attendees were surprised to learn that researchers
   -1    39 often begin their searches on platforms like Google, and only turn to the
   -1    40 library for "known item search" when they want to get access to a publication
   -1    41 that is not open access.
   -1    42 
   -1    43 Some of the attendees were open to accepting that fact and concluded that we
   -1    44 should focus on making the known item search really good. Others were offended
   -1    45 and felt like we need to do a better job of communicating the benefits of a
   -1    46 proper topical search. Yet others noted that in very competitive fields,
   -1    47 researchers do not use external search providers because they are afraid that
   -1    48 others could find out what they are working on.
   -1    49 
   -1    50 Any of these strategies is better than ignoring the issue.
   -1    51 
   -1    52 ## Conclusion: Context Matters
   -1    53 
   -1    54 In all three examples, the underlying issue was a tendency to be self-obsessed,
   -1    55 overlooking the fact that users engage with a multitude of systems. If we
   -1    56 recognize that we are not the only place, we can ultimately build better
   -1    57 systems that actually provide value for our users.