This commit is contained in:
NotII
2025-03-10 17:39:37 +00:00
parent c08df8919d
commit 20d5559832
69 changed files with 7676 additions and 78 deletions

View File

@@ -0,0 +1,44 @@
import mongoose from "mongoose";
import bcrypt from "bcryptjs";
import dotenv from "dotenv";
import Staff from "../models/Staff.model.js";
dotenv.config();
mongoose
.connect(process.env.MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
})
.then(() => console.log("✅ MongoDB Connected"))
.catch((err) => console.error("❌ MongoDB Connection Error:", err));
const createAdmin = async () => {
const username = "admin";
const password = "88sO)£2igu-:";
try {
const existingAdmin = await Staff.findOne({ username });
if (existingAdmin) {
console.log("⚠️ Admin user already exists.");
process.exit(1);
}
const hashedPassword = await bcrypt.hash(password, 10);
const admin = new Staff({
username,
passwordHash: hashedPassword,
role: "admin",
});
await admin.save();
console.log(`✅ Admin user '${username}' created successfully!`);
process.exit();
} catch (error) {
console.error("❌ Error creating admin user:", error);
process.exit(1);
}
};
createAdmin();

View File

@@ -0,0 +1,56 @@
import mongoose from "mongoose";
import dotenv from "dotenv";
import Order from "../models/Order.model.js"; // Adjust path if needed
import Vendor from "../models/Vendor.model.js"; // Import Vendor model
dotenv.config();
// ✅ Connect to MongoDB
const mongoUri = process.env.MONGO_URI || "mongodb://localhost:27017/yourDatabaseName";
mongoose
.connect(mongoUri, { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => console.log("✅ Connected to MongoDB"))
.catch((err) => console.error("❌ MongoDB Connection Error:", err));
// ✅ Insert Fake Order for an Existing Vendor
async function insertFakeOrder() {
try {
// ✅ Find an existing vendor
const existingVendor = await Vendor.findOne();
if (!existingVendor) {
console.log("❌ No vendors found. Create a vendor first.");
return;
}
console.log(`✅ Using Vendor: ${existingVendor.username} (${existingVendor._id})`);
const fakeOrder = new Order({
buyerId: new mongoose.Types.ObjectId(), // Fake buyer
vendorId: existingVendor._id, // Assign to existing vendor
storeId: new mongoose.Types.ObjectId(),
products: [
{
productId: new mongoose.Types.ObjectId(),
quantity: 2,
pricePerUnit: 25.99,
totalItemPrice: 51.98,
},
],
totalPrice: 51.98,
status: "paid",
paymentAddress: "ltc1qxyzfakeaddress123456",
txid: "faketxid1234567890abcdef",
escrowExpiresAt: new Date(Date.now() + 8 * 24 * 60 * 60 * 1000), // 8 days from now
});
const savedOrder = await fakeOrder.save();
console.log("✅ Fake Order Inserted:", savedOrder);
} catch (error) {
console.error("❌ Error inserting fake order:", error);
} finally {
mongoose.connection.close(); // Close DB connection
}
}
// ✅ Run Script
insertFakeOrder();

View File

@@ -0,0 +1,67 @@
import mongoose from "mongoose";
import dotenv from "dotenv";
import Staff from "../models/Staff.model.js"
import Invitation from "../models/Invitation.model.js"
import crypto from "crypto";
dotenv.config();
// ✅ Connect to MongoDB
const mongoUri = process.env.MONGO_URI;
mongoose
.connect(mongoUri, { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => console.log("✅ Connected to MongoDB"))
.catch((err) => console.error("❌ MongoDB Connection Error:", err));
const generateInviteCode = () => {
return crypto.randomBytes(16).toString('hex');
};
const createInvitation = async (staffEmail) => {
try {
// Find staff member
const staff = await Staff.findOne({ username: "admin" });
if (!staff) {
throw new Error("Staff member not found");
}
// Check if staff has permission to create invitations
if (!['admin', 'support'].includes(staff.role)) {
throw new Error("Insufficient permissions to create vendor invitations");
}
// Generate unique invite code
const inviteCode = generateInviteCode();
// Create invitation
const invitation = await Invitation.create({
code: inviteCode,
createdBy: staff._id,
expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), // 7 days from now
isUsed: false
});
console.log(`✅ Vendor invitation created successfully!
Code: ${invitation.code}
Created by: ${staff.email}
Expires: ${invitation.expiresAt}
`);
// Exit process after creating invitation
process.exit(0);
} catch (error) {
console.error("❌ Error creating invitation:", error.message);
process.exit(1);
}
};
// Get staff email from command line argument
const staffEmail = process.argv[2];
if (!staffEmail) {
console.error("❌ Please provide staff email: node createInvitation.js <staffEmail>");
process.exit(1);
}
createInvitation(staffEmail);

View File

@@ -0,0 +1,7 @@
import crypto from "crypto";
const encryptionKey = crypto.randomBytes(32).toString("hex"); // 32 bytes (256-bit)
const iv = crypto.randomBytes(16).toString("hex"); // 16 bytes (128-bit)
console.log("Encryption Key:", encryptionKey);
console.log("IV:", iv);

View File

@@ -0,0 +1,55 @@
import mongoose from 'mongoose';
import dotenv from 'dotenv';
import Product from '../models/Product.model.js';
import logger from './logger.js';
// Load environment variables
dotenv.config();
// Connect to MongoDB
mongoose.connect(process.env.MONGO_URI)
.then(() => logger.info('MongoDB connected'))
.catch(err => {
logger.error('MongoDB connection error:', err);
process.exit(1);
});
async function disableStockTrackingForAllProducts() {
try {
logger.info('Disabling stock tracking for all products...');
const result = await Product.updateMany(
{}, // Empty filter matches all documents
{
stockTracking: false,
stockStatus: "in_stock" // Set a default status
}
);
logger.info(`Stock tracking disabled for ${result.modifiedCount} products out of ${result.matchedCount} total products`);
return result;
} catch (error) {
logger.error('Error disabling stock tracking:', error);
throw error;
} finally {
// Close database connection
mongoose.connection.close();
logger.info('Database connection closed');
}
}
// Execute the function if this script is run directly
if (process.argv[1].includes('disableStockTracking.js')) {
disableStockTrackingForAllProducts()
.then(() => {
logger.info('Script completed successfully');
process.exit(0);
})
.catch(err => {
logger.error('Script failed:', err);
process.exit(1);
});
}
export default disableStockTrackingForAllProducts;

View File

@@ -0,0 +1,54 @@
import * as openpgp from 'openpgp';
import logger from './logger.js';
/**
* Encrypts a message using PGP
* @param {string} message - The message to encrypt
* @param {string} publicKey - PGP public key for encryption
* @returns {Promise<string>} - The encrypted message
*/
export const encryptWithPGP = async (message, publicKey) => {
try {
// Parse the public key
const decodedPublicKey = await openpgp.readKey({ armoredKey: publicKey });
// Encrypt the message
const encrypted = await openpgp.encrypt({
message: await openpgp.createMessage({ text: message }),
encryptionKeys: decodedPublicKey
});
return encrypted;
} catch (error) {
logger.error('Error during PGP encryption', { error: error.message });
throw new Error('Failed to encrypt message: ' + error.message);
}
};
/**
* Decrypts a message using PGP
* @param {string} encryptedMessage - The encrypted message
* @param {string} privateKey - PGP private key for decryption
* @param {string} passphrase - Passphrase for the private key
* @returns {Promise<string>} - The decrypted message
*/
export const decryptWithPGP = async (encryptedMessage, privateKey, passphrase) => {
try {
// Parse the private key
const decodedPrivateKey = await openpgp.readPrivateKey({
armoredKey: privateKey
});
// Decrypt the message
const decrypted = await openpgp.decrypt({
message: await openpgp.readMessage({ armoredMessage: encryptedMessage }),
decryptionKeys: decodedPrivateKey,
config: { allowInsecureDecryptionWithSignature: true }
});
return decrypted.data;
} catch (error) {
logger.error('Error during PGP decryption', { error: error.message });
throw new Error('Failed to decrypt message: ' + error.message);
}
};

View File

@@ -0,0 +1,96 @@
import ky from "ky";
const rpcUrl = "http://152.53.124.126:9332/";
const rpcUser = "notiiwasntherexdddd";
const rpcPassword = "NYwsxePgMrThiapHnfCzUfaEfVlNKZECwvlqhHcWjerlZfcaTp";
const headers = {
"Content-Type": "application/json",
Authorization: `Basic ${Buffer.from(`${rpcUser}:${rpcPassword}`).toString(
"base64"
)}`,
};
async function callRpc(method, params = [], walletName = null) {
console.log(`Calling RPC method: ${method} with params: ${JSON.stringify(params)}`);
const url = walletName ? `${rpcUrl}wallet/${walletName}` : rpcUrl;
try {
const response = await ky
.post(url, {
json: {
jsonrpc: "1.0",
id: "curltest",
method,
params,
},
headers,
})
.json();
console.log(
`RPC Response for method ${method}:`,
JSON.stringify(response, null, 2)
);
if (response.error) {
throw new Error(`RPC Error: ${JSON.stringify(response.error, null, 2)}`);
}
return response.result;
} catch (error) {
console.error(`Error calling RPC method ${method}:`, error);
throw error;
}
}
async function createWallet(walletName) {
const result = await callRpc("createwallet", [walletName]);
console.log("Wallet created:", result);
return result;
}
async function generateAddress(walletName = null) {
const address = await callRpc("getnewaddress", [], walletName);
console.log("Generated Address:", address);
return address;
}
async function checkWalletLoaded(walletName) {
const walletInfo = await callRpc("getwalletinfo", [], walletName);
console.log("Wallet Info:", walletInfo);
return walletInfo;
}
async function walletExists(walletName) {
try {
await callRpc("getwalletinfo", [], walletName);
return true;
} catch (error) {
return false;
}
}
async function dumpPrivateKey(address, walletName) {
const privateKey = await callRpc("dumpprivkey", [address], walletName);
console.log("Private Key:", privateKey);
return privateKey;
}
async function setupWallet(walletName) {
const createResult = await createWallet(walletName);
const address = await generateAddress(walletName);
console.log("Address:", address);
console.log("Wallet Name:", walletName);
console.log("Create Result:", createResult);
const privKey = await dumpPrivateKey(address, walletName);
console.log("Wallet Info:", privKey);
return { address, privKey };
}
export { setupWallet };

77
backend/utils/logger.js Normal file
View File

@@ -0,0 +1,77 @@
const colors = {
reset: "\x1b[0m",
bright: "\x1b[1m",
dim: "\x1b[2m",
underscore: "\x1b[4m",
blink: "\x1b[5m",
reverse: "\x1b[7m",
hidden: "\x1b[8m",
fgBlack: "\x1b[30m",
fgRed: "\x1b[31m",
fgGreen: "\x1b[32m",
fgYellow: "\x1b[33m",
fgBlue: "\x1b[34m",
fgMagenta: "\x1b[35m",
fgCyan: "\x1b[36m",
fgWhite: "\x1b[37m",
bgBlack: "\x1b[40m",
bgRed: "\x1b[41m",
bgGreen: "\x1b[42m",
bgYellow: "\x1b[43m",
bgBlue: "\x1b[44m",
bgMagenta: "\x1b[45m",
bgCyan: "\x1b[46m",
bgWhite: "\x1b[47m",
};
/**
* Formats a timestamp for logging.
* @returns {string} Formatted timestamp
*/
const getTimestamp = () => {
return new Date().toISOString();
};
/**
* Logs an INFO message.
* @param {string} message - Log message
* @param {Object} [data] - Additional data
*/
const info = (message, data = null) => {
console.log(`${colors.fgGreen}[INFO] ${getTimestamp()} - ${message}${colors.reset}`);
if (data) console.log(data);
};
/**
* Logs a WARNING message.
* @param {string} message - Log message
* @param {Object} [data] - Additional data
*/
const warn = (message, data = null) => {
console.warn(`${colors.fgYellow}[WARN] ${getTimestamp()} - ${message}${colors.reset}`);
if (data) console.warn(data);
};
/**
* Logs an ERROR message.
* @param {string} message - Log message
* @param {Object} [data] - Additional data
*/
const error = (message, data = null) => {
console.error(`${colors.fgRed}[ERROR] ${getTimestamp()} - ${message}${colors.reset}`);
if (data) console.error(data);
};
/**
* Logs a DEBUG message.
* @param {string} message - Log message
* @param {Object} [data] - Additional data
*/
const debug = (message, data = null) => {
console.log(`${colors.fgBlue}[DEBUG] ${getTimestamp()} - ${message}${colors.reset}`);
if (data) console.log(data);
};
export default { info, warn, error, debug };

View File

@@ -0,0 +1,171 @@
import ky from "ky";
import logger from "../utils/logger.js";
import FormData from "form-data";
import fs from "fs";
import path from "path";
// Function to escape special characters for MarkdownV2
const escapeMarkdown = (text) => {
return text.replace(/([_*\[\]()~`>#+=|{}.!\\-])/g, '\\$1');
};
// Function to preserve markdown formatting while escaping other special characters
const preserveMarkdown = (text) => {
// First, temporarily replace valid markdown
text = text
.replace(/\*\*(.*?)\*\*/g, '%%%BOLD%%%$1%%%BOLD%%%')
.replace(/__(.*?)__/g, '%%%ITALIC%%%$1%%%ITALIC%%%')
.replace(/`(.*?)`/g, '%%%CODE%%%$1%%%CODE%%%')
.replace(/\[(.*?)\]\((.*?)\)/g, '%%%LINK_TEXT%%%$1%%%LINK_URL%%%$2%%%LINK%%%');
// Escape all special characters
text = escapeMarkdown(text);
// Restore markdown formatting
return text
.replace(/%%%BOLD%%%(.*?)%%%BOLD%%%/g, '*$1*')
.replace(/%%%ITALIC%%%(.*?)%%%ITALIC%%%/g, '_$1_')
.replace(/%%%CODE%%%(.*?)%%%CODE%%%/g, '`$1`')
.replace(/%%%LINK_TEXT%%%(.*?)%%%LINK_URL%%%(.*?)%%%LINK%%%/g, '[$1]($2)');
};
/**
* Sends a message via a Telegram bot.
* @param {string} telegramToken - The bot's API token.
* @param {number} chatId - The recipient's Telegram chat ID.
* @param {string} message - The message text.
* @param {string} [photoPath] - Optional path to photo file.
* @returns {Promise<boolean>} - Returns `true` if the message is sent successfully, otherwise `false`.
*/
export const sendTelegramMessage = async (telegramToken, chatId, message, photoPath = null) => {
try {
// Process message text if it exists
const processedMessage = message?.trim() ? preserveMarkdown(message) : '';
if (photoPath) {
const formData = new FormData();
formData.append('chat_id', chatId);
// Debug information before reading file
logger.info('Attempting to read file:', {
photoPath,
exists: fs.existsSync(photoPath),
stats: fs.existsSync(photoPath) ? fs.statSync(photoPath) : null,
dirname: path.dirname(photoPath),
basename: path.basename(photoPath)
});
try {
// Ensure the file exists before reading
if (!fs.existsSync(photoPath)) {
throw new Error(`File does not exist at path: ${photoPath}`);
}
// Create read stream and append to FormData
const photoStream = fs.createReadStream(photoPath);
formData.append('photo', photoStream);
if (processedMessage) {
formData.append('caption', processedMessage);
formData.append('parse_mode', 'MarkdownV2');
}
// Debug the FormData contents
logger.info('FormData created:', {
boundaryUsed: formData.getBoundary?.() || 'No boundary found',
headers: formData.getHeaders?.() || 'No headers available',
messageLength: processedMessage.length
});
// Wait for the entire request to complete
await new Promise((resolve, reject) => {
formData.submit({
host: 'api.telegram.org',
path: `/bot${telegramToken}/sendPhoto`,
protocol: 'https:',
}, (err, res) => {
if (err) {
reject(err);
return;
}
let data = '';
res.on('data', chunk => {
data += chunk;
});
res.on('end', () => {
try {
const response = JSON.parse(data);
if (!response.ok) {
reject(new Error(response.description || 'Failed to send photo'));
} else {
resolve(response);
}
} catch (e) {
reject(new Error('Failed to parse Telegram response'));
}
});
});
});
} catch (error) {
// Log detailed error information
logger.error(`❌ Telegram API Error for chat ${chatId}:`, {
error: error.message,
response: error.response ? await error.response.json().catch(() => ({})) : undefined,
photoPath,
messageLength: processedMessage.length,
fileExists: fs.existsSync(photoPath),
fileStats: fs.existsSync(photoPath) ? fs.statSync(photoPath) : null
});
throw error;
}
} else {
try {
await ky.post(`https://api.telegram.org/bot${telegramToken}/sendMessage`, {
json: {
chat_id: chatId,
text: processedMessage,
parse_mode: "MarkdownV2",
},
timeout: 5000,
});
} catch (error) {
// Log detailed error information
logger.error(`❌ Telegram API Error for chat ${chatId}:`, {
error: error.message,
response: await error.response?.json().catch(() => ({})),
messageLength: processedMessage.length
});
throw error;
}
}
logger.info(`✅ Telegram message sent to ${chatId}`);
return true;
} catch (error) {
logger.error(`❌ Failed to send Telegram message to ${chatId}: ${error.message}`);
return false;
}
};
/**
* Sends messages in bulk while respecting Telegram's rate limits.
* @param {string} telegramToken - The bot's API token.
* @param {Array<number>} chatIds - An array of chat IDs to send to.
* @param {string} message - The message text.
* @param {string} [photoPath] - Optional path to photo file.
* @returns {Promise<void>}
*/
export const sendBulkTelegramMessages = async (telegramToken, chatIds, message, photoPath = null) => {
for (let i = 0; i < chatIds.length; i++) {
const chatId = chatIds[i];
await sendTelegramMessage(telegramToken, chatId, message, photoPath);
if ((i + 1) % 30 === 0) {
logger.info(`⏳ Rate limit pause (sent ${i + 1} messages)...`);
await new Promise((resolve) => setTimeout(resolve, 1000));
}
}
};

View File