Passed
Pull Request — master (#34)
by Kyungmi
02:04
created

src/server.js   A

Complexity

Total Complexity 28
Complexity/F 1.4

Size

Lines of Code 151
Function Count 20

Duplication

Duplicated Lines 0
Ratio 0 %

Test Coverage

Coverage 77.03%

Importance

Changes 8
Bugs 2 Features 0
Metric Value
cc 0
wmc 28
c 8
b 2
f 0
nc 4
mnd 1
bc 19
fnc 20
dl 0
loc 151
ccs 57
cts 74
cp 0.7703
crap 0
rs 10
bpm 0.95
cpm 1.4
noi 0

1 Function

Rating   Name   Duplication   Size   Complexity  
B server.js ➔ ??? 0 33 1
1
/**
2
 * Server main
3
 *
4
 * @since 1.0.0
5
 *
6
 */
7
8 3
const Hapi = require('hapi');
9
10 3
const vision = require('vision');
11 3
const inert = require('inert');
12 3
const HapiAuthJwt2 = require('hapi-auth-jwt2');
13 3
const HapiReactViews = require('hapi-react-views');
14 3
const HapiErrorHandler = require('./middleware/error-handler');
15 3
const HapiTransformer = require('./middleware/transformer');
16 3
const HapiAuthChecker = require('./middleware/auth-info-checker');
17
18 3
const commonApiRouter = require('./router/common-api-router');
19 3
const statusApiRouter = require('./router/status-api-router');
20 3
const statusTypeApiRouter = require('./router/status-type-api-router');
21 3
const baseRouter = require('./router/ui-router');
22 3
const User = require('./repository/User');
23 3
const DeviceType = require('./repository/DeviceType');
24 3
const StatusType = require('./repository/StatusType');
25
26 3
const config = require('./config/server.config');
27 3
const NotifierError = require('./common/Error');
28
29 3
const util = require('./common/common-util');
30 3
const logger = require('winston');
31
32
// For JSX transpiling
33 3
require('babel-register');
34 3
require('babel-polyfill');
35
36 3
const server = new Hapi.Server();
37 3
server.connection({ port: process.env.PORT || config.defaults.port });
38
39 3
server.state('token', {
40
  ttl: config.auth.tokenTTL,
41
  isSecure: process.env.USE_HTTPS && process.env.USE_HTTPS === 'true',
42
  path: '/',
43
});
44
45 3
const plugins = [
46
  { register: vision },
47
  { register: inert },
48
  { register: HapiAuthJwt2 },
49
  { register: HapiErrorHandler, options: { apiPrefix: config.url.apiPrefix, errorView: 'Error' } },
50
  { register: HapiAuthChecker,
51
    options: {
52
      excludeUrlPatterns: [new RegExp(`^${config.url.apiPrefix}`), new RegExp('^/logout')],
53
    },
54
  },
55
  { register: HapiTransformer, options: { apiPrefix: config.url.apiPrefix } },
56
];
57
58 3
const _setAuthStrategy = () => {
59 3
  server.auth.strategy('jwt', 'jwt', {
60
    key: process.env.SECRET_KEY || config.auth.secretKey,
61
    validateFunc: (decoded, request, callback) => {
62
      // Check token IP address
63
      const clientIP = util.getClientIp(request);
64
      if (clientIP !== decoded.ip) {
65
        logger.warn(`[Auth] This client IP is matched with token info.: decoded.ip => ${decoded.ip}, client IP => ${clientIP}`);
66
        return callback(new NotifierError(NotifierError.Types.AUTH_TOKEN_INVALID), false);
67
      }
68
      // Check token expiration
69
      if (decoded.exp < new Date().getTime()) {
70
        logger.warn(`[Auth] This auth token is expired.: decoded.exp => ${decoded.exp}, now => ${new Date().getTime()}`);
71
        return callback(new NotifierError(NotifierError.Types.AUTH_TOKEN_EXPIRED), false);
72
      }
73
      return User.find({ username: decoded.username })
74
        .then((accounts) => {
75
          if (!accounts || accounts.length === 0) {
76
            logger.warn(`[Auth] This account is not exist.: ${decoded.username}`);
77
            return callback(new NotifierError(NotifierError.Types.AUTH_USER_NOT_EXIST, { username: decoded.username }), false);
78
          }
79
          return callback(null, true, accounts[0]);
80
        })
81
        .catch((e) => {
82
          logger.error(`[DB] DB error occurred: ${e.message}`);
83
          callback(new NotifierError(NotifierError.Types.DB), false);
84
        });
85
    },
86
    verifyOptions: { algorithms: ['HS256'] },
87
  });
88
89 3
  server.auth.default('jwt');
90
};
91
92 3
const _setViewEngine = () => {
93 3
  server.views({
94
    engines: { jsx: HapiReactViews },
95
    relativeTo: __dirname,
96
    path: config.directory.component,
97
  });
98
};
99
100 3
const _setRoutes = (extraRoutes) => {
101
  // for static assets
102 3
  server.route({
103
    method: 'GET',
104
    path: `${config.url.publicPrefix}/{param*}`,
105
    handler: {
106
      directory: {
107
        path: config.directory.public,
108
        listing: false,
109
      },
110
    },
111
    config: {
112
      auth: false,
113
    },
114
  });
115 3
  server.route(commonApiRouter);
116 3
  server.route(statusApiRouter);
117 3
  server.route(statusTypeApiRouter);
118 3
  server.route(baseRouter);
119 3
  if (extraRoutes) {
120
    server.route(extraRoutes);
121
  }
122
};
123
124 3
const _setInitalData = () => {
125 3
  let promises = [];
126 3
  return Promise.all([User.count(), DeviceType.count(), StatusType.count()])
127
    .then(([userCount, deviceTypeCount, statusTypeCount]) => {
128 3
      if (userCount === 0) {
129 1
        promises = promises.concat(config.initialData.users.map(user => User.add(user)));
130
      }
131 3
      if (deviceTypeCount === 0) {
132 4
        promises = promises.concat(config.initialData.deviceTypes.map(dt => DeviceType.add(dt)));
133
      }
134 3
      if (statusTypeCount === 0) {
135 2
        promises = promises.concat(config.initialData.statusTypes.map(user => StatusType.add(user)));
136
      }
137
    })
138 3
    .then(() => Promise.all(promises))
139 3
    .then(result => logger.log('[SET INITIAL DATA] success: ', result));
140
};
141
142 3
exports.addPlugin = (pluginSetting) => {
143
  plugins.push(pluginSetting);
144
};
145
146 3
exports.start = extraRoutes => server.register(plugins)
147
    .then(() => {
148 3
      _setAuthStrategy();
149 3
      _setViewEngine();
150 3
      _setRoutes(extraRoutes);
151
    })
152 3
    .then(() => _setInitalData())
153 3
    .then(() => server.start())
154
    .then(() => {
155 3
      logger.log('Server running at:', server.info.uri);
156 3
      return server;
157
    })
158
    .catch((error) => { throw error; });
159