import type { NextAuthOptions } from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import { cookies } from "next/headers";
import { getAppcondaClient } from "../getAppcondaClient";
import { Account } from "../modules/account/service";
import { getEnv } from "../lib/env";
import { getSDKForCurrentUser } from "../getSDKForCurrentUser";
import { Query } from "../query";
/* const getEnv = () => {
return {
APPCONDA_ENDPOINT: 'process.env.APPCONDA_ENDPOINT',
APPCONDA_CLIENT_ENDPOINT: 'process.env.APPCONDA_CLIENT_ENDPOINT',
_SERVICE_TOKEN: 'process.env._SERVICE_TOKEN',
ENTERPRISE_LICENSE_KEY: 'process.env.ENTERPRISE_LICENSE_KEY',
};
}; */
export async function signIn({ userName, password }: { userName: string, password: string }) {
const adminClient = await getAppcondaClient();
const account = new Account(adminClient);
const session = await account.createEmailPasswordSession(userName, password);
const c = await cookies();
c.set('a_session', session.secret, {
path: "/",
httpOnly: true,
sameSite: "strict",
secure: true,
});
return session;
}
export const authOptions = (() => {
let options : any= null;
return () => {
if (options == null) {
options = {
providers: [
CredentialsProvider({
id: "credentials",
// The name to display on the sign in form (e.g. "Sign in with...")
name: "Credentials",
// The credentials is used to generate a suitable form on the sign in page.
// You can specify whatever fields you are expecting to be submitted.
// e.g. domain, username, password, 2FA token, etc.
// You can pass any HTML attribute to the tag through the object.
credentials: {
email: {
label: "Email Address",
type: "email",
placeholder: "Your email address",
},
password: {
label: "Password",
type: "password",
placeholder: "Your password",
},
totpCode: { label: "Two-factor Code", type: "input", placeholder: "Code from authenticator app" },
backupCode: { label: "Backup Code", type: "input", placeholder: "Two-factor backup code" },
},
async authorize(credentials, _req) {
debugger;
let user;
const appcondaSession = await signIn({ userName: credentials?.email as string, password: credentials?.password as string });
console.log(credentials);
/* try {
user = await prisma.user.findUnique({
where: {
email: credentials?.email,
},
});
} catch (e) {
console.error(e);
throw Error("Internal server error. Please try again later");
}
if (!user || !credentials) {
throw new Error("Invalid credentials");
}
if (!user.password) {
throw new Error("Invalid credentials");
}
const isValid = await verifyPassword(credentials.password, user.password);
if (!isValid) {
throw new Error("Invalid credentials");
}
if (user.twoFactorEnabled && credentials.backupCode) {
if (!ENCRYPTION_KEY) {
console.error("Missing encryption key; cannot proceed with backup code login.");
throw new Error("Internal Server Error");
}
if (!user.backupCodes) throw new Error("No backup codes found");
const backupCodes = JSON.parse(symmetricDecrypt(user.backupCodes, ENCRYPTION_KEY));
// check if user-supplied code matches one
const index = backupCodes.indexOf(credentials.backupCode.replaceAll("-", ""));
if (index === -1) throw new Error("Invalid backup code");
// delete verified backup code and re-encrypt remaining
backupCodes[index] = null;
await prisma.user.update({
where: {
id: user.id,
},
data: {
backupCodes: symmetricEncrypt(JSON.stringify(backupCodes), ENCRYPTION_KEY),
},
});
} else if (user.twoFactorEnabled) {
if (!credentials.totpCode) {
throw new Error("second factor required");
}
if (!user.twoFactorSecret) {
throw new Error("Internal Server Error");
}
if (!ENCRYPTION_KEY) {
throw new Error("Internal Server Error");
}
const secret = symmetricDecrypt(user.twoFactorSecret, ENCRYPTION_KEY);
if (secret.length !== 32) {
throw new Error("Internal Server Error");
}
const isValidToken = (await import("./totp")).totpAuthenticatorCheck(credentials.totpCode, secret);
if (!isValidToken) {
throw new Error("Invalid second factor code");
}
} */
console.log("asafdf")
return {
id: appcondaSession.userId,
email: appcondaSession.providerUid,
emailVerified: true,
imageUrl: "",
};
},
}),
CredentialsProvider({
id: "token",
// The name to display on the sign in form (e.g. "Sign in with...")
name: "Token",
// The credentials is used to generate a suitable form on the sign in page.
// You can specify whatever fields you are expecting to be submitted.
// e.g. domain, username, password, 2FA token, etc.
// You can pass any HTML attribute to the tag through the object.
credentials: {
token: {
label: "Verification Token",
type: "string",
},
},
async authorize(credentials, _req) {
let user;
/* try {
if (!credentials?.token) {
throw new Error("Token not found");
}
const { id } = await verifyToken(credentials?.token);
user = await prisma.user.findUnique({
where: {
id: id,
},
});
} catch (e) {
console.error(e);
throw new Error("Either a user does not match the provided token or the token is invalid");
}
if (!user) {
throw new Error("Either a user does not match the provided token or the token is invalid");
}
if (user.emailVerified) {
throw new Error("Email already verified");
}
user = await updateUser(user.id, { emailVerified: new Date() }); */
return user || null;
},
}),
// Conditionally add enterprise SSO providers
...(getEnv().ENTERPRISE_LICENSE_KEY ? [] : []),
],
callbacks: {
async jwt({ token }) {
const { users } = await getSDKForCurrentUser();
const userList = await users.list([Query.equal("email", token.email!)])
const user = userList.users[0] ?? {};
/* const existingUser = await getUserByEmail(token?.email!);
if (!existingUser) {
return token;
} */
return {
...token,
//@ts-ignore
profile: { id: user.$id, ...user },
};
},
async session({ session, token }) {
//@ts-ignore
session.user.id = token?.id;
//@ts-ignore
session.user = token.profile;
return session;
},
//@ts-ignore
async signIn({ user, account }: { user: any; account: Account | null }) {
/* if (account?.provider === "credentials" || account?.provider === "token") {
// check if user's email is verified or not
if (!user.emailVerified && !EMAIL_VERIFICATION_DISABLED) {
throw new Error("Email Verification is Pending");
}
return true;
}
if (ENTERPRISE_LICENSE_KEY) {
return handleSSOCallback({ user, account });
} */
return true;
},
},
pages: {
signIn: "/auth/login",
signOut: "/auth/logout",
error: "/auth/login", // Error code passed in query string as ?error=
},
}
}
return options;
}
})();