18d307f52SEvan Baconimport { getExpoHomeDirectory, getUserStatePath } from '@expo/config/build/getUserState';
28d307f52SEvan Baconimport JsonFile from '@expo/json-file';
3b1f66971SLinus Unnebäckimport crypto from 'crypto';
48d307f52SEvan Bacon
58d307f52SEvan Bacontype SessionData = {
68d307f52SEvan Bacon  sessionSecret: string;
78d307f52SEvan Bacon  // These fields are potentially used by Expo CLI.
88d307f52SEvan Bacon  userId: string;
98d307f52SEvan Bacon  username: string;
10*d88ac65dSlzkb  currentConnection: 'Username-Password-Authentication' | 'Browser-Flow-Authentication';
118d307f52SEvan Bacon};
128d307f52SEvan Bacon
138d307f52SEvan Baconexport type UserSettingsData = {
148d307f52SEvan Bacon  auth?: SessionData | null;
158d307f52SEvan Bacon  ignoreBundledBinaries?: string[];
168d307f52SEvan Bacon  PATH?: string;
17384598e2SBrent Vatne  /** Last development code signing ID used for `npx expo run:ios`. */
188d307f52SEvan Bacon  developmentCodeSigningId?: string;
198d307f52SEvan Bacon  /** Unique user ID which is generated anonymously and can be cleared locally. */
208d307f52SEvan Bacon  uuid?: string;
218d307f52SEvan Bacon};
228d307f52SEvan Bacon
238d307f52SEvan Bacon/** Return the user cache directory. */
248d307f52SEvan Baconfunction getDirectory() {
258d307f52SEvan Bacon  return getExpoHomeDirectory();
268d307f52SEvan Bacon}
278d307f52SEvan Bacon
288d307f52SEvan Baconfunction getFilePath(): string {
298d307f52SEvan Bacon  return getUserStatePath();
308d307f52SEvan Bacon}
318d307f52SEvan Bacon
328d307f52SEvan Baconfunction userSettingsJsonFile(): JsonFile<UserSettingsData> {
338d307f52SEvan Bacon  return new JsonFile<UserSettingsData>(getFilePath(), {
348d307f52SEvan Bacon    ensureDir: true,
358d307f52SEvan Bacon    jsonParseErrorDefault: {},
368d307f52SEvan Bacon    cantReadFileDefault: {},
378d307f52SEvan Bacon  });
388d307f52SEvan Bacon}
398d307f52SEvan Bacon
408d307f52SEvan Baconasync function setSessionAsync(sessionData?: SessionData): Promise<void> {
418d307f52SEvan Bacon  await UserSettings.setAsync('auth', sessionData, {
428d307f52SEvan Bacon    default: {},
438d307f52SEvan Bacon    ensureDir: true,
448d307f52SEvan Bacon  });
458d307f52SEvan Bacon}
468d307f52SEvan Bacon
478d307f52SEvan Baconfunction getSession(): SessionData | null {
488d307f52SEvan Bacon  try {
498d307f52SEvan Bacon    return JsonFile.read<UserSettingsData>(getUserStatePath())?.auth ?? null;
508d307f52SEvan Bacon  } catch (error: any) {
518d307f52SEvan Bacon    if (error.code === 'ENOENT') {
528d307f52SEvan Bacon      return null;
538d307f52SEvan Bacon    }
548d307f52SEvan Bacon    throw error;
558d307f52SEvan Bacon  }
568d307f52SEvan Bacon}
578d307f52SEvan Bacon
588d307f52SEvan Baconfunction getAccessToken(): string | null {
598d307f52SEvan Bacon  return process.env.EXPO_TOKEN ?? null;
608d307f52SEvan Bacon}
618d307f52SEvan Bacon
628d307f52SEvan Bacon// returns an anonymous, unique identifier for a user on the current computer
638d307f52SEvan Baconasync function getAnonymousIdentifierAsync(): Promise<string> {
648d307f52SEvan Bacon  const settings = await userSettingsJsonFile();
658d307f52SEvan Bacon  let id = await settings.getAsync('uuid', null);
668d307f52SEvan Bacon
678d307f52SEvan Bacon  if (!id) {
68b1f66971SLinus Unnebäck    id = crypto.randomUUID();
698d307f52SEvan Bacon    await settings.setAsync('uuid', id);
708d307f52SEvan Bacon  }
718d307f52SEvan Bacon
728d307f52SEvan Bacon  return id;
738d307f52SEvan Bacon}
748d307f52SEvan Bacon
758d307f52SEvan Baconconst UserSettings = Object.assign(userSettingsJsonFile(), {
768d307f52SEvan Bacon  getSession,
778d307f52SEvan Bacon  setSessionAsync,
788d307f52SEvan Bacon  getAccessToken,
798d307f52SEvan Bacon  getDirectory,
808d307f52SEvan Bacon  getFilePath,
818d307f52SEvan Bacon  userSettingsJsonFile,
828d307f52SEvan Bacon  getAnonymousIdentifierAsync,
838d307f52SEvan Bacon});
848d307f52SEvan Bacon
858d307f52SEvan Baconexport default UserSettings;
86