-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
18 changed files
with
1,193 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,8 @@ | ||
# MongoDB connection string | ||
MONGODB_URI=mongodb://localhost:27017/neurosift_jobs | ||
|
||
# API Keys for authentication | ||
API_SUBMIT_KEY=your-submit-key-here | ||
# Admin configuration | ||
ADMIN_SECRET_KEY=your-secure-admin-secret-key-here | ||
|
||
# Memobin API Key for file storage | ||
MEMOBIN_API_KEY=your-memobin-key-here | ||
MEMOBIN_API_KEY=the-memobin-key-here |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import { NextRequest, NextResponse } from 'next/server'; | ||
import connectDB, { User } from '../../../../../lib/db'; | ||
import { validateApiKey } from '../../../../../middleware/auth'; | ||
|
||
export async function OPTIONS() { | ||
return new NextResponse(null, { | ||
status: 200, | ||
headers: { | ||
'Access-Control-Allow-Origin': 'http://localhost:5173', | ||
'Access-Control-Allow-Methods': 'GET, OPTIONS', | ||
'Access-Control-Allow-Headers': 'Content-Type, Authorization' | ||
} | ||
}); | ||
} | ||
|
||
export async function GET( | ||
request: NextRequest, | ||
{ params }: { params: { userId: string } } | ||
) { | ||
// Only admin can retrieve API keys | ||
const adminKey = process.env.ADMIN_SECRET_KEY; | ||
const authHeader = request.headers.get('Authorization'); | ||
const isAdmin = adminKey && authHeader?.split(' ')[1] === adminKey; | ||
|
||
if (!isAdmin) { | ||
return new NextResponse('Unauthorized - Admin access required', { status: 401 }); | ||
} | ||
|
||
try { | ||
await connectDB(); | ||
|
||
const user = await User.findOne({ userId: params.userId }); | ||
|
||
if (!user) { | ||
return new NextResponse('User not found', { status: 404 }); | ||
} | ||
|
||
return NextResponse.json({ apiKey: user.apiKey }); | ||
} catch (error) { | ||
console.error('Error retrieving API key:', error); | ||
return new NextResponse('Internal Server Error', { status: 500 }); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
import { NextRequest, NextResponse } from 'next/server'; | ||
import connectDB, { User } from '../../../../lib/db'; | ||
import { validateApiKey } from '../../../../middleware/auth'; | ||
|
||
/** | ||
* Handle CORS preflight requests | ||
*/ | ||
export async function OPTIONS() { | ||
return new NextResponse(null, { | ||
status: 200, | ||
headers: { | ||
'Access-Control-Allow-Origin': 'http://localhost:5173', | ||
'Access-Control-Allow-Methods': 'GET, PUT, DELETE, OPTIONS, POST', | ||
'Access-Control-Allow-Headers': 'Content-Type, Authorization' | ||
} | ||
}); | ||
} | ||
|
||
/** | ||
* Get user details | ||
* Requires either: | ||
* - Admin secret key | ||
* - User's own API key | ||
*/ | ||
export async function GET( | ||
request: NextRequest, | ||
{ params }: { params: { userId: string } } | ||
) { | ||
// Admin key allows access to any user | ||
const adminKey = process.env.ADMIN_SECRET_KEY; | ||
const authHeader = request.headers.get('Authorization'); | ||
const isAdmin = adminKey && authHeader?.split(' ')[1] === adminKey; | ||
|
||
if (!isAdmin) { | ||
const auth = await validateApiKey(request); | ||
if (auth instanceof NextResponse) return auth; | ||
if (auth.userId !== params.userId) { | ||
return new NextResponse('Unauthorized', { status: 401 }); | ||
} | ||
} | ||
|
||
try { | ||
await connectDB(); | ||
|
||
const user = await User.findOne( | ||
{ userId: params.userId }, | ||
{ apiKey: 0 } // Exclude API key from response | ||
); | ||
|
||
if (!user) { | ||
return new NextResponse('User not found', { status: 404 }); | ||
} | ||
|
||
return NextResponse.json({ user }); | ||
} catch (error) { | ||
console.error('Error getting user:', error); | ||
return new NextResponse('Internal Server Error', { status: 500 }); | ||
} | ||
} | ||
|
||
/** | ||
* Update user details | ||
* Requires either: | ||
* - Admin secret key | ||
* - User's own API key | ||
*/ | ||
export async function DELETE( | ||
request: NextRequest, | ||
{ params }: { params: { userId: string } } | ||
) { | ||
// Only admin can delete users | ||
const adminKey = process.env.ADMIN_SECRET_KEY; | ||
const authHeader = request.headers.get('Authorization'); | ||
const isAdmin = adminKey && authHeader?.split(' ')[1] === adminKey; | ||
|
||
if (!isAdmin) { | ||
return new NextResponse('Unauthorized - Admin access required', { status: 401 }); | ||
} | ||
|
||
try { | ||
await connectDB(); | ||
|
||
const result = await User.deleteOne({ userId: params.userId }); | ||
|
||
if (result.deletedCount === 0) { | ||
return new NextResponse('User not found', { status: 404 }); | ||
} | ||
|
||
return new NextResponse('User deleted successfully', { status: 200 }); | ||
} catch (error) { | ||
console.error('Error deleting user:', error); | ||
return new NextResponse('Internal Server Error', { status: 500 }); | ||
} | ||
} | ||
|
||
/** | ||
* Update user details | ||
* Requires either: | ||
* - Admin secret key | ||
* - User's own API key | ||
*/ | ||
export async function PUT( | ||
request: NextRequest, | ||
{ params }: { params: { userId: string } } | ||
) { | ||
// Admin key allows access to any user | ||
const adminKey = process.env.ADMIN_SECRET_KEY; | ||
const authHeader = request.headers.get('Authorization'); | ||
const isAdmin = adminKey && authHeader?.split(' ')[1] === adminKey; | ||
|
||
// Users can only update their own details unless they're admin | ||
if (!isAdmin && auth.userId !== params.userId) { | ||
return new NextResponse('Unauthorized', { status: 401 }); | ||
} | ||
|
||
try { | ||
const body = await request.json(); | ||
const { name, email, researchDescription } = body; | ||
|
||
await connectDB(); | ||
|
||
const user = await User.findOne({ userId: params.userId }); | ||
|
||
if (!user) { | ||
return new NextResponse('User not found', { status: 404 }); | ||
} | ||
|
||
// Update allowed fields | ||
if (name) user.name = name; | ||
if (email) user.email = email; | ||
if (researchDescription) user.researchDescription = researchDescription; | ||
|
||
await user.save(); | ||
|
||
// Return updated user without API key | ||
const userResponse = { | ||
userId: user.userId, | ||
name: user.name, | ||
email: user.email, | ||
researchDescription: user.researchDescription, | ||
createdAt: user.createdAt, | ||
updatedAt: user.updatedAt | ||
}; | ||
|
||
return NextResponse.json({ user: userResponse }); | ||
} catch (error) { | ||
console.error('Error updating user:', error); | ||
return new NextResponse('Internal Server Error', { status: 500 }); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
import { NextRequest, NextResponse } from 'next/server'; | ||
import crypto from 'crypto'; | ||
import connectDB, { User } from '../../../lib/db'; | ||
|
||
/** | ||
* Handle CORS preflight requests | ||
*/ | ||
export async function OPTIONS() { | ||
return new NextResponse(null, { | ||
status: 200, | ||
headers: { | ||
'Access-Control-Allow-Origin': 'http://localhost:5173', | ||
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS', | ||
'Access-Control-Allow-Headers': 'Content-Type, Authorization' | ||
} | ||
}); | ||
} | ||
|
||
/** | ||
* Create a new user with a unique API key | ||
* Requires admin secret key for authorization | ||
*/ | ||
export async function POST(request: NextRequest) { | ||
// Only admin can create users | ||
const adminKey = process.env.ADMIN_SECRET_KEY; | ||
if (!adminKey) { | ||
return new NextResponse('Admin secret key not configured', { status: 500 }); | ||
} | ||
|
||
const authHeader = request.headers.get('Authorization'); | ||
if (!authHeader || !authHeader.startsWith('Bearer ') || authHeader.split(' ')[1] !== adminKey) { | ||
return new NextResponse('Unauthorized', { status: 401 }); | ||
} | ||
|
||
try { | ||
const body = await request.json(); | ||
const { name, email, researchDescription } = body; | ||
|
||
if (!name || !email || !researchDescription) { | ||
return new NextResponse('Missing required fields', { status: 400 }); | ||
} | ||
|
||
await connectDB(); | ||
|
||
// Generate unique user ID and API key | ||
const userId = crypto.randomBytes(16).toString('hex'); | ||
const apiKey = crypto.randomBytes(32).toString('hex'); | ||
|
||
const newUser = await User.create({ | ||
userId, | ||
apiKey, | ||
name, | ||
email, | ||
researchDescription | ||
}); | ||
|
||
// Only return the API key during user creation | ||
return NextResponse.json({ | ||
user: { | ||
userId: newUser.userId, | ||
name: newUser.name, | ||
email: newUser.email, | ||
researchDescription: newUser.researchDescription, | ||
createdAt: newUser.createdAt, | ||
apiKey // Include API key only in creation response | ||
} | ||
}); | ||
} catch (error) { | ||
console.error('Error creating user:', error); | ||
return new NextResponse('Internal Server Error', { status: 500 }); | ||
} | ||
} | ||
|
||
/** | ||
* List all users (without API keys) | ||
* Requires admin secret key for authorization | ||
*/ | ||
export async function GET(request: NextRequest) { | ||
// Only admin can list users | ||
const adminKey = process.env.ADMIN_SECRET_KEY; | ||
if (!adminKey) { | ||
return new NextResponse('Admin secret key not configured', { status: 500 }); | ||
} | ||
|
||
const authHeader = request.headers.get('Authorization'); | ||
if (!authHeader || !authHeader.startsWith('Bearer ') || authHeader.split(' ')[1] !== adminKey) { | ||
return new NextResponse('Unauthorized', { status: 401 }); | ||
} | ||
|
||
try { | ||
await connectDB(); | ||
|
||
const users = await User.find({}, { | ||
apiKey: 0 // Exclude API keys from the response | ||
}).sort({ createdAt: -1 }); | ||
|
||
return NextResponse.json({ users }); | ||
} catch (error) { | ||
console.error('Error listing users:', error); | ||
return new NextResponse('Internal Server Error', { status: 500 }); | ||
} | ||
} |
Oops, something went wrong.