auth.ts 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import { serverIdentityValue } from './serverIdentity'
  2. import type { BootstrapResponse, CurrentUser, JsonValue, Profile } from '@shared/types'
  3. import { apiRequest, setApiCsrfToken, unwrapData } from './client'
  4. import { bool, normalizeProfile, normalizeUser, record, string, values } from '@/utils/normalize'
  5. import { getProfileIdentities } from './profiles'
  6. function normalizeBootstrap(payload: unknown): BootstrapResponse {
  7. const root = record(unwrapData(payload as never))
  8. const status = record(root.status)
  9. const authRequired = bool(root.authRequired ?? root.auth_required ?? status.authRequired ?? status.auth_required)
  10. const rawUser = root.user ?? root.identity
  11. const profiles = values(root.profiles).map(normalizeProfile)
  12. const csrfToken = string(root.csrfToken ?? root.csrf_token ?? root.csrf)
  13. const response: BootstrapResponse = {
  14. status: string(status.state ?? root.state) || undefined,
  15. authRequired,
  16. registrationAvailable: bool(root.registrationAvailable),
  17. setupRequired: bool(root.setupRequired ?? root.setup_required),
  18. profiles,
  19. csrfToken,
  20. insecureLan: bool(root.insecureLan ?? root.insecure_lan),
  21. groupUploadsEnabled: bool(root.groupUploadsEnabled ?? root.group_uploads_enabled),
  22. upstreamReady: bool(root.upstreamReady ?? root.upstream_ready),
  23. upstreamError: string(root.upstreamError ?? root.upstream_error) || undefined,
  24. serverKind: string(root.serverKind ?? root.server_kind) || undefined,
  25. serverIdentity: serverIdentityValue(root.serverIdentity),
  26. }
  27. if (rawUser) response.user = normalizeUser(rawUser)
  28. setApiCsrfToken(csrfToken, response.user?.id ?? (authRequired ? null : 'local'))
  29. return response
  30. }
  31. export async function bootstrap(): Promise<BootstrapResponse> {
  32. return normalizeBootstrap(await apiRequest<unknown>('/api/app/bootstrap', { csrf: false }))
  33. }
  34. export interface LoginInput {
  35. username: string
  36. password: string
  37. provider?: string
  38. }
  39. export async function login(input: LoginInput): Promise<BootstrapResponse> {
  40. const payload = await apiRequest<unknown>('/api/app/login', {
  41. method: 'POST',
  42. body: { ...input, next: '/' } as JsonValue,
  43. notifyUnauthorized: false,
  44. })
  45. const response = normalizeBootstrap(payload)
  46. if (!response.user && response.authRequired) return bootstrap()
  47. return response
  48. }
  49. export async function setup(input: LoginInput): Promise<BootstrapResponse> {
  50. return normalizeBootstrap(await apiRequest<unknown>('/api/app/setup', {
  51. method: 'POST',
  52. body: input as unknown as JsonValue,
  53. notifyUnauthorized: false,
  54. }))
  55. }
  56. export async function logout(): Promise<void> {
  57. await apiRequest('/api/app/logout', { method: 'POST', body: {}, notifyUnauthorized: false })
  58. setApiCsrfToken('')
  59. }
  60. export async function fetchProfiles(): Promise<Profile[]> {
  61. const payload = record(unwrapData(await apiRequest<unknown>('/api/app/profiles')))
  62. return values(payload.profiles ?? payload.items ?? payload).map(normalizeProfile)
  63. }
  64. export async function fetchProfileIdentities(profiles: Profile[]): Promise<Record<string, { displayName: string; avatar: string }>> {
  65. return getProfileIdentities(profiles)
  66. }
  67. export async function fetchCurrentUser(): Promise<CurrentUser | undefined> {
  68. const response = await bootstrap()
  69. return response.user
  70. }
  71. export async function changeCredentials(input: {
  72. currentPassword: string
  73. newPassword: string
  74. username?: string
  75. }): Promise<CurrentUser> {
  76. const payload = record(unwrapData(await apiRequest<unknown>('/api/app/account/credentials', {
  77. method: 'PUT', body: input as unknown as JsonValue, notifyUnauthorized: false,
  78. })))
  79. return normalizeUser(payload.user ?? payload)
  80. }
  81. export async function updateAccountAvatar(avatar: string | null): Promise<CurrentUser> {
  82. const payload = record(unwrapData(await apiRequest<unknown>('/api/app/account/avatar', {
  83. method: 'PUT', body: { avatar } as unknown as JsonValue,
  84. })))
  85. return normalizeUser(payload.user ?? payload)
  86. }
  87. export async function register(input: LoginInput): Promise<void> {
  88. await bootstrap()
  89. await apiRequest('/api/app/register', { method: 'POST', body: { username: input.username, password: input.password }, notifyUnauthorized: false })
  90. }