src/app/core/session/auth/local/local-auth.service.ts

Description

Manages the offline login.

Metadata

Index

Methods

Methods

Async getStoredUsers
getStoredUsers()

Get a list of users stored in the local storage that have an existing local database. Users without a local IndexedDB are filtered out (e.g. stale entries from online-only logins).

saveUser
saveUser(user: SessionInfo)

Saves a user to the local storage so they can log in offline later. Has no effect in online-only mode, since no local database is available.

Parameters :
Name Type Optional
user SessionInfo No
Returns : void
import { Injectable, inject } from "@angular/core";
import { SessionInfo } from "../session-info";
import { environment } from "../../../../../environments/environment";
import { SessionType } from "../../session-type";
import { LOCAL_STORAGE_TOKEN } from "../../../../utils/di-tokens";

/**
 * Manages the offline login.
 */
@Injectable({
  providedIn: "root",
})
export class LocalAuthService {
  private readonly localStorage = inject(LOCAL_STORAGE_TOKEN);
  private readonly STORED_USER_PREFIX = "USER-";

  /**
   * Get a list of users stored in the local storage that have an existing local database.
   * Users without a local IndexedDB are filtered out (e.g. stale entries from online-only logins).
   */
  async getStoredUsers(): Promise<SessionInfo[]> {
    const users: SessionInfo[] = Object.entries(this.localStorage)
      .filter(([key]) => key.startsWith(this.STORED_USER_PREFIX))
      .map(([_, user]) => JSON.parse(user));

    if (users.length === 0) {
      return [];
    }

    // Mock (demo) mode uses the in-memory PouchDB adapter, so no IndexedDB
    // database exists to check against. Return all stored users directly.
    if (environment.session_type === SessionType.mock) {
      return users;
    }

    const existingDbNames = await this.listIndexedDbNames();
    return users.filter((user) => this.hasLocalDatabase(user, existingDbNames));
  }

  /**
   * Check whether a user has an existing local PouchDB in IndexedDB.
   * PouchDB prefixes IndexedDB database names with "_pouch_".
   * Checks both the current UUID-based name (<id>-app) and the legacy username-based name (<name>-app).
   */
  private hasLocalDatabase(user: SessionInfo, dbNames: Set<string>): boolean {
    return (
      dbNames.has(`_pouch_${user.id}-app`) ||
      dbNames.has(`_pouch_${user.name}-app`)
    );
  }

  /**
   * List all IndexedDB database names, or return an empty set if the API is unavailable.
   */
  private async listIndexedDbNames(): Promise<Set<string>> {
    try {
      if (typeof indexedDB?.databases === "function") {
        const dbs = await indexedDB.databases();
        return new Set(dbs.map((db) => db.name).filter(Boolean));
      }
    } catch {
      // API not available (e.g. SSR or restricted context)
    }
    // If API is not available, allow all stored users (safe fallback)
    return new Set(
      Object.entries(this.localStorage)
        .filter(([key]) => key.startsWith(this.STORED_USER_PREFIX))
        .map(([_, user]) => {
          const u: SessionInfo = JSON.parse(user);
          return `_pouch_${u.id}-app`;
        }),
    );
  }

  /**
   * Saves a user to the local storage so they can log in offline later.
   * Has no effect in online-only mode, since no local database is available.
   */
  saveUser(user: SessionInfo) {
    if (environment.session_type === SessionType.online) {
      return;
    }
    this.localStorage.setItem(
      this.STORED_USER_PREFIX + user.name,
      JSON.stringify(user),
    );
  }
}

results matching ""

    No results matching ""