|
import { refreshSessionCookie } from "$lib/server/auth"; |
|
import { collections } from "$lib/server/database"; |
|
import { ObjectId } from "mongodb"; |
|
import { DEFAULT_SETTINGS } from "$lib/types/Settings"; |
|
import { z } from "zod"; |
|
import type { UserinfoResponse } from "openid-client"; |
|
import { error, type Cookies } from "@sveltejs/kit"; |
|
import crypto from "crypto"; |
|
import { sha256 } from "$lib/utils/sha256"; |
|
import { addWeeks } from "date-fns"; |
|
|
|
export async function updateUser(params: { |
|
userData: UserinfoResponse; |
|
locals: App.Locals; |
|
cookies: Cookies; |
|
userAgent?: string; |
|
ip?: string; |
|
}) { |
|
const { userData, locals, cookies, userAgent, ip } = params; |
|
|
|
const { |
|
preferred_username: username, |
|
name, |
|
email, |
|
picture: avatarUrl, |
|
sub: hfUserId, |
|
} = z |
|
.object({ |
|
preferred_username: z.string().optional(), |
|
name: z.string(), |
|
picture: z.string(), |
|
sub: z.string(), |
|
email: z.string().email().optional(), |
|
}) |
|
.refine((data) => data.preferred_username || data.email, { |
|
message: "Either preferred_username or email must be provided by the provider.", |
|
}) |
|
.parse(userData); |
|
|
|
|
|
const existingUser = await collections.users.findOne({ hfUserId }); |
|
let userId = existingUser?._id; |
|
|
|
|
|
const previousSessionId = locals.sessionId; |
|
const secretSessionId = crypto.randomUUID(); |
|
const sessionId = await sha256(secretSessionId); |
|
|
|
if (await collections.sessions.findOne({ sessionId })) { |
|
throw error(500, "Session ID collision"); |
|
} |
|
|
|
locals.sessionId = sessionId; |
|
|
|
if (existingUser) { |
|
|
|
await collections.users.updateOne( |
|
{ _id: existingUser._id }, |
|
{ $set: { username, name, avatarUrl } } |
|
); |
|
|
|
|
|
await collections.sessions.deleteOne({ sessionId: previousSessionId }); |
|
await collections.sessions.insertOne({ |
|
_id: new ObjectId(), |
|
sessionId: locals.sessionId, |
|
userId: existingUser._id, |
|
createdAt: new Date(), |
|
updatedAt: new Date(), |
|
userAgent, |
|
ip, |
|
expiresAt: addWeeks(new Date(), 2), |
|
}); |
|
|
|
|
|
refreshSessionCookie(cookies, secretSessionId); |
|
} else { |
|
|
|
const { insertedId } = await collections.users.insertOne({ |
|
_id: new ObjectId(), |
|
createdAt: new Date(), |
|
updatedAt: new Date(), |
|
username, |
|
name, |
|
email, |
|
avatarUrl, |
|
hfUserId, |
|
}); |
|
|
|
userId = insertedId; |
|
|
|
await collections.sessions.insertOne({ |
|
_id: new ObjectId(), |
|
sessionId: locals.sessionId, |
|
userId, |
|
createdAt: new Date(), |
|
updatedAt: new Date(), |
|
userAgent, |
|
ip, |
|
expiresAt: addWeeks(new Date(), 2), |
|
}); |
|
|
|
|
|
const { matchedCount } = await collections.settings.updateOne( |
|
{ sessionId: previousSessionId }, |
|
{ |
|
$set: { userId, updatedAt: new Date() }, |
|
$unset: { sessionId: "" }, |
|
} |
|
); |
|
|
|
if (!matchedCount) { |
|
|
|
await collections.settings.insertOne({ |
|
userId, |
|
ethicsModalAcceptedAt: new Date(), |
|
updatedAt: new Date(), |
|
createdAt: new Date(), |
|
...DEFAULT_SETTINGS, |
|
}); |
|
} |
|
} |
|
|
|
|
|
await collections.conversations.updateMany( |
|
{ sessionId: previousSessionId }, |
|
{ |
|
$set: { userId }, |
|
$unset: { sessionId: "" }, |
|
} |
|
); |
|
} |
|
|