xtablo-source/xtablo-expo/lib/supabase.ts
Arthur Belleville 75328fbe96
Format codebase
2025-10-10 08:50:56 +02:00

74 lines
2.3 KiB
TypeScript

import "react-native-url-polyfill/auto";
import AsyncStorage from "@react-native-async-storage/async-storage";
import { createClient } from "@supabase/supabase-js";
import { Database } from "@/types/database.types";
import * as SecureStore from "expo-secure-store";
import * as aesjs from "aes-js";
import * as Crypto from "expo-crypto";
const supabaseUrl = process.env.EXPO_PUBLIC_SUPABASE_URL as string;
const supabaseAnonKey = process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY as string;
if (!supabaseUrl || !supabaseAnonKey) {
throw new Error("Missing Supabase environment variables");
}
// As Expo's SecureStore does not support values larger than 2048
// bytes, an AES-256 key is generated and stored in SecureStore, while
// it is used to encrypt/decrypt values stored in AsyncStorage.
class LargeSecureStore {
private async _encrypt(key: string, value: string) {
const encryptionKey = Crypto.getRandomValues(new Uint8Array(256 / 8));
const cipher = new aesjs.ModeOfOperation.ctr(encryptionKey, new aesjs.Counter(1));
const encryptedBytes = cipher.encrypt(aesjs.utils.utf8.toBytes(value));
await SecureStore.setItemAsync(key, aesjs.utils.hex.fromBytes(encryptionKey));
return aesjs.utils.hex.fromBytes(encryptedBytes);
}
private async _decrypt(key: string, value: string) {
const encryptionKeyHex = await SecureStore.getItemAsync(key);
if (!encryptionKeyHex) {
return encryptionKeyHex;
}
const cipher = new aesjs.ModeOfOperation.ctr(
aesjs.utils.hex.toBytes(encryptionKeyHex),
new aesjs.Counter(1)
);
const decryptedBytes = cipher.decrypt(aesjs.utils.hex.toBytes(value));
return aesjs.utils.utf8.fromBytes(decryptedBytes);
}
async getItem(key: string) {
const encrypted = await AsyncStorage.getItem(key);
if (!encrypted) {
return encrypted;
}
return await this._decrypt(key, encrypted);
}
async removeItem(key: string) {
await AsyncStorage.removeItem(key);
await SecureStore.deleteItemAsync(key);
}
async setItem(key: string, value: string) {
const encrypted = await this._encrypt(key, value);
await AsyncStorage.setItem(key, encrypted);
}
}
export const supabase = createClient<Database>(supabaseUrl, supabaseAnonKey, {
auth: {
storage: new LargeSecureStore(),
autoRefreshToken: true,
persistSession: true,
detectSessionInUrl: false,
},
});