checking end points of icici bank register api
This commit is contained in:
18
.gitignore
vendored
Normal file
18
.gitignore
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
# Dependencies
|
||||
node_modules
|
||||
|
||||
# yarn error logs
|
||||
yarn-error.log
|
||||
|
||||
# Environment varibales
|
||||
.env*
|
||||
!.env*.example
|
||||
|
||||
# Code coverage
|
||||
coverage
|
||||
|
||||
# Public
|
||||
public
|
||||
|
||||
# test
|
||||
test
|
||||
1920
package-lock.json
generated
Normal file
1920
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
30
package.json
Normal file
30
package.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "optifii",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "nodemon src/index",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"description": "",
|
||||
"dependencies": {
|
||||
"axios": "^1.7.7",
|
||||
"compression": "^1.7.4",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.4.5",
|
||||
"express": "^4.21.0",
|
||||
"express-rate-limit": "^7.4.0",
|
||||
"helmet": "^7.1.0",
|
||||
"http-status": "^1.7.4",
|
||||
"morgan": "^1.10.0",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"mysql2": "^3.11.2",
|
||||
"sequelize": "^6.37.3",
|
||||
"winston": "^3.14.2",
|
||||
"xss-clean": "^0.1.4",
|
||||
"yup": "^1.4.0"
|
||||
}
|
||||
}
|
||||
62
src/app.js
Normal file
62
src/app.js
Normal file
@@ -0,0 +1,62 @@
|
||||
const express = require('express');
|
||||
const helmet = require('helmet');
|
||||
const xss = require('xss-clean');
|
||||
const compression = require('compression');
|
||||
const cors = require('cors');
|
||||
const httpStatus = require('http-status');
|
||||
const config = require('./config/config');
|
||||
const morgan = require('./config/morgan');
|
||||
const { authLimiter } = require('./middlewares/rateLimiter');
|
||||
const routes = require('./routes');
|
||||
const { errorConverter, errorHandler } = require('./middlewares/error');
|
||||
const ApiError = require('./utils/handler/ApiError.handler');
|
||||
const path = require('path')
|
||||
|
||||
const app = express();
|
||||
|
||||
if (config.env !== 'test') {
|
||||
app.use(morgan.successHandler);
|
||||
app.use(morgan.errorHandler);
|
||||
}
|
||||
|
||||
// set security HTTP headers
|
||||
// app.use(helmet());
|
||||
|
||||
// parse json request body
|
||||
app.use(express.json());
|
||||
|
||||
// parse urlencoded request body
|
||||
app.use(express.urlencoded({ extended: true }));
|
||||
|
||||
// sanitize request data
|
||||
app.use(xss());
|
||||
|
||||
// gzip compression
|
||||
app.use(compression());
|
||||
|
||||
// enable cors
|
||||
app.use(cors());
|
||||
app.options('*', cors());
|
||||
|
||||
app.use('/public', express.static(path.join(__dirname, '../public')));
|
||||
|
||||
// limit repeated failed requests to auth endpoints
|
||||
if (config.env === 'production') {
|
||||
app.use('/api/v1/auth', authLimiter);
|
||||
}
|
||||
|
||||
// v1 api routes
|
||||
app.use('/api/v1', routes);
|
||||
|
||||
// send back a 404 error for any unknown api request
|
||||
app.use((req, res, next) => {
|
||||
next(new ApiError(httpStatus.NOT_FOUND, 'Not found'));
|
||||
});
|
||||
|
||||
// convert error to ApiError, if needed
|
||||
app.use(errorConverter);
|
||||
|
||||
// handle error
|
||||
app.use(errorHandler);
|
||||
|
||||
module.exports = app;
|
||||
150
src/config/config.js
Normal file
150
src/config/config.js
Normal file
@@ -0,0 +1,150 @@
|
||||
const dotenv = require('dotenv');
|
||||
const path = require('path');
|
||||
const yup = require('yup');
|
||||
const crypto = require('crypto');
|
||||
const algorithm = 'aes-256-cbc';
|
||||
|
||||
dotenv.config({ path: path.join(__dirname, '../../.env') });
|
||||
|
||||
const envVarsSchema = yup.object().shape({
|
||||
NODE_ENV: yup.string().oneOf(['production', 'development', 'test']).required(),
|
||||
PORT: yup.number().default(3000),
|
||||
BY_PASS_OTP: yup.boolean().default(true).required('by pass otp is required'),
|
||||
JWT_SECRET: yup.string().required('JWT secret key is required'),
|
||||
JWT_ACCESS_EXPIRATION_MINUTES: yup.number().default(30).required('minutes after which access tokens expire'),
|
||||
JWT_REFRESH_EXPIRATION_DAYS: yup.number().default(30).required('days after which refresh tokens expire'),
|
||||
JWT_RESET_PASSWORD_EXPIRATION_MINUTES: yup.number()
|
||||
.default(10)
|
||||
.required('minutes after which reset password token expires'),
|
||||
JWT_VERIFY_EMAIL_EXPIRATION_MINUTES: yup.number()
|
||||
.default(10)
|
||||
.required('minutes after which verify email token expires'),
|
||||
SMTP_HOST: yup.string().nullable().required('server that will send the emails'),
|
||||
SMTP_PORT: yup.number().nullable().required('port to connect to the email server'),
|
||||
SMTP_USERNAME: yup.string().nullable().required('username for email server'),
|
||||
SMTP_PASSWORD: yup.string().nullable().required('password for email server'),
|
||||
EMAIL_FROM: yup.string().nullable().required('the from field in the emails sent by the app'),
|
||||
TWILIO_ACCOUNT_SID: yup.string().nullable().required(),
|
||||
TWILIO_AUTH_TOKEN: yup.string().nullable().required(),
|
||||
TWILIO_SMS_FROM: yup.string().nullable().required(),
|
||||
OTP_EXPIRE_IN_MIN: yup.number().nullable(),
|
||||
CODE_SECRET: yup.string().required('Code secret key is required'),
|
||||
ONESIGNAL_APPID: yup.string().required('app id key is required'),
|
||||
ONESIGNAL_REST_APIKEY: yup.string().required('api key is required'),
|
||||
ONESIGNAL_AUTHKEY: yup.string().required('auth key is required'),
|
||||
}).noUnknown();
|
||||
|
||||
|
||||
try {
|
||||
const envVars = envVarsSchema.validateSync(process.env, { abortEarly: false, stripUnknown: true });
|
||||
|
||||
module.exports = {
|
||||
env: envVars?.NODE_ENV,
|
||||
port: envVars?.PORT,
|
||||
byPassOTP: envVars?.BY_PASS_OTP,
|
||||
mysql: {
|
||||
development: {
|
||||
username: "root",
|
||||
password: "root",
|
||||
database: "optifii",
|
||||
host: "127.0.0.1",
|
||||
port: 3306,
|
||||
dialect: "mysql",
|
||||
dialectOptions: {
|
||||
bigNumberStrings: true,
|
||||
},
|
||||
logging: false,
|
||||
define: {
|
||||
freezeTableName: true,
|
||||
},
|
||||
pool: {
|
||||
max: 10, // Maximum number of connection in pool
|
||||
min: 0, // Minimum number of connection in pool
|
||||
acquire: 30000, // Maximum time in ms to acquire a connection
|
||||
idle: 10000, // Maximum time in ms a connection can be idle before being released
|
||||
}
|
||||
},
|
||||
test: {
|
||||
username: "root",
|
||||
password: "root",
|
||||
database: "optifii_test",
|
||||
host: "127.0.0.1",
|
||||
port: 3306,
|
||||
dialect: "mysql",
|
||||
dialectOptions: {
|
||||
bigNumberStrings: true,
|
||||
},
|
||||
logging: false,
|
||||
define: {
|
||||
freezeTableName: true,
|
||||
},
|
||||
pool: {
|
||||
max: 10, // Maximum number of connection in pool
|
||||
min: 0, // Minimum number of connection in pool
|
||||
acquire: 30000, // Maximum time in ms to acquire a connection
|
||||
idle: 10000, // Maximum time in ms a connection can be idle before being released
|
||||
}
|
||||
},
|
||||
production: {
|
||||
username: "mymotukuser",
|
||||
password: "password_Carrot11",
|
||||
database: "optifii_sprint",
|
||||
host: "127.0.0.1",
|
||||
port: 3306,
|
||||
dialect: "mysql",
|
||||
dialectOptions: {
|
||||
bigNumberStrings: true,
|
||||
},
|
||||
logging: false,
|
||||
define: {
|
||||
freezeTableName: true,
|
||||
socketPath: "/var/run/mysqld/mysqld.sock",
|
||||
},
|
||||
pool: {
|
||||
max: 10, // Maximum number of connection in pool
|
||||
min: 0, // Minimum number of connection in pool
|
||||
acquire: 30000, // Maximum time in ms to acquire a connection
|
||||
idle: 10000, // Maximum time in ms a connection can be idle before being released
|
||||
}
|
||||
},
|
||||
},
|
||||
jwt: {
|
||||
secret: envVars?.JWT_SECRET,
|
||||
accessExpirationMinutes: envVars?.JWT_ACCESS_EXPIRATION_MINUTES,
|
||||
refreshExpirationDays: envVars?.JWT_REFRESH_EXPIRATION_DAYS,
|
||||
resetPasswordExpirationMinutes: envVars?.JWT_RESET_PASSWORD_EXPIRATION_MINUTES,
|
||||
verifyEmailExpirationMinutes: envVars?.JWT_VERIFY_EMAIL_EXPIRATION_MINUTES,
|
||||
},
|
||||
email: {
|
||||
smtp: {
|
||||
host: envVars?.SMTP_HOST,
|
||||
port: envVars?.SMTP_PORT,
|
||||
secure: process.env.SMTP_PORT == 465, // true for 465, false for other ports
|
||||
auth: {
|
||||
user: envVars?.SMTP_USERNAME,
|
||||
pass: envVars?.SMTP_PASSWORD,
|
||||
},
|
||||
},
|
||||
from: envVars?.EMAIL_FROM,
|
||||
},
|
||||
SMS: {
|
||||
accountSid: envVars.TWILIO_ACCOUNT_SID,
|
||||
authToken: envVars.TWILIO_AUTH_TOKEN,
|
||||
from: envVars.TWILIO_SMS_FROM,
|
||||
},
|
||||
expiryTime: {
|
||||
otp_in_Min: envVars.OTP_EXPIRE_IN_MIN || 2,
|
||||
},
|
||||
code: {
|
||||
secret: crypto.createHash('sha256').update(envVars.CODE_SECRET).digest(),
|
||||
blacklist: new Set(),
|
||||
},
|
||||
oneSignal:{
|
||||
appID:envVars.ONESIGNAL_APPID,
|
||||
userAuthKey:envVars.ONESIGNAL_AUTHKEY,
|
||||
restApiKey:envVars.ONESIGNAL_REST_APIKEY,
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
throw new Error(`Config validation error: ${Array.isArray(error.errors) ? error?.errors?.join(', ') : error}`);
|
||||
}
|
||||
26
src/config/logger.js
Normal file
26
src/config/logger.js
Normal file
@@ -0,0 +1,26 @@
|
||||
const winston = require('winston');
|
||||
const config = require('./config');
|
||||
|
||||
const enumerateErrorFormat = winston.format((info) => {
|
||||
if (info instanceof Error) {
|
||||
Object.assign(info, { message: info.stack });
|
||||
}
|
||||
return info;
|
||||
});
|
||||
|
||||
const logger = winston.createLogger({
|
||||
level: config.env === 'development' ? 'debug' : 'info',
|
||||
format: winston.format.combine(
|
||||
enumerateErrorFormat(),
|
||||
config.env === 'development' ? winston.format.colorize() : winston.format.uncolorize(),
|
||||
winston.format.splat(),
|
||||
winston.format.printf(({ level, message }) => `${level}: ${message}`)
|
||||
),
|
||||
transports: [
|
||||
new winston.transports.Console({
|
||||
stderrLevels: ['error'],
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
module.exports = logger;
|
||||
24
src/config/morgan.js
Normal file
24
src/config/morgan.js
Normal file
@@ -0,0 +1,24 @@
|
||||
const morgan = require('morgan');
|
||||
const config = require('./config');
|
||||
const logger = require('./logger');
|
||||
|
||||
morgan.token('message', (req, res) => res.locals.errorMessage || '');
|
||||
|
||||
const getIpFormat = () => (config.env === 'production' ? ':remote-addr - ' : '');
|
||||
const successResponseFormat = `${getIpFormat()}:method :url :status - :response-time ms`;
|
||||
const errorResponseFormat = `${getIpFormat()}:method :url :status - :response-time ms - message: :message`;
|
||||
|
||||
const successHandler = morgan(successResponseFormat, {
|
||||
skip: (req, res) => res.statusCode >= 400,
|
||||
stream: { write: (message) => logger.info(message.trim()) },
|
||||
});
|
||||
|
||||
const errorHandler = morgan(errorResponseFormat, {
|
||||
skip: (req, res) => res.statusCode < 400,
|
||||
stream: { write: (message) => logger.error(message.trim()) },
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
successHandler,
|
||||
errorHandler,
|
||||
};
|
||||
60
src/controllers/bankDetails/bankDetails.controller.js
Normal file
60
src/controllers/bankDetails/bankDetails.controller.js
Normal file
@@ -0,0 +1,60 @@
|
||||
const crypto = require('crypto');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const axios = require('axios');
|
||||
|
||||
const bankApi = async (req, res) => {
|
||||
try {
|
||||
const publicKeyPath = path.join(__dirname, 'public_key.pem');
|
||||
const publicKeyPem = fs.readFileSync(publicKeyPath, 'utf8');
|
||||
|
||||
const jsonData = {
|
||||
"AGGRNAME": "CIBTESTING",
|
||||
"AGGRID": "TXBCIBTEST001",
|
||||
"CORPID": "TXBCORP1",
|
||||
"USERID": "USER1",
|
||||
"URN": "TESTING123",
|
||||
"ALIASID": ""
|
||||
};
|
||||
const jsonString = JSON.stringify(jsonData);
|
||||
|
||||
// Encrypt JSON data with the public key
|
||||
const buffer = Buffer.from(jsonString, 'utf-8');
|
||||
const encrypted = crypto.publicEncrypt(
|
||||
{
|
||||
key: publicKeyPem,
|
||||
padding: crypto.constants.RSA_PKCS1_PADDING
|
||||
},
|
||||
buffer
|
||||
);
|
||||
|
||||
// Encode encrypted bytes to Base64
|
||||
const base64Encrypted = encrypted.toString('base64');
|
||||
|
||||
console.log('Base64 Encrypted Data:', base64Encrypted);
|
||||
|
||||
// Make an Axios request
|
||||
const response = await axios.post(
|
||||
'https://apibankingonesandbox.icicibank.com/api/Corporate/CIB_SV/v1/Create',
|
||||
base64Encrypted,
|
||||
{
|
||||
headers: {
|
||||
'accept': "*",
|
||||
'Content-Type': 'text/plain',
|
||||
'apikey': 'COIbAAYzt0SMosd3fFexJlk42uqnPvvu',
|
||||
'x-forwarded-for': '77.68.102.23',
|
||||
'Content-Length': Buffer.byteLength(base64Encrypted).toString()
|
||||
}
|
||||
}
|
||||
);
|
||||
res.status(200).json(response.data);
|
||||
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
res.status(500).json({ error: 'Encryption or API request failed' });
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
bankApi
|
||||
}
|
||||
50
src/controllers/bankDetails/certificate.pem
Normal file
50
src/controllers/bankDetails/certificate.pem
Normal file
@@ -0,0 +1,50 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFhDCCA2wCCQCIqfcsomoC1jANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMCSU4xF
|
||||
DASBgNV
|
||||
BAgMC01BSEFSQVNIVFJBMQ8wDQYDVQQHDAZNVU1CQUkxGDAWBgNVBAoMD0lDSUN
|
||||
JIEJhbmsgTHRk
|
||||
LjEMMAoGA1UECwwDQ0lCMSUwIwYDVQQDDBx3d3cuY2libmV4dGFwaS5pY2ljaWJhbmsuY
|
||||
29tMB4X
|
||||
DTE3MDQxMzA3MTkyOVoXDTIyMDQxMjA3MTkyOVowgYMxCzAJBgNVBAYTAklOMRQwEgY
|
||||
DVQQIDAtN
|
||||
QUhBUkFTSFRSQTEPMA0GA1UEBwwGTVVNQkFJMRgwFgYDVQQKDA9JQ0lDSSBCYW5rI
|
||||
Ex0ZC4xDDAK
|
||||
BgNVBAsMA0NJQjElMCMGA1UEAwwcd3d3LmNpYm5leHRhcGkuaWNpY2liYW5rLmNvbTCC
|
||||
AiIwDQYJ
|
||||
KoZIhvcNAQEBBQADggIPADCCAgoCggIBAM+en2ErEsETmfoZJjf3I5DIc8KAt6dv/ZkKYHcpli1
|
||||
g
|
||||
yLFjJNbZnyk4Um7UaKvU0fpqnsLboapXKR0iHFp4/7SR9kTh4FfvFrrp2pKmQd8f/Rf6OPk2/48i
|
||||
X7sCs0nl8IZYMqe1Tt1YAMFPJjPIH/ERx3vnWYhgHUmRGJqjHfo4NeNR0IarF3HAYX4hh6K0L
|
||||
aAQ
|
||||
hUoq6SuWyWf9m9qzHRHpWq4eJRsbhPYLaTtt8XS+vPpBjFjfQreDtgWdIXwKuHq8EOS/KxBif
|
||||
ThC
|
||||
tEBMGZUSYZBoldq1kdaakkt5FaXhe+g0FWrLcxalaSS4bHK0QCv1Lbh3tcPetCO3XyR1Jj28SL
|
||||
+5
|
||||
gYm464jmjMGURJwocWUhuNd0qAKt8bMv9NCDgKiWSmAlzeznRYeNaay2ckg5aB5tNO5l/8pU
|
||||
h8Ew
|
||||
qLyKECFnCoNvBlcaoJIvZ0sprQO+dHzggT/Q9wl0XRFUkPh4SFGHIiqldy6VgA6I7uVWb7ve1Y3
|
||||
P
|
||||
4yhlfTDV/Hr4ZL4gTFVrorS1a4Tqap38iqHnfM3djwgwbnzv0TJZCywZ5ED8MRDmub6W4jNYMV
|
||||
ar
|
||||
uG1gLVf7gE2sUY/dgTRu1Hdw3/YlOY9XpQebBP37RD3+Up+oEYxjPe04Cy4rTFx9/8SluuBPvw
|
||||
NH
|
||||
WVmHkv1ULNHum0VQ3kej17jbEeO+FftJAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAMGX2
|
||||
dKuXsGj
|
||||
ujhKxZOFzo8A0QKu+nsw+pFtiJ5KjyOR1vW9pOdG7roJJGr6cU5fUDlUpYDDVIvPiVbPYgWLkV
|
||||
e3
|
||||
7+tpM8T77ZYSXdO7G9hhU8uw2pcRHiQMlDotV/RcTGZHyVVaw7TJty3xMH2j0/FIHejcFaYXZY
|
||||
QB
|
||||
A5+zKc7PBsvwn/KQgJ9R4BTqmdWeca1r0+iBXGq1iRg4IGePf0lIc+80AUneC1ceC07RfvI0PJp
|
||||
k
|
||||
LVTkDCXdNK7QtG/cIqjdZ1jtB+ne7cwtksw1ewu5dE3BFNmqdT3DmKHAupTc2ILSup2w/JEEep
|
||||
MI
|
||||
DHO8GvqR0dUXS5xCcXNKwXUMiLPYA56mRKoST5+e2RO5WtVQMHiizEF5iID+WjyXNlVtqM
|
||||
arEjih
|
||||
Z0+/vkABp/Q3AfKs3rtaXxU4crt+RLaaldG/dBXOoUDTpaNR+ktUkNmEPTe9zc7pwwRDC2zNylt
|
||||
4
|
||||
FnhNP2b2t+RLuP+smAROVaXA1owpte3zeh7aiUe02Y6udEzVrKCAvRUiCKoCDH9N101k3lzC
|
||||
Fy80
|
||||
rRquHZ7ZZmUrX4DksuPnSuLILR5ss6UkQTZbg7HXtMN2lDTgPjO2UMCjqI+5gPGTqdld4XWD
|
||||
TEW0
|
||||
xdyhJiEgATeqQllbn47B7C7603ltWFpoInafn2NwxBW89wv938bMKpxFxmQcseGH
|
||||
-----END CERTIFICATE-----
|
||||
14
src/controllers/bankDetails/public_key.pem
Normal file
14
src/controllers/bankDetails/public_key.pem
Normal file
@@ -0,0 +1,14 @@
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAz56fYSsSwROZ+hkmN/cj
|
||||
kMhzwoC3p2/9mQpgdymWLWDIsWMk1tmfKThSbtRoq9TR+mqewtuhqlcpHSIcWnj/
|
||||
tJH2ROHgV+8WuunakqZB3x/9F/o4+Tb/jyJfuwKzSeXwhlgyp7VO3VgAwU8mM8gf
|
||||
8RHHe+dZiGAdSZEYmqMd+jg141HQhqsXccBhfiGHorQtoBCFSirpK5bJZ/2b2rMd
|
||||
Eelarh4lGxuE9gtpO23xdL68+kGMWN9Ct4O2BZ0hfAq4erwQ5L8rEGJ9OEK0QEwZ
|
||||
lRJhkGiV2rWR1pqSS3kVpeF76DQVastzFqVpJLhscrRAK/UtuHe1w960I7dfJHUm
|
||||
PbxIv7mBibjriOaMwZREnChxZSG413SoAq3xsy/00IOAqJZKYCXN7OdFh41prLZy
|
||||
SDloHm007mX/ylSHwTCovIoQIWcKg28GVxqgki9nSymtA750fOCBP9D3CXRdEVSQ
|
||||
+HhIUYciKqV3LpWADoju5VZvu97Vjc/jKGV9MNX8evhkviBMVWuitLVrhOpqnfyK
|
||||
oed8zd2PCDBufO/RMlkLLBnkQPwxEOa5vpbiM1gxVqu4bWAtV/uATaxRj92BNG7U
|
||||
d3Df9iU5j1elB5sE/ftEPf5Sn6gRjGM97TgLLitMXH3/xKW64E+/A0dZWYeS/VQs
|
||||
0e6bRVDeR6PXuNsR474V+0kCAwEAAQ==
|
||||
-----END PUBLIC KEY-----
|
||||
3
src/controllers/index.js
Normal file
3
src/controllers/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.export = {
|
||||
bankDetailsController: require('./bankDetails/bankDetails.controller'),
|
||||
}
|
||||
49
src/index.js
Normal file
49
src/index.js
Normal file
@@ -0,0 +1,49 @@
|
||||
const app = require('./app');
|
||||
const config = require('./config/config');
|
||||
const logger = require('./config/logger');
|
||||
const db = require('./models');
|
||||
// const seed = require('./seed');
|
||||
|
||||
let server;
|
||||
|
||||
db.sequelize
|
||||
.sync({ force: config.env === 'test' })
|
||||
.then(() => {
|
||||
logger.info('Connected to MySQL');
|
||||
// seed(db)
|
||||
server = app.listen(config.port, () => {
|
||||
logger.info(`Server listening on port ${config.port}`)
|
||||
logger.info(`Enviorment :- ${config.env}`);
|
||||
logger.info(`Is OTP by pass :- ${config.byPassOTP}`);
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
logger.error('Error connecting to MySQL:', error);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
const exitHandler = () => {
|
||||
if (server) {
|
||||
server.close(() => {
|
||||
logger.info('Server closed');
|
||||
process.exit(1);
|
||||
});
|
||||
} else {
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
const unexpectedErrorHandler = (error) => {
|
||||
logger.error(error);
|
||||
exitHandler();
|
||||
};
|
||||
|
||||
process.on('uncaughtException', unexpectedErrorHandler);
|
||||
process.on('unhandledRejection', unexpectedErrorHandler);
|
||||
|
||||
process.on('SIGTERM', () => {
|
||||
logger.info('SIGTERM received');
|
||||
if (server) {
|
||||
server.close();
|
||||
}
|
||||
});
|
||||
55
src/middlewares/error.js
Normal file
55
src/middlewares/error.js
Normal file
@@ -0,0 +1,55 @@
|
||||
const { BaseError, ValidationError, UniqueConstraintError } = require("sequelize");
|
||||
const ApiError = require("../utils/handler/ApiError.handler");
|
||||
const config = require("../config/config");
|
||||
const httpStatus = require("http-status");
|
||||
const logger = require("../config/logger");
|
||||
const multer = require("multer");
|
||||
|
||||
const errorConverter = (err, req, res, next) => {
|
||||
let error = err;
|
||||
|
||||
if (error instanceof multer.MulterError) {
|
||||
// Handle Multer errors
|
||||
error = new ApiError(httpStatus.BAD_REQUEST, error.message, error, false, err.stack);
|
||||
} else if (error instanceof ValidationError || error instanceof UniqueConstraintError) {
|
||||
// Handle Sequelize validation and unique constraint errors
|
||||
const messages = error.errors.map(e => e.message);
|
||||
error = new ApiError(httpStatus.BAD_REQUEST, messages.join(", "), error, false, err.stack);
|
||||
} else if (!(error instanceof ApiError)) {
|
||||
// Handle other errors
|
||||
const statusCode =
|
||||
error.statusCode || error instanceof BaseError ? httpStatus.BAD_REQUEST : httpStatus.INTERNAL_SERVER_ERROR;
|
||||
const message = error.message || httpStatus[statusCode];
|
||||
error = new ApiError(statusCode, message, error, false, err.stack);
|
||||
}
|
||||
|
||||
next(error);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const errorHandler = (err, req, res, next) => {
|
||||
let { statusCode, message } = err;
|
||||
if (config.env === 'production' && !err.isOperational) {
|
||||
statusCode = httpStatus.INTERNAL_SERVER_ERROR;
|
||||
message = httpStatus[httpStatus.INTERNAL_SERVER_ERROR];
|
||||
}
|
||||
|
||||
res.locals.errorMessage = err.message;
|
||||
|
||||
const response = {
|
||||
code: statusCode,
|
||||
message,
|
||||
...(config.env === 'development' && { stack: err.stack }),
|
||||
};
|
||||
|
||||
if (config.env === 'development') {
|
||||
logger.error(err);
|
||||
}
|
||||
|
||||
res.status(statusCode).send(response);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
errorConverter,
|
||||
errorHandler,
|
||||
};
|
||||
11
src/middlewares/rateLimiter.js
Normal file
11
src/middlewares/rateLimiter.js
Normal file
@@ -0,0 +1,11 @@
|
||||
const rateLimit = require('express-rate-limit');
|
||||
|
||||
const authLimiter = rateLimit({
|
||||
windowMs: 15 * 60 * 1000,
|
||||
max: 100,
|
||||
skipSuccessfulRequests: true,
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
authLimiter,
|
||||
};
|
||||
39
src/models/index.js
Normal file
39
src/models/index.js
Normal file
@@ -0,0 +1,39 @@
|
||||
"use strict";
|
||||
|
||||
const { Sequelize } = require("sequelize");
|
||||
const config = require("../config/config");
|
||||
const logger = require("../config/logger");
|
||||
|
||||
// Initialize Sequelize instance
|
||||
const sequelize = new Sequelize(
|
||||
config.mysql[config.env].database,
|
||||
config.mysql[config.env].username,
|
||||
config.mysql[config.env].password,
|
||||
config.mysql[config.env]
|
||||
);
|
||||
|
||||
// Test database connection
|
||||
sequelize
|
||||
.authenticate()
|
||||
.then(() => logger.info("Connection has been established successfully."))
|
||||
.catch((error) => logger.error("Unable to connect to the database: ", error));
|
||||
|
||||
// Load models
|
||||
const db = {};
|
||||
|
||||
|
||||
// db.bank_details = require('./main/bank_details.model')(sequelize);
|
||||
|
||||
// Handle model associations
|
||||
(async () => {
|
||||
for (const modelName of Object.keys(db)) {
|
||||
if (db[modelName].associate) {
|
||||
await db[modelName].associate(db);
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
db.sequelize = sequelize;
|
||||
db.Sequelize = Sequelize;
|
||||
|
||||
module.exports = db;
|
||||
69
src/routes/index.js
Normal file
69
src/routes/index.js
Normal file
@@ -0,0 +1,69 @@
|
||||
const express = require('express');
|
||||
const { bankApi } = require('../controllers/bankDetails/bankDetails.controller'); // Adjust the path to your controller
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
// Define your route here
|
||||
router.post('/bankDetails/create', bankApi); // Define the route directly in this file
|
||||
|
||||
module.exports = router;
|
||||
|
||||
|
||||
// const express = require('express');
|
||||
// const router = express.Router();
|
||||
|
||||
// // Ensure the correct path to your route file
|
||||
// const defaultRoutes = [
|
||||
// {
|
||||
// path: '/bankDetails',
|
||||
// route: require('./bankDetails.route'), // Check this path
|
||||
// },
|
||||
// ];
|
||||
|
||||
// defaultRoutes.forEach((route) => {
|
||||
// router.use(route.path, route.route);
|
||||
// });
|
||||
|
||||
// module.exports = router;
|
||||
|
||||
// // const express = require('express');
|
||||
|
||||
// // const router = express.Router();
|
||||
|
||||
// // const defaultRoutes = [
|
||||
// // {
|
||||
// // path: '/bankDetails',
|
||||
// // route: require('./bankDetails.route'),
|
||||
// // },
|
||||
// // ];
|
||||
|
||||
// // defaultRoutes.forEach((route) => {
|
||||
// // router.use(route.path, route.route);
|
||||
// // });
|
||||
|
||||
// // module.exports = router;
|
||||
|
||||
|
||||
|
||||
|
||||
// // const express = require('express');;
|
||||
// // const config = require('../../config/config');
|
||||
|
||||
// // const router = express.Router();
|
||||
|
||||
// // const defaultRoutes = [
|
||||
// // {
|
||||
// // path: '/bankDetails',
|
||||
// // route: require('./bankDetails')
|
||||
// // },
|
||||
// // ];
|
||||
|
||||
|
||||
// // /* istanbul ignore next */
|
||||
// // // if (config.env === 'development') {
|
||||
// // // devRoutes.forEach((route) => {
|
||||
// // // router.use(route.path, route.route);
|
||||
// // // })
|
||||
// // // }
|
||||
|
||||
// // module.exports = router;
|
||||
41
src/utils/handler/ApiError.handler.js
Normal file
41
src/utils/handler/ApiError.handler.js
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Custom error class for handling API errors. Extends the native Error class.
|
||||
* @class ApiError
|
||||
* @extends Error
|
||||
*
|
||||
* @param {number} statusCode - HTTP status code associated with the error.
|
||||
* @param {string} [message="Something went wrong"] - Error message (default is a generic message).
|
||||
* @param {Array} [errors=[]] - Array containing specific error details or additional information.
|
||||
* @param {boolean} [isOperational=true] - Indicates if the error is operational or not.
|
||||
* @param {string} [stack=""] - Stack trace for the error (optional, defaults to an empty string).
|
||||
*/
|
||||
class ApiError extends Error {
|
||||
constructor(
|
||||
statusCode,
|
||||
message = "Something went wrong",
|
||||
errors = [],
|
||||
isOperational = true,
|
||||
stack = ""
|
||||
) {
|
||||
// Call the constructor of the parent class (Error)
|
||||
super(message);
|
||||
|
||||
// Custom properties for API error handling
|
||||
this.statusCode = statusCode; // HTTP status code associated with the error.
|
||||
this.data = null; // Additional data associated with the error (initially set to null).
|
||||
this.message = message; // Error message for the API response.
|
||||
this.success = false; // Indicates the failure nature of the API request.
|
||||
this.errors = errors; // Specific error details or additional information.
|
||||
this.isOperational = isOperational; // Indicates if the error is operational or not.
|
||||
|
||||
// Set the stack trace if provided; otherwise, capture the current stack trace.
|
||||
if (stack) {
|
||||
this.stack = stack; // Provided stack trace.
|
||||
} else {
|
||||
Error.captureStackTrace(this, this.constructor); // Capture the current stack trace.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Export the ApiError class for use in other modules.
|
||||
module.exports = ApiError;
|
||||
19
src/utils/handler/ApiResponse.handler.js
Normal file
19
src/utils/handler/ApiResponse.handler.js
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Class representing a standard API response.
|
||||
* @class ApiResponse
|
||||
*
|
||||
* @param {number} statusCode - HTTP status code associated with the response.
|
||||
* @param {any} data - Data to be returned in the response.
|
||||
* @param {string} [message="Success"] - Response message (default is "Success").
|
||||
*/
|
||||
class ApiResponse {
|
||||
constructor(statusCode, data, message = "Success") {
|
||||
this.statusCode = statusCode; // HTTP status code associated with the response.
|
||||
this.data = data; // Data to be returned in the response.
|
||||
this.message = message; // Response message (default is "Success").
|
||||
this.success = statusCode < 400; // Indicates if the response is successful based on the status code.
|
||||
}
|
||||
}
|
||||
|
||||
// Export the ApiResponse class for use in other modules.
|
||||
module.exports = ApiResponse;
|
||||
11
src/utils/handler/Async.handler.js
Normal file
11
src/utils/handler/Async.handler.js
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Asynchronous error handler for Express routes.
|
||||
* @function AsyncHandler
|
||||
*
|
||||
* @param {Function} fn - Asynchronous function to be executed.
|
||||
* @returns {Function} Middleware function that handles errors for asynchronous routes.
|
||||
*/
|
||||
module.exports.AsyncHandler = (fn) => (req, res, next) => {
|
||||
// Wrap the asynchronous function in a promise and handle any errors by passing them to the next middleware.
|
||||
Promise.resolve(fn(req, res, next)).catch(next);
|
||||
};
|
||||
21
src/utils/handler/pick.handler.js
Normal file
21
src/utils/handler/pick.handler.js
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Create an object composed of the picked object properties.
|
||||
* @function pick
|
||||
*
|
||||
* @param {Object} object - The source object to pick properties from.
|
||||
* @param {string[]} keys - The array of property names to pick from the source object.
|
||||
* @returns {Object} New object with only the picked properties.
|
||||
*/
|
||||
const pick = (object, keys) => {
|
||||
return keys.reduce((obj, key) => {
|
||||
// Check if the object has the specified property
|
||||
if (object && Object.prototype.hasOwnProperty.call(object, key)) {
|
||||
obj[key] = object[key]; // Assign the property to the new object
|
||||
}
|
||||
return obj; // Return the new object
|
||||
}, {}); // Initialize the new object as an empty object
|
||||
};
|
||||
|
||||
// Export the pick function for use in other modules.
|
||||
module.exports = pick;
|
||||
|
||||
Reference in New Issue
Block a user