-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathserver.js
More file actions
143 lines (126 loc) · 5.05 KB
/
server.js
File metadata and controls
143 lines (126 loc) · 5.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/*
* server.js
*
* XRPL XBorder Payroll Demo Backend
*
* Copyright (c) 2024 Alexander Alten
* GitHub Handle: 2pk03
*
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
*
* Under the MPL, you must preserve this notice. You must also disclose your source
* code if you distribute a modified version of this program.
*/
require('dotenv').config();
const express = require('express');
const cors = require('cors');
const helmet = require('helmet'); // For security headers
const morgan = require('morgan'); // For logging
const rateLimit = require('express-rate-limit'); // For rate limiting
const enforce = require('express-sslify');
const sequelize = require('./src/models/index');
const csvRoutes = require('./src/routes/csvRoutes');
const transactionRoutes = require('./src/routes/transactionRoutes');
const authRoutes = require('./src/routes/authRoutes'); // Existing auth routes
const userRoutes = require('./src/routes/userRoutes'); // New user routes
const employerRoutes = require('./src/routes/employerRoutes');
const employeeRoutes = require('./src/routes/employeeRoutes');
const testnetRoutes = require('./src/routes/testnetRoutes'); // New Testnet routes
const { getIssuerWalletAndJwtSecret } = require('./issuerWallet');
const { getXRPLSettings, parseIssuerWallets, getDefaultIssuerWallet, getXRPLCurrency, getPayoutWallet } = require('./src/config/xrpl');
const xrpl = require('xrpl');
const app = express();
const PORT = process.env.PORT || 3000;
// Enable trust proxy to handle X-Forwarded-For correctly
app.set('trust proxy', true);
// Middleware
app.use(helmet()); // Set security-related HTTP headers
app.use(cors()); // Enable CORS
app.use(express.json()); // Parse JSON bodies
app.use(morgan('combined')); // Log HTTP requests
// Enforce HTTPS in production
if (process.env.NODE_ENV === 'production') {
app.use(enforce.HTTPS({ trustProtoHeader: true }));
}
// Rate Limiting
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests per windowMs
message: 'Too many requests from this IP, please try again later.',
keyGenerator: (req, res) => req.ip, // Explicitly use req.ip for client identification
});
app.use(limiter); // Apply rate limiting to all requests
// Initialize Variables to Hold Wallet and JWT Secret
let issuerWallet;
let jwtSecret;
// Initialize XRPL Client in app.locals
app.locals.xrplClient = null;
app.locals.xrplNetwork = null;
app.locals.issuerWallets = [];
app.locals.xrplCurrency = getXRPLCurrency();
// Routes
app.use('/api/auth', authRoutes);
app.use('/api/users', userRoutes);
app.use('/api/csv', csvRoutes);
app.use('/api/transactions', transactionRoutes);
app.use('/api/employers', employerRoutes);
app.use('/api/employees', employeeRoutes);
app.use('/api/testnet', testnetRoutes); // Mount the new Testnet routes
app.set('etag', false); // disable etag to avoid 304 caching on API responses
// Root Endpoint
app.get('/', (req, res) => {
res.send('XRPayroll Backend is running.');
});
// Config Endpoint (safe subset)
app.get('/api/config', (req, res) => {
res.json({
network: app.locals.xrplNetwork || 'testnet',
issuerAddresses: (app.locals.issuerWallets || []).map((w) => w.address),
currency: app.locals.xrplCurrency,
payoutAddress: app.locals.payoutAddress || null,
});
});
// Centralized Error Handling Middleware
app.use((err, req, res, next) => {
console.error('Unhandled error:', err);
res.status(500).json({ message: 'An unexpected error occurred.' });
});
// Function to start the server after ensuring issuer wallet and JWT secret are loaded
async function startServer() {
try {
const credentials = await getIssuerWalletAndJwtSecret();
issuerWallet = credentials.wallet;
jwtSecret = credentials.jwtSecret;
// Make jwtSecret and issuerWallet available to other modules if needed
app.set('jwtSecret', jwtSecret);
app.set('issuerWallet', issuerWallet);
app.locals.issuerWallets = parseIssuerWallets();
const xrplSettings = getXRPLSettings();
app.locals.xrplNetwork = xrplSettings.network;
app.set('xrplEndpoint', xrplSettings.endpoint);
if (!app.locals.issuerWallets.length && issuerWallet) {
app.locals.issuerWallets = [{ seed: issuerWallet.seed, address: issuerWallet.classicAddress }];
}
const payout = getPayoutWallet();
app.locals.payoutAddress = payout ? payout.address : null;
// Start Server
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
console.log(`Issuer Wallet Address: ${issuerWallet.classicAddress}`);
});
} catch (error) {
console.error('Failed to initialize issuer wallet and JWT secret:', error.message);
process.exit(1);
}
}
startServer();
// Graceful Shutdown
process.on('SIGINT', async () => {
if (app.locals.xrplClient && app.locals.xrplClient.isConnected()) {
await app.locals.xrplClient.disconnect();
console.log('Disconnected from XRPL Testnet.');
}
process.exit();
});