diff --git a/front/apps/mobile/package.json b/front/apps/mobile/package.json index 191f7631..1d9dd8e5 100644 --- a/front/apps/mobile/package.json +++ b/front/apps/mobile/package.json @@ -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", diff --git a/front/apps/web/src/pages/_app.tsx b/front/apps/web/src/pages/_app.tsx index 5533d931..aba8e287 100755 --- a/front/apps/web/src/pages/_app.tsx +++ b/front/apps/web/src/pages/_app.tsx @@ -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 ( diff --git a/front/packages/models/package.json b/front/packages/models/package.json index 7b2d76fd..0b5c0fc5 100644 --- a/front/packages/models/package.json +++ b/front/packages/models/package.json @@ -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": { diff --git a/front/packages/models/src/login.ts b/front/packages/models/src/login.ts index 5ee3c104..3c35c7fb 100644 --- a/front/packages/models/src/login.ts +++ b/front/packages/models/src/login.ts @@ -42,33 +42,31 @@ type Result = export type Account = Token & { apiUrl: string; username: string }; export const useAccounts = () => { - const [accounts, setAccounts] = useState([]); - const [selected, setSelected] = useState(0); + const [accounts] = useState(JSON.parse(getSecureItem("accounts") ?? "[]")); + const [selected, setSelected] = useState(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 => { - 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> => { 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 => - (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(); -} +}; diff --git a/front/packages/models/src/secure-store.ts b/front/packages/models/src/secure-store.ts index a4fd300d..a6d1d94c 100644 --- a/front/packages/models/src/secure-store.ts +++ b/front/packages/models/src/secure-store.ts @@ -18,8 +18,19 @@ * along with Kyoo. If not, see . */ -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; +} diff --git a/front/packages/models/src/secure-store.web.ts b/front/packages/models/src/secure-store.web.ts index 7a832104..275a909e 100644 --- a/front/packages/models/src/secure-store.web.ts +++ b/front/packages/models/src/secure-store.web.ts @@ -18,7 +18,7 @@ * along with Kyoo. If not, see . */ -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 => - 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 => { +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 + "="; diff --git a/front/yarn.lock b/front/yarn.lock index 578da6ec..08b3ccb2 100644 --- a/front/yarn.lock +++ b/front/yarn.lock @@ -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"