File size: 2,717 Bytes
41e9886
 
3f0bce1
48059af
64950db
 
 
 
6a1be24
41e9886
 
 
 
45ec8d7
 
64950db
 
41e9886
64950db
45ec8d7
916f204
 
 
 
 
 
41e9886
 
 
018a142
41e9886
 
3471d51
41e9886
 
ad03756
41e9886
916f204
41e9886
018a142
0ab6df0
 
 
 
 
 
 
 
 
 
 
41e9886
3f0bce1
ad03756
 
 
3f0bce1
 
 
 
 
 
 
 
 
 
0ab6df0
 
 
 
 
 
 
3f0bce1
 
64950db
 
48059af
64950db
 
 
3471d51
64950db
 
 
 
 
 
 
 
3471d51
 
 
 
 
 
64950db
 
 
 
 
 
 
41e9886
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import { z } from "zod";
import type { UserinfoResponse } from "openid-client";
import { OIDConfig } from "$lib/server/auth";
import { config } from "$lib/server/config";
import { updateUserSession } from "./userSession";
import type { Cookies } from "@sveltejs/kit";

import type { AuthProvider } from "$lib/types/User";

export async function updateUser(params: {
	userData: UserinfoResponse;
	locals: App.Locals;
	cookies: Cookies;
	userAgent?: string;
	ip?: string;
	authProvider: AuthProvider;
	accessToken?: string;
}) {
	const { userData, locals, cookies, userAgent, ip, authProvider, accessToken } = params;

	// Microsoft Entra v1 tokens do not provide preferred_username, instead the username is provided in the upn
	// claim. See https://learn.microsoft.com/en-us/entra/identity-platform/access-token-claims-reference
	if (!userData.preferred_username && userData.upn) {
		userData.preferred_username = userData.upn as string;
	}

	const {
		preferred_username: username,
		name,
		email,
		picture: avatarUrl,
		sub: hfUserId,
		orgs,
	} = z
		.object({
			preferred_username: z.string().optional(),
			name: z.string(),
			picture: z.string().optional(),
			sub: z.string(),
			email: z.string().email().optional(),
			orgs: z
				.array(
					z.object({
						sub: z.string(),
						name: z.string(),
						picture: z.string(),
						preferred_username: z.string(),
						isEnterprise: z.boolean(),
					})
				)
				.optional(),
		})
		.setKey(OIDConfig.NAME_CLAIM, z.string())
		.refine((data) => data.preferred_username || data.email, {
			message: "Either preferred_username or email must be provided by the provider.",
		})
		.transform((data) => ({
			...data,
			name: data[OIDConfig.NAME_CLAIM],
		}))
		.parse(userData) as {
		preferred_username?: string;
		email?: string;
		picture?: string;
		sub: string;
		name: string;
		orgs?: Array<{
			sub: string;
			name: string;
			picture: string;
			preferred_username: string;
			isEnterprise: boolean;
		}>;
	} & Record<string, string>;

	const isHuggingFace = authProvider === "huggingface";
	// if using huggingface as auth provider, check orgs for early access and admin rights
	const isAdmin =
		isHuggingFace && config.HF_ORG_ADMIN
			? orgs?.some((org) => org.sub === config.HF_ORG_ADMIN) || false
			: false;
	const isEarlyAccess =
		isHuggingFace && config.HF_ORG_EARLY_ACCESS
			? orgs?.some((org) => org.sub === config.HF_ORG_EARLY_ACCESS) || false
			: false;

	return await updateUserSession({
		userData: {
			authProvider,
			authId: hfUserId,
			username,
			name,
			email,
			avatarUrl,
			isAdmin,
			isEarlyAccess,
		},
		locals,
		cookies,
		userAgent,
		ip,
		hfAccessToken: isHuggingFace ? accessToken : undefined,
	});
}