<commit_before>import type {NextApiRequest, NextApiResponse} from "next"
import type {NextAuthOptions} from "next-auth"
import {createRouter} from "next-connect"
import {pickBy} from "lodash"

import NextAuth from "next-auth"
import CredentialsProvider from "next-auth/providers/credentials"

import withORMContext from "server/middleware/withORMContext"

import {assertRequiredEnv} from "server/lib/util/assertRequiredEnv"
import {getORM} from "server/lib/db"

import {User} from "server/db/entity/User"

assertRequiredEnv([
  {
    name: "NEXTAUTH_SECRET",
    value: process.env.NEXTAUTH_SECRET
  },
  {
    name: "NEXTAUTH_URL",
    value: process.env.NEXTAUTH_URL
  }
])

const COOKIE_PREFIX = "eri"

const getCookieName = (name: string) => `${COOKIE_PREFIX}.${name}`

const getCookieOptions = () => ({
  httpOnly: true,
  sameSite: "lax",
  path: "/",
  secure: new URL(process.env.NEXTAUTH_URL).protocol === "https:"
})

export const options: NextAuthOptions = {
  debug: process.env.NODE_ENV !== "production",
  pages: {
    signIn: "/auth/login"
  },
  session: {
    strategy: "jwt"
  },
  cookies: {
    sessionToken: {
      name: getCookieName("sid"),
      options: getCookieOptions()
    },
    callbackUrl: {
      name: getCookieName("callback"),
      options: getCookieOptions()
    },
    csrfToken: {
      name: getCookieName("csrf"),
      options: getCookieOptions()
    },
    pkceCodeVerifier: {
      name: getCookieName("pkce.code_verifier"),
      options: getCookieOptions()
    },
    state: {
      name: getCookieName("state"),
      options: getCookieOptions()
    }
  },
  providers: [
    CredentialsProvider({
      credentials: {
        email: {
          label: "Email",
          type: "email"
        },
        password: {
          label: "Password",
          type: "password"
        }
      },

      async authorize(credentials) {
        if (!credentials) {
          return null
        }

        const orm = await getORM()
        const userRepo = orm.em.getRepository(User)

        const user = await userRepo.findOne({email: credentials.email})

        if (!user) {
          throw new Error("Can't find a user.")
        }

        if (!(await user.isPasswordValid(credentials.password))) {
          throw new Error("Invalid password.")
        }

        // TODO: Improve session serialization
        return {
          email: null,
          image: null,
          name: null
        }
      }
    })
  ],
  callbacks: {
    async session({session, token}) {
      const orm = await getORM()
      const userRepo = orm.em.getRepository(User)

      const user = await userRepo.findOneOrFail({id: token.sub}, {
        fields: ["login", "role", "id"]
      })
<commit_msg>Fixes for authorization and authentication<commit_after>import type {NextApiRequest, NextApiResponse} from "next"
import type {NextAuthOptions} from "next-auth"
import {createRouter} from "next-connect"
import {pickBy} from "lodash"

import NextAuth from "next-auth"
import CredentialsProvider from "next-auth/providers/credentials"

import withORMContext from "server/middleware/withORMContext"

import {assertRequiredEnv} from "server/lib/util/assertRequiredEnv"
import {getORM} from "server/lib/db"

import {User} from "server/db/entity/User"

assertRequiredEnv([
  {
    name: "NEXTAUTH_SECRET",
    value: process.env.NEXTAUTH_SECRET
  },
  {
    name: "NEXTAUTH_URL",
    value: process.env.NEXTAUTH_URL
  }
])

const COOKIE_PREFIX = "eri"

const getCookieName = (name: string) => `${COOKIE_PREFIX}.${name}`

const getCookieOptions = () => ({
  httpOnly: true,
  sameSite: "lax",
  path: "/",
  secure: new URL(process.env.NEXTAUTH_URL).protocol === "https:"
})

export const options: NextAuthOptions = {
  debug: process.env.NODE_ENV !== "production",
  pages: {
    signIn: "/auth/login"
  },
  session: {
    strategy: "jwt"
  },
  cookies: {
    sessionToken: {
      name: getCookieName("sid"),
      options: getCookieOptions()
    },
    callbackUrl: {
      name: getCookieName("callback"),
      options: getCookieOptions()
    },
    csrfToken: {
      name: getCookieName("csrf"),
      options: getCookieOptions()
    },
    pkceCodeVerifier: {
      name: getCookieName("pkce.code_verifier"),
      options: getCookieOptions()
    },
    state: {
      name: getCookieName("state"),
      options: getCookieOptions()
    }
  },
  providers: [
    CredentialsProvider({
      credentials: {
        email: {
          label: "Email",
          type: "email"
        },
        password: {
          label: "Password",
          type: "password"
        }
      },

      async authorize(credentials) {
        if (!credentials) {
          return null
        }

        const orm = await getORM()
        const userRepo = orm.em.getRepository(User)

        const user = await userRepo.findOne({email: credentials.email})

        if (!user) {
          throw new Error("Can't find a user.")
        }

        if (!(await user.isPasswordValid(credentials.password))) {
          throw new Error("Invalid password.")
        }

        return {
          id: user.id,
          email: user.email
        }
      }
    })
  ],
  callbacks: {
    async session({session, token}) {
      const orm = await getORM()
      const userRepo = orm.em.getRepository(User)

      const user = await userRepo.findOneOrFail({id: token.sub}, {
        fields: ["id", "login", "role"]
      })

{'fraction_non_alphanumeric': 0.130939226519337, 'fraction_numerical': 0.0, 'mean_word_length': 2.587186261558785, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '803319', 'n_tokens_mistral': 1683, 'n_tokens_neox': 1696, 'n_words': 372}