File size: 3,022 Bytes
bd4057b
 
263e0b9
519f85d
bd4057b
dbfb96e
 
 
 
 
 
edd2023
 
 
 
 
 
 
 
263e0b9
bd4057b
 
dbfb96e
 
bd4057b
 
 
dbfb96e
263e0b9
dbfb96e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bd4057b
263e0b9
bd4057b
 
 
 
 
07dd5b7
263e0b9
2aabbd0
a318da0
519f85d
bd4057b
263e0b9
 
 
 
 
 
2aabbd0
263e0b9
 
 
 
 
dbfb96e
 
bd4057b
edd2023
 
 
dbfb96e
 
edd2023
 
dbfb96e
 
edd2023
bd4057b
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
"use client";

import { refreshSession } from "@/lib/api";
import { buildSessionExpiresAt, clearStoredAuthSession, getStoredAuthSession, setStoredAuthSession, type StoredAuthSession } from "@/store/auth";

const VALIDATION_CACHE_MS = 10_000;
let cachedSession: StoredAuthSession | null = null;
let cachedAt = 0;
let validationPromise: Promise<StoredAuthSession | null> | null = null;
let validationKey = "";

function isUnauthorizedError(error: unknown) {
  if (!error || typeof error !== "object") {
    return false;
  }
  const item = error as { status?: unknown };
  return item.status === 401;
}

export async function getValidatedAuthSession(options: { force?: boolean } = {}): Promise<StoredAuthSession | null> {
  const storedSession = await getStoredAuthSession();
  if (!storedSession) {
    cachedSession = null;
    cachedAt = 0;
    return null;
  }

  const now = Date.now();
  if (!options.force && cachedSession?.key === storedSession.key && now - cachedAt < VALIDATION_CACHE_MS) {
    return cachedSession;
  }

  if (validationPromise && validationKey === storedSession.key) {
    return validationPromise;
  }

  validationKey = storedSession.key;
  validationPromise = validateStoredSession(storedSession).finally(() => {
    validationPromise = null;
    validationKey = "";
  });
  return validationPromise;
}

async function validateStoredSession(storedSession: StoredAuthSession): Promise<StoredAuthSession | null> {
  try {
    const data = await refreshSession(storedSession.key);
    const nextSession: StoredAuthSession = {
      key: storedSession.key,
      role: data.role,
      subjectId: data.subject_id,
      name: data.name,
      accountPoolEnabled: Boolean(data.account_pool_enabled),
      imageMemoryButtonEnabled: data.image_memory_button_enabled === true,
      imageShareEvidenceEnabled: data.image_share_evidence_enabled === true,
      wechatOpenid: storedSession.wechatOpenid,
      expiresAt: storedSession.expiresAt || buildSessionExpiresAt(data.login_session_duration_hours),
    };
    const sessionChanged =
      storedSession.role !== nextSession.role
      || storedSession.subjectId !== nextSession.subjectId
      || storedSession.name !== nextSession.name
      || storedSession.accountPoolEnabled !== nextSession.accountPoolEnabled
      || storedSession.imageMemoryButtonEnabled !== nextSession.imageMemoryButtonEnabled
      || storedSession.imageShareEvidenceEnabled !== nextSession.imageShareEvidenceEnabled
      || storedSession.wechatOpenid !== nextSession.wechatOpenid
      || storedSession.expiresAt !== nextSession.expiresAt;
    if (sessionChanged) {
      await setStoredAuthSession(nextSession);
    }
    cachedSession = nextSession;
    cachedAt = Date.now();
    return nextSession;
  } catch (error) {
    if (isUnauthorizedError(error)) {
      await clearStoredAuthSession();
      cachedSession = null;
      cachedAt = 0;
      return null;
    }
    cachedSession = storedSession;
    cachedAt = Date.now();
    return storedSession;
  }
}