Преглед изворни кода

Merge pull request #181 from thedevs-network/use-env

Use .env instead of config files
Pouria Ezzati пре 6 година
родитељ
комит
caa1914354

+ 0 - 1
.env

@@ -1 +0,0 @@
-TEST=test

+ 55 - 0
.example.env

@@ -0,0 +1,55 @@
+# App port to run on
+PORT=3000
+
+# The domain that this website is on
+DEFAULT_DOMAIN="localhost:3000"
+
+# Neo4j database credential details
+DB_URI="bolt://localhost"
+DB_USERNAME=
+DB_PASSWORD=
+
+# Redis host and port
+REDIS_DISABLED=false
+REDIS_HOST="127.0.0.1"
+REDIS_PORT=6379
+REDIS_PASSWORD=
+
+# The daily limit for each user
+USER_LIMIT_PER_DAY=50
+
+# A passphrase to encrypt JWT. Use a long and secure key.
+JWT_SECRET=securekey
+
+# Admin emails so they can access admin actions on settings page
+# Comma seperated
+ADMIN_EMAILS=
+
+# Invisible reCaptcha secret key
+# Create one in https://www.google.com/recaptcha/intro/
+RECAPTCHA_SITE_KEY=
+RECAPTCHA_SECRET_KEY=
+
+# Google Cloud API to prevent from users from submitting malware URLs.
+# Get it from https://developers.google.com/safe-browsing/v4/get-started
+GOOGLE_SAFE_BROWSING_KEY=
+
+# Google Analytics tracking ID for universal analytics.
+# Example: UA-XXXX-XX
+GOOGLE_ANALYTICS=
+
+# Your email host details to use to send verification emails.
+# More info on http://nodemailer.com/
+# Mail from example "Kutt <support@kutt.it>". Leave empty to use MAIL_USER
+MAIL_HOST=
+MAIL_PORT=
+MAIL_SECURE=
+MAIL_USER=
+MAIL_FROM=
+MAIL_PASSWORD=
+
+# The email address that will receive submitted reports.
+REPORT_MAIL=
+
+# Support email to show on the app
+CONTACT_EMAIL=

+ 4 - 1
.gitignore

@@ -1,5 +1,8 @@
+.env
 .vscode/
 client/.next/
 node_modules/
 client/config.js
-server/config.js
+client/old.config.js
+server/config.js
+server/old.config.js

+ 55 - 0
.template.env

@@ -0,0 +1,55 @@
+# App port to run on
+PORT={{PORT}}
+
+# The domain that this website is on
+DEFAULT_DOMAIN={{DEFAULT_DOMAIN}}
+
+# Neo4j database credential details
+DB_URI={{DB_URI}}
+DB_USERNAME={{DB_USERNAME}}
+DB_PASSWORD={{DB_PASSWORD}}
+
+# Redis host and port
+REDIS_DISABLED={{REDIS_DISABLED}}
+REDIS_HOST={{REDIS_HOST}}
+REDIS_PORT={{REDIS_PORT}}
+REDIS_PASSWORD={{REDIS_PASSWORD}}
+
+# The daily limit for each user
+USER_LIMIT_PER_DAY={{USER_LIMIT_PER_DAY}}
+
+# A passphrase to encrypt JWT. Use a long and secure key.
+JWT_SECRET={{JWT_SECRET}}
+
+# Admin emails so they can access admin actions on settings page
+# Comma seperated
+ADMIN_EMAILS={{ADMIN_EMAILS}}
+
+# Invisible reCaptcha secret key
+# Create one in https://www.google.com/recaptcha/intro/
+RECAPTCHA_SITE_KEY={{RECAPTCHA_SITE_KEY}}
+RECAPTCHA_SECRET_KEY={{RECAPTCHA_SECRET_KEY}}
+
+# Google Cloud API to prevent from users from submitting malware URLs.
+# Get it from https://developers.google.com/safe-browsing/v4/get-started
+GOOGLE_SAFE_BROWSING_KEY={{GOOGLE_SAFE_BROWSING_KEY}}
+
+# Google Analytics tracking ID for universal analytics.
+# Example: UA-XXXX-XX
+GOOGLE_ANALYTICS={{GOOGLE_ANALYTICS}}
+
+# Your email host details to use to send verification emails.
+# More info on http://nodemailer.com/
+# Mail from example "Kutt <support@kutt.it>". Leave empty to use MAIL_USER
+MAIL_HOST={{MAIL_HOST}}
+MAIL_PORT={{MAIL_PORT}}
+MAIL_SECURE={{MAIL_SECURE}}
+MAIL_USER={{MAIL_USER}}
+MAIL_FROM={{MAIL_FROM}}
+MAIL_PASSWORD={{MAIL_PASSWORD}}
+
+# The email address that will receive submitted reports.
+REPORT_MAIL={{REPORT_MAIL}}
+
+# Support email to show on the app
+CONTACT_EMAIL={{CONTACT_EMAIL}}

+ 0 - 4
.travis.yml

@@ -3,10 +3,6 @@ language: node_js
 node_js:
   - "9"
 
-before_install:
-  - cp ./server/config.example.js ./server/config.js
-  - cp ./client/config.example.js ./client/config.js
-
 script:
   - yarn run lint:nofix
   - yarn test

+ 1 - 1
README.md

@@ -47,7 +47,7 @@
 You need to have [Node.js](https://nodejs.org/), [Neo4j](https://neo4j.com/) and [Redis](https://redis.io/) installed on your machine.
 
 1. Clone this repository or [download zip](https://github.com/thedevs-network/kutt/archive/develop.zip).
-2. Copy `config.example.js` to `config.js` in both server and client folders and fill them properly.
+2. Copy `.example.env` to `.env`  and fill it properly.
 3. Install dependencies: `npm install`.
 4. Start Neo4j database.
 5. Run for development: `npm run dev`.

+ 1 - 2
client/components/BodyWrapper/BodyWrapper.js

@@ -8,7 +8,6 @@ import Header from '../Header';
 import PageLoading from '../PageLoading';
 import { renewAuthUser, hidePageLoading } from '../../actions';
 import { initGA, logPageView } from '../../helpers/analytics';
-import { GOOGLE_ANALYTICS_ID } from '../../config';
 
 const Wrapper = styled.div`
   position: relative;
@@ -43,7 +42,7 @@ const ContentWrapper = styled.div`
 
 class BodyWrapper extends React.Component {
   componentDidMount() {
-    if (GOOGLE_ANALYTICS_ID) {
+    if (process.env.GOOGLE_ANALYTICS_ID) {
       if (!window.GA_INITIALIZED) {
         initGA();
         window.GA_INITIALIZED = true;

+ 2 - 3
client/components/Footer/Footer.js

@@ -4,7 +4,6 @@ import { connect } from 'react-redux';
 import styled from 'styled-components';
 import ReCaptcha from './ReCaptcha';
 import showRecaptcha from '../../helpers/recaptcha';
-import config from '../../config';
 
 const Wrapper = styled.footer`
   width: 100%;
@@ -61,10 +60,10 @@ class Footer extends Component {
           <a href="/report" title="Report abuse">
             Report Abuse
           </a>
-          {config.CONTACT_EMAIL && (
+          {process.env.CONTACT_EMAIL && (
             <Fragment>
               {' | '}
-              <a href={`mailto:${config.CONTACT_EMAIL}`} title="Contact us">
+              <a href={`mailto:${process.env.CONTACT_EMAIL}`} title="Contact us">
                 Contact us
               </a>
             </Fragment>

+ 1 - 2
client/components/Footer/ReCaptcha.js

@@ -1,6 +1,5 @@
 import React from 'react';
 import styled from 'styled-components';
-import config from '../../config';
 
 const Recaptcha = styled.div`
   display: flex;
@@ -11,7 +10,7 @@ const ReCaptcha = () => (
   <Recaptcha
     id="g-recaptcha"
     className="g-recaptcha"
-    data-sitekey={config.RECAPTCHA_SITE_KEY}
+    data-sitekey={process.env.RECAPTCHA_SITE_KEY}
     data-callback="recaptchaCallback"
     data-size="invisible"
     data-badge="inline"

+ 0 - 16
client/config.example.js

@@ -1,16 +0,0 @@
-module.exports = {
-  /*
-    Invisible reCaptcha site key
-    Create one in https://www.google.com/recaptcha/intro/
-  */
-  RECAPTCHA_SITE_KEY: '',
-
-  // Google analytics tracking ID
-  GOOGLE_ANALYTICS_ID: '',
-
-  // Contact email address
-  CONTACT_EMAIL: '',
-
-  // Report email address
-  REPORT_EMAIL: '',
-};

+ 1 - 2
client/helpers/analytics.js

@@ -1,8 +1,7 @@
 import ReactGA from 'react-ga';
-import { GOOGLE_ANALYTICS_ID } from '../config';
 
 export const initGA = () => {
-  ReactGA.initialize(GOOGLE_ANALYTICS_ID);
+  ReactGA.initialize(process.env.GOOGLE_ANALYTICS_ID);
 };
 
 export const logPageView = () => {

+ 1 - 2
client/pages/report.js

@@ -3,7 +3,6 @@ import styled from 'styled-components';
 import axios from 'axios';
 import BodyWrapper from '../components/BodyWrapper';
 import { authUser } from '../actions';
-import { REPORT_EMAIL } from '../config';
 import TextInput from '../components/TextInput';
 import Button from '../components/Button';
 
@@ -98,7 +97,7 @@ class ReportPage extends Component {
             Report abuses, malware and phishing links to the below email address or use the form. We
             will take actions shortly.
           </p>
-          <p>{REPORT_EMAIL}</p>
+          <p>{(process.env.REPORT_EMAIL || '').replace('@', '[at]')}</p>
           <p>
             <b>URL containting malware/scam:</b>
           </p>

+ 10 - 0
next.config.js

@@ -0,0 +1,10 @@
+const { parsed: localEnv } = require('dotenv').config();
+const webpack = require('webpack'); // eslint-disable-line
+
+module.exports = {
+  webpack(config) {
+    config.plugins.push(new webpack.EnvironmentPlugin(localEnv));
+
+    return config;
+  },
+};

Разлика између датотеке није приказан због своје велике величине
+ 211 - 504
package-lock.json


+ 1 - 0
package.json

@@ -36,6 +36,7 @@
     "cookie-parser": "^1.4.4",
     "cors": "^2.8.5",
     "date-fns": "^1.30.1",
+    "dotenv": "^8.0.0",
     "email-validator": "^1.2.3",
     "express": "^4.16.4",
     "express-validator": "^4.3.0",

+ 0 - 63
server/config.example.js

@@ -1,63 +0,0 @@
-module.exports = {
-  PORT: 3000,
-
-  /* The domain that this website is on */
-  DEFAULT_DOMAIN: 'kutt.it',
-
-  /* Neo4j database credential details */
-  DB_URI: 'bolt://localhost',
-  DB_USERNAME: '',
-  DB_PASSWORD: '',
-
-  /* Redis host and port */
-  REDIS_DISABLED: false,
-  REDIS_HOST: '127.0.0.1',
-  REDIS_PORT: 6379,
-  REDIS_PASSWORD: '',
-
-  /* The daily limit for each user */
-  USER_LIMIT_PER_DAY: 50,
-
-  /* A passphrase to encrypt JWT. Use a long and secure key. */
-  JWT_SECRET: 'securekey',
-
-  /*
-    Admin emails so they can access admin actions on settings page
-    Array of strings
-  */
-  ADMIN_EMAILS: [],
-
-  /*
-    Invisible reCaptcha secret key
-    Create one in https://www.google.com/recaptcha/intro/
-  */
-  RECAPTCHA_SECRET_KEY: '',
-
-  /* 
-    Google Cloud API to prevent from users from submitting malware URLs.
-    Get it from https://developers.google.com/safe-browsing/v4/get-started
-  */
-  GOOGLE_SAFE_BROWSING_KEY: '',
-
-  /* 
-    Google Analytics tracking ID for universal analytics.
-    Example: UA-XXXX-XX
-  */
-  GOOGLE_ANALYTICS: '',
-
-  /*
-    Your email host details to use to send verification emails.
-    More info on http://nodemailer.com/
-  */
-  MAIL_HOST: '',
-  MAIL_PORT: 587,
-  MAIL_SECURE: false,
-  MAIL_USER: '',
-  MAIL_FROM: '', // Example: "Kutt <support@kutt.it>". Leave empty to use MAIL_USER
-  MAIL_PASSWORD: '',
-
-  /*
-    The email address that will receive submitted reports.
-  */
-  REPORT_MAIL: '',
-};

+ 51 - 0
server/configToEnv.js

@@ -0,0 +1,51 @@
+/* eslint-disable global-require */
+/* eslint-disable import/no-unresolved */
+const fs = require('fs');
+const path = require('path');
+
+const hasServerConfig = fs.existsSync(path.resolve(__dirname, 'config.js'));
+const hasClientConfig = fs.existsSync(path.resolve(__dirname, '../client/config.js'));
+
+if (hasServerConfig && hasClientConfig) {
+  const serverConfig = require('./config.js');
+  const clientConfig = require('../client/config.js');
+  let envTemplate = fs.readFileSync(path.resolve(__dirname, '../.template.env'), 'utf-8');
+
+  const configs = {
+    PORT: serverConfig.PORT || 3000,
+    DEFAULT_DOMAIN: serverConfig.DEFAULT_DOMAIN || 'localhost:3000',
+    DB_URI: serverConfig.DB_URI || 'bolt://localhost',
+    DB_USERNAME: serverConfig.DB_USERNAME,
+    DB_PASSWORD: serverConfig.DB_PASSWORD,
+    REDIS_DISABLED: serverConfig.REDIS_DISABLED || false,
+    REDIS_HOST: serverConfig.REDIS_HOST || '127.0.0.1',
+    REDIS_PORT: serverConfig.REDIS_PORT || 6379,
+    REDIS_PASSWORD: serverConfig.REDIS_PASSWORD,
+    USER_LIMIT_PER_DAY: serverConfig.USER_LIMIT_PER_DAY || 50,
+    JWT_SECRET: serverConfig.JWT_SECRET || 'securekey',
+    ADMIN_EMAILS: serverConfig.ADMIN_EMAILS.join(','),
+    RECAPTCHA_SITE_KEY: clientConfig.RECAPTCHA_SITE_KEY,
+    RECAPTCHA_SECRET_KEY: serverConfig.RECAPTCHA_SECRET_KEY,
+    GOOGLE_SAFE_BROWSING_KEY: serverConfig.GOOGLE_SAFE_BROWSING_KEY,
+    GOOGLE_ANALYTICS: serverConfig.GOOGLE_ANALYTICS || clientConfig.GOOGLE_ANALYTICS,
+    MAIL_HOST: serverConfig.MAIL_HOST,
+    MAIL_PORT: serverConfig.MAIL_PORT,
+    MAIL_SECURE: serverConfig.MAIL_SECURE,
+    MAIL_USER: serverConfig.MAIL_USER,
+    MAIL_FROM: serverConfig.MAIL_FROM,
+    MAIL_PASSWORD: serverConfig.MAIL_PASSWORD,
+    REPORT_MAIL: serverConfig.REPORT_MAIL,
+    CONTACT_EMAIL: clientConfig.CONTACT_EMAIL,
+  };
+
+  Object.keys(configs).forEach(c => {
+    envTemplate = envTemplate.replace(new RegExp(`{{${c}}}`, 'gm'), configs[c] || '');
+  });
+
+  fs.writeFileSync(path.resolve(__dirname, '../.env'), envTemplate);
+  fs.renameSync(path.resolve(__dirname, 'config.js'), path.resolve(__dirname, 'old.config.js'));
+  fs.renameSync(
+    path.resolve(__dirname, '../client/config.js'),
+    path.resolve(__dirname, '../client/old.config.js')
+  );
+}

+ 8 - 9
server/controllers/authController.js

@@ -3,7 +3,6 @@ const path = require('path');
 const passport = require('passport');
 const JWT = require('jsonwebtoken');
 const axios = require('axios');
-const config = require('../config');
 const { isAdmin } = require('../utils');
 const transporter = require('../mail/mail');
 const { resetMailText, verifyMailText } = require('../mail/text');
@@ -22,10 +21,10 @@ const resetEmailTemplatePath = path.join(__dirname, '../mail/template-reset.html
 const verifyEmailTemplatePath = path.join(__dirname, '../mail/template-verify.html');
 const resetEmailTemplate = fs
   .readFileSync(resetEmailTemplatePath, { encoding: 'utf-8' })
-  .replace(/{{domain}}/gm, config.DEFAULT_DOMAIN);
+  .replace(/{{domain}}/gm, process.env.DEFAULT_DOMAIN);
 const verifyEmailTemplate = fs
   .readFileSync(verifyEmailTemplatePath, { encoding: 'utf-8' })
-  .replace(/{{domain}}/gm, config.DEFAULT_DOMAIN);
+  .replace(/{{domain}}/gm, process.env.DEFAULT_DOMAIN);
 
 /* Function to generate JWT */
 const signToken = user =>
@@ -38,7 +37,7 @@ const signToken = user =>
       iat: new Date().getTime(),
       exp: new Date().setDate(new Date().getDate() + 7),
     },
-    config.JWT_SECRET
+    process.env.JWT_SECRET
   );
 
 /* Passport.js authentication controller */
@@ -84,7 +83,7 @@ exports.recaptcha = async (req, res, next) => {
         'Content-type': 'application/x-www-form-urlencoded',
       },
       params: {
-        secret: config.RECAPTCHA_SECRET_KEY,
+        secret: process.env.RECAPTCHA_SECRET_KEY,
         response: req.body.reCaptchaToken,
         remoteip: req.realIp,
       },
@@ -115,7 +114,7 @@ exports.signup = async (req, res) => {
   if (user && user.verified) return res.status(403).json({ error: 'Email is already in use.' });
   const newUser = await createUser({ email, password });
   const mail = await transporter.sendMail({
-    from: config.MAIL_FROM || config.MAIL_USER,
+    from: process.env.MAIL_FROM || process.env.MAIL_USER,
     to: newUser.email,
     subject: 'Verify your account',
     text: verifyMailText.replace(/{{verification}}/gim, newUser.verificationToken),
@@ -183,15 +182,15 @@ exports.requestPasswordReset = async ({ body: { email } }, res) => {
     return res.status(400).json({ error: "Couldn't reset password." });
   }
   const mail = await transporter.sendMail({
-    from: config.MAIL_USER,
+    from: process.env.MAIL_USER,
     to: user.email,
     subject: 'Reset your password',
     text: resetMailText
       .replace(/{{resetpassword}}/gm, user.resetPasswordToken)
-      .replace(/{{domain}}/gm, config.DEFAULT_DOMAIN),
+      .replace(/{{domain}}/gm, process.env.DEFAULT_DOMAIN),
     html: resetEmailTemplate
       .replace(/{{resetpassword}}/gm, user.resetPasswordToken)
-      .replace(/{{domain}}/gm, config.DEFAULT_DOMAIN),
+      .replace(/{{domain}}/gm, process.env.DEFAULT_DOMAIN),
   });
   if (mail.accepted.length) {
     return res.status(200).json({ email, message: 'Reset password email has been sent.' });

+ 16 - 17
server/controllers/urlController.js

@@ -32,7 +32,6 @@ const {
 const transporter = require('../mail/mail');
 const redis = require('../redis');
 const { addProtocol, generateShortUrl, getStatsCacheTime } = require('../utils');
-const config = require('../config');
 
 const dnsLookup = promisify(dns.lookup);
 
@@ -48,8 +47,8 @@ exports.urlShortener = async ({ body, user }, res) => {
     const domain = URL.parse(body.target).hostname;
 
     const queries = await Promise.all([
-      config.GOOGLE_SAFE_BROWSING_KEY && cooldownCheck(user),
-      config.GOOGLE_SAFE_BROWSING_KEY && malwareCheck(user, body.target),
+      process.env.GOOGLE_SAFE_BROWSING_KEY && cooldownCheck(user),
+      process.env.GOOGLE_SAFE_BROWSING_KEY && malwareCheck(user, body.target),
       user && urlCountsCheck(user.email),
       user && body.reuse && findUrl({ target: addProtocol(body.target) }),
       user && body.customurl && findUrl({ id: body.customurl || '' }),
@@ -109,7 +108,7 @@ exports.goToUrl = async (req, res, next) => {
   const { host } = req.headers;
   const reqestedId = req.params.id || req.body.id;
   const id = reqestedId.replace('+', '');
-  const domain = host !== config.DEFAULT_DOMAIN && host;
+  const domain = host !== process.env.DEFAULT_DOMAIN && host;
   const agent = useragent.parse(req.headers['user-agent']);
   const [browser = 'Other'] = browsersList.filter(filterInBrowser(agent));
   const [os = 'Other'] = osList.filter(filterInOs(agent));
@@ -131,7 +130,7 @@ exports.goToUrl = async (req, res, next) => {
   }
 
   if (!url) {
-    if (host !== config.DEFAULT_DOMAIN) {
+    if (host !== process.env.DEFAULT_DOMAIN) {
       const { homepage } = await getCustomDomain({ customDomain: domain });
       if (!homepage) return next();
       return res.redirect(301, homepage);
@@ -185,8 +184,8 @@ exports.goToUrl = async (req, res, next) => {
     });
   }
 
-  if (config.GOOGLE_ANALYTICS && !isBot) {
-    const visitor = ua(config.GOOGLE_ANALYTICS);
+  if (process.env.GOOGLE_ANALYTICS && !isBot) {
+    const visitor = ua(process.env.GOOGLE_ANALYTICS);
     visitor
       .pageview({
         dp: `/${id}`,
@@ -217,7 +216,7 @@ exports.setCustomDomain = async ({ body, user }, res) => {
   if (customDomain.length > 40) {
     return res.status(400).json({ error: 'Maximum custom domain length is 40.' });
   }
-  if (customDomain === config.DEFAULT_DOMAIN) {
+  if (customDomain === process.env.DEFAULT_DOMAIN) {
     return res.status(400).json({ error: "You can't use default domain." });
   }
   const isValidHomepage =
@@ -256,19 +255,19 @@ exports.deleteCustomDomain = async ({ user }, res) => {
 exports.customDomainRedirection = async (req, res, next) => {
   const { headers, path } = req;
   if (
-    headers.host !== config.DEFAULT_DOMAIN &&
+    headers.host !== process.env.DEFAULT_DOMAIN &&
     (path === '/' ||
       preservedUrls.filter(u => u !== 'url-password').some(item => item === path.replace('/', '')))
   ) {
     const { homepage } = await getCustomDomain({ customDomain: headers.host });
-    return res.redirect(301, homepage || `https://${config.DEFAULT_DOMAIN + path}`);
+    return res.redirect(301, homepage || `https://${process.env.DEFAULT_DOMAIN + path}`);
   }
   return next();
 };
 
 exports.deleteUrl = async ({ body: { id, domain }, user }, res) => {
   if (!id) return res.status(400).json({ error: 'No id has been provided.' });
-  const customDomain = domain !== config.DEFAULT_DOMAIN && domain;
+  const customDomain = domain !== process.env.DEFAULT_DOMAIN && domain;
   const urls = await findUrl({ id, domain: customDomain });
   if (!urls && !urls.length) return res.status(400).json({ error: "Couldn't find the short URL." });
   redis.del(id + (customDomain || ''));
@@ -279,7 +278,7 @@ exports.deleteUrl = async ({ body: { id, domain }, user }, res) => {
 
 exports.getStats = async ({ query: { id, domain }, user }, res) => {
   if (!id) return res.status(400).json({ error: 'No id has been provided.' });
-  const customDomain = domain !== config.DEFAULT_DOMAIN && domain;
+  const customDomain = domain !== process.env.DEFAULT_DOMAIN && domain;
   const redisKey = id + (customDomain || '') + user.email;
   const cached = await redis.get(redisKey);
   if (cached) return res.status(200).json(JSON.parse(cached));
@@ -288,9 +287,9 @@ exports.getStats = async ({ query: { id, domain }, user }, res) => {
   const [url] = urls;
   const stats = await getStats({ id, domain: customDomain, user });
   if (!stats) return res.status(400).json({ error: 'Could not get the short URL stats.' });
-  stats.shortUrl = `http${!domain ? 's' : ''}://${domain ? url.domain : config.DEFAULT_DOMAIN}/${
-    url.id
-  }`;
+  stats.shortUrl = `http${!domain ? 's' : ''}://${
+    domain ? url.domain : process.env.DEFAULT_DOMAIN
+  }/${url.id}`;
   stats.target = url.target;
   const cacheTime = getStatsCacheTime(stats.total);
   redis.set(redisKey, JSON.stringify(stats), 'EX', cacheTime);
@@ -304,8 +303,8 @@ exports.reportUrl = async ({ body: { url } }, res) => {
   if (!isValidUrl) return res.status(400).json({ error: 'URL is not valid.' });
 
   const mail = await transporter.sendMail({
-    from: config.MAIL_USER,
-    to: config.REPORT_MAIL,
+    from: process.env.MAIL_USER,
+    to: process.env.REPORT_MAIL,
     subject: '[REPORT]',
     text: url,
     html: url,

+ 4 - 5
server/controllers/validateBodyController.js

@@ -7,7 +7,6 @@ const { subHours } = require('date-fns/');
 const { validationResult } = require('express-validator/check');
 const { addCooldown, banUser } = require('../db/user');
 const { getBannedDomain, getBannedHost, urlCountFromDate } = require('../db/url');
-const config = require('../config');
 const subDay = require('date-fns/sub_days');
 
 const dnsLookup = promisify(dns.lookup);
@@ -119,11 +118,11 @@ exports.cooldownCheck = async user => {
 exports.malwareCheck = async (user, target) => {
   const isMalware = await axios.post(
     `https://safebrowsing.googleapis.com/v4/threatMatches:find?key=${
-      config.GOOGLE_SAFE_BROWSING_KEY
+      process.env.GOOGLE_SAFE_BROWSING_KEY
     }`,
     {
       client: {
-        clientId: config.DEFAULT_DOMAIN.toLowerCase().replace('.', ''),
+        clientId: process.env.DEFAULT_DOMAIN.toLowerCase().replace('.', ''),
         clientVersion: '1.0.0',
       },
       threatInfo: {
@@ -153,9 +152,9 @@ exports.urlCountsCheck = async email => {
     email,
     date: subDay(new Date(), 1).toJSON(),
   });
-  if (count > config.USER_LIMIT_PER_DAY) {
+  if (count > Number(process.env.USER_LIMIT_PER_DAY)) {
     throw new Error(
-      `You have reached your daily limit (${config.USER_LIMIT_PER_DAY}). Please wait 24h.`
+      `You have reached your daily limit (${process.env.USER_LIMIT_PER_DAY}). Please wait 24h.`
     );
   }
 };

+ 2 - 3
server/db/neo4j.js

@@ -1,9 +1,8 @@
 const neo4j = require('neo4j-driver').v1;
-const config = require('../config');
 
 const driver = neo4j.driver(
-  config.DB_URI,
-  neo4j.auth.basic(config.DB_USERNAME, config.DB_PASSWORD)
+  process.env.DB_URI,
+  neo4j.auth.basic(process.env.DB_USERNAME, process.env.DB_PASSWORD)
 );
 
 module.exports = driver;

+ 1 - 2
server/db/url.js

@@ -2,7 +2,6 @@ const bcrypt = require('bcryptjs');
 const _ = require('lodash/');
 const { isAfter, subDays } = require('date-fns');
 const driver = require('./neo4j');
-const config = require('../config');
 const {
   generateShortUrl,
   statsObjectToArray,
@@ -181,7 +180,7 @@ exports.getUrls = ({ user, options, setCount }) =>
             ...record.get('l').properties,
             count: typeof visitCount === 'object' ? visitCount.toNumber() : visitCount,
             password: !!record.get('l').properties.password,
-            shortUrl: `${protocol}${domain || config.DEFAULT_DOMAIN}/${
+            shortUrl: `${protocol}${domain || process.env.DEFAULT_DOMAIN}/${
               record.get('l').properties.id
             }`,
           };

+ 5 - 6
server/mail/mail.js

@@ -1,13 +1,12 @@
-const config = require('../config');
 const nodemailer = require('nodemailer');
 
 const mailConfig = {
-  host: config.MAIL_HOST,
-  port: config.MAIL_PORT,
-  secure: config.MAIL_SECURE,
+  host: process.env.MAIL_HOST,
+  port: process.env.MAIL_PORT,
+  secure: process.env.MAIL_SECURE === 'true',
   auth: {
-    user: config.MAIL_USER,
-    pass: config.MAIL_PASSWORD,
+    user: process.env.MAIL_USER,
+    pass: process.env.MAIL_PASSWORD,
   },
 };
 

+ 1 - 2
server/passport.js

@@ -4,12 +4,11 @@ const { ExtractJwt } = require('passport-jwt');
 const LocalStratergy = require('passport-local').Strategy;
 const LocalAPIKeyStrategy = require('passport-localapikey-update').Strategy;
 const bcrypt = require('bcryptjs');
-const config = require('./config');
 const { getUser } = require('./db/user');
 
 const jwtOptions = {
   jwtFromRequest: ExtractJwt.fromHeader('authorization'),
-  secretOrKey: config.JWT_SECRET,
+  secretOrKey: process.env.JWT_SECRET,
 };
 
 passport.use(

+ 4 - 5
server/redis.js

@@ -1,16 +1,15 @@
 const { promisify } = require('util');
 const redis = require('redis');
-const config = require('./config');
 
-if (config.REDIS_DISABLED === true) {
+if (process.env.REDIS_DISABLED === 'true') {
   exports.get = () => Promise.resolve(null);
   exports.set = () => Promise.resolve(null);
   exports.del = () => Promise.resolve(null);
 } else {
   const client = redis.createClient({
-    host: config.REDIS_HOST || '127.0.0.1',
-    port: config.REDIS_PORT || 6379,
-    ...(config.REDIS_PASSWORD && { password: config.REDIS_PASSWORD }),
+    host: process.env.REDIS_HOST || '127.0.0.1',
+    port: Number(process.env.REDIS_PORT) || 6379,
+    ...(process.env.REDIS_PASSWORD && { password: process.env.REDIS_PASSWORD }),
   });
 
   exports.get = promisify(client.get).bind(client);

+ 6 - 5
server/server.js

@@ -1,3 +1,5 @@
+require('./configToEnv');
+require('dotenv').config();
 const nextApp = require('next');
 const express = require('express');
 const helmet = require('helmet');
@@ -14,17 +16,16 @@ const {
 } = require('./controllers/validateBodyController');
 const auth = require('./controllers/authController');
 const url = require('./controllers/urlController');
-const config = require('./config');
 
 require('./passport');
 
-if (config.RAVEN_DSN) {
-  Raven.config(config.RAVEN_DSN).install();
+if (process.env.RAVEN_DSN) {
+  Raven.config(process.env.RAVEN_DSN).install();
 }
 const catchErrors = fn => (req, res, next) =>
   fn(req, res, next).catch(err => {
     res.status(500).json({ error: 'Sorry an error ocurred. Please try again later.' });
-    if (config.RAVEN_DSN) {
+    if (process.env.RAVEN_DSN) {
       Raven.captureException(err, {
         user: { email: req.user && req.user.email },
       });
@@ -33,7 +34,7 @@ const catchErrors = fn => (req, res, next) =>
     }
   });
 
-const port = Number(config.PORT) || 3000;
+const port = Number(process.env.PORT) || 3000;
 const dev = process.env.NODE_ENV !== 'production';
 const app = nextApp({ dir: './client', dev });
 const handle = app.getRequestHandler();

+ 5 - 3
server/utils/index.js

@@ -1,7 +1,6 @@
 const URL = require('url');
 const ms = require('ms');
 const { differenceInDays, differenceInHours, differenceInMonths } = require('date-fns');
-const config = require('../config');
 
 exports.addProtocol = url => {
   const hasProtocol = /^https?/.test(URL.parse(url).protocol);
@@ -10,10 +9,13 @@ exports.addProtocol = url => {
 
 exports.generateShortUrl = (id, domain, useHttps) => {
   const protocol = useHttps || !domain ? 'https://' : 'http://';
-  return `${protocol}${domain || config.DEFAULT_DOMAIN}/${id}`;
+  return `${protocol}${domain || process.env.DEFAULT_DOMAIN}/${id}`;
 };
 
-exports.isAdmin = email => config.ADMIN_EMAILS.includes(email);
+exports.isAdmin = email =>
+  process.env.ADMIN_EMAILS.split(',')
+    .map(e => e.trim())
+    .includes(email);
 
 exports.getStatsCacheTime = total => {
   switch (true) {

Неке датотеке нису приказане због велике количине промена