mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-13 15:34:13 +03:00
Merge pull request #4288 from gitbutlerapp/remove-unused-keys-mod
remove unused keys module
This commit is contained in:
commit
e89cd04c31
@ -41,8 +41,4 @@ export class AuthService {
|
|||||||
if (resp) throw new Error(resp);
|
if (resp) throw new Error(resp);
|
||||||
return { name: 'push', ok: true };
|
return { name: 'push', ok: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
async getPublicKey() {
|
|
||||||
return await invoke<string>('get_public_key');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,23 +1,16 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { AuthService } from '$lib/backend/auth';
|
|
||||||
import { GitConfigService } from '$lib/backend/gitConfigService';
|
import { GitConfigService } from '$lib/backend/gitConfigService';
|
||||||
import SectionCard from '$lib/components/SectionCard.svelte';
|
import SectionCard from '$lib/components/SectionCard.svelte';
|
||||||
import ContentWrapper from '$lib/settings/ContentWrapper.svelte';
|
import ContentWrapper from '$lib/settings/ContentWrapper.svelte';
|
||||||
import Button from '$lib/shared/Button.svelte';
|
|
||||||
import Link from '$lib/shared/Link.svelte';
|
import Link from '$lib/shared/Link.svelte';
|
||||||
import Spacer from '$lib/shared/Spacer.svelte';
|
import Spacer from '$lib/shared/Spacer.svelte';
|
||||||
import TextBox from '$lib/shared/TextBox.svelte';
|
|
||||||
import Toggle from '$lib/shared/Toggle.svelte';
|
import Toggle from '$lib/shared/Toggle.svelte';
|
||||||
import { copyToClipboard } from '$lib/utils/clipboard';
|
|
||||||
import { getContext } from '$lib/utils/context';
|
import { getContext } from '$lib/utils/context';
|
||||||
import { openExternalUrl } from '$lib/utils/url';
|
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
const gitConfig = getContext(GitConfigService);
|
const gitConfig = getContext(GitConfigService);
|
||||||
const authService = getContext(AuthService);
|
|
||||||
|
|
||||||
let annotateCommits = true;
|
let annotateCommits = true;
|
||||||
let sshKey = '';
|
|
||||||
|
|
||||||
function toggleCommitterSigning() {
|
function toggleCommitterSigning() {
|
||||||
annotateCommits = !annotateCommits;
|
annotateCommits = !annotateCommits;
|
||||||
@ -25,7 +18,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
sshKey = await authService.getPublicKey();
|
|
||||||
annotateCommits = (await gitConfig.get('gitbutler.gitbutlerCommitter')) === '1';
|
annotateCommits = (await gitConfig.get('gitbutler.gitbutlerCommitter')) === '1';
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
@ -50,29 +42,4 @@
|
|||||||
</SectionCard>
|
</SectionCard>
|
||||||
|
|
||||||
<Spacer />
|
<Spacer />
|
||||||
|
|
||||||
<SectionCard>
|
|
||||||
<svelte:fragment slot="title">SSH key</svelte:fragment>
|
|
||||||
<svelte:fragment slot="caption">
|
|
||||||
GitButler uses SSH keys to authenticate with your Git provider. Add the following public key
|
|
||||||
to your Git provider to enable GitButler to push code.
|
|
||||||
</svelte:fragment>
|
|
||||||
|
|
||||||
<TextBox readonly selectall bind:value={sshKey} />
|
|
||||||
<div class="row-buttons">
|
|
||||||
<Button style="pop" kind="solid" icon="copy" on:click={() => copyToClipboard(sshKey)}>
|
|
||||||
Copy to clipboard
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
style="ghost"
|
|
||||||
outline
|
|
||||||
icon="open-link"
|
|
||||||
on:mousedown={() => {
|
|
||||||
openExternalUrl('https://github.com/settings/ssh/new');
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Add key to GitHub
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</SectionCard>
|
|
||||||
</ContentWrapper>
|
</ContentWrapper>
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
use anyhow::Context;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use super::{storage::Storage, PrivateKey};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Controller {
|
|
||||||
storage: Storage,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Controller {
|
|
||||||
pub fn new(storage: Storage) -> Self {
|
|
||||||
Self { storage }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_path(path: impl Into<PathBuf>) -> Self {
|
|
||||||
Self::new(Storage::from_path(path))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_or_create(&self) -> anyhow::Result<PrivateKey> {
|
|
||||||
if let Some(key) = self.storage.get().context("failed to get key")? {
|
|
||||||
Ok(key)
|
|
||||||
} else {
|
|
||||||
let key = PrivateKey::generate();
|
|
||||||
self.storage.create(&key).context("failed to save key")?;
|
|
||||||
Ok(key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,120 +0,0 @@
|
|||||||
use std::{fmt, str::FromStr};
|
|
||||||
|
|
||||||
use rand::rngs::OsRng;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use ssh_key::{HashAlg, LineEnding, SshSig};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq)]
|
|
||||||
pub struct PrivateKey(ssh_key::PrivateKey);
|
|
||||||
|
|
||||||
impl PrivateKey {
|
|
||||||
pub fn generate() -> Self {
|
|
||||||
Self::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn public_key(&self) -> PublicKey {
|
|
||||||
PublicKey::from(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sign(&self, bytes: &[u8]) -> anyhow::Result<String> {
|
|
||||||
let sig = SshSig::sign(&self.0, "git", HashAlg::Sha512, bytes)?;
|
|
||||||
sig.to_pem(LineEnding::default()).map_err(Into::into)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for PrivateKey {
|
|
||||||
fn default() -> Self {
|
|
||||||
let ed25519_keypair = ssh_key::private::Ed25519Keypair::random(&mut OsRng);
|
|
||||||
let ed25519_key = ssh_key::PrivateKey::from(ed25519_keypair);
|
|
||||||
Self(ed25519_key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for PrivateKey {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.0.to_bytes().eq(&other.0.to_bytes())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Serialize for PrivateKey {
|
|
||||||
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
|
||||||
self.to_string().serialize(serializer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromStr for PrivateKey {
|
|
||||||
type Err = ssh_key::Error;
|
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
||||||
let key = ssh_key::PrivateKey::from_openssh(s.as_bytes())?;
|
|
||||||
Ok(Self(key))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for PrivateKey {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
self.0
|
|
||||||
.to_openssh(ssh_key::LineEnding::default())
|
|
||||||
.map_err(|_| fmt::Error)?
|
|
||||||
.fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for PrivateKey {
|
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
||||||
where
|
|
||||||
D: serde::Deserializer<'de>,
|
|
||||||
{
|
|
||||||
let s = String::deserialize(deserializer)?;
|
|
||||||
Self::from_str(&s).map_err(serde::de::Error::custom)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct PublicKey(ssh_key::PublicKey);
|
|
||||||
|
|
||||||
impl From<&PrivateKey> for PublicKey {
|
|
||||||
fn from(value: &PrivateKey) -> Self {
|
|
||||||
Self(value.0.public_key().clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for PublicKey {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.0.to_bytes().eq(&other.0.to_bytes())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for PublicKey {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
self.0.to_openssh().map_err(|_| fmt::Error)?.fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromStr for PublicKey {
|
|
||||||
type Err = ssh_key::Error;
|
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
||||||
let key = ssh_key::PublicKey::from_openssh(s)?;
|
|
||||||
Ok(Self(key))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Serialize for PublicKey {
|
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
S: serde::Serializer,
|
|
||||||
{
|
|
||||||
self.to_string().serialize(serializer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for PublicKey {
|
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
||||||
where
|
|
||||||
D: serde::Deserializer<'de>,
|
|
||||||
{
|
|
||||||
let s = String::deserialize(deserializer)?;
|
|
||||||
Self::from_str(s.as_str()).map_err(serde::de::Error::custom)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
pub mod controller;
|
|
||||||
mod key;
|
|
||||||
pub mod storage;
|
|
||||||
|
|
||||||
pub use controller::*;
|
|
||||||
pub use key::{PrivateKey, PublicKey};
|
|
@ -1,33 +0,0 @@
|
|||||||
use super::PrivateKey;
|
|
||||||
use crate::storage;
|
|
||||||
use anyhow::Result;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
// TODO(ST): get rid of this type, it's more trouble than it's worth.
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Storage {
|
|
||||||
inner: storage::Storage,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Storage {
|
|
||||||
pub fn new(storage: storage::Storage) -> Storage {
|
|
||||||
Storage { inner: storage }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_path(path: impl Into<PathBuf>) -> Storage {
|
|
||||||
Storage::new(storage::Storage::new(path))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get(&self) -> Result<Option<PrivateKey>> {
|
|
||||||
let key = self.inner.read("keys/ed25519")?;
|
|
||||||
key.map(|s| s.parse().map_err(Into::into)).transpose()
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(ST): see if Key should rather deal with bytes instead for this kind of serialization.
|
|
||||||
pub fn create(&self, key: &PrivateKey) -> Result<()> {
|
|
||||||
self.inner.write("keys/ed25519", &key.to_string())?;
|
|
||||||
self.inner
|
|
||||||
.write("keys/ed25519.pub", &key.public_key().to_string())?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
@ -18,7 +18,6 @@ pub mod error;
|
|||||||
pub mod fs;
|
pub mod fs;
|
||||||
pub mod git;
|
pub mod git;
|
||||||
pub mod id;
|
pub mod id;
|
||||||
pub mod keys;
|
|
||||||
pub mod lock;
|
pub mod lock;
|
||||||
pub mod path;
|
pub mod path;
|
||||||
pub mod secret;
|
pub mod secret;
|
||||||
|
@ -1,3 +1,2 @@
|
|||||||
mod keys;
|
|
||||||
mod lock;
|
mod lock;
|
||||||
mod types;
|
mod types;
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
use gitbutler_core::keys::{PrivateKey, PublicKey};
|
|
||||||
|
|
||||||
mod controller {
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
|
||||||
mod not_windows {
|
|
||||||
use std::fs;
|
|
||||||
#[cfg(target_family = "unix")]
|
|
||||||
use std::os::unix::prelude::*;
|
|
||||||
|
|
||||||
use gitbutler_core::keys::{storage::Storage, Controller};
|
|
||||||
|
|
||||||
use gitbutler_testsupport::Suite;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn get_or_create() {
|
|
||||||
let suite = Suite::default();
|
|
||||||
let controller = Controller::new(Storage::from_path(suite.local_app_data()));
|
|
||||||
|
|
||||||
let once = controller.get_or_create().unwrap();
|
|
||||||
let twice = controller.get_or_create().unwrap();
|
|
||||||
assert_eq!(once, twice);
|
|
||||||
|
|
||||||
// check permissions of the private key
|
|
||||||
let permissions = fs::metadata(suite.local_app_data().join("keys/ed25519"))
|
|
||||||
.unwrap()
|
|
||||||
.permissions();
|
|
||||||
let perms = format!("{:o}", permissions.mode());
|
|
||||||
assert_eq!(perms, "100600");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn to_from_string_private() {
|
|
||||||
let private_key = PrivateKey::generate();
|
|
||||||
let serialized = private_key.to_string();
|
|
||||||
let deserialized: PrivateKey = serialized.parse().unwrap();
|
|
||||||
assert_eq!(private_key, deserialized);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn to_from_string_public() {
|
|
||||||
let private_key = PrivateKey::generate();
|
|
||||||
let public_key = private_key.public_key();
|
|
||||||
let serialized = public_key.to_string();
|
|
||||||
let deserialized: PublicKey = serialized.parse().unwrap();
|
|
||||||
assert_eq!(public_key, deserialized);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn serde_private() {
|
|
||||||
let private_key = PrivateKey::generate();
|
|
||||||
let serialized = serde_json::to_string(&private_key).unwrap();
|
|
||||||
let deserialized: PrivateKey = serde_json::from_str(&serialized).unwrap();
|
|
||||||
assert_eq!(private_key, deserialized);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn serde_public() {
|
|
||||||
let private_key = PrivateKey::generate();
|
|
||||||
let public_key = private_key.public_key();
|
|
||||||
let serialized = serde_json::to_string(&public_key).unwrap();
|
|
||||||
let deserialized: PublicKey = serde_json::from_str(&serialized).unwrap();
|
|
||||||
assert_eq!(public_key, deserialized);
|
|
||||||
}
|
|
@ -4,7 +4,6 @@ use std::{path::PathBuf, vec};
|
|||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
|
|
||||||
use gitbutler_command_context::ProjectRepo;
|
use gitbutler_command_context::ProjectRepo;
|
||||||
use gitbutler_core::keys;
|
|
||||||
|
|
||||||
use gitbutler_core::git::Url;
|
use gitbutler_core::git::Url;
|
||||||
use gitbutler_project::AuthKey;
|
use gitbutler_project::AuthKey;
|
||||||
@ -15,7 +14,6 @@ pub enum SshCredential {
|
|||||||
key_path: PathBuf,
|
key_path: PathBuf,
|
||||||
passphrase: Option<String>,
|
passphrase: Option<String>,
|
||||||
},
|
},
|
||||||
GitButlerKey(Box<keys::PrivateKey>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
@ -51,12 +49,6 @@ impl From<Credential> for git2::RemoteCallbacks<'_> {
|
|||||||
git2::Cred::ssh_key("git", None, &key_path, passphrase.as_deref())
|
git2::Cred::ssh_key("git", None, &key_path, passphrase.as_deref())
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Credential::Ssh(SshCredential::GitButlerKey(key)) => {
|
|
||||||
remote_callbacks.credentials(move |url, _username_from_url, _allowed_types| {
|
|
||||||
tracing::info!("authenticating with {} using gitbutler's key", url);
|
|
||||||
git2::Cred::ssh_key_from_memory("git", None, &key.to_string(), None)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Credential::Https(HttpsCredential::CredentialHelper { username, password }) => {
|
Credential::Https(HttpsCredential::CredentialHelper { username, password }) => {
|
||||||
remote_callbacks.credentials(move |url, _username_from_url, _allowed_types| {
|
remote_callbacks.credentials(move |url, _username_from_url, _allowed_types| {
|
||||||
tracing::info!("authenticating with {url} as '{username}' with password using credential helper");
|
tracing::info!("authenticating with {url} as '{username}' with password using credential helper");
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
pub mod commands {
|
|
||||||
use gitbutler_core::keys::{controller, PublicKey};
|
|
||||||
use tauri::Manager;
|
|
||||||
use tracing::instrument;
|
|
||||||
|
|
||||||
use crate::error::Error;
|
|
||||||
|
|
||||||
#[tauri::command(async)]
|
|
||||||
#[instrument(skip(handle), err(Debug))]
|
|
||||||
pub async fn get_public_key(handle: tauri::AppHandle) -> Result<PublicKey, Error> {
|
|
||||||
handle
|
|
||||||
.state::<controller::Controller>()
|
|
||||||
.get_or_create()
|
|
||||||
.map(|key| key.public_key())
|
|
||||||
.map_err(Into::into)
|
|
||||||
}
|
|
||||||
}
|
|
@ -24,7 +24,6 @@ pub mod askpass;
|
|||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod github;
|
pub mod github;
|
||||||
pub mod keys;
|
|
||||||
pub mod projects;
|
pub mod projects;
|
||||||
pub mod remotes;
|
pub mod remotes;
|
||||||
pub mod repo;
|
pub mod repo;
|
||||||
|
@ -16,8 +16,8 @@
|
|||||||
use gitbutler_core::storage;
|
use gitbutler_core::storage;
|
||||||
use gitbutler_repo::credentials::Helper;
|
use gitbutler_repo::credentials::Helper;
|
||||||
use gitbutler_tauri::{
|
use gitbutler_tauri::{
|
||||||
app, askpass, commands, config, github, keys, logs, menu, projects, remotes, repo, secret,
|
app, askpass, commands, config, github, logs, menu, projects, remotes, repo, secret, undo,
|
||||||
undo, users, virtual_branches, watcher, zip,
|
users, virtual_branches, watcher, zip,
|
||||||
};
|
};
|
||||||
use gitbutler_virtual::assets;
|
use gitbutler_virtual::assets;
|
||||||
use tauri::{generate_context, Manager};
|
use tauri::{generate_context, Manager};
|
||||||
@ -128,12 +128,6 @@ fn main() {
|
|||||||
|
|
||||||
app_handle.manage(gitbutler_feedback::controller::Controller::new(app_data_dir.clone(), app_log_dir.clone(), zipper.clone(), projects_controller.clone()));
|
app_handle.manage(gitbutler_feedback::controller::Controller::new(app_data_dir.clone(), app_log_dir.clone(), zipper.clone(), projects_controller.clone()));
|
||||||
|
|
||||||
let keys_storage_controller = gitbutler_core::keys::storage::Storage::new(storage_controller.clone());
|
|
||||||
app_handle.manage(keys_storage_controller.clone());
|
|
||||||
|
|
||||||
let keys_controller = gitbutler_core::keys::Controller::new(keys_storage_controller.clone());
|
|
||||||
app_handle.manage(keys_controller.clone());
|
|
||||||
|
|
||||||
let git_credentials_controller = Helper::default();
|
let git_credentials_controller = Helper::default();
|
||||||
app_handle.manage(git_credentials_controller.clone());
|
app_handle.manage(git_credentials_controller.clone());
|
||||||
|
|
||||||
@ -215,7 +209,6 @@ fn main() {
|
|||||||
config::set_gb_config,
|
config::set_gb_config,
|
||||||
menu::menu_item_set_enabled,
|
menu::menu_item_set_enabled,
|
||||||
menu::resolve_vscode_variant,
|
menu::resolve_vscode_variant,
|
||||||
keys::commands::get_public_key,
|
|
||||||
github::commands::init_device_oauth,
|
github::commands::init_device_oauth,
|
||||||
github::commands::check_auth_status,
|
github::commands::check_auth_status,
|
||||||
askpass::commands::submit_prompt_response,
|
askpass::commands::submit_prompt_response,
|
||||||
|
@ -15,7 +15,6 @@ pub struct Suite {
|
|||||||
pub storage: gitbutler_core::storage::Storage,
|
pub storage: gitbutler_core::storage::Storage,
|
||||||
pub users: gitbutler_user::Controller,
|
pub users: gitbutler_user::Controller,
|
||||||
pub projects: gitbutler_project::Controller,
|
pub projects: gitbutler_project::Controller,
|
||||||
pub keys: gitbutler_core::keys::Controller,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Suite {
|
impl Drop for Suite {
|
||||||
@ -32,13 +31,11 @@ impl Default for Suite {
|
|||||||
let storage = gitbutler_core::storage::Storage::new(local_app_data.path());
|
let storage = gitbutler_core::storage::Storage::new(local_app_data.path());
|
||||||
let users = gitbutler_user::Controller::from_path(local_app_data.path());
|
let users = gitbutler_user::Controller::from_path(local_app_data.path());
|
||||||
let projects = gitbutler_project::Controller::from_path(local_app_data.path());
|
let projects = gitbutler_project::Controller::from_path(local_app_data.path());
|
||||||
let keys = gitbutler_core::keys::Controller::from_path(local_app_data.path());
|
|
||||||
Self {
|
Self {
|
||||||
storage,
|
storage,
|
||||||
local_app_data: Some(local_app_data),
|
local_app_data: Some(local_app_data),
|
||||||
users,
|
users,
|
||||||
projects,
|
projects,
|
||||||
keys,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user