-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a3427cf
commit 222c8f6
Showing
69 changed files
with
10,762 additions
and
0 deletions.
There are no files selected for viewing
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import WebSocket from 'ws'; | ||
import url from 'url'; | ||
import security from './security'; | ||
|
||
let wss = null; | ||
|
||
const listen = server => { | ||
wss = new WebSocket.Server({ | ||
path: '/ws/dashboard', //Accept only connections matching this path | ||
maxPayload: 1024, //The maximum allowed message size | ||
backlog: 100, //The maximum length of the queue of pending connections. | ||
verifyClient: verifyClient, //An hook to reject connections | ||
server //A pre-created HTTP/S server to use | ||
}); | ||
|
||
wss.on('connection', onConnection); | ||
wss.broadcast = broadcastToAll; | ||
}; | ||
|
||
const getTokenFromRequestPath = requestPath => { | ||
try { | ||
const urlObj = url.parse(requestPath, true); | ||
return urlObj.query.token; | ||
} catch (e) { | ||
return null; | ||
} | ||
}; | ||
|
||
const verifyClient = (info, done) => { | ||
if (security.DEVELOPER_MODE === true) { | ||
done(true); | ||
} else { | ||
const requestPath = info.req.url; | ||
const token = getTokenFromRequestPath(requestPath); | ||
security | ||
.verifyToken(token) | ||
.then(tokenDecoded => { | ||
// TODO: check access to dashboard | ||
done(true); | ||
}) | ||
.catch(err => { | ||
done(false, 401); | ||
}); | ||
} | ||
}; | ||
|
||
const onConnection = (ws, req) => { | ||
// TODO: ws.user = token.email | ||
ws.on('error', () => {}); | ||
}; | ||
|
||
const broadcastToAll = data => { | ||
wss.clients.forEach(client => { | ||
if (client.readyState === WebSocket.OPEN) { | ||
client.send(data, error => {}); | ||
} | ||
}); | ||
}; | ||
|
||
const send = ({ event, payload }) => { | ||
wss.broadcast(JSON.stringify({ event, payload })); | ||
}; | ||
|
||
const events = { | ||
ORDER_CREATED: 'order.created', | ||
THEME_INSTALLED: 'theme.installed' | ||
}; | ||
|
||
export default { | ||
listen: listen, | ||
send: send, | ||
events: events | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import winston from 'winston'; | ||
const LOGS_FILE = 'logs/server.log'; | ||
|
||
winston.configure({ | ||
transports: [ | ||
new winston.transports.Console({ | ||
level: 'debug', | ||
handleExceptions: true, | ||
format: winston.format.combine( | ||
winston.format.colorize(), | ||
winston.format.simple() | ||
) | ||
}), | ||
new winston.transports.File({ | ||
level: 'info', | ||
handleExceptions: true, | ||
format: winston.format.json(), | ||
filename: LOGS_FILE | ||
}) | ||
] | ||
}); | ||
|
||
const getResponse = message => ({ | ||
error: true, | ||
message | ||
}); | ||
|
||
const logUnauthorizedRequests = req => { | ||
// todo | ||
}; | ||
|
||
const sendResponse = (err, req, res, next) => { | ||
if (err && err.name === 'UnauthorizedError') { | ||
logUnauthorizedRequests(req); | ||
res.status(401).send(getResponse(err.message)); | ||
} else if (err) { | ||
winston.error(err.stack); | ||
res.status(500).send(getResponse(err.message)); | ||
} else { | ||
next(); | ||
} | ||
}; | ||
|
||
export default { | ||
sendResponse | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import winston from 'winston'; | ||
import nodemailer from 'nodemailer'; | ||
import smtpTransport from 'nodemailer-smtp-transport'; | ||
import settings from './settings'; | ||
import EmailSettingsService from '../services/settings/email'; | ||
|
||
const SMTP_FROM_CONFIG_FILE = { | ||
host: settings.smtpServer.host, | ||
port: settings.smtpServer.port, | ||
secure: settings.smtpServer.secure, | ||
auth: { | ||
user: settings.smtpServer.user, | ||
pass: settings.smtpServer.pass | ||
} | ||
}; | ||
|
||
const getSmtpFromEmailSettings = emailSettings => { | ||
return { | ||
host: emailSettings.host, | ||
port: emailSettings.port, | ||
secure: emailSettings.port === 465, | ||
auth: { | ||
user: emailSettings.user, | ||
pass: emailSettings.pass | ||
} | ||
}; | ||
}; | ||
|
||
const getSmtp = emailSettings => { | ||
const useSmtpServerFromConfigFile = emailSettings.host === ''; | ||
const smtp = useSmtpServerFromConfigFile | ||
? SMTP_FROM_CONFIG_FILE | ||
: getSmtpFromEmailSettings(emailSettings); | ||
|
||
return smtp; | ||
}; | ||
|
||
const sendMail = (smtp, message) => { | ||
return new Promise((resolve, reject) => { | ||
if (!message.to.includes('@')) { | ||
reject('Invalid email address'); | ||
return; | ||
} | ||
|
||
const transporter = nodemailer.createTransport(smtpTransport(smtp)); | ||
transporter.sendMail(message, (err, info) => { | ||
if (err) { | ||
reject(err); | ||
} else { | ||
resolve(info); | ||
} | ||
}); | ||
}); | ||
}; | ||
|
||
const getFrom = emailSettings => { | ||
const useSmtpServerFromConfigFile = emailSettings.host === ''; | ||
return useSmtpServerFromConfigFile | ||
? `"${settings.smtpServer.fromName}" <${settings.smtpServer.fromAddress}>` | ||
: `"${emailSettings.from_name}" <${emailSettings.from_address}>`; | ||
}; | ||
|
||
const send = async message => { | ||
const emailSettings = await EmailSettingsService.getEmailSettings(); | ||
const smtp = getSmtp(emailSettings); | ||
message.from = getFrom(emailSettings); | ||
|
||
try { | ||
const result = await sendMail(smtp, message); | ||
winston.info('Email sent', result); | ||
return true; | ||
} catch (e) { | ||
winston.error('Email send failed', e); | ||
return false; | ||
} | ||
}; | ||
|
||
export default { | ||
send: send | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import winston from 'winston'; | ||
import url from 'url'; | ||
import { MongoClient } from 'mongodb'; | ||
import settings from './settings'; | ||
|
||
const mongodbConnection = settings.mongodbServerUrl; | ||
const mongoPathName = url.parse(mongodbConnection).pathname; | ||
const dbName = mongoPathName.substring(mongoPathName.lastIndexOf('/') + 1); | ||
|
||
const RECONNECT_INTERVAL = 1000; | ||
const CONNECT_OPTIONS = { | ||
reconnectTries: 3600, | ||
reconnectInterval: RECONNECT_INTERVAL, | ||
useNewUrlParser: true | ||
}; | ||
|
||
const onClose = () => { | ||
winston.info('MongoDB connection was closed'); | ||
}; | ||
|
||
const onReconnect = () => { | ||
winston.info('MongoDB reconnected'); | ||
}; | ||
|
||
export let db = null; | ||
|
||
const connectWithRetry = () => { | ||
MongoClient.connect( | ||
mongodbConnection, | ||
CONNECT_OPTIONS, | ||
(err, client) => { | ||
if (err) { | ||
winston.error( | ||
`MongoDB connection was failed: ${err.message}`, | ||
err.message | ||
); | ||
setTimeout(connectWithRetry, RECONNECT_INTERVAL); | ||
} else { | ||
db = client.db(dbName); | ||
db.on('close', onClose); | ||
db.on('reconnect', onReconnect); | ||
winston.info('MongoDB connected successfully'); | ||
} | ||
} | ||
); | ||
}; | ||
|
||
connectWithRetry(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
import { ObjectID } from 'mongodb'; | ||
|
||
const getString = value => (value || '').toString(); | ||
|
||
const getDateIfValid = value => { | ||
const date = Date.parse(value); | ||
return isNaN(date) ? null : new Date(date); | ||
}; | ||
|
||
const getArrayIfValid = value => { | ||
return Array.isArray(value) ? value : null; | ||
}; | ||
|
||
const getArrayOfObjectID = value => { | ||
if (Array.isArray(value) && value.length > 0) { | ||
return value.map(id => getObjectIDIfValid(id)).filter(id => !!id); | ||
} else { | ||
return []; | ||
} | ||
}; | ||
|
||
const isNumber = value => !isNaN(parseFloat(value)) && isFinite(value); | ||
|
||
const getNumberIfValid = value => (isNumber(value) ? parseFloat(value) : null); | ||
|
||
const getNumberIfPositive = value => { | ||
const n = getNumberIfValid(value); | ||
return n && n >= 0 ? n : null; | ||
}; | ||
|
||
const getBooleanIfValid = (value, defaultValue = null) => { | ||
if (value === 'true' || value === 'false') { | ||
return value === 'true'; | ||
} else { | ||
return typeof value === 'boolean' ? value : defaultValue; | ||
} | ||
}; | ||
|
||
const getObjectIDIfValid = value => { | ||
return ObjectID.isValid(value) ? new ObjectID(value) : null; | ||
}; | ||
|
||
const getBrowser = browser => { | ||
return browser | ||
? { | ||
ip: getString(browser.ip), | ||
user_agent: getString(browser.user_agent) | ||
} | ||
: { | ||
ip: '', | ||
user_agent: '' | ||
}; | ||
}; | ||
|
||
const getCustomerAddress = address => { | ||
let coordinates = { | ||
latitude: '', | ||
longitude: '' | ||
}; | ||
|
||
if (address && address.coordinates) { | ||
coordinates.latitude = address.coordinates.latitude; | ||
coordinates.longitude = address.coordinates.longitude; | ||
} | ||
|
||
return address | ||
? { | ||
id: new ObjectID(), | ||
address1: getString(address.address1), | ||
address2: getString(address.address2), | ||
city: getString(address.city), | ||
country: getString(address.country).toUpperCase(), | ||
state: getString(address.state), | ||
phone: getString(address.phone), | ||
postal_code: getString(address.postal_code), | ||
full_name: getString(address.full_name), | ||
company: getString(address.company), | ||
tax_number: getString(address.tax_number), | ||
coordinates: coordinates, | ||
details: address.details, | ||
default_billing: false, | ||
default_shipping: false | ||
} | ||
: {}; | ||
}; | ||
|
||
const getOrderAddress = address => { | ||
let coordinates = { | ||
latitude: '', | ||
longitude: '' | ||
}; | ||
|
||
if (address && address.coordinates) { | ||
coordinates.latitude = address.coordinates.latitude; | ||
coordinates.longitude = address.coordinates.longitude; | ||
} | ||
|
||
const emptyAddress = { | ||
address1: '', | ||
address2: '', | ||
city: '', | ||
country: '', | ||
state: '', | ||
phone: '', | ||
postal_code: '', | ||
full_name: '', | ||
company: '', | ||
tax_number: '', | ||
coordinates: coordinates, | ||
details: null | ||
}; | ||
|
||
return address | ||
? Object.assign( | ||
{}, | ||
{ | ||
address1: getString(address.address1), | ||
address2: getString(address.address2), | ||
city: getString(address.city), | ||
country: getString(address.country).toUpperCase(), | ||
state: getString(address.state), | ||
phone: getString(address.phone), | ||
postal_code: getString(address.postal_code), | ||
full_name: getString(address.full_name), | ||
company: getString(address.company), | ||
tax_number: getString(address.tax_number), | ||
coordinates: coordinates, | ||
details: address.details | ||
}, | ||
address | ||
) | ||
: emptyAddress; | ||
}; | ||
|
||
export default { | ||
getString: getString, | ||
getObjectIDIfValid: getObjectIDIfValid, | ||
getDateIfValid: getDateIfValid, | ||
getArrayIfValid: getArrayIfValid, | ||
getArrayOfObjectID: getArrayOfObjectID, | ||
getNumberIfValid: getNumberIfValid, | ||
getNumberIfPositive: getNumberIfPositive, | ||
getBooleanIfValid: getBooleanIfValid, | ||
getBrowser: getBrowser, | ||
getCustomerAddress: getCustomerAddress, | ||
getOrderAddress: getOrderAddress | ||
}; |
Oops, something went wrong.