mirror of
https://github.com/RayLabsHQ/gitea-mirror.git
synced 2025-12-10 13:36:45 +03:00
🎉 Gitea Mirror: Added
This commit is contained in:
83
src/pages/api/auth/index.ts
Normal file
83
src/pages/api/auth/index.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import type { APIRoute } from "astro";
|
||||
import { db, users, configs, client } from "@/lib/db";
|
||||
import { eq, and } from "drizzle-orm";
|
||||
import jwt from "jsonwebtoken";
|
||||
|
||||
const JWT_SECRET = process.env.JWT_SECRET || "your-secret-key";
|
||||
|
||||
export const GET: APIRoute = async ({ request, cookies }) => {
|
||||
const authHeader = request.headers.get("Authorization");
|
||||
const token = authHeader?.split(" ")[1] || cookies.get("token")?.value;
|
||||
|
||||
if (!token) {
|
||||
const userCountResult = await client.execute(
|
||||
`SELECT COUNT(*) as count FROM users`
|
||||
);
|
||||
const userCount = userCountResult.rows[0].count;
|
||||
|
||||
if (userCount === 0) {
|
||||
return new Response(JSON.stringify({ error: "No users found" }), {
|
||||
status: 404,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
}
|
||||
|
||||
return new Response(JSON.stringify({ error: "Unauthorized" }), {
|
||||
status: 401,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
const decoded = jwt.verify(token, JWT_SECRET) as { id: string };
|
||||
|
||||
const userResult = await db
|
||||
.select()
|
||||
.from(users)
|
||||
.where(eq(users.id, decoded.id))
|
||||
.limit(1);
|
||||
|
||||
if (!userResult.length) {
|
||||
return new Response(JSON.stringify({ error: "User not found" }), {
|
||||
status: 404,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
}
|
||||
|
||||
const { password, ...userWithoutPassword } = userResult[0];
|
||||
|
||||
const configResult = await db
|
||||
.select({
|
||||
scheduleConfig: configs.scheduleConfig,
|
||||
})
|
||||
.from(configs)
|
||||
.where(and(eq(configs.userId, decoded.id), eq(configs.isActive, true)))
|
||||
.limit(1);
|
||||
|
||||
const scheduleConfig = configResult[0]?.scheduleConfig;
|
||||
|
||||
const syncEnabled = scheduleConfig?.enabled ?? false;
|
||||
const syncInterval = scheduleConfig?.interval ?? 3600;
|
||||
const lastSync = scheduleConfig?.lastRun ?? null;
|
||||
const nextSync = scheduleConfig?.nextRun ?? null;
|
||||
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
...userWithoutPassword,
|
||||
syncEnabled,
|
||||
syncInterval,
|
||||
lastSync,
|
||||
nextSync,
|
||||
}),
|
||||
{
|
||||
status: 200,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
return new Response(JSON.stringify({ error: "Invalid token" }), {
|
||||
status: 401,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
}
|
||||
};
|
||||
62
src/pages/api/auth/login.ts
Normal file
62
src/pages/api/auth/login.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import type { APIRoute } from "astro";
|
||||
import bcrypt from "bcryptjs";
|
||||
import jwt from "jsonwebtoken";
|
||||
import { db, users } from "@/lib/db";
|
||||
import { eq } from "drizzle-orm";
|
||||
|
||||
const JWT_SECRET = process.env.JWT_SECRET || "your-secret-key";
|
||||
|
||||
export const POST: APIRoute = async ({ request }) => {
|
||||
const { username, password } = await request.json();
|
||||
|
||||
if (!username || !password) {
|
||||
return new Response(
|
||||
JSON.stringify({ error: "Username and password are required" }),
|
||||
{
|
||||
status: 400,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const user = await db
|
||||
.select()
|
||||
.from(users)
|
||||
.where(eq(users.username, username))
|
||||
.limit(1);
|
||||
|
||||
if (!user.length) {
|
||||
return new Response(
|
||||
JSON.stringify({ error: "Invalid username or password" }),
|
||||
{
|
||||
status: 401,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const isPasswordValid = await bcrypt.compare(password, user[0].password);
|
||||
|
||||
if (!isPasswordValid) {
|
||||
return new Response(
|
||||
JSON.stringify({ error: "Invalid username or password" }),
|
||||
{
|
||||
status: 401,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const { password: _, ...userWithoutPassword } = user[0];
|
||||
const token = jwt.sign({ id: user[0].id }, JWT_SECRET, { expiresIn: "7d" });
|
||||
|
||||
return new Response(JSON.stringify({ token, user: userWithoutPassword }), {
|
||||
status: 200,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Set-Cookie": `token=${token}; Path=/; HttpOnly; SameSite=Strict; Max-Age=${
|
||||
60 * 60 * 24 * 7
|
||||
}`,
|
||||
},
|
||||
});
|
||||
};
|
||||
11
src/pages/api/auth/logout.ts
Normal file
11
src/pages/api/auth/logout.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import type { APIRoute } from "astro";
|
||||
|
||||
export const POST: APIRoute = async () => {
|
||||
return new Response(JSON.stringify({ success: true }), {
|
||||
status: 200,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Set-Cookie": "token=; Path=/; HttpOnly; SameSite=Strict; Max-Age=0",
|
||||
},
|
||||
});
|
||||
};
|
||||
72
src/pages/api/auth/register.ts
Normal file
72
src/pages/api/auth/register.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import type { APIRoute } from "astro";
|
||||
import bcrypt from "bcryptjs";
|
||||
import jwt from "jsonwebtoken";
|
||||
import { db, users } from "@/lib/db";
|
||||
import { eq, or } from "drizzle-orm";
|
||||
|
||||
const JWT_SECRET = process.env.JWT_SECRET || "your-secret-key";
|
||||
|
||||
export const POST: APIRoute = async ({ request }) => {
|
||||
const { username, email, password } = await request.json();
|
||||
|
||||
if (!username || !email || !password) {
|
||||
return new Response(
|
||||
JSON.stringify({ error: "Username, email, and password are required" }),
|
||||
{
|
||||
status: 400,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Check if username or email already exists
|
||||
const existingUser = await db
|
||||
.select()
|
||||
.from(users)
|
||||
.where(or(eq(users.username, username), eq(users.email, email)))
|
||||
.limit(1);
|
||||
|
||||
if (existingUser.length) {
|
||||
return new Response(
|
||||
JSON.stringify({ error: "Username or email already exists" }),
|
||||
{
|
||||
status: 409,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Hash password
|
||||
const hashedPassword = await bcrypt.hash(password, 10);
|
||||
|
||||
// Generate UUID
|
||||
const id = crypto.randomUUID();
|
||||
|
||||
// Create user
|
||||
const newUser = await db
|
||||
.insert(users)
|
||||
.values({
|
||||
id,
|
||||
username,
|
||||
email,
|
||||
password: hashedPassword,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
})
|
||||
.returning();
|
||||
|
||||
const { password: _, ...userWithoutPassword } = newUser[0];
|
||||
const token = jwt.sign({ id: newUser[0].id }, JWT_SECRET, {
|
||||
expiresIn: "7d",
|
||||
});
|
||||
|
||||
return new Response(JSON.stringify({ token, user: userWithoutPassword }), {
|
||||
status: 201,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Set-Cookie": `token=${token}; Path=/; HttpOnly; SameSite=Strict; Max-Age=${
|
||||
60 * 60 * 24 * 7
|
||||
}`,
|
||||
},
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user