fantasy-manager/pages/api/auth/[...nextauth].js
Lukas Schaefer 33a307d19a
Some checks failed
Build / build (pull_request) Successful in 1m2s
Cypress / cypress (pull_request) Successful in 2m31s
Build / build (push) Successful in 1m11s
Cypress / cypress (push) Has been cancelled
First commit for moving git instances
Signed-off-by: Lukas Schaefer <lukas@lschaefer.xyz>
2026-07-30 19:08:51 -04:00

208 lines
7.1 KiB
JavaScript

import NextAuth from "next-auth";
import db from "../../../Modules/database";
import CredentialsProvider from "next-auth/providers/credentials";
import GoogleProvider from "next-auth/providers/google";
import GithubProvider from "next-auth/providers/github";
import { hash, compareSync } from "bcrypt";
import { sql } from "kysely";
let ran = false;
const options = {
pages: {
signIn: "/signin",
error: "signin",
},
// Configure one or more authentication providers
providers: [
CredentialsProvider({
// Used to sign in
id: "Sign-In",
name: "Sign-In",
credentials: {
username: { label: "Username", type: "username" },
password: { label: "Password", type: "password" },
},
// Used to make sure that the credentails are correct
authorize: async (credentials) => {
// Goes through every user that has the email or username that was given and has password authentication enabled
const users =
await sql`SELECT * FROM users WHERE username=${credentials.username} AND password!=''`.execute(
db,
);
const unthrottledUsers = users.rows.filter((e) => e.throttle > 0);
let finished = false;
let result = null;
unthrottledUsers.forEach((e) => {
// Loops through every available user until the password is correct
console.log("e.password", e.password);
console.log("credentials.password", credentials.password);
console.log(
"compareSync",
compareSync(credentials.password, e.password),
);
console.log("finished", finished);
if (!finished) {
// Checks if the password is correct
if (compareSync(credentials.password, e.password)) {
finished = true;
result = { name: e.id };
} else {
// Lowers the throttle by 1
sql`UPDATE users SET throttle=throttle-1 WHERE id=${e.id}`.execute(
db,
);
}
}
});
// Checks if all the users are throttled
if (unthrottledUsers.length === 0 && users.length > 0) {
users.rows.forEach((e) => {
console.log(`User id ${e.id} is locked`);
});
return "/error/locked";
}
return Promise.resolve(result);
},
}),
CredentialsProvider({
// Used to sign up
id: "Sign-Up",
name: "Sign-Up",
credentials: {
username: { label: "Username", type: "username" },
password: { label: "Password", type: "password" },
},
// Used to make sure that the credentails are correct
authorize: async (credentials) => {
// Goes through every user that has the email or username that was given
if (credentials.username == "" || credentials.password == "") {
throw Error("no_username");
}
const bcrypt_rounds =
parseInt(process.env.BCRYPT_ROUNDS) > 0
? parseInt(process.env.BCRYPT_ROUNDS)
: 9;
const password = await hash(credentials.password, bcrypt_rounds);
await sql`INSERT INTO users (username, password) VALUES(${credentials.username}, ${password})`.execute(
db,
);
const users =
await sql`SELECT * FROM users WHERE (username=${credentials.username} AND password=${password})`.execute(
db,
);
let result = null;
if (users.rows.length > 0) {
result = {
name: users.rows[0].id,
};
}
return Promise.resolve(result);
},
}),
],
callbacks: {
async signIn({ account, profile, user }) {
// Will make sure that if this was sign in with google only a verified user logs in.
if (account.provider === "google" || account.provider === "github") {
// Checks if the user has already registered and if no then the user is created
const registered =
await sql`SELECT * FROM users WHERE ${sql.raw(account.provider)}=${profile.email}`
.execute(db)
.then((e) => e.rows.length > 0);
if (!registered) {
await sql`INSERT INTO users (${sql.raw(account.provider)}, username, password) VALUES (${profile.email}, ${profile.name}, '')`.execute(
db,
);
}
if (account.provider === "google") return profile.email_verified;
return true;
}
await sql`UPDATE users SET admin=1 WHERE id=${process.env.ADMIN}`.execute(
db,
);
await sql`UPDATE users SET admin=0 WHERE id!=${process.env.ADMIN}`.execute(
db,
);
return user;
},
async jwt({ token, account }) {
// Makes sure that the id is in the name parameter
if (account) {
// Gets the id from the database
if (account.provider === "google" || account.provider === "github") {
token.name =
await sql`SELECT id FROM users WHERE ${sql.raw(account.provider)}=${token.email}`
.execute(db)
.then((res) => (res.rows.length > 0 ? res.rows[0].id : 0));
}
}
return token;
},
// Uses the users id and then returns the data for the user
async session({ session }) {
if (session && session.user.name) {
await sql`UPDATE users SET active=1 WHERE id=${session.user.name} AND active=0`.execute(
db,
);
session.user =
await sql`SELECT * FROM users WHERE id=${session.user.name}`
.execute(db)
.then((res) => (res.rows.length > 0 ? res.rows[0] : undefined));
if (session.user !== undefined) {
session.user.password = session.user.password !== "";
session.user.active = session.user.active == 1;
session.user.admin = session.user.admin == 1;
return session;
}
}
return null;
},
},
};
export default async function authenticate(req, res) {
if (ran === false) {
// Only adds sign in with github and google if they are setup by the server owner
if (
!(process.env.GITHUB_ID === undefined || process.env.GITHUB_ID === "") &&
!(
process.env.GITHUB_SECRET === undefined ||
process.env.GITHUB_SECRET === ""
)
) {
options.providers = [
GithubProvider({
clientId: process.env.GITHUB_ID,
clientSecret: process.env.GITHUB_SECRET,
}),
...options.providers,
];
}
if (
!(process.env.GOOGLE_ID === undefined || process.env.GOOGLE_ID === "") &&
!(
process.env.GOOGLE_SECRET === undefined ||
process.env.GOOGLE_SECRET === ""
)
) {
options.providers = [
GoogleProvider({
clientId: process.env.GOOGLE_ID,
clientSecret: process.env.GOOGLE_SECRET,
authorization: {
params: {
prompt: "consent",
access_type: "offline",
response_type: "code",
},
},
}),
...options.providers,
];
}
ran = true;
}
await NextAuth(req, res, options);
}
export const authOptions = options;