- 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.