@defikitdotnet/x-ai-combat
Version:
XCombatAI - Social Media Engagement Template for the Agent Framework
288 lines • 12.8 kB
JavaScript
;
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.XAICombatAuthController = void 0;
const agent_framework_backend_1 = require("@defikitdotnet/agent-framework-backend");
const uuid_1 = require("uuid");
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
const User_1 = require("../models/User");
const XAIAdapter_1 = require("../db/XAIAdapter");
const twitter_api_v2_1 = require("twitter-api-v2");
const logger_1 = require("../utils/logger");
/**
* Authentication controller
* Handles user authentication including Twitter OAuth, JWT management, and session control
*/
let XAICombatAuthController = class XAICombatAuthController {
constructor(adapter) {
this.JWT_SECRET = process.env.JWT_SECRET || "x-combat-ai-secret-key";
this.TWITTER_CONSUMER_KEY = process.env.TWITTER_CONSUMER_KEY || "";
this.TWITTER_CONSUMER_SECRET = process.env.TWITTER_CONSUMER_SECRET || "";
this.FRONTEND_URL = process.env.FRONTEND_URL || "http://localhost:3001";
this.BACKEND_URL = process.env.BACKEND_URL || "http://localhost:3005";
this.adapter = adapter;
this.client = new twitter_api_v2_1.TwitterApi({
appKey: this.TWITTER_CONSUMER_KEY,
appSecret: this.TWITTER_CONSUMER_SECRET,
});
}
/**
* Initiate Twitter OAuth login flow
*/
async initiateTwitterLogin(req, res) {
try {
// Create CSRF protection state
const state = (0, uuid_1.v4)();
res.cookie('oauth_state', state, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
maxAge: 3600000,
});
// Get the agentId from query parameter
const agentId = req.query.agentId;
(0, logger_1.log)("agentId", agentId);
if (agentId) {
res.cookie('agent_id', agentId, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
maxAge: 3600000,
});
}
// Get authentication URL and temporary token
const { url, oauth_token, oauth_token_secret } = await this.client.generateAuthLink(`${this.BACKEND_URL}/xaicombat/api/auth/twitter/callback?state=${state}`);
// Store token secret in cookie
res.cookie('oauth_token_secret', oauth_token_secret, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
maxAge: 3600000,
});
res.redirect(url);
}
catch (error) {
console.error('Twitter login error:', error);
res.status(500).json({ error: 'Failed to initiate Twitter login' });
}
}
/**
* Handle Twitter OAuth callback
*/
async handleTwitterCallback(req, res) {
try {
const { oauth_token, oauth_verifier, state } = req.query;
const storedState = req.cookies?.oauth_state;
const oauthTokenSecret = req.cookies?.oauth_token_secret;
const agentId = req.cookies?.agent_id;
// Verify CSRF state
if (!state || state !== storedState) {
res.status(400).json({ error: 'Invalid state parameter' });
return;
}
// Clear cookies
res.clearCookie('oauth_state');
res.clearCookie('oauth_token_secret');
res.clearCookie('agent_id');
if (!oauth_token || !oauth_verifier || !oauthTokenSecret) {
res.status(400).json({ error: 'Missing OAuth parameters' });
return;
}
// Get access token
const client = new twitter_api_v2_1.TwitterApi({
appKey: this.TWITTER_CONSUMER_KEY,
appSecret: this.TWITTER_CONSUMER_SECRET,
accessToken: oauth_token,
accessSecret: oauthTokenSecret,
});
const { accessToken, accessSecret, userId, screenName } = await client.login(oauth_verifier);
if (!accessToken || !accessSecret) {
res.status(400).json({ error: 'Failed to get access token' });
return;
}
// Check if user already exists in the database
// First, try to find user with both twitterId and agentId (if provided)
let user = null;
if (agentId) {
user = await this.adapter.findUserByTwitterId(userId, agentId);
}
// If no user found with agentId + twitterId, check if user exists with just twitterId
if (!user) {
user = await this.adapter.findUserByTwitterId(userId);
}
if (!user) {
// Create new user if they don't exist
const newUser = new User_1.UserResource();
newUser.id = (0, uuid_1.v4)();
newUser.twitterId = userId;
newUser.username = screenName;
newUser.linkedAt = new Date();
newUser.agentId = agentId || null; // Set agentId if provided
// Save user to database
await this.adapter.createUser(newUser);
(0, logger_1.log)(`Created new user for Twitter account: ${screenName} (${userId}), Agent: ${agentId || 'None'}`);
user = newUser;
}
else {
// Check if the user is already linked to a different agent
if (user.agentId && agentId && user.agentId !== agentId) {
// This Twitter user is already linked to a different agent
// Create a new user for this agent
const newUser = new User_1.UserResource();
newUser.id = (0, uuid_1.v4)();
newUser.twitterId = userId;
newUser.username = screenName;
newUser.linkedAt = new Date();
newUser.agentId = agentId;
// Save user to database
await this.adapter.createUser(newUser);
(0, logger_1.log)(`Created new user for Twitter account: ${screenName} (${userId}), Agent: ${agentId}`);
user = newUser;
}
else {
// Update existing user information
user.username = screenName;
user.updatedAt = new Date();
// Only update agentId if provided and not already set
if (agentId && !user.agentId) {
user.agentId = agentId;
}
await this.adapter.updateUser(user);
(0, logger_1.log)(`Updated existing user for Twitter account: ${screenName} (${userId}), Agent: ${user.agentId || 'None'}`);
}
}
// Create JWT containing user info including agentId
const token = jsonwebtoken_1.default.sign({
userId: user.id,
twitterId: userId,
username: screenName,
agentId: user.agentId // Include agentId in JWT
}, this.JWT_SECRET, { expiresIn: '7d' });
res.cookie('jwt', token, {
httpOnly: true,
secure: true,
maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days
sameSite: 'none',
});
res.redirect(`${this.FRONTEND_URL}/${agentId}/xaicombat/auth/callback`);
}
catch (error) {
console.error('Twitter callback error:', error);
res.status(500).json({ error: 'Failed to authenticate with Twitter' });
}
}
/**
* Check current authentication status
*/
async checkAuth(req, res) {
try {
const jwt = req.cookies?.jwt;
if (!jwt) {
res.status(401).json({ error: 'No authentication token found' });
return;
}
res.json({ authenticated: true, jwt });
}
catch (error) {
console.error('Check auth error:', error);
res.status(401).json({ error: 'Authentication failed' });
}
}
/**
* Get current user from JWT token
*/
async getCurrentUser(req, res) {
try {
// Extract token from Authorization header
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
res.status(401).json({ error: "No token provided" });
return;
}
const token = authHeader.split(' ')[1];
// Verify token
const decoded = jsonwebtoken_1.default.verify(token, this.JWT_SECRET);
// Find user
const user = await this.adapter.findUserById(decoded.userId);
if (!user) {
res.status(404).json({ error: "User not found" });
return;
}
res.status(200).json({ data: user });
}
catch (error) {
console.error("Error retrieving current user:", error);
if (error.name === 'JsonWebTokenError') {
res.status(401).json({ error: "Invalid token" });
return;
}
if (error.name === 'TokenExpiredError') {
res.status(401).json({ error: "Token expired" });
return;
}
res.status(500).json({ error: "Failed to retrieve user" });
}
}
/**
* Logout user
*/
async logout(req, res) {
try {
res.clearCookie('jwt', {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
path: '/', // Đảm bảo cookie bị xóa ở tất cả path
});
res.status(200).json({ message: "Logged out successfully" });
}
catch (error) {
console.error("Error during logout:", error);
res.status(500).json({ error: "Failed to logout" });
}
}
};
exports.XAICombatAuthController = XAICombatAuthController;
__decorate([
(0, agent_framework_backend_1.Get)('/twitter/login'),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], XAICombatAuthController.prototype, "initiateTwitterLogin", null);
__decorate([
(0, agent_framework_backend_1.Get)('/twitter/callback'),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], XAICombatAuthController.prototype, "handleTwitterCallback", null);
__decorate([
(0, agent_framework_backend_1.Get)('/check'),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], XAICombatAuthController.prototype, "checkAuth", null);
__decorate([
(0, agent_framework_backend_1.Get)('/me'),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], XAICombatAuthController.prototype, "getCurrentUser", null);
__decorate([
(0, agent_framework_backend_1.Post)('/logout'),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], XAICombatAuthController.prototype, "logout", null);
exports.XAICombatAuthController = XAICombatAuthController = __decorate([
(0, agent_framework_backend_1.Controller)("/xaicombat/api/auth"),
__metadata("design:paramtypes", [XAIAdapter_1.XAIAdapter])
], XAICombatAuthController);
//# sourceMappingURL=AuthController.js.map