Remove keyring crate

We found a different solution, as the keyring crate isn't supported on Android
This commit is contained in:
Arnab Chakraborty
2024-08-12 20:26:11 +03:00
parent 0406a6b9f7
commit 8f6100e5bc
8 changed files with 170 additions and 172 deletions

BIN
Cargo.lock generated
View File

Binary file not shown.

View File

@@ -30,9 +30,7 @@ import SuperTokens from 'supertokens-web-js';
import EmailPassword from 'supertokens-web-js/recipe/emailpassword';
import Session from 'supertokens-web-js/recipe/session';
import ThirdParty from 'supertokens-web-js/recipe/thirdparty';
import getCookieHandler, {
setAppReady
} from '@sd/interface/app/$libraryId/settings/client/account/handlers/cookieHandler';
import getCookieHandler from '@sd/interface/app/$libraryId/settings/client/account/handlers/cookieHandler';
import getWindowHandler from '@sd/interface/app/$libraryId/settings/client/account/handlers/windowHandler';
import { useLocale } from '@sd/interface/hooks';
@@ -62,9 +60,7 @@ const startupError = (window as any).__SD_ERROR__ as string | undefined;
export default function App() {
useEffect(() => {
// This tells Tauri to show the current window because it's finished loading
commands.appReady().then(() => {
setAppReady();
});
commands.appReady();
}, []);
useEffect(() => {

View File

@@ -133,8 +133,6 @@ sysinfo = "0.29.11" # Update blocked due to API breaking changes
tar = "0.4.41"
tower-service = "0.3.2"
tracing-appender = "0.2.3"
keyring = { version = "3.0.4", features = ["apple-native", "windows-native", "sync-secret-service"] }
whoami = "1.5.1"
# Override features of transitive dependencies
[dependencies.openssl]

View File

@@ -1,10 +1,10 @@
// TODO: Ensure this file has normalised caching setup before reenabling
use keyring::Entry;
use rspc::alpha::AlphaRouter;
// use keyring::Entry;
// use rspc::alpha::AlphaRouter;
use serde_json::Value;
use tracing::{debug, error};
// use serde_json::Value;
// use tracing::{debug, error};
// use sd_crypto::keys::keymanager::{StoredKey, StoredKeyType};
// use sd_crypto::primitives::SECRET_KEY_IDENTIFIER;
// use sd_crypto::types::{Algorithm, HashingAlgorithm, OnboardingConfig, SecretKeyString};
@@ -20,7 +20,7 @@ use tracing::{debug, error};
// use crate::{invalidate_query, prisma::key};
// use super::utils::library;
use super::{Ctx, R};
// use super::{Ctx, R};
// #[derive(Type, Deserialize)]
// pub struct KeyAddArgs {
@@ -57,73 +57,73 @@ use super::{Ctx, R};
// status: bool,
// }
pub(crate) fn mount() -> AlphaRouter<Ctx> {
R.router()
.procedure("set", {
R.mutation(|_, key: String| async move {
let username = whoami::username();
let entry = match Entry::new("spacedrive-auth-service", username.as_str()) {
Ok(entry) => entry,
Err(e) => {
error!("Error creating entry: {}", e);
return Err(rspc::Error::new(
rspc::ErrorCode::InternalServerError,
"Error creating entry".to_string(),
));
}
};
// pub(crate) fn mount() -> AlphaRouter<Ctx> {
// R.router()
// .procedure("set", {
// R.mutation(|_, key: String| async move {
// let username = whoami::username();
// let entry = match Entry::new("spacedrive-auth-service", username.as_str()) {
// Ok(entry) => entry,
// Err(e) => {
// error!("Error creating entry: {}", e);
// return Err(rspc::Error::new(
// rspc::ErrorCode::InternalServerError,
// "Error creating entry".to_string(),
// ));
// }
// };
match entry.set_password(key.as_str()) {
Ok(_) => (),
Err(e) => {
error!("Error setting key: {}", e);
return Err(rspc::Error::new(
rspc::ErrorCode::InternalServerError,
"Error setting key".to_string(),
));
}
}
// match entry.set_password(key.as_str()) {
// Ok(_) => (),
// Err(e) => {
// error!("Error setting key: {}", e);
// return Err(rspc::Error::new(
// rspc::ErrorCode::InternalServerError,
// "Error setting key".to_string(),
// ));
// }
// }
debug!(
"Key set successfully: key={key}, service={service}",
key = key,
service = "spacedrive-auth-service",
);
Ok(())
})
})
.procedure("get", {
R.query(|_, _: ()| async move {
let username = whoami::username();
let entry = match Entry::new("spacedrive-auth-service", username.as_str()) {
Ok(entry) => entry,
Err(e) => {
error!("Error creating entry: {}", e);
return Err(rspc::Error::new(
rspc::ErrorCode::InternalServerError,
"Error creating entry".to_string(),
));
}
};
// debug!(
// "Key set successfully: key={key}, service={service}",
// key = key,
// service = "spacedrive-auth-service",
// );
// Ok(())
// })
// })
// .procedure("get", {
// R.query(|_, _: ()| async move {
// let username = whoami::username();
// let entry = match Entry::new("spacedrive-auth-service", username.as_str()) {
// Ok(entry) => entry,
// Err(e) => {
// error!("Error creating entry: {}", e);
// return Err(rspc::Error::new(
// rspc::ErrorCode::InternalServerError,
// "Error creating entry".to_string(),
// ));
// }
// };
let data = match entry.get_password() {
Ok(key) => key,
Err(e) => {
error!("Error retrieving key: {}. Does the key exist yet?", e);
return Ok("".to_string());
}
};
// let data = match entry.get_password() {
// Ok(key) => key,
// Err(e) => {
// error!("Error retrieving key: {}. Does the key exist yet?", e);
// return Ok("".to_string());
// }
// };
debug!(
"Key retrieved successfully: service={service}, data={_data}",
_data = data,
service = "spacedrive-auth-service",
);
// debug!(
// "Key retrieved successfully: service={service}, data={_data}",
// _data = data,
// service = "spacedrive-auth-service",
// );
Ok(data)
})
})
}
// Ok(data)
// })
// })
// }
//NOTE(@Rocky43007): OLD PROCEDURES -> MAY BE USEFUL FOR REFERENCE AND COULD BE USED IN THE FUTURE
// .procedure("list", {

View File

@@ -28,7 +28,8 @@ mod cloud;
mod ephemeral_files;
mod files;
mod jobs;
mod keys;
// #[cfg(not(any(target_os = "ios", target_os = "android")))]
// mod keys;
mod labels;
mod libraries;
pub mod locations;
@@ -201,7 +202,6 @@ pub(crate) fn mount() -> Arc<Router> {
.merge("tags.", tags::mount())
.merge("labels.", labels::mount())
// .merge("categories.", categories::mount())
.merge("keys.", keys::mount())
.merge("locations.", locations::mount())
.merge("ephemeralFiles.", ephemeral_files::mount())
.merge("files.", files::mount())
@@ -225,6 +225,9 @@ pub(crate) fn mount() -> Arc<Router> {
);
});
// #[cfg(not(any(target_os = "ios", target_os = "android")))]
// let r = r.merge("keys.", keys::mount());
let r = r
.build(
#[allow(clippy::let_and_return)]

View File

@@ -1,6 +1,8 @@
use std::path::Path;
use keyring::Entry;
// #[cfg(not(any(target_os = "ios", target_os = "android")))]
// use keyring::Entry;
use regex::Regex;
use tokio::{fs, io};
use tracing::{debug, error};
@@ -39,63 +41,71 @@ pub async fn get_size(path: impl AsRef<Path>) -> Result<u64, io::Error> {
}
}
pub fn get_access_token() -> Result<String, rspc::Error> {
let username = whoami::username();
let entry = match Entry::new("spacedrive-auth-service", username.as_str()) {
Ok(entry) => entry,
Err(e) => {
error!("Error creating entry: {}", e);
return Err(rspc::Error::new(
rspc::ErrorCode::InternalServerError,
"Error creating entry".to_string(),
));
}
};
// pub fn get_access_token() -> Result<String, rspc::Error> {
// // If target is ios or android, return an error as this function is not supported on those platforms
// if cfg!(any(target_os = "ios", target_os = "android")) {
// return Err(rspc::Error::new(
// rspc::ErrorCode::InternalServerError,
// "Function not supported on this platform".to_string(),
// ));
// } else {
// let username = whoami::username();
// let entry = match Entry::new("spacedrive-auth-service", username.as_str()) {
// Ok(entry) => entry,
// Err(e) => {
// error!("Error creating entry: {}", e);
// return Err(rspc::Error::new(
// rspc::ErrorCode::InternalServerError,
// "Error creating entry".to_string(),
// ));
// }
// };
let data = match entry.get_password() {
Ok(key) => key,
Err(e) => {
error!("Error retrieving key: {}. Does the key exist yet?", e);
return Err(rspc::Error::new(
rspc::ErrorCode::InternalServerError,
"Error retrieving key".to_string(),
));
}
};
// let data = match entry.get_password() {
// Ok(key) => key,
// Err(e) => {
// error!("Error retrieving key: {}. Does the key exist yet?", e);
// return Err(rspc::Error::new(
// rspc::ErrorCode::InternalServerError,
// "Error retrieving key".to_string(),
// ));
// }
// };
let re = match Regex::new(r#"st-access-token=([^;]+)"#) {
Ok(re) => re,
Err(e) => {
error!("Error creating regex: {}", e);
return Err(rspc::Error::new(
rspc::ErrorCode::InternalServerError,
"Error creating regex".to_string(),
));
}
};
// let re = match Regex::new(r#"st-access-token=([^;]+)"#) {
// Ok(re) => re,
// Err(e) => {
// error!("Error creating regex: {}", e);
// return Err(rspc::Error::new(
// rspc::ErrorCode::InternalServerError,
// "Error creating regex".to_string(),
// ));
// }
// };
let token = match re.captures(&data) {
Some(captures) => match captures.get(1) {
Some(token) => token.as_str(),
None => {
error!("Error parsing Cookie String value: {}", "No token found");
return Err(rspc::Error::new(
rspc::ErrorCode::InternalServerError,
"Error parsing Cookie String value".to_string(),
));
}
},
None => {
error!(
"Error parsing Cookie String value: {}",
"No token cookie string found"
);
return Err(rspc::Error::new(
rspc::ErrorCode::InternalServerError,
"Error parsing Cookie String value".to_string(),
));
}
};
// let token = match re.captures(&data) {
// Some(captures) => match captures.get(1) {
// Some(token) => token.as_str(),
// None => {
// error!("Error parsing Cookie String value: {}", "No token found");
// return Err(rspc::Error::new(
// rspc::ErrorCode::InternalServerError,
// "Error parsing Cookie String value".to_string(),
// ));
// }
// },
// None => {
// error!(
// "Error parsing Cookie String value: {}",
// "No token cookie string found"
// );
// return Err(rspc::Error::new(
// rspc::ErrorCode::InternalServerError,
// "Error parsing Cookie String value".to_string(),
// ));
// }
// };
Ok(token.to_string())
}
// Ok(token.to_string())
// }
// }

View File

@@ -1,15 +1,18 @@
import { CookieHandlerInterface } from "supertokens-website/utils/cookieHandler/types";
import { nonLibraryClient } from '@sd/client'
let APP_READY = false;
const frontendCookiesKey = "frontendCookies";
async function getCookiesFromStorage(): Promise<string> {
if (!APP_READY) {
return "";
}
const cookiesFromStorage = await nonLibraryClient.query(['keys.get'])
/**
* Tauri handles cookies differently than in browser environments. The SuperTokens
* SDK uses frontend cookies, to make sure everything work correctly we add custom
* cookie handling and store cookies in local storage instead (This is not a problem
* since these are frontend cookies and not server side cookies)
*/
function getCookiesFromStorage(): string {
const cookiesFromStorage = window.localStorage.getItem(frontendCookiesKey);
if (cookiesFromStorage.length === 0) {
if (cookiesFromStorage === null) {
window.localStorage.setItem(frontendCookiesKey, "[]");
return "";
}
@@ -22,54 +25,47 @@ async function getCookiesFromStorage(): Promise<string> {
for (let cookieIndex = 0; cookieIndex < cookieArrayInStorage.length; cookieIndex++) {
const currentCookieString = cookieArrayInStorage[cookieIndex];
const parts = currentCookieString?.split(";") ?? [];
const parts = currentCookieString?.split(";");
let expirationString: string = "";
for (let partIndex = 0; partIndex < parts.length; partIndex++) {
const currentPart = parts[partIndex];
for (let partIndex = 0; partIndex < parts!.length; partIndex++) {
const currentPart = parts![partIndex];
if (currentPart?.toLocaleLowerCase().includes("expires=")) {
expirationString = currentPart;
if (currentPart!.toLocaleLowerCase().includes("expires=")) {
expirationString = currentPart!;
break;
}
}
if (expirationString !== "") {
const expirationValueString = expirationString.split("=")[1];
const expirationDate = expirationValueString ? new Date(expirationValueString) : null;
const expirationDate = new Date(expirationValueString!);
const currentTimeInMillis = Date.now();
// if the cookie has expired, we skip it
if (expirationDate && expirationDate.getTime() < currentTimeInMillis) {
if (expirationDate.getTime() < currentTimeInMillis) {
continue;
}
}
if (currentCookieString !== undefined) {
cookieArrayToReturn.push(currentCookieString);
}
cookieArrayToReturn.push(currentCookieString!);
}
/**
* After processing and removing expired cookies we need to update the cookies
* in storage so we dont have to process the expired ones again
*/
await nonLibraryClient.mutation(['keys.set', JSON.stringify(cookieArrayToReturn)])
window.localStorage.setItem(frontendCookiesKey, JSON.stringify(cookieArrayToReturn));
return cookieArrayToReturn.join("; ");
}
async function setCookieToStorage(cookieString: string): Promise<void> {
if (!APP_READY) {
return;
}
const cookieName = cookieString.split(";")[0]?.split("=")[0];
const cookiesFromStorage = await nonLibraryClient.query(['keys.get'])
function setCookieToStorage(cookieString: string) {
const cookieName = cookieString.split(";")[0]!.split("=")[0];
const cookiesFromStorage = window.localStorage.getItem(frontendCookiesKey);
let cookiesArray: string[] = [];
if (cookiesFromStorage.length !== 0) {
if (cookiesFromStorage !== null) {
const cookiesArrayFromStorage: string[] = JSON.parse(cookiesFromStorage);
cookiesArray = cookiesArrayFromStorage;
}
@@ -79,7 +75,7 @@ async function setCookieToStorage(cookieString: string): Promise<void> {
for (let i = 0; i < cookiesArray.length; i++) {
const currentCookie = cookiesArray[i];
if (currentCookie?.indexOf(`${cookieName}=`) !== -1) {
if (currentCookie!.indexOf(`${cookieName}=`) !== -1) {
cookieIndex = i;
break;
}
@@ -97,21 +93,18 @@ async function setCookieToStorage(cookieString: string): Promise<void> {
cookiesArray.push(cookieString);
}
await nonLibraryClient.mutation(['keys.set', JSON.stringify(cookiesArray)])
window.localStorage.setItem(frontendCookiesKey, JSON.stringify(cookiesArray));
}
export default function getCookieHandler(original: CookieHandlerInterface): CookieHandlerInterface {
return {
...original,
getCookie: async function () {
return getCookiesFromStorage();
const cookies = getCookiesFromStorage();
return cookies;
},
setCookie: async function (cookieString: string) {
return setCookieToStorage(cookieString);
setCookieToStorage(cookieString);
},
};
}
export function setAppReady() {
APP_READY = true;
}

View File

@@ -23,7 +23,6 @@ export type Procedures = {
{ key: "invalidation.test-invalidate", input: never, result: number } |
{ key: "jobs.isActive", input: LibraryArgs<null>, result: boolean } |
{ key: "jobs.reports", input: LibraryArgs<null>, result: JobGroup[] } |
{ key: "keys.get", input: never, result: string } |
{ key: "labels.count", input: LibraryArgs<null>, result: number } |
{ key: "labels.get", input: LibraryArgs<number>, result: Label | null } |
{ key: "labels.getForObject", input: LibraryArgs<number>, result: Label[] } |
@@ -111,7 +110,6 @@ export type Procedures = {
{ key: "jobs.objectValidator", input: LibraryArgs<ObjectValidatorArgs>, result: null } |
{ key: "jobs.pause", input: LibraryArgs<string>, result: null } |
{ key: "jobs.resume", input: LibraryArgs<string>, result: null } |
{ key: "keys.set", input: string, result: null } |
{ key: "labels.delete", input: LibraryArgs<number>, result: null } |
{ key: "library.create", input: CreateLibraryArgs, result: LibraryConfigWrapped } |
{ key: "library.delete", input: string, result: null } |