wip: Replace the secure store

This commit is contained in:
Zoe Roux 2023-07-13 23:23:10 +09:00
parent fee59833f2
commit 1237a9157c
7 changed files with 64 additions and 46 deletions

View File

@ -40,6 +40,7 @@
"react-dom": "18.2.0",
"react-i18next": "^12.2.0",
"react-native": "0.71.8",
"react-native-mmkv": "^2.10.1",
"react-native-reanimated": "~2.14.4",
"react-native-safe-area-context": "4.5.0",
"react-native-screens": "~3.20.0",

View File

@ -24,7 +24,7 @@ import { Hydrate, QueryClientProvider } from "@tanstack/react-query";
import { HiddenIfNoJs, SkeletonCss, ThemeSelector } from "@kyoo/primitives";
import { WebTooltip } from "@kyoo/primitives/src/tooltip.web";
import { createQueryClient, fetchQuery, getTokenWJ, QueryIdentifier, QueryPage } from "@kyoo/models";
import { setSecureItemSync } from "@kyoo/models/src/secure-store.web";
import { setSecureItem } from "@kyoo/models/src/secure-store.web";
import { useState } from "react";
import NextApp, { AppContext, type AppProps } from "next/app";
import { Poppins } from "next/font/google";
@ -101,7 +101,7 @@ const App = ({ Component, pageProps }: AppProps) => {
// Set the auth from the server (if the token was refreshed during SSR).
if (typeof window !== "undefined" && token)
setSecureItemSync("auth", JSON.stringify(token));
setSecureItem("auth", JSON.stringify(token));
return (
<YoshikiDebug>

View File

@ -5,7 +5,7 @@
"packageManager": "yarn@3.2.4",
"devDependencies": {
"@types/react": "^18.0.28",
"expo-secure-store": "^12.1.1",
"react-native-mmkv": "^2.10.1",
"typescript": "^4.9.5"
},
"peerDependencies": {

View File

@ -42,33 +42,31 @@ type Result<A, B> =
export type Account = Token & { apiUrl: string; username: string };
export const useAccounts = () => {
const [accounts, setAccounts] = useState<Account[]>([]);
const [selected, setSelected] = useState(0);
const [accounts] = useState<Account[]>(JSON.parse(getSecureItem("accounts") ?? "[]"));
const [selected, setSelected] = useState<number>(parseInt(getSecureItem("selected") ?? "0"));
useEffect(() => {
async function run() {
setAccounts(JSON.parse(await getSecureItem("accounts") ?? "[]"));
}
return {
accounts,
selected,
setSelected: (selected: number) => {
setSelected(selected);
setSecureItem("selected", selected.toString());
},
};
};
run();
}, []);
return {accounts, selected, setSelected};
}
const addAccount = async (token: Token, apiUrl: string, username: string | null): Promise<void> => {
const accounts: Account[] = JSON.parse(await getSecureItem("accounts") ?? "[]");
const accIdx = accounts.findIndex(x => x.refresh_token === token.refresh_token);
if (accIdx === -1)
accounts.push({...token, username, apiUrl});
else
accounts[accIdx] = {...accounts[accIdx], ...token};
await setSecureItem("accounts", JSON.stringify(accounts));
}
const addAccount = (token: Token, apiUrl: string, username: string | null) => {
const accounts: Account[] = JSON.parse(getSecureItem("accounts") ?? "[]");
const accIdx = accounts.findIndex((x) => x.refresh_token === token.refresh_token);
if (accIdx === -1) accounts.push({ ...token, username: username!, apiUrl });
else accounts[accIdx] = { ...accounts[accIdx], ...token };
setSecureItem("accounts", JSON.stringify(accounts));
};
export const loginFunc = async (
action: "register" | "login" | "refresh",
body: { username: string, password: string, email?: string } | string,
apiUrl?: string
body: { username: string; password: string; email?: string } | string,
apiUrl?: string,
): Promise<Result<Token, string>> => {
try {
const token = await queryFn(
@ -107,23 +105,23 @@ export const getTokenWJ = async (cookies?: string): Promise<[string, Token] | [n
};
export const getToken = async (cookies?: string): Promise<string | null> =>
(await getTokenWJ(cookies))[0]
(await getTokenWJ(cookies))[0];
export const logout = async () =>{
export const logout = async () => {
if (Platform.OS !== "web") {
const tokenStr = await getSecureItem("auth");
if (!tokenStr) return;
const token = TokenP.parse(JSON.parse(tokenStr));
let accounts: Account[] = JSON.parse(await getSecureItem("accounts") ?? "[]");
accounts = accounts.filter(x => x.refresh_token !== token.refresh_token);
let accounts: Account[] = JSON.parse((await getSecureItem("accounts")) ?? "[]");
accounts = accounts.filter((x) => x.refresh_token !== token.refresh_token);
await setSecureItem("accounts", JSON.stringify(accounts));
}
await deleteSecureItem("auth")
}
await deleteSecureItem("auth");
};
export const deleteAccount = async () => {
await queryFn({ path: ["auth", "me"], method: "DELETE"});
await queryFn({ path: ["auth", "me"], method: "DELETE" });
await logout();
}
};

View File

@ -18,8 +18,19 @@
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
*/
export {
setItemAsync as setSecureItem,
deleteItemAsync as deleteSecureItem,
getItemAsync as getSecureItem,
} from "expo-secure-store";
import { MMKV } from 'react-native-mmkv'
const storage = new MMKV();
export const setSecureItem = (key: string, value: string | null) => {
if (value === null)
storage.delete(key);
else
storage.set(key, value);
}
export const deleteSecureItem = (key: string) => setSecureItem(key, null);
export const getSecureItem = (key: string, _cookies?: string): string | null => {
return storage.getString(key) || null;
}

View File

@ -18,7 +18,7 @@
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
*/
export const setSecureItemSync = (key: string, value: string | null) => {
export const setSecureItem = (key: string, value: string | null) => {
const d = new Date();
// A year
d.setTime(d.getTime() + 365 * 24 * 60 * 60 * 1000);
@ -27,12 +27,9 @@ export const setSecureItemSync = (key: string, value: string | null) => {
return null;
};
export const setSecureItem = async (key: string, value: string | null): Promise<null> =>
setSecureItemSync(key, value);
export const deleteSecureItem = (key: string) => setSecureItem(key, null);
export const deleteSecureItem = async (key: string) => setSecureItem(key, null);
export const getSecureItem = async (key: string, cookies?: string): Promise<string | null> => {
export const getSecureItem = (key: string, cookies?: string): string | null => {
// Don't try to use document's cookies on SSR.
if (!cookies && typeof window === "undefined") return null;
const name = key + "=";

View File

@ -2263,7 +2263,7 @@ __metadata:
resolution: "@kyoo/models@workspace:packages/models"
dependencies:
"@types/react": ^18.0.28
expo-secure-store: ^12.1.1
react-native-mmkv: ^2.10.1
typescript: ^4.9.5
zod: ^3.21.4
peerDependencies:
@ -6907,7 +6907,7 @@ __metadata:
languageName: node
linkType: hard
"expo-secure-store@npm:^12.1.1, expo-secure-store@npm:~12.1.1":
"expo-secure-store@npm:~12.1.1":
version: 12.1.1
resolution: "expo-secure-store@npm:12.1.1"
peerDependencies:
@ -10339,6 +10339,7 @@ __metadata:
react-dom: 18.2.0
react-i18next: ^12.2.0
react-native: 0.71.8
react-native-mmkv: ^2.10.1
react-native-reanimated: ~2.14.4
react-native-safe-area-context: 4.5.0
react-native-screens: ~3.20.0
@ -11678,6 +11679,16 @@ __metadata:
languageName: node
linkType: hard
"react-native-mmkv@npm:^2.10.1":
version: 2.10.1
resolution: "react-native-mmkv@npm:2.10.1"
peerDependencies:
react: "*"
react-native: ">=0.71.0"
checksum: 2db42a667acd104047ddf307e852ffd9d9c6302454364fcc4cd35d8510d6f500bcd3562e14d95ae7fd520eac1cd3cc8a239c539a7339b70a4e6fd2d3f70daee7
languageName: node
linkType: hard
"react-native-reanimated@npm:2.14.4, react-native-reanimated@npm:~2.14.4":
version: 2.14.4
resolution: "react-native-reanimated@npm:2.14.4"