fix alot of things
This commit is contained in:
29
.env.backend
29
.env.backend
@@ -1,29 +0,0 @@
|
||||
MONGO_URI=mongodb://root:OkZl9TEPteFk75@captain.inboxi.ng/mydatabase?authSource=admin
|
||||
PORT=3001
|
||||
|
||||
JWT_SECRET=450417bc552e573f95c6d115b45dee27b8c544e5015ec8dd34147d59e1b0c360e3ab705e08511285bd0f5900e11cc4b6841f6391b24dc2c0e86ac2de473f4cb60b18fdc995304a27225db7ea13cece60f4afa50296a7b640b2042fe9072e1cd675cbd134ffeef9ee5a4b234830c53b98b21dcf8224acc6aec3745f5b7e46106eb2db946263cbf3d41add1a269d96de4034533cc9dcf1b74a155eccd0eae55cd958150c31ef0518346ac0471b7b5c83a6e4b26f9526b1c6702c65c38166db4bde57da1ba65a425e4ffba14b86d0279b907bd2eb29a86fd5b57ed78f5319dd5d78dc258cd801595978e042c4a2ca355825d894f8c4fcd39b57a3f78b1a9fd563758f0688d8f3b439c1cdfd161eb92e5ffea647b3a69c2889acd79e33c3a7dd64d32ddd14919be47cbfc46cea68df355f041530a3b0cddfb1042f7f96af7316a66a09fde4e18391dbe5d001a75ae8f8d44edc764b418a7525f55d5d593ca219336f467090b3d329528fd6535ad2c706eda9ed481da824931167dc4fa44a51cdbd13202ffea1375380c8dbdfec85665612c66d2df4bb44a322c54915fb46da50db6ff8e02d4b602069f0267fd29ec4bf865ac03597488d4ac59837fc1d51704f8dcf176681713ee9a24c3abaf58907f01581f7b2ac44a98cf177d6403ef1cf2b61e92cfa2939654ac9ef805d717c846520a02e6e054bcd2fee5394e1a05eb3d85f0d
|
||||
INTERNAL_API_KEY=5cffe0dedbbcc8761f6ddc7dc7cc2d299d599
|
||||
|
||||
ENCRYPTION_KEY=48c66ee5a54e596e2029ea832a512401099533ece34cb0fbbb8c4023ca68ba8e
|
||||
ENCRYPTION_IV=539e26d426cd4bac9844a8e446d63ab1
|
||||
|
||||
BTC_RPC_USER=your_rpc_user
|
||||
BTC_RPC_PASSWORD=your_rpc_password
|
||||
|
||||
BTC_RPC_HOST=127.0.0.1
|
||||
BTC_RPC_PORT=8332
|
||||
|
||||
LTC_RPC_USER=notiiwasntherexdddd
|
||||
LTC_RPC_PASSWORD=NYwsxePgMrThiapHnfCzUfaEfVlNKZECwvlqhHcWjerlZfcaTp
|
||||
|
||||
LTC_RPC_HOST=127.0.0.1
|
||||
LTC_RPC_PORT=9332
|
||||
|
||||
XMR_RPC_USER=your_rpc_user
|
||||
XMR_RPC_PASSWORD=your_rpc_password
|
||||
|
||||
XMR_RPC_HOST=127.0.0.1
|
||||
XMR_RPC_PORT=18081
|
||||
|
||||
OkZl9TEPteFk75=OkZl9TEPteFk75
|
||||
WL4E8H72nvSF=WL4E8H72nvSF
|
||||
13
.env.tor
13
.env.tor
@@ -1,13 +0,0 @@
|
||||
# Tor-specific environment variables
|
||||
# Using relative URLs for maximum compatibility
|
||||
NEXT_PUBLIC_API_URL=/api
|
||||
# Flag to indicate we're running in Tor mode
|
||||
NEXT_PUBLIC_TOR_MODE=true
|
||||
# Use relative URLs for all API communications - critical for Tor
|
||||
SERVER_API_URL=/api
|
||||
# Disable HTTPS for Tor communication (onion services already provide encryption)
|
||||
USE_HTTPS=false
|
||||
# Tor uses the same port for both internal and external communications
|
||||
INTERNAL_API_PORT=3000
|
||||
# Tell the app to check for onion addresses
|
||||
CHECK_ONION_ADDRESS=true
|
||||
@@ -1,83 +0,0 @@
|
||||
# Ember Market Integrated Application
|
||||
|
||||
This project combines both the Ember Market frontend (Next.js) and backend (Express) into a single application. This approach eliminates the need to run two separate servers and avoids routing conflicts between Next.js and Express.
|
||||
|
||||
## Setup Instructions
|
||||
|
||||
1. **Clone both repositories** if you haven't already:
|
||||
```bash
|
||||
git clone https://github.com/your-username/ember-market-frontend.git
|
||||
git clone https://github.com/your-username/ember-market-backend.git
|
||||
```
|
||||
|
||||
2. **Install dependencies**:
|
||||
```bash
|
||||
cd ember-market-frontend
|
||||
npm install
|
||||
```
|
||||
|
||||
3. **Run the setup script** to copy backend files to the frontend project:
|
||||
```bash
|
||||
npm run setup-backend
|
||||
```
|
||||
|
||||
4. **Update environment variables**:
|
||||
- The setup script copies the backend `.env` file to `.env.backend` in the frontend project
|
||||
- Make sure to review and adjust environment variables as needed
|
||||
- Ensure MongoDB connection string and other critical variables are set correctly
|
||||
|
||||
## Running the Application
|
||||
|
||||
### Development Mode
|
||||
|
||||
```bash
|
||||
npm run dev:custom
|
||||
```
|
||||
|
||||
This starts the combined server in development mode on port 3000 (or the port specified in your environment variables).
|
||||
|
||||
### Production Mode
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
npm run start:custom
|
||||
```
|
||||
|
||||
## How It Works
|
||||
|
||||
This integration uses a custom Express server that:
|
||||
|
||||
1. Handles API routes at `/api/*` using the existing Express backend code
|
||||
2. Delegates all other routes to Next.js to handle frontend rendering
|
||||
|
||||
### Key Files
|
||||
|
||||
- `server.js`: Custom server that combines Express and Next.js
|
||||
- `setup-backend.js`: Script to copy backend files into the frontend project
|
||||
- `next.config.mjs`: Configured to work with the custom Express server
|
||||
|
||||
## API Routes
|
||||
|
||||
All backend API routes are available at the same paths as before, but now they're served from the same server as your frontend:
|
||||
|
||||
- Authentication: `/api/auth/*`
|
||||
- Products: `/api/products/*`
|
||||
- Orders: `/api/orders/*`
|
||||
- etc.
|
||||
|
||||
## Development Workflow
|
||||
|
||||
When making changes:
|
||||
|
||||
1. **Frontend changes**: Modify files in the frontend project as usual
|
||||
2. **Backend changes**: You have two options:
|
||||
- Make changes in the original backend repo and run `npm run setup-backend` to sync
|
||||
- Make changes directly in the frontend project's `backend/` directory
|
||||
|
||||
Remember that changes made directly in the frontend project's `backend/` directory won't automatically sync back to the original backend repository.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Port conflicts**: Make sure no other service is using port 3000 (or your configured port)
|
||||
- **MongoDB connection issues**: Verify your connection string in the environment variables
|
||||
- **Path issues**: Ensure paths in imports are correct for the new project structure
|
||||
28
Dockerfile
28
Dockerfile
@@ -7,9 +7,7 @@ RUN npm install --force
|
||||
|
||||
COPY . .
|
||||
|
||||
# Set build-time environment variables to use relative URLs
|
||||
ENV NEXT_PUBLIC_API_URL=/api
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
ENV NEXT_PUBLIC_API_URL=https://internal-api.inboxi.ng/api
|
||||
|
||||
# Build the Next.js application
|
||||
RUN npm run build
|
||||
@@ -26,30 +24,12 @@ RUN mkdir -p /app/public
|
||||
COPY --from=builder /app/package.json /app/package-lock.json ./
|
||||
COPY --from=builder /app/.next ./.next
|
||||
COPY --from=builder /app/node_modules ./node_modules
|
||||
COPY --from=builder /app/server.js ./
|
||||
COPY --from=builder /app/.env.tor ./
|
||||
COPY --from=builder /app/.env.backend ./
|
||||
COPY --from=builder /app/public ./public
|
||||
|
||||
# If you have a backend folder, copy it as well
|
||||
COPY --from=builder /app/backend ./backend
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
# Set runtime environment variables - these will be overridden by .env.tor when running in Tor mode
|
||||
ENV NODE_ENV=production
|
||||
# Use relative URLs for maximum Tor compatibility
|
||||
ENV NEXT_PUBLIC_API_URL=/api
|
||||
# Running in Tor mode
|
||||
ENV NEXT_PUBLIC_TOR_MODE=true
|
||||
# Use relative URLs for server components - critical for Tor
|
||||
ENV SERVER_API_URL=/api
|
||||
# Disable HTTPS for onion services (they're already encrypted)
|
||||
ENV USE_HTTPS=false
|
||||
# Set port for internal API calls
|
||||
ENV INTERNAL_API_PORT=3000
|
||||
# Disable telemetry
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
ENV NEXT_PUBLIC_API_URL=https://internal-api.inboxi.ng/api
|
||||
|
||||
|
||||
# Start Next.js server
|
||||
CMD ["npm", "run", "start:tor"]
|
||||
CMD ["npm", "run", "start"]
|
||||
@@ -1,61 +0,0 @@
|
||||
# Ember Market on Tor
|
||||
|
||||
This document explains how to run Ember Market in a Tor-friendly way, ensuring compatibility with .onion domains and the Tor network.
|
||||
|
||||
## Tor-Optimized Configuration
|
||||
|
||||
The application is designed to work seamlessly with Tor by:
|
||||
|
||||
1. Using relative URLs throughout the codebase
|
||||
2. Avoiding hardcoded domain names
|
||||
3. Ensuring all API requests work regardless of the domain
|
||||
|
||||
## Running in Tor Mode
|
||||
|
||||
To start the application in Tor mode:
|
||||
|
||||
```bash
|
||||
# Development
|
||||
npm run dev:tor
|
||||
|
||||
# Production
|
||||
npm run start:tor
|
||||
```
|
||||
|
||||
These commands use the `.env.tor` configuration file, which sets appropriate environment variables for Tor usage.
|
||||
|
||||
## Accessing via .onion Domain
|
||||
|
||||
When deployed to a Tor hidden service:
|
||||
|
||||
1. The application automatically detects the .onion domain
|
||||
2. All API requests are made relative to the current domain
|
||||
3. No changes are needed to the codebase or configuration
|
||||
|
||||
## Security Considerations for Tor
|
||||
|
||||
- All API requests use relative URLs to prevent domain leakage
|
||||
- Authentication is performed on the same domain to maintain anonymity
|
||||
- No external resources are loaded that could compromise Tor anonymity
|
||||
|
||||
## Deployment to a Tor Hidden Service
|
||||
|
||||
To deploy as a Tor hidden service:
|
||||
|
||||
1. Set up a Tor hidden service pointing to the application port (default: 3000)
|
||||
2. Use the `start:tor` script to ensure proper environment variables
|
||||
3. The application will automatically work with the .onion domain
|
||||
|
||||
## Checking Tor Compatibility
|
||||
|
||||
To verify the application is working correctly with Tor:
|
||||
|
||||
1. Check network requests in the browser's developer tools
|
||||
2. All API requests should go to relative paths (e.g., `/api/auth/me`)
|
||||
3. No absolute URLs should be used in requests
|
||||
|
||||
## Troubleshooting Tor Issues
|
||||
|
||||
- If authentication fails, check that cookies are enabled in your Tor browser
|
||||
- If API requests fail, verify that the application is accessible via the .onion domain
|
||||
- For security issues, ensure JavaScript is enabled for the .onion domain in Tor browser settings
|
||||
@@ -1,9 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import Dashboard from "@/components/dashboard/dashboard";
|
||||
import Content from "@/components/dashboard/content";
|
||||
import { fetchClient } from '@/lib/client-service';
|
||||
import { fetchServer } from '@/lib/server-service';
|
||||
|
||||
// ✅ Corrected Vendor Type
|
||||
interface Vendor {
|
||||
@@ -25,43 +22,13 @@ interface OrderStats {
|
||||
cancelledOrders: number;
|
||||
}
|
||||
|
||||
export default function DashboardPage() {
|
||||
const [vendor, setVendor] = useState<Vendor | null>(null);
|
||||
const [orderStats, setOrderStats] = useState<OrderStats | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
async function fetchData() {
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
// Fetch data from API using relative URLs and client-side fetch
|
||||
const [userResponse, stats] = await Promise.all([
|
||||
fetchClient<User>("auth/me"),
|
||||
fetchClient<OrderStats>("orders/stats"),
|
||||
export default async function DashboardPage() {
|
||||
const [userResponse, orderStats] = await Promise.all([
|
||||
fetchServer<User>("/auth/me"),
|
||||
fetchServer<OrderStats>("/orders/stats"),
|
||||
]);
|
||||
|
||||
setVendor(userResponse.vendor);
|
||||
setOrderStats(stats);
|
||||
} catch (err) {
|
||||
console.error('Error fetching dashboard data:', err);
|
||||
setError('Failed to load dashboard data');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
if (loading) {
|
||||
return <Dashboard><div>Loading dashboard...</div></Dashboard>;
|
||||
}
|
||||
|
||||
if (error || !vendor || !orderStats) {
|
||||
return <Dashboard><div>Error: {error || 'Failed to load data'}</div></Dashboard>;
|
||||
}
|
||||
const vendor = userResponse.vendor;
|
||||
|
||||
return (
|
||||
<Dashboard>
|
||||
|
||||
@@ -42,7 +42,7 @@ services:
|
||||
- web
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- NEXT_PUBLIC_API_URL=/api
|
||||
- NEXT_PUBLIC_API_URL=https://internal-api.inboxi.ng/api
|
||||
restart: unless-stopped
|
||||
|
||||
networks:
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
'use client';
|
||||
|
||||
// Helper function to verify authentication with the local API
|
||||
export async function verifyAuth(token: string) {
|
||||
try {
|
||||
let authEndpoint;
|
||||
const torMode = process.env.NEXT_PUBLIC_TOR_MODE === 'true';
|
||||
|
||||
// Check if we're running in a browser environment
|
||||
if (typeof window !== 'undefined') {
|
||||
// For Tor mode in browser, prefer relative URLs
|
||||
if (torMode) {
|
||||
authEndpoint = '/api/auth/me';
|
||||
console.log(`Tor mode: Using relative URL for auth endpoint: ${authEndpoint}`);
|
||||
} else {
|
||||
// Use the current origin in regular browser environments
|
||||
const origin = window.location.origin;
|
||||
authEndpoint = new URL('/api/auth/me', origin).toString();
|
||||
console.log(`Using browser origin for auth endpoint: ${authEndpoint}`);
|
||||
}
|
||||
} else {
|
||||
// For SSR or when window is not available (e.g. in Docker container)
|
||||
|
||||
// For Tor mode, always use relative URLs
|
||||
if (torMode) {
|
||||
authEndpoint = '/api/auth/me';
|
||||
console.log(`Tor mode SSR: Using relative URL for auth endpoint: ${authEndpoint}`);
|
||||
}
|
||||
// Use the environment variable if available
|
||||
else if (process.env.SERVER_API_URL) {
|
||||
// If SERVER_API_URL already includes /auth/me, don't append it again
|
||||
if (process.env.SERVER_API_URL.includes('/auth/me')) {
|
||||
authEndpoint = process.env.SERVER_API_URL;
|
||||
} else {
|
||||
// Otherwise append the endpoint to the base URL
|
||||
authEndpoint = `${process.env.SERVER_API_URL}/auth/me`;
|
||||
}
|
||||
console.log(`Using SERVER_API_URL for auth endpoint: ${authEndpoint}`);
|
||||
} else {
|
||||
// Fallback for local development
|
||||
const protocol = (process.env.USE_HTTPS === 'false') ? 'http' : 'https';
|
||||
const port = process.env.INTERNAL_API_PORT || '3000';
|
||||
authEndpoint = `${protocol}://localhost:${port}/api/auth/me`;
|
||||
console.log(`Using fallback for auth endpoint: ${authEndpoint}`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`Verifying authentication with endpoint: ${authEndpoint}`);
|
||||
|
||||
const response = await fetch(authEndpoint, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
// Prevent caching of auth requests
|
||||
cache: 'no-store'
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
console.error(`Auth verification failed: ${response.status}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error("Authentication verification failed:", error);
|
||||
console.error("Error details:", error instanceof Error ? error.message : 'Unknown error');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -21,44 +21,31 @@ function getAuthToken(): string | null {
|
||||
?.split('=')[1] || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the API base URL for client-side fetch calls
|
||||
*/
|
||||
function getClientApiBaseUrl(): string {
|
||||
// For client-side, we can access window.location if in browser
|
||||
if (typeof window !== 'undefined') {
|
||||
// Use the same origin (which includes the correct port)
|
||||
return `${window.location.origin}/api`;
|
||||
}
|
||||
|
||||
// Fallback when window is not available
|
||||
// For development mode, use port 3001 to match our server
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
return 'http://localhost:3001/api';
|
||||
}
|
||||
|
||||
// Default fallback - relative URL
|
||||
return '/api';
|
||||
}
|
||||
|
||||
export async function fetchClient<T>(
|
||||
endpoint: string,
|
||||
options: FetchOptions = {}
|
||||
): Promise<T> {
|
||||
const { method = 'GET', body, headers = {}, ...rest } = options;
|
||||
|
||||
try {
|
||||
// Get the base API URL
|
||||
const baseUrl = getClientApiBaseUrl();
|
||||
// Get the base API URL from environment or fallback
|
||||
const apiUrl = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001';
|
||||
|
||||
// Ensure endpoint doesn't start with a slash if baseUrl ends with one
|
||||
const normalizedEndpoint = endpoint.startsWith('/') ? endpoint.substring(1) : endpoint;
|
||||
// Ensure the endpoint starts with a slash
|
||||
const normalizedEndpoint = endpoint.startsWith('/') ? endpoint : `/${endpoint}`;
|
||||
|
||||
// Ensure baseUrl ends with a slash if it doesn't already
|
||||
const normalizedBaseUrl = baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`;
|
||||
|
||||
// Combine them for the final URL
|
||||
const url = `${normalizedBaseUrl}${normalizedEndpoint}`;
|
||||
// For the specific case of internal-api.inboxi.ng - remove duplicate /api
|
||||
let url;
|
||||
if (apiUrl.includes('internal-api.inboxi.ng')) {
|
||||
// Special case for internal-api.inboxi.ng
|
||||
if (normalizedEndpoint.startsWith('/api/')) {
|
||||
url = `${apiUrl}${normalizedEndpoint.substring(4)}`; // Remove the /api part
|
||||
} else {
|
||||
url = `${apiUrl}${normalizedEndpoint}`;
|
||||
}
|
||||
} else {
|
||||
// Normal case for other environments
|
||||
url = `${apiUrl}${normalizedEndpoint}`;
|
||||
}
|
||||
|
||||
// Get auth token from cookies
|
||||
const authToken = getAuthToken();
|
||||
@@ -92,6 +79,7 @@ export async function fetchClient<T>(
|
||||
fetchOptions.body = JSON.stringify(body);
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(url, fetchOptions);
|
||||
|
||||
if (!response.ok) {
|
||||
@@ -109,7 +97,6 @@ export async function fetchClient<T>(
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error('API request failed:', error);
|
||||
console.error('Error details:', error instanceof Error ? error.message : 'Unknown error');
|
||||
|
||||
// Only show toast if this is a client-side error (not during SSR)
|
||||
if (typeof window !== 'undefined') {
|
||||
|
||||
@@ -1,77 +1,6 @@
|
||||
import { cookies } from 'next/headers';
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
/**
|
||||
* Gets the base URL for server API requests with proper fallbacks
|
||||
*/
|
||||
function getBaseUrl() {
|
||||
// Check if we're running in Tor mode
|
||||
const torMode = process.env.NEXT_PUBLIC_TOR_MODE === 'true';
|
||||
|
||||
// First check for the specific server API URL environment variable
|
||||
if (process.env.SERVER_API_URL) {
|
||||
console.log(`Using SERVER_API_URL: ${process.env.SERVER_API_URL}`);
|
||||
|
||||
// If we're in Tor mode and the SERVER_API_URL is set to a relative path, use it directly
|
||||
if (torMode && process.env.SERVER_API_URL.startsWith('/')) {
|
||||
return process.env.SERVER_API_URL;
|
||||
}
|
||||
|
||||
return process.env.SERVER_API_URL;
|
||||
}
|
||||
|
||||
// For server components, we normally would use environment variables
|
||||
// But we need to be careful with how they're accessed
|
||||
|
||||
// Try to get the API URL from environment variables
|
||||
const apiUrl = process.env.NEXT_PUBLIC_API_URL;
|
||||
|
||||
// Check if we're running in a container/production environment
|
||||
const inContainer = process.env.NODE_ENV === 'production';
|
||||
|
||||
// If in Tor mode, prefer relative URLs
|
||||
if (torMode && apiUrl && apiUrl.startsWith('/')) {
|
||||
return apiUrl;
|
||||
}
|
||||
|
||||
// We need to get the host from somewhere to construct the URL
|
||||
// In production, we can rely on the VERCEL_URL or similar
|
||||
if (process.env.VERCEL_URL) {
|
||||
return `https://${process.env.VERCEL_URL}/api`;
|
||||
}
|
||||
|
||||
// If we have a configured API URL, use that
|
||||
if (apiUrl) {
|
||||
// If it's already an absolute URL, use it
|
||||
if (apiUrl.startsWith('http')) {
|
||||
return apiUrl;
|
||||
}
|
||||
|
||||
// For container environments, use the internal port
|
||||
const port = process.env.INTERNAL_API_PORT || '3000';
|
||||
const protocol = (process.env.USE_HTTPS === 'false') ? 'http' : 'https';
|
||||
|
||||
// If in Tor mode, prefer relative URLs
|
||||
if (torMode) {
|
||||
return apiUrl.startsWith('/') ? apiUrl : `/${apiUrl}`;
|
||||
}
|
||||
|
||||
// Otherwise, it's likely a relative path like /api
|
||||
// Use localhost with the correct port for container environments
|
||||
return `${protocol}://localhost:${port}${apiUrl.startsWith('/') ? apiUrl : `/${apiUrl}`}`;
|
||||
}
|
||||
|
||||
// Last resort fallback - if in Tor mode, use a relative URL
|
||||
if (torMode) {
|
||||
return '/api';
|
||||
}
|
||||
|
||||
// For regular container environments
|
||||
const protocol = (process.env.USE_HTTPS === 'false') ? 'http' : 'https';
|
||||
const port = process.env.INTERNAL_API_PORT || '3000';
|
||||
return `${protocol}://localhost:${port}/api`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Server-side fetch wrapper with authentication.
|
||||
*/
|
||||
@@ -85,52 +14,8 @@ export async function fetchServer<T = unknown>(
|
||||
if (!authToken) redirect('/login');
|
||||
|
||||
try {
|
||||
const baseUrl = getBaseUrl();
|
||||
const torMode = process.env.NEXT_PUBLIC_TOR_MODE === 'true';
|
||||
|
||||
// Special handling for Tor mode
|
||||
if (torMode) {
|
||||
// For Tor, we need to be extra careful with URL construction
|
||||
|
||||
// Remove leading slash from endpoint if present
|
||||
const normalizedEndpoint = endpoint.startsWith('/') ? endpoint.substring(1) : endpoint;
|
||||
|
||||
// If baseUrl is a relative path (starts with /)
|
||||
if (baseUrl.startsWith('/')) {
|
||||
// Combine paths carefully to create a relative URL
|
||||
const url = `${baseUrl}${baseUrl.endsWith('/') ? '' : '/'}${normalizedEndpoint}`;
|
||||
console.log(`Tor mode: Using relative URL for server fetch: ${url}`);
|
||||
|
||||
const res = await fetch(url, {
|
||||
...options,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${authToken}`,
|
||||
...options.headers,
|
||||
},
|
||||
cache: 'no-store',
|
||||
});
|
||||
|
||||
if (res.status === 401) redirect('/login');
|
||||
if (!res.ok) throw new Error(`Request failed: ${res.statusText}`);
|
||||
|
||||
return res.json();
|
||||
}
|
||||
}
|
||||
|
||||
// Regular URL construction for non-Tor environments
|
||||
// Ensure endpoint doesn't start with a slash if baseUrl ends with one
|
||||
const normalizedEndpoint = endpoint.startsWith('/') ? endpoint.substring(1) : endpoint;
|
||||
|
||||
// Ensure baseUrl ends with a slash if it doesn't already
|
||||
const normalizedBaseUrl = baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`;
|
||||
|
||||
// Combine them to get a complete URL
|
||||
const url = `${normalizedBaseUrl}${normalizedEndpoint}`;
|
||||
|
||||
console.log(`Server fetch to: ${url}`);
|
||||
|
||||
const res = await fetch(url, {
|
||||
console.log(`${endpoint}`)
|
||||
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}${endpoint}`, {
|
||||
...options,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
/**
|
||||
* Helper function to construct proper URLs for server components.
|
||||
* In Next.js server components, relative URLs don't work in fetch() calls.
|
||||
*/
|
||||
export function getServerApiUrl(endpoint: string): string {
|
||||
// Base API URL - use a hardcoded value for server components
|
||||
// This must be an absolute URL with protocol and domain
|
||||
const baseUrl = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3000/api';
|
||||
|
||||
// Ensure endpoint doesn't start with a slash if baseUrl ends with one
|
||||
const normalizedEndpoint = endpoint.startsWith('/') ? endpoint.substring(1) : endpoint;
|
||||
|
||||
// Ensure the baseUrl ends with a slash if it doesn't already
|
||||
const normalizedBaseUrl = baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`;
|
||||
|
||||
// Combine them to get a complete URL
|
||||
return `${normalizedBaseUrl}${normalizedEndpoint}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to detect if code is running on server or client
|
||||
*/
|
||||
export function isServer(): boolean {
|
||||
return typeof window === 'undefined';
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to detect if code is running in development mode
|
||||
*/
|
||||
export function isDevelopment(): boolean {
|
||||
return process.env.NODE_ENV === 'development';
|
||||
}
|
||||
@@ -10,30 +10,19 @@ export async function middleware(req: NextRequest) {
|
||||
}
|
||||
|
||||
try {
|
||||
// Make sure we use a complete URL with protocol
|
||||
// When running locally with integrated backend, we need to specify the full URL including protocol
|
||||
const origin = req.nextUrl.origin;
|
||||
const authEndpoint = new URL("/api/auth/me", origin).toString();
|
||||
|
||||
console.log("Verifying authentication with endpoint:", authEndpoint);
|
||||
|
||||
const res = await fetch(authEndpoint, {
|
||||
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/auth/me`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
// Ensure we're not caching authentication checks
|
||||
cache: 'no-store'
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
console.error(`Auth check failed with status: ${res.status}`);
|
||||
return NextResponse.redirect(new URL("/auth/login", req.url));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Authentication validation failed:", error);
|
||||
console.error("Error details:", error instanceof Error ? error.message : 'Unknown error');
|
||||
return NextResponse.redirect(new URL("/auth/login", req.url));
|
||||
}
|
||||
|
||||
|
||||
@@ -8,46 +8,6 @@ const nextConfig = {
|
||||
},
|
||||
],
|
||||
},
|
||||
// Disable Next.js handling of API routes that our Express server will handle
|
||||
async rewrites() {
|
||||
return [
|
||||
{
|
||||
// Don't rewrite actual Next.js API routes
|
||||
source: "/api/_next/:path*",
|
||||
destination: "/api/_next/:path*",
|
||||
},
|
||||
{
|
||||
// Rewrite API requests to be handled by our custom Express server
|
||||
source: "/api/:path*",
|
||||
destination: "/api/:path*",
|
||||
},
|
||||
];
|
||||
},
|
||||
// Make environment variables available to both client and server components
|
||||
env: {
|
||||
// For integrated backend, use http://localhost:3000/api
|
||||
NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3000/api',
|
||||
},
|
||||
// Prevent dynamic URLs from being hard-coded at build time
|
||||
// This is important for Tor compatibility
|
||||
experimental: {
|
||||
// This prevents URLs from being hardcoded at build time
|
||||
esmExternals: true,
|
||||
},
|
||||
// Ensure server components can handle URL objects
|
||||
serverComponentsExternalPackages: ['next/dist/compiled/path-to-regexp'],
|
||||
// Allow server-side fetch calls to the local API
|
||||
serverRuntimeConfig: {
|
||||
apiUrl: 'http://localhost:3000/api',
|
||||
},
|
||||
|
||||
// Special handling for server components
|
||||
webpack: (config, { isServer }) => {
|
||||
if (isServer) {
|
||||
// Server-side specific config
|
||||
}
|
||||
return config;
|
||||
},
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
|
||||
2183
package-lock.json
generated
2183
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
19
package.json
19
package.json
@@ -2,16 +2,10 @@
|
||||
"name": "my-v0-project",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"dev:custom": "node server.js",
|
||||
"dev:tor": "NODE_ENV=production node -r dotenv/config server.js dotenv_config_path=.env.tor",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"start:custom": "NODE_ENV=production node server.js",
|
||||
"start:tor": "NODE_ENV=production node -r dotenv/config server.js dotenv_config_path=.env.tor",
|
||||
"setup-backend": "node setup-backend.js",
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -45,28 +39,17 @@
|
||||
"@radix-ui/react-tooltip": "^1.1.6",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"axios": "^1.8.1",
|
||||
"bcrypt": "^5.1.1",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "1.0.4",
|
||||
"cors": "^2.8.5",
|
||||
"date-fns": "4.1.0",
|
||||
"dotenv": "^16.4.7",
|
||||
"embla-carousel-react": "8.5.1",
|
||||
"express": "^4.21.2",
|
||||
"form-data": "^4.0.2",
|
||||
"input-otp": "1.4.1",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"jwt-decode": "^4.0.0",
|
||||
"ky": "^1.7.5",
|
||||
"lucide-react": "^0.454.0",
|
||||
"mongoose": "^8.9.6",
|
||||
"mongoose-sequence": "^6.0.1",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"next": "14.2.16",
|
||||
"next-themes": "latest",
|
||||
"openpgp": "^6.1.0",
|
||||
"react": "^18",
|
||||
"react-day-picker": "8.10.1",
|
||||
"react-dom": "^18",
|
||||
@@ -74,11 +57,9 @@
|
||||
"react-markdown": "^10.0.0",
|
||||
"react-resizable-panels": "^2.1.7",
|
||||
"recharts": "2.15.0",
|
||||
"sharp": "^0.33.5",
|
||||
"sonner": "^1.7.4",
|
||||
"tailwind-merge": "^2.5.5",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"uuid": "^11.0.5",
|
||||
"vaul": "^0.9.6",
|
||||
"zod": "^3.24.1"
|
||||
},
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
const backendPath = path.join(__dirname, '..', 'ember-market-backend');
|
||||
const targetPath = path.join(__dirname, 'backend');
|
||||
|
||||
// Create backend directory if it doesn't exist
|
||||
if (!fs.existsSync(targetPath)) {
|
||||
fs.mkdirSync(targetPath, { recursive: true });
|
||||
}
|
||||
|
||||
// Function to copy directory recursively
|
||||
function copyDir(src, dest) {
|
||||
// Create destination directory if it doesn't exist
|
||||
if (!fs.existsSync(dest)) {
|
||||
fs.mkdirSync(dest, { recursive: true });
|
||||
}
|
||||
|
||||
// Read contents of source directory
|
||||
const entries = fs.readdirSync(src, { withFileTypes: true });
|
||||
|
||||
for (const entry of entries) {
|
||||
const srcPath = path.join(src, entry.name);
|
||||
const destPath = path.join(dest, entry.name);
|
||||
|
||||
// Skip node_modules and .git directories
|
||||
if (entry.name === 'node_modules' || entry.name === '.git') {
|
||||
console.log(`Skipping ${entry.name}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry.isDirectory()) {
|
||||
// Recursive call for directories
|
||||
copyDir(srcPath, destPath);
|
||||
} else {
|
||||
// Copy file
|
||||
fs.copyFileSync(srcPath, destPath);
|
||||
console.log(`Copied: ${srcPath} -> ${destPath}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy files from backend to frontend/backend
|
||||
try {
|
||||
// Copy main backend directories
|
||||
const dirsToSync = ['config', 'controllers', 'middleware', 'models', 'routes', 'scripts', 'utils'];
|
||||
|
||||
dirsToSync.forEach(dir => {
|
||||
const sourcePath = path.join(backendPath, dir);
|
||||
const destPath = path.join(targetPath, dir);
|
||||
|
||||
if (fs.existsSync(sourcePath)) {
|
||||
copyDir(sourcePath, destPath);
|
||||
} else {
|
||||
console.warn(`Warning: Directory ${sourcePath} does not exist`);
|
||||
}
|
||||
});
|
||||
|
||||
// Copy .env file (you might want to modify this for different environments)
|
||||
const envSource = path.join(backendPath, '.env');
|
||||
const envDest = path.join(__dirname, '.env.backend');
|
||||
|
||||
if (fs.existsSync(envSource)) {
|
||||
fs.copyFileSync(envSource, envDest);
|
||||
console.log(`Copied: ${envSource} -> ${envDest}`);
|
||||
}
|
||||
|
||||
console.log('Backend setup completed successfully!');
|
||||
} catch (error) {
|
||||
console.error('Error setting up backend:', error);
|
||||
}
|
||||
247
test.ts
247
test.ts
@@ -1,247 +0,0 @@
|
||||
const wallets = [{
|
||||
"walletName": "order_436f35e1085fcbad"
|
||||
},
|
||||
{
|
||||
"walletName": "order_2c9bbe4ae6c4eef6"
|
||||
},
|
||||
{
|
||||
"walletName": "order_2af479fa96d55181"
|
||||
},
|
||||
{
|
||||
"walletName": "order_1dc02cf6d5515c74"
|
||||
},
|
||||
{
|
||||
"walletName": "order_a4a5f5ed3ede8907"
|
||||
},
|
||||
{
|
||||
"walletName": "order_7f90d78300af3d1f"
|
||||
},
|
||||
{
|
||||
"walletName": "order_b07959c94030eb57"
|
||||
},
|
||||
{
|
||||
"walletName": "order_ea1dab8dc6ea3a9f"
|
||||
},
|
||||
{
|
||||
"walletName": "order_784c47a3e75c0757"
|
||||
},
|
||||
{
|
||||
"walletName": "order_6e4a961a36489ed7"
|
||||
},
|
||||
{
|
||||
"walletName": "order_022f32abeb8df016"
|
||||
},
|
||||
{
|
||||
"walletName": "order_5eb43e2ebf061eef"
|
||||
},
|
||||
{
|
||||
"walletName": "order_5564e8fc6cdd178f"
|
||||
},
|
||||
{
|
||||
"walletName": "order_b903698054a946b7"
|
||||
},
|
||||
{
|
||||
"walletName": "order_ec18ba3d2b841d1e"
|
||||
},
|
||||
{
|
||||
"walletName": "order_cbdeecf081e7fca9"
|
||||
},
|
||||
{
|
||||
"walletName": "order_31bbce61f3086609"
|
||||
},
|
||||
{
|
||||
"walletName": "order_6fc27689e34665b7"
|
||||
},
|
||||
{
|
||||
"walletName": "order_0913867abc1ac574"
|
||||
},
|
||||
{
|
||||
"walletName": "order_62b9c4078e73987a"
|
||||
},
|
||||
{
|
||||
"walletName": "order_08ce3f3ecb52f951"
|
||||
},
|
||||
{
|
||||
"walletName": "order_168754ee60c498cc"
|
||||
},
|
||||
{
|
||||
"walletName": "order_b260229ad465326d"
|
||||
},
|
||||
{
|
||||
"walletName": "order_8b6ee943d834f6d9"
|
||||
},
|
||||
{
|
||||
"walletName": "order_7a66dda04b38f3d4"
|
||||
},
|
||||
{
|
||||
"walletName": "order_f7c08834e0f2dd7e"
|
||||
},
|
||||
{
|
||||
"walletName": "order_4f545ff25b60217c"
|
||||
},
|
||||
{
|
||||
"walletName": "order_abca6840cd07c802"
|
||||
},
|
||||
{
|
||||
"walletName": "order_0b833e1c4db24bc2"
|
||||
},
|
||||
{
|
||||
"walletName": "order_0c237fe9bb7cd664"
|
||||
},
|
||||
{
|
||||
"walletName": "order_a317ad0f9ef453c1"
|
||||
},
|
||||
{
|
||||
"walletName": "order_eb5179b2fcb03505"
|
||||
},
|
||||
{
|
||||
"walletName": "order_9ce17563c61e9596"
|
||||
},
|
||||
{
|
||||
"walletName": "order_a7590d44397eceb3"
|
||||
},
|
||||
{
|
||||
"walletName": "order_88c8143c34efa91f"
|
||||
},
|
||||
{
|
||||
"walletName": "order_aae40e72084b4bcf"
|
||||
},
|
||||
{
|
||||
"walletName": "order_d81c7b22222d57e8"
|
||||
},
|
||||
{
|
||||
"walletName": "order_597141fc3d7d6c98"
|
||||
},
|
||||
{
|
||||
"walletName": "order_49ccc32e68c35843"
|
||||
},
|
||||
{
|
||||
"walletName": "order_e2961ed60392d07e"
|
||||
},
|
||||
{
|
||||
"walletName": "order_a48546f981de5380"
|
||||
},
|
||||
{
|
||||
"walletName": "order_77d1bd8df8318e9e"
|
||||
},
|
||||
{
|
||||
"walletName": "order_69706a17d6126c97"
|
||||
},
|
||||
{
|
||||
"walletName": "order_bafb24915caf828a"
|
||||
},
|
||||
{
|
||||
"walletName": "order_d93635b18c3409eb"
|
||||
},
|
||||
{
|
||||
"walletName": "order_03823e253b82c171"
|
||||
},
|
||||
{
|
||||
"walletName": "order_285d87cea8f684a6"
|
||||
},
|
||||
{
|
||||
"walletName": "order_43550fea608097bf"
|
||||
},
|
||||
{
|
||||
"walletName": "order_54bf9f7ab106cfca"
|
||||
},
|
||||
{
|
||||
"walletName": "order_c6d48e3b803115db"
|
||||
},
|
||||
{
|
||||
"walletName": "order_0bec1d36f2b315df"
|
||||
},
|
||||
{
|
||||
"walletName": "order_bcd511c30bbee158"
|
||||
},
|
||||
{
|
||||
"walletName": "order_1f91cc66630bba77"
|
||||
},
|
||||
{
|
||||
"walletName": "order_e11be5d3948106b9"
|
||||
},
|
||||
{
|
||||
"walletName": "order_d942ef659e5aa01a"
|
||||
},
|
||||
{
|
||||
"walletName": "order_b6410c5daed33312"
|
||||
},
|
||||
{
|
||||
"walletName": "order_430143968de1a1f1"
|
||||
},
|
||||
{
|
||||
"walletName": "order_0a46d56b27ff0bb2"
|
||||
},
|
||||
{
|
||||
"walletName": "order_b0498d3c46b0eed8"
|
||||
},
|
||||
{
|
||||
"walletName": "order_7ea739f584eff793"
|
||||
},
|
||||
{
|
||||
"walletName": "order_bc0166a8bc334f88"
|
||||
},
|
||||
{
|
||||
"walletName": "order_7e7b1c718ea579d4"
|
||||
},
|
||||
{
|
||||
"walletName": "order_7c776972e4c04329"
|
||||
},
|
||||
{
|
||||
"walletName": "order_15eae822eb1ca3a2"
|
||||
},
|
||||
{
|
||||
"walletName": "order_c57eae689ac827ab"
|
||||
},
|
||||
{
|
||||
"walletName": "order_162a8aefdee3934a"
|
||||
},
|
||||
{
|
||||
"walletName": "order_79ff4f118bb49a46"
|
||||
},
|
||||
{
|
||||
"walletName": "order_a6d6e685cb93627d"
|
||||
},
|
||||
{
|
||||
"walletName": "order_770c05f8f9aa3281"
|
||||
},
|
||||
{
|
||||
"walletName": "order_4eafb519b8b64129"
|
||||
},
|
||||
{
|
||||
"walletName": "order_533feb6a4843b162"
|
||||
},
|
||||
{
|
||||
"walletName": "order_40b640bfcaba6303"
|
||||
},
|
||||
{
|
||||
"walletName": "order_3de1a9cd802bc895"
|
||||
},
|
||||
{
|
||||
"walletName": "order_4b592780fc9c8e5a"
|
||||
},
|
||||
{
|
||||
"walletName": "order_ba395cd8fba0239f"
|
||||
}]
|
||||
|
||||
for (let wallet in wallets) {
|
||||
const walletName = wallets[wallet].walletName
|
||||
|
||||
const auth = Buffer.from(`notiiwasntherexdddd:NYwsxePgMrThiapHnfCzUfaEfVlNKZECwvlqhHcWjerlZfcaTp`).toString('base64')
|
||||
fetch(`http://152.53.124.126:9332/wallet/${walletName}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Basic ${auth}`
|
||||
},
|
||||
body: JSON.stringify({"jsonrpc": "1.0", "id": "curltest", "method": "getbalance", "params": ["*", 0]})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
console.log(data)
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching wallet:', error)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user