mirror of
https://github.com/zed-industries/zed.git
synced 2024-09-19 10:29:35 +03:00
linux: add credentials impl via oo7 (#8035)
This change implements gpui's credentials API for the linux platform, using the [`oo7`](https://lib.rs/crates/oo7) library. We had a short discussion on Discord about where to store credentials and landed on the two dbus APIs [`org.freedesktop.Secrets`](https://specifications.freedesktop.org/secret-service/latest/index.html) and [`org.freedesktop.portal.Secrets`](https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Secret.html). The first one provides access to a more or less general purpose keystore, the second provides a way of obtaining a unique masterkey which in turn can be used for encrypting stuff and storing it to disk (especially interesting for sandboxed apps, think flatpak/snap). I decided to give the implementation a try with `oo7`, which uses the portal if the app is sandboxed and the secret service otherwise. If we do not want to use that library, we would probably have to more or less copy its functionality anyways. I also heard rumors of eventually changing the credentials API and I think this implementation serves as a starting point to discuss the need for this? With a working credentials implementation the sign in button now works (it panicked before). Todos: - [x] implement keystore unlocking - [x] try the change with oo7's tracing enabled? - [x] test the password deletion Release Notes: - N/A --------- Signed-off-by: Niklas Wimmer <mail@nwimmer.me> Co-authored-by: Mikayla Maki <mikayla@zed.dev>
This commit is contained in:
parent
1442fcb497
commit
ff65008316
625
Cargo.lock
generated
625
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -113,6 +113,7 @@ xkbcommon = { version = "0.7", features = ["wayland", "x11"] }
|
||||
as-raw-xcb-connection = "1"
|
||||
calloop = "0.12.4"
|
||||
calloop-wayland-source = "0.2.0"
|
||||
oo7 = "0.3.0"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
windows.workspace = true
|
||||
|
@ -9,6 +9,7 @@ use std::{
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use anyhow::anyhow;
|
||||
use ashpd::desktop::file_chooser::{OpenFileRequest, SaveFileRequest};
|
||||
use async_task::Runnable;
|
||||
use calloop::{EventLoop, LoopHandle, LoopSignal};
|
||||
@ -107,6 +108,8 @@ impl LinuxPlatform {
|
||||
}
|
||||
}
|
||||
|
||||
const KEYRING_LABEL: &str = "zed-github-account";
|
||||
|
||||
impl Platform for LinuxPlatform {
|
||||
fn background_executor(&self) -> BackgroundExecutor {
|
||||
self.inner.background_executor.clone()
|
||||
@ -361,23 +364,70 @@ impl Platform for LinuxPlatform {
|
||||
|
||||
//todo!(linux)
|
||||
fn write_credentials(&self, url: &str, username: &str, password: &[u8]) -> Task<Result<()>> {
|
||||
Task::Ready(Some(Err(anyhow::Error::msg(
|
||||
"Platform<LinuxPlatform>::with_credentials is not implemented yet",
|
||||
))))
|
||||
let url = url.to_string();
|
||||
let username = username.to_string();
|
||||
let password = password.to_vec();
|
||||
self.background_executor().spawn(async move {
|
||||
let keyring = oo7::Keyring::new().await?;
|
||||
keyring.unlock().await?;
|
||||
keyring
|
||||
.create_item(
|
||||
KEYRING_LABEL,
|
||||
&vec![("url", &url), ("username", &username)],
|
||||
password,
|
||||
true,
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
//todo!(linux)
|
||||
fn read_credentials(&self, url: &str) -> Task<Result<Option<(String, Vec<u8>)>>> {
|
||||
Task::Ready(Some(Err(anyhow::Error::msg(
|
||||
"Platform<LinuxPlatform>::read_credentials is not implemented yet",
|
||||
))))
|
||||
let url = url.to_string();
|
||||
self.background_executor().spawn(async move {
|
||||
let keyring = oo7::Keyring::new().await?;
|
||||
keyring.unlock().await?;
|
||||
|
||||
let items = keyring.search_items(&vec![("url", &url)]).await?;
|
||||
|
||||
for item in items.into_iter() {
|
||||
if item.label().await.is_ok_and(|label| label == KEYRING_LABEL) {
|
||||
let attributes = item.attributes().await?;
|
||||
let username = attributes
|
||||
.get("username")
|
||||
.ok_or_else(|| anyhow!("Cannot find username in stored credentials"))?;
|
||||
let secret = item.secret().await?;
|
||||
|
||||
// we lose the zeroizing capabilities at this boundary,
|
||||
// a current limitation GPUI's credentials api
|
||||
return Ok(Some((username.to_string(), secret.to_vec())));
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
})
|
||||
}
|
||||
|
||||
//todo!(linux)
|
||||
fn delete_credentials(&self, url: &str) -> Task<Result<()>> {
|
||||
Task::Ready(Some(Err(anyhow::Error::msg(
|
||||
"Platform<LinuxPlatform>::delete_credentials is not implemented yet",
|
||||
))))
|
||||
let url = url.to_string();
|
||||
self.background_executor().spawn(async move {
|
||||
let keyring = oo7::Keyring::new().await?;
|
||||
keyring.unlock().await?;
|
||||
|
||||
let items = keyring.search_items(&vec![("url", &url)]).await?;
|
||||
|
||||
for item in items.into_iter() {
|
||||
if item.label().await.is_ok_and(|label| label == KEYRING_LABEL) {
|
||||
item.delete().await?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn window_appearance(&self) -> crate::WindowAppearance {
|
||||
|
Loading…
Reference in New Issue
Block a user