mirror of
https://github.com/elicpeter/nyx.git
synced 2026-06-27 20:29:39 +02:00
Critical bug fixes and recall improvements (#68)
This commit is contained in:
parent
7d0e7320e2
commit
55247b7fcd
352 changed files with 60069 additions and 900 deletions
17
tests/fixtures/fp_guards/auth_nextauth_callback/expectations.json
vendored
Normal file
17
tests/fixtures/fp_guards/auth_nextauth_callback/expectations.json
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"required_findings": [],
|
||||
"forbidden_findings": [
|
||||
{ "id_prefix": "js.auth.missing_ownership_check" },
|
||||
{ "id_prefix": "ts.auth.missing_ownership_check" }
|
||||
],
|
||||
"noise_budget": {
|
||||
"max_total_findings": 2,
|
||||
"max_high_findings": 1
|
||||
},
|
||||
"performance_expectations": {
|
||||
"max_ms_no_index": 1000,
|
||||
"max_ms_index_cold": 1500,
|
||||
"max_ms_index_warm": 500,
|
||||
"ci_mode": "lenient"
|
||||
}
|
||||
}
|
||||
95
tests/fixtures/fp_guards/auth_nextauth_callback/next-auth-custom-adapter.ts
vendored
Normal file
95
tests/fixtures/fp_guards/auth_nextauth_callback/next-auth-custom-adapter.ts
vendored
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
// cal.com NextAuth Adapter factory shape. The function returns the
|
||||
// Adapter implementation directly, with no `callbacks: { ... }`
|
||||
// wrapper. Inner method bodies are object method shorthands that
|
||||
// don't become their own units, so every identity-resolution
|
||||
// operation inside them accumulates onto the OUTER `CalComAdapter`
|
||||
// unit. Without the Adapter-shape arm of `body_returns_nextauth_options`,
|
||||
// `is_nextauth_callback_unit` cannot match by name and the
|
||||
// missing-ownership rule fires on every `prismaClient.user.findUnique`
|
||||
// / `prismaClient.account.findUnique` call.
|
||||
|
||||
import { prisma } from "./prisma";
|
||||
|
||||
type AdapterUser = { id: string; email: string; emailVerified?: Date };
|
||||
type AdapterAccount = {
|
||||
userId: string;
|
||||
provider: string;
|
||||
providerAccountId: string;
|
||||
};
|
||||
|
||||
const toAdapterUser = (user: { id: number; email: string }): AdapterUser => ({
|
||||
id: user.id.toString(),
|
||||
email: user.email,
|
||||
});
|
||||
|
||||
const getAccountWhere = (provider: string, providerAccountId: string) => ({
|
||||
provider_providerAccountId: { provider, providerAccountId },
|
||||
});
|
||||
|
||||
export default function CalComAdapter(prismaClient: typeof prisma) {
|
||||
return {
|
||||
createUser: async (data: Omit<AdapterUser, "id">) => {
|
||||
const user = await prismaClient.user.create({ data });
|
||||
return toAdapterUser(user);
|
||||
},
|
||||
|
||||
getUser: async (id: string) => {
|
||||
const user = await prismaClient.user.findUnique({ where: { id: parseInt(id, 10) } });
|
||||
return user ? toAdapterUser(user) : null;
|
||||
},
|
||||
|
||||
getUserByEmail: async (email: string) => {
|
||||
const user = await prismaClient.user.findUnique({ where: { email } });
|
||||
return user ? toAdapterUser(user) : null;
|
||||
},
|
||||
|
||||
async getUserByAccount(providerAccountId: { provider: string; providerAccountId: string }) {
|
||||
const account = await prismaClient.account.findUnique({
|
||||
where: getAccountWhere(providerAccountId.provider, providerAccountId.providerAccountId),
|
||||
select: { user: true },
|
||||
});
|
||||
return account?.user ? toAdapterUser(account.user) : null;
|
||||
},
|
||||
|
||||
updateUser: async (userData: AdapterUser) => {
|
||||
const { id, ...data } = userData;
|
||||
const user = await prismaClient.user.update({
|
||||
where: { id: parseInt(id, 10) },
|
||||
data,
|
||||
});
|
||||
return toAdapterUser(user);
|
||||
},
|
||||
|
||||
deleteUser: async (userId: string) => {
|
||||
const user = await prismaClient.user.delete({ where: { id: parseInt(userId, 10) } });
|
||||
return toAdapterUser(user);
|
||||
},
|
||||
|
||||
createVerificationToken: async (data: { identifier: string; token: string; expires: Date }) => {
|
||||
const token = await prismaClient.verificationToken.create({ data });
|
||||
return token;
|
||||
},
|
||||
|
||||
useVerificationToken: async (identifier_token: { identifier: string; token: string }) => {
|
||||
const token = await prismaClient.verificationToken.delete({ where: { identifier_token } });
|
||||
return token;
|
||||
},
|
||||
|
||||
linkAccount: async (account: AdapterAccount) => {
|
||||
const created = await prismaClient.account.create({ data: account });
|
||||
return created;
|
||||
},
|
||||
|
||||
unlinkAccount: async (providerAccountId: Pick<AdapterAccount, "provider" | "providerAccountId">) => {
|
||||
const deleted = await prismaClient.account.delete({
|
||||
where: getAccountWhere(providerAccountId.provider, providerAccountId.providerAccountId),
|
||||
});
|
||||
return deleted;
|
||||
},
|
||||
|
||||
createSession: async (session: { sessionToken: string; userId: string; expires: Date }) => session,
|
||||
getSessionAndUser: async () => null,
|
||||
updateSession: async (session: { sessionToken: string }) => ({ sessionToken: session.sessionToken }),
|
||||
deleteSession: async () => undefined,
|
||||
};
|
||||
}
|
||||
57
tests/fixtures/fp_guards/auth_nextauth_callback/next-auth-options-factory.ts
vendored
Normal file
57
tests/fixtures/fp_guards/auth_nextauth_callback/next-auth-options-factory.ts
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
// Same NextAuth options content, but exposed via a factory arrow that
|
||||
// returns the options object. Matches cal.com's `getOptions` shape:
|
||||
//
|
||||
// export const getOptions = (deps): AuthOptions => ({
|
||||
// callbacks: { async signIn(...) { ... }, async jwt(...) { ... } },
|
||||
// });
|
||||
//
|
||||
// The top-level unit-creation pass attributes every operation inside
|
||||
// the inner callback methods to the OUTER arrow's unit, because object
|
||||
// method shorthands are not enumerated as their own units. Without the
|
||||
// factory-aware suppressor the outer unit name is `getOptions`, not
|
||||
// `jwt`, so `is_nextauth_callback_unit`'s name match fails and the
|
||||
// missing-ownership-check rule fires on every identity-resolution
|
||||
// operation inside the callbacks.
|
||||
|
||||
import { prisma } from "./prisma";
|
||||
|
||||
type Token = { sub?: string };
|
||||
type Account = { provider: string };
|
||||
type Profile = { email?: string };
|
||||
type User = { id: number; email: string };
|
||||
|
||||
export const getOptions = ({
|
||||
getDubId,
|
||||
getTrackingData,
|
||||
}: {
|
||||
getDubId: () => string | undefined;
|
||||
getTrackingData: () => any;
|
||||
}) => ({
|
||||
callbacks: {
|
||||
async signIn({ user, account, profile }: { user: User; account: Account; profile: Profile }) {
|
||||
await prisma.user.update({
|
||||
where: { id: user.id },
|
||||
data: { lastSignInProvider: account.provider },
|
||||
});
|
||||
return true;
|
||||
},
|
||||
|
||||
async session({ session, user, token }: { session: any; user: User; token: Token }) {
|
||||
const existingUser = await prisma.user.findUnique({ where: { id: user.id } });
|
||||
if (!existingUser) return session;
|
||||
const profile = await prisma.profile.findUnique({ where: { userId: existingUser.id } });
|
||||
session.user = { ...session.user, profileId: profile?.id };
|
||||
return session;
|
||||
},
|
||||
|
||||
async jwt({ token, user, account }: { token: Token; user?: User; account?: Account }) {
|
||||
if (user) {
|
||||
const dbUser = await prisma.user.findUnique({ where: { id: user.id } });
|
||||
if (dbUser) {
|
||||
token.sub = String(dbUser.id);
|
||||
}
|
||||
}
|
||||
return token;
|
||||
},
|
||||
},
|
||||
});
|
||||
54
tests/fixtures/fp_guards/auth_nextauth_callback/next-auth-options.ts
vendored
Normal file
54
tests/fixtures/fp_guards/auth_nextauth_callback/next-auth-options.ts
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
// Minimal NextAuth-style configuration. The named callbacks below are
|
||||
// the authentication boundary itself: operations on `user.id` /
|
||||
// `existingUser.id` inside them resolve the authenticated identity,
|
||||
// they are not request-driven foreign-id lookups. The auth analyser
|
||||
// must NOT flag js.auth.missing_ownership_check on these operations.
|
||||
|
||||
import { prisma } from "./prisma";
|
||||
|
||||
type Token = { sub?: string };
|
||||
type Account = { provider: string; providerAccountId: string };
|
||||
type Profile = { email?: string };
|
||||
type User = { id: number; email: string };
|
||||
|
||||
export const authOptions = {
|
||||
callbacks: {
|
||||
async signIn({ user, account, profile }: { user: User; account: Account; profile: Profile }) {
|
||||
// Authentication-time mutation: record provider linkage on the
|
||||
// authenticated user. Not a tenant-scoped resource lookup.
|
||||
await prisma.user.update({
|
||||
where: { id: user.id },
|
||||
data: { lastSignInProvider: account.provider },
|
||||
});
|
||||
return true;
|
||||
},
|
||||
|
||||
async session({ session, user, token }: { session: any; user: User; token: Token }) {
|
||||
// Identity-resolution read against `user.id` / `token.sub`.
|
||||
const existingUser = await prisma.user.findUnique({ where: { id: user.id } });
|
||||
if (!existingUser) return session;
|
||||
const profile = await prisma.profile.findUnique({ where: { userId: existingUser.id } });
|
||||
session.user = { ...session.user, profileId: profile?.id };
|
||||
return session;
|
||||
},
|
||||
|
||||
async jwt({ token, user, account }: { token: Token; user?: User; account?: Account }) {
|
||||
if (user) {
|
||||
const dbUser = await prisma.user.findUnique({ where: { id: user.id } });
|
||||
if (dbUser) {
|
||||
token.sub = String(dbUser.id);
|
||||
}
|
||||
}
|
||||
return token;
|
||||
},
|
||||
|
||||
async authorize(credentials: { email: string; password: string }) {
|
||||
// Credentials-provider authorize: looks up the user by email and
|
||||
// verifies the password. Authentication boundary, not foreign-id
|
||||
// targeting.
|
||||
const user = await prisma.user.findUnique({ where: { email: credentials.email } });
|
||||
if (!user) return null;
|
||||
return { id: user.id, email: user.email };
|
||||
},
|
||||
},
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue