Compare View
Commits (2)
Changes
Showing 5 changed files Inline Diff
lib/webadmin/index.js
1 | const express = require('express'); | 1 | const express = require('express'); |
2 | const morgan = require('morgan'); | 2 | const morgan = require('morgan'); |
3 | const rfs = require('rotating-file-stream'); | 3 | const rfs = require('rotating-file-stream'); |
4 | const nunjucks = require('nunjucks'); | 4 | const nunjucks = require('nunjucks'); |
5 | const moment = require('moment'); | 5 | const moment = require('moment'); |
6 | const session = require('express-session'); | ||
6 | const session = require('express-session'); | 7 | |
7 | 8 | const config = require('komodo-sdk/config'); | |
8 | const config = require('komodo-sdk/config'); | 9 | const logger = require('komodo-sdk/logger'); |
9 | const logger = require('komodo-sdk/logger'); | 10 | |
10 | 11 | const routerConfig = require('./router/config'); | |
12 | const routerAuth = require('./router/auth'); | ||
11 | const routerConfig = require('./router/config'); | 13 | |
12 | const routerAuth = require('./router/auth'); | 14 | const app = express(); |
13 | 15 | ||
14 | const app = express(); | 16 | nunjucks.configure('./webadmin-views', { |
15 | app.use((req, res, next) => { | 17 | autoescape: true, |
16 | res.locals.main_config = config; | 18 | express: app, |
17 | next(); | 19 | noCache: true, |
18 | }); | 20 | }); |
19 | 21 | ||
20 | nunjucks.configure('./webadmin-views', { | 22 | app.use(express.static('./webadmin-statics')); |
23 | app.use(session({ | ||
24 | secret: 'b4ba8b94-1bbe-11ea-9815-1c872cb0e3c0', | ||
25 | resave: false, | ||
26 | saveUninitialized: true, | ||
27 | })); | ||
21 | autoescape: true, | 28 | |
22 | express: app, | 29 | const accessLogStream = rfs.createStream( |
23 | noCache: true, | 30 | (time, index) => { |
24 | }); | 31 | const ts = time ? `.${moment(time).format('YYYY-MM-DD')}` : ''; |
25 | 32 | const idx = index ? `.${index}` : ''; | |
26 | app.use(express.static('./webadmin-statics')); | 33 | return `webadmin.access_log${ts}${idx}`; |
27 | app.use(session({ | 34 | }, |
28 | secret: 'b4ba8b94-1bbe-11ea-9815-1c872cb0e3c0', | 35 | { |
29 | resave: false, | 36 | interval: '1d', |
30 | saveUninitialized: true, | 37 | path: './logs', |
31 | })); | 38 | }, |
32 | 39 | ); | |
33 | const accessLogStream = rfs.createStream( | 40 | |
34 | (time, index) => { | 41 | app.use(morgan('combined', { stream: accessLogStream })); |
35 | const ts = time ? `.${moment(time).format('YYYY-MM-DD')}` : ''; | 42 | |
43 | app.use((req, res, next) => { // check if user is logged in | ||
44 | if (!req.session.user && req.path !== '/auth/login') { | ||
45 | res.redirect('/auth/login'); | ||
46 | return; | ||
47 | } | ||
48 | res.locals.loggedInUser = req.session.user; | ||
49 | next(); | ||
50 | }); | ||
51 | |||
52 | |||
36 | const idx = index ? `.${index}` : ''; | 53 | app.use((req, res, next) => { |
37 | return `apiserver.access_log${ts}${idx}`; | 54 | res.locals.config = config; |
38 | }, | 55 | next(); |
39 | { | 56 | }); |
40 | interval: '1d', | 57 | |
41 | path: './logs', | 58 | app.get('/', (req, res) => { |
42 | }, | 59 | res.redirect('/config/modem'); |
43 | ); | 60 | }); |
44 | 61 | ||
62 | app.use('/auth', routerAuth); | ||
45 | app.use(morgan('combined', { stream: accessLogStream })); | 63 | app.use('/config', routerConfig); |
46 | 64 | ||
47 | app.use((req, res, next) => { // check if user is logged in | 65 | const listenPort = (config.webadmin && config.webadmin.port) || 21923; |
48 | if (!req.session.user && req.path !== '/auth/login') { | 66 | app.listen(listenPort, () => { |
49 | res.redirect('/auth/login'); | 67 | logger.info(`WEBADMIN listen on port ${listenPort}`); |
50 | return; | 68 | }).on('error', (err) => { |
51 | } | 69 | logger.warn(`WEBADMIN can not start / listen on port ${listenPort}`, { err: err.message }); |
52 | res.locals.loggedInUser = req.session.user; | 70 | process.exit(); |
53 | next(); | 71 | }); |
54 | }); | 72 |
lib/webadmin/router/auth.js
File was created | 1 | const express = require('express'); | |
2 | const axios = require('axios'); | ||
3 | const querystring = require('querystring'); | ||
4 | const config = require('komodo-sdk/config'); | ||
5 | const coreUrl = require('komodo-sdk/core-url'); | ||
6 | const logger = require('komodo-sdk/logger'); | ||
7 | |||
8 | const router = express.Router(); | ||
9 | module.exports = router; | ||
10 | |||
11 | function login(req, res) { | ||
12 | res.render('auth.login.html', { | ||
13 | baseUrl: req.baseUrl, | ||
14 | }); | ||
15 | } | ||
16 | |||
17 | async function loginProcess(req, res) { | ||
18 | const params = { | ||
19 | terminal_name: req.body.terminal_name || '', | ||
20 | web_password: req.body.web_password || '', | ||
21 | request_by: config.name, | ||
22 | }; | ||
23 | |||
24 | try { | ||
25 | const loginUrl = `${coreUrl}/services/terminalAuthentication?${querystring.stringify(params)}`; | ||
26 | logger.verbose(`lib/webadmin/router/auth.js:login(): request login to: ${loginUrl}`); | ||
27 | const response = await axios.get(loginUrl); | ||
28 | logger.verbose(`lib/webadmin/router/auth.js:login(): status: ${response.status}, body: ${JSON.stringify(response.data)}`); | ||
29 | if (response.data.error === false && response.data.terminal.store_is_super) { | ||
30 | req.session.user = response.data; | ||
31 | res.redirect('/'); | ||
32 | return; | ||
33 | } | ||
34 | } catch (err) { | ||
35 | logger.error(`lib/webadmin/router/auth.js:login(): ${err.message}`); | ||
36 | } | ||
37 | res.redirect(`${req.baseUrl}/login?message=Terminal / Password tidak sesuai`); | ||
38 | } | ||
39 | |||
40 | function logout(req, res) { | ||
41 | req.session.destroy(); | ||
42 | res.redirect(`${req.baseUrl}/login`); | ||
43 | } | ||
44 | |||
45 | router.get('/login', login); | ||
46 | router.post('/login', express.urlencoded({ extended: true }), loginProcess); | ||
47 | router.get('/logout', express.urlencoded({ extended: true }), logout); | ||
1 | const express = require('express'); | 48 |
package.json
1 | { | 1 | { |
2 | "name": "komodo-center-evo-cp", | 2 | "name": "komodo-center-evo-cp", |
3 | "version": "0.9.2", | 3 | "version": "1.0.0", |
4 | "description": "Komodo center for EVO - CP", | 4 | "description": "Komodo center for EVO - CP", |
5 | "main": "index.js", | 5 | "main": "index.js", |
6 | "scripts": { | 6 | "scripts": { |
7 | "test": "mocha", | 7 | "test": "mocha", |
8 | "postversion": "git push && git push --tags" | 8 | "postversion": "git push && git push --tags" |
9 | }, | 9 | }, |
10 | "repository": { | 10 | "repository": { |
11 | "type": "git", | 11 | "type": "git", |
12 | "url": "git@gitlab.kodesumber.com:komodo/komodo-center-evo-cp.git" | 12 | "url": "git@gitlab.kodesumber.com:komodo/komodo-center-evo-cp.git" |
13 | }, | 13 | }, |
14 | "keywords": [ | 14 | "keywords": [ |
15 | "komodo", | 15 | "komodo", |
16 | "tektrans", | 16 | "tektrans", |
17 | "ppob", | 17 | "ppob", |
18 | "evo" | 18 | "evo" |
19 | ], | 19 | ], |
20 | "author": "Adhidarma Hadiwinoto <me@adhisimon.org>", | 20 | "author": "Adhidarma Hadiwinoto <me@adhisimon.org>", |
21 | "license": "SEE LICENSE IN LICENSE.txt", | 21 | "license": "SEE LICENSE IN LICENSE.txt", |
22 | "dependencies": { | 22 | "dependencies": { |
23 | "axios": "^0.19.0", | 23 | "axios": "^0.19.0", |
24 | "escape-string-regexp": "^2.0.0", | 24 | "escape-string-regexp": "^2.0.0", |
25 | "express": "^4.17.1", | 25 | "express": "^4.17.1", |
26 | "express-session": "^1.17.0", | ||
26 | "express-session": "^1.17.0", | 27 | "komodo-center-messaging-client-lib": "git+http://gitlab.kodesumber.com/komodo/komodo-center-messaging-client-lib.git", |
27 | "komodo-center-messaging-client-lib": "git+http://gitlab.kodesumber.com/komodo/komodo-center-messaging-client-lib.git", | 28 | "komodo-sdk": "git+http://gitlab.kodesumber.com/komodo/komodo-sdk.git", |
28 | "komodo-sdk": "git+http://gitlab.kodesumber.com/komodo/komodo-sdk.git", | 29 | "locks": "^0.2.2", |
29 | "locks": "^0.2.2", | 30 | "moment": "^2.24.0", |
30 | "moment": "^2.24.0", | 31 | "morgan": "^1.9.1", |
31 | "morgan": "^1.9.1", | 32 | "natural-orderby": "^2.0.3", |
32 | "natural-orderby": "^2.0.3", | 33 | "nunjucks": "^3.2.0", |
33 | "nunjucks": "^3.2.0", | 34 | "rotating-file-stream": "^2.0.0", |
34 | "rotating-file-stream": "^2.0.0", | 35 | "uniqid": "^5.2.0" |
35 | "uniqid": "^5.2.0" | 36 | }, |
36 | }, | 37 | "devDependencies": { |
37 | "devDependencies": { | 38 | "eslint": "^6.7.2", |
38 | "eslint": "^6.7.2", | 39 | "eslint-config-airbnb-base": "^14.0.0", |
39 | "eslint-config-airbnb-base": "^14.0.0", | 40 | "eslint-plugin-import": "^2.18.2", |
40 | "eslint-plugin-import": "^2.18.2", | 41 | "mocha": "^6.2.2", |
41 | "mocha": "^6.2.2", | 42 | "should": "^13.2.3" |
42 | "should": "^13.2.3" | 43 | } |
43 | } | 44 | } |
44 | } | 45 |
webadmin-views/auth.login.html
File was created | 1 | {% extends "template.starter.html" %} | |
2 | |||
3 | {% block content %} | ||
4 | |||
5 | <!-- | ||
6 | <code> | ||
7 | {{ config | nl2br | safe }} | ||
8 | </code> | ||
9 | --> | ||
10 | <div class="row"> | ||
11 | <div class="col-md-6 offset-md-3"> | ||
12 | <div class="card"> | ||
13 | <div class="card-header bg-info"> | ||
14 | Login {{ main_config.name }} | ||
15 | </div> | ||
16 | <div class="card-body"> | ||
17 | <form method="post" action="{{ baseUrl }}/login"> | ||
18 | <div class="form-group"> | ||
19 | <input type="text" name="terminal_name" class="form-control" placeholder="Masukkan nama terminal"> | ||
20 | </div> | ||
21 | <div class="form-group"> | ||
22 | <input type="password" name="web_password" class="form-control" placeholder="Masukkan password anda"> | ||
23 | </div> | ||
24 | <div class="text-right"> | ||
25 | <button type="submit" class="btn btn-primary">Login</button> | ||
26 | </div> | ||
27 | </form> | ||
28 | </div> | ||
29 | </div> | ||
30 | </div> | ||
31 | </div> | ||
32 | |||
33 | {% endblock %} |
webadmin-views/template.starter.html
1 | 1 | ||
2 | <!doctype html> | 2 | <!doctype html> |
3 | <html lang="en"> | 3 | <html lang="en"> |
4 | <head> | 4 | <head> |
5 | <meta charset="utf-8"> | 5 | <meta charset="utf-8"> |
6 | <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> | 6 | <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> |
7 | <meta name="description" content=""> | 7 | <meta name="description" content=""> |
8 | <meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors"> | 8 | <meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors"> |
9 | <meta name="generator" content="Jekyll v3.8.6"> | 9 | <meta name="generator" content="Jekyll v3.8.6"> |
10 | <title>{{ main_config.name }}</title> | 10 | <title>{{ config.name }}</title> |
11 | 11 | ||
12 | <!-- Bootstrap core CSS --> | 12 | <!-- Bootstrap core CSS --> |
13 | <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous"> | 13 | <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous"> |
14 | 14 | ||
15 | <!-- Favicons --> | 15 | <!-- Favicons --> |
16 | <link rel="apple-touch-icon" href="/assets/img/favicons/apple-touch-icon.png" sizes="180x180"> | 16 | <link rel="apple-touch-icon" href="/assets/img/favicons/apple-touch-icon.png" sizes="180x180"> |
17 | <link rel="icon" href="/assets/img/favicons/favicon-32x32.png" sizes="32x32" type="image/png"> | 17 | <link rel="icon" href="/assets/img/favicons/favicon-32x32.png" sizes="32x32" type="image/png"> |
18 | <link rel="icon" href="/assets/img/favicons/favicon-16x16.png" sizes="16x16" type="image/png"> | 18 | <link rel="icon" href="/assets/img/favicons/favicon-16x16.png" sizes="16x16" type="image/png"> |
19 | <link rel="manifest" href="/assets/img/favicons/manifest.json"> | 19 | <link rel="manifest" href="/assets/img/favicons/manifest.json"> |
20 | <link rel="mask-icon" href="/assets/img/favicons/safari-pinned-tab.svg" color="#563d7c"> | 20 | <link rel="mask-icon" href="/assets/img/favicons/safari-pinned-tab.svg" color="#563d7c"> |
21 | <link rel="icon" href="/assets/img/favicons/favicon.ico"> | 21 | <link rel="icon" href="/assets/img/favicons/favicon.ico"> |
22 | <meta name="msapplication-config" content="/assets/img/favicons/browserconfig.xml"> | 22 | <meta name="msapplication-config" content="/assets/img/favicons/browserconfig.xml"> |
23 | <meta name="theme-color" content="#563d7c"> | 23 | <meta name="theme-color" content="#563d7c"> |
24 | 24 | ||
25 | 25 | ||
26 | <style> | 26 | <style> |
27 | .bd-placeholder-img { | 27 | .bd-placeholder-img { |
28 | font-size: 1.125rem; | 28 | font-size: 1.125rem; |
29 | text-anchor: middle; | 29 | text-anchor: middle; |
30 | -webkit-user-select: none; | 30 | -webkit-user-select: none; |
31 | -moz-user-select: none; | 31 | -moz-user-select: none; |
32 | -ms-user-select: none; | 32 | -ms-user-select: none; |
33 | user-select: none; | 33 | user-select: none; |
34 | } | 34 | } |
35 | 35 | ||
36 | @media (min-width: 768px) { | 36 | @media (min-width: 768px) { |
37 | .bd-placeholder-img-lg { | 37 | .bd-placeholder-img-lg { |
38 | font-size: 3.5rem; | 38 | font-size: 3.5rem; |
39 | } | 39 | } |
40 | } | 40 | } |
41 | </style> | 41 | </style> |
42 | <!-- Custom styles for this template --> | 42 | <!-- Custom styles for this template --> |
43 | <link href="/assets/starter-template.css" rel="stylesheet"> | 43 | <link href="/assets/starter-template.css" rel="stylesheet"> |
44 | </head> | 44 | </head> |
45 | <body> | 45 | <body> |
46 | {% if loggedInUser %} | 46 | {% if loggedInUser %} |
47 | <nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top"> | 47 | <nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top"> |
48 | <a class="navbar-brand" href="#">{{ main_config.name }}</a> | 48 | <a class="navbar-brand" href="#">{{ config.name }}</a> |
49 | <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation"> | 49 | <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation"> |
50 | <span class="navbar-toggler-icon"></span> | 50 | <span class="navbar-toggler-icon"></span> |
51 | </button> | ||
51 | </button> | 52 | |
52 | 53 | <div class="collapse navbar-collapse" id="navbarsExampleDefault"> | |
53 | <div class="collapse navbar-collapse" id="navbarsExampleDefault"> | 54 | <ul class="navbar-nav mr-auto"> |
54 | <ul class="navbar-nav mr-auto"> | 55 | <li class="nav-item active"> |
55 | <li class="nav-item active"> | 56 | <a class="nav-link" href="/">Home <span class="sr-only">(current)</span></a> |
56 | <a class="nav-link" href="/">Home <span class="sr-only">(current)</span></a> | 57 | </li> |
57 | </li> | 58 | </ul> |
58 | </ul> | 59 | <ul class="navbar-nav px-3"> |
59 | <ul class="navbar-nav px-3"> | 60 | <li class="nav-item"> |
61 | <a class="nav-link" href="/">Welcome, {{ loggedInUser.terminal_name }}</a> | ||
62 | </li> | ||
63 | <li class="nav-item"> | ||
64 | <a class="nav-link" href="/auth/logout">Logout <span class="sr-only">(current)</span></a> | ||
65 | </li> | ||
66 | </ul> | ||
67 | </div> | ||
68 | </nav> | ||
69 | {% endif %} | ||
60 | <li class="nav-item"> | 70 | |
61 | <a class="nav-link" href="/">Welcome, {{ loggedInUser.terminal_name }}</a> | 71 | <main role="main" class="container"> |
62 | </li> | 72 | |
63 | <li class="nav-item"> | 73 | <div class="starter-template"> |
64 | <a class="nav-link" href="/auth/logout">Logout <span class="sr-only">(current)</span></a> | 74 | {% block content %} |
65 | </li> | 75 | |
66 | </ul> | 76 | {% endblock %} |
67 | </div> | 77 | </div> |
68 | </nav> | 78 | |
69 | {% endif %} | 79 | </main><!-- /.container --> |
70 | 80 | ||
71 | <main role="main" class="container"> | 81 | <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script> |
72 | 82 | <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script> | |
73 | <div class="starter-template"> | 83 | <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script> |
84 | </body> | ||
74 | {% block content %} | 85 | </html> |
75 | | 86 |