This commit is contained in:
Martin Donnelly 2021-03-09 14:04:16 +00:00
commit 73221af968
56 changed files with 5331 additions and 0 deletions

55
.eslintrc Executable file
View File

@ -0,0 +1,55 @@
{
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module",
"ecmaFeatures": {
"jsx": false
}
},
"env": {
"browser": true,
"node": true,
"es6": true
},
"rules": {
"arrow-spacing": "error",
"block-scoped-var": "error",
"block-spacing": "error",
"brace-style": ["error", "stroustrup", {}],
"camelcase": "error",
"comma-dangle": ["error", "never"],
"comma-spacing": ["error", { "before": false, "after": true }],
"comma-style": [1, "last"],
"consistent-this": [1, "_this"],
"curly": [1, "multi"],
"eol-last": 1,
"eqeqeq": 1,
"func-names": 1,
"indent": ["error", 2, { "SwitchCase": 1 }],
"lines-around-comment": ["error", { "beforeBlockComment": true, "allowArrayStart": true }],
"max-len": [1, 180, 2, { "ignoreTemplateLiterals": true, "ignoreStrings": true, "ignoreUrls": true, "ignoreTrailingComments": true, "ignoreComments": true }], // 2 spaces per tab, max 80 chars per line
"new-cap": 1,
"newline-before-return": "error",
"no-array-constructor": 1,
"no-inner-declarations": [1, "both"],
"no-mixed-spaces-and-tabs": 1,
"no-multi-spaces": 2,
"no-new-object": 1,
"no-shadow-restricted-names": 1,
"object-curly-spacing": ["error", "always"],
"padded-blocks": ["error", { "blocks": "never", "switches": "always" }],
"prefer-const": "error",
"prefer-template": "error",
"one-var": 0,
"quote-props": ["error", "always"],
"quotes": [1, "single"],
"radix": 1,
"semi": [1, "always"],
"space-before-blocks": [1, "always"],
"space-infix-ops": 1,
"vars-on-top": 1,
"no-multiple-empty-lines": ["error", { "max": 1, "maxEOF": 1 }],
"spaced-comment": ["error", "always", { "markers": ["/"] }]
}
}

166
.gitignore vendored Executable file
View File

@ -0,0 +1,166 @@
# Created by .ignore support plugin (hsz.mobi)
### Node template
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Typescript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
### macOS template
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### JetBrains template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
.idea/
# User-specific stuff:
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/dictionaries
# Sensitive or high-churn files:
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.xml
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
# Gradle:
.idea/**/gradle.xml
.idea/**/libraries
# CMake
cmake-build-debug/
# Mongo Explorer plugin:
.idea/**/mongoSettings.xml
## File-based project format:
*.iws
## Plugin-specific files:
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# artefacts/screenshots/*.png
artefacts/*.txt
artefacts/*.json
# artefacts/*.html
# artefacts/*
/tests/*.zip
/output/
# /dist/
!/tests/data/
/tests/sink/
/debug/
/update.sh
/setup/web/
/backup/
/db/
/archive.tar.gz
/user/
/zip
!/artefacts/
menu.db
menu.db.backup

2
.prettierignore Executable file
View File

@ -0,0 +1,2 @@
node_modules/*
public

8
.prettierrc Executable file
View File

@ -0,0 +1,8 @@
{
"semi": true,
"singleQuote": true,
"trailingComma": "all",
"printWidth": 160,
"tabWidth": 2,
"useTabs": false
}

4157
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

58
package.json Normal file
View File

@ -0,0 +1,58 @@
{
"name": "jwt-test",
"version": "1.0.0",
"description": "",
"main": "./server/index.js",
"scripts": {
"run:ts": "ts-node ./src/development.ts",
"clean": "rm -rf dist",
"prebuild": "rimraf ./server",
"test:js": "mocha test/**/*.js",
"test:ts": "mocha -r ts-node/register test/**/*.ts",
"lint": "eslint . --ext .ts",
"coverage": "nyc npm run test:js",
"build:js": "rollup -c rollup.config.js",
"compile:es": "tsc --declaration true --declarationMap true --module esnext --outDir './server/es'",
"compile:commonjs": "tsc --declaration true --declarationMap true --module commonjs --outDir './server/commonjs'",
"compile:ts": "tsc --outDir './server'",
"compile": "npm run prebuild && npm run compile:es && npm run compile:commonjs"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@types/dotenv": "^8.2.0",
"@types/helmet": "^4.0.0",
"@types/joi": "^17.2.3",
"@types/sqlite3": "^3.1.7",
"cors": "^2.8.5",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"express-session": "^1.17.1",
"fecha": "^4.2.0",
"helmet": "^4.4.1",
"joi": "^17.4.0",
"jsonfile": "^6.1.0",
"jsonwebtoken": "^8.5.1",
"lodash": "^4.17.21",
"log4js": "^6.3.0",
"mongoose": "^5.10.11",
"morgan": "^1.10.0",
"short-hash": "^1.0.0",
"sqlite3": "^5.0.2"
},
"devDependencies": {
"@types/cors": "^2.8.10",
"@types/express": "^4.17.8",
"@types/express-session": "^1.17.0",
"@types/jsonwebtoken": "^8.5.0",
"@types/morgan": "^1.9.2",
"eslint": "^7.21.0",
"prettier": "^2.2.1",
"rimraf": "^3.0.2",
"rollup": "^2.33.1",
"ts-node": "^9.0.0",
"typescript": "^4.0.5",
"typings": "^2.1.1"
}
}

96
public/index.html Normal file
View File

@ -0,0 +1,96 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv=X-UA-Compatible content="IE=edge">
<meta name=viewport content="width=device-width,initial-scale=1">
<title>Login</title>
<style>
@import url(https://fonts.googleapis.com/css?family=Open+Sans);
.btn { display: inline-block; *display: inline; *zoom: 1; padding: 4px 10px 4px; margin-bottom: 0; font-size: 13px; line-height: 18px; color: #333333; text-align: center;text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); vertical-align: middle; background-color: #f5f5f5; background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); background-image: linear-gradient(top, #ffffff, #e6e6e6); background-repeat: repeat-x; filter: progid:dximagetransform.microsoft.gradient(startColorstr=#ffffff, endColorstr=#e6e6e6, GradientType=0); border-color: #e6e6e6 #e6e6e6 #e6e6e6; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); border: 1px solid #e6e6e6; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); cursor: pointer; *margin-left: .3em; }
.btn:hover, .btn:active, .btn.active, .btn.disabled, .btn[disabled] { background-color: #e6e6e6; }
.btn-large { padding: 9px 14px; font-size: 15px; line-height: normal; -webkit-border-radius: 5px; -moz-border-radius: 5px; border-radius: 5px; }
.btn:hover { color: #333333; text-decoration: none; background-color: #e6e6e6; background-position: 0 -15px; -webkit-transition: background-position 0.1s linear; -moz-transition: background-position 0.1s linear; -ms-transition: background-position 0.1s linear; -o-transition: background-position 0.1s linear; transition: background-position 0.1s linear; }
.btn-primary, .btn-primary:hover { text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); color: #ffffff; }
.btn-primary.active { color: rgba(255, 255, 255, 0.75); }
.btn-primary { background-color: #4a77d4; background-image: -moz-linear-gradient(top, #6eb6de, #4a77d4); background-image: -ms-linear-gradient(top, #6eb6de, #4a77d4); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#6eb6de), to(#4a77d4)); background-image: -webkit-linear-gradient(top, #6eb6de, #4a77d4); background-image: -o-linear-gradient(top, #6eb6de, #4a77d4); background-image: linear-gradient(top, #6eb6de, #4a77d4); background-repeat: repeat-x; filter: progid:dximagetransform.microsoft.gradient(startColorstr=#6eb6de, endColorstr=#4a77d4, GradientType=0); border: 1px solid #3762bc; text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.4); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.5); }
.btn-primary:hover, .btn-primary:active, .btn-primary.active, .btn-primary.disabled, .btn-primary[disabled] { filter: none; background-color: #4a77d4; }
.btn-block { width: 100%; display: block; }
* { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; -ms-box-sizing: border-box; -o-box-sizing: border-box; box-sizing: border-box; }
html { width: 100%; height: 100%; overflow: hidden; }
body {
width: 100%;
height: 100%;
font-family: 'Open Sans', sans-serif;
background: #092756;
background: -moz-radial-gradient(0% 100%, ellipse cover, #4C4C9D66 10%, rgba(138, 114, 76, 0) 40%), linear-gradient(to bottom, #976391 0%, #712F7966 100%), linear-gradient(135deg, #48639C 0%, #F7996E 100%);
background: -webkit-radial-gradient(0% 100%, ellipse cover, #4C4C9D66 10%, rgba(138, 114, 76, 0) 40%), linear-gradient(to bottom, #976391 0%, #712F7966 100%), linear-gradient(135deg, #48639C 0%, #F7996E 100%);
background: -o-radial-gradient(0% 100%, ellipse cover, #4C4C9D66 10%, rgba(138, 114, 76, 0) 40%), linear-gradient(to bottom, #976391 0%, #712F7966 100%), linear-gradient(135deg, #48639C 0%, #F7996E 100%);
background: -ms-radial-gradient(0% 100%, ellipse cover, #4C4C9D66 10%, rgba(138, 114, 76, 0) 40%), linear-gradient(to bottom, #976391 0%, #712F7966 100%), linear-gradient(135deg, #48639C 0%, #F7996E 100%);
background: -webkit-radial-gradient(0% 100%, ellipse cover, #4C4C9D66 10%, rgba(138, 114, 76, 0) 40%), linear-gradient(to bottom, #976391 0%, #712F7966 100%), linear-gradient(135deg, #48639C 0%, #F7996E 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#3E1D6D', endColorstr='#092756', GradientType=1);
}
.login {
position: absolute;
top: 50%;
left: 50%;
margin: -150px 0 0 -150px;
min-width: 300px;
width: 300px;
height: 300px;
}
.login h1 { color: #fff; text-shadow: 0 0 10px rgba(0, 0, 0, 0.3); letter-spacing: 1px; text-align: center; }
input {
width: 100%;
margin-bottom: 10px;
background: rgba(0, 0, 0, 0.3);
border: none;
outline: none;
padding: 10px;
font-size: 13px;
color: #fff;
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3);
border: 1px solid rgba(0, 0, 0, 0.3);
border-radius: 4px;
box-shadow: inset 0 -5px 45px rgba(100, 100, 100, 0.2), 0 1px 1px rgba(255, 255, 255, 0.2);
-webkit-transition: box-shadow .5s ease;
-moz-transition: box-shadow .5s ease;
-o-transition: box-shadow .5s ease;
-ms-transition: box-shadow .5s ease;
transition: box-shadow .5s ease;
}
input:focus { box-shadow: inset 0 -5px 45px rgba(100, 100, 100, 0.4), 0 1px 1px rgba(255, 255, 255, 0.2); }
</style>
</head>
<body>
<div class="login">
<h1>Login</h1>
<form action="auth" method="post">
<input type="text" name="u" placeholder="Username" required="required"/>
<input type="password" name="p" placeholder="Password" required="required"/>
<button type="submit" class="btn btn-primary btn-block btn-large">
Let me in.
</button>
</form>
</div>
</body>
</html>

17
rollup.config.js Executable file
View File

@ -0,0 +1,17 @@
export default {
input: 'lib/carpark.js',
output: [
{
file: 'dist/carpark.js',
format: 'umd',
name: 'carpark',
sourcemap: true
},
{
file: 'dist/carpark.mjs',
format: 'es',
sourcemap: true
}
],
plugins: []
};

7
server/commonjs/server.d.ts vendored Normal file
View File

@ -0,0 +1,7 @@
import 'dotenv';
import express from 'express';
export declare class App {
protected app: express.Application;
constructor(NODE_ENV?: string, PORT?: number);
}
//# sourceMappingURL=server.d.ts.map

View File

@ -0,0 +1 @@
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,CAAC;AAEhB,OAAO,OAAO,MAAM,SAAS,CAAC;AAQ9B,qBAAa,GAAG;IACd,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,WAAW,CAAC;gBAEvB,QAAQ,GAAE,MAAsB,EAAE,IAAI,GAAE,MAAa;CAoBlE"}

19
server/commonjs/server.js Normal file
View File

@ -0,0 +1,19 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.App = void 0;
require("dotenv");
const express_1 = __importDefault(require("express"));
class App {
constructor(NODE_ENV = 'development', PORT = 8080) {
const serverPort = process.env.PORT || 8120;
this.app = express_1.default();
this.app.listen(serverPort, function () {
console.log('The server is running in port localhost: ', serverPort);
});
}
}
exports.App = App;
//# sourceMappingURL=server.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":";;;;;;AAAA,kBAAgB;AAEhB,sDAA8B;AAQ9B,MAAa,GAAG;IAGd,YAAY,WAAmB,aAAa,EAAE,OAAe,IAAI;QAC/D,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC;QAE5C,IAAI,CAAC,GAAG,GAAG,iBAAO,EAAE,CAAC;QAIrB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,EAAE;YAC1B,OAAO,CAAC,GAAG,CAAC,2CAA2C,EAAE,UAAU,CAAC,CAAC;QACvE,CAAC,CAAC,CAAC;IACL,CAAC;CAUF;AAvBD,kBAuBC"}

1
server/db/connect.d.ts vendored Normal file
View File

@ -0,0 +1 @@
export declare const db: any;

7
server/db/connect.js Normal file
View File

@ -0,0 +1,7 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.db = void 0;
const sqlite3 = require('sqlite3').verbose();
console.log(`${__dirname}/../../db/users.db`);
exports.db = new sqlite3.Database(`${__dirname}/../../db/users.db`);
//# sourceMappingURL=connect.js.map

1
server/db/connect.js.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"connect.js","sourceRoot":"","sources":["../../src/db/connect.ts"],"names":[],"mappings":";;;AAAA,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC;AAC7C,OAAO,CAAC,GAAG,CAAC,GAAG,SAAS,oBAAoB,CAAC,CAAC;AACjC,QAAA,EAAE,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,SAAS,oBAAoB,CAAC,CAAC"}

1
server/db/loginmanager.d.ts vendored Normal file
View File

@ -0,0 +1 @@
export declare const getOne: (username: string, password: string) => Promise<unknown>;

17
server/db/loginmanager.js Normal file
View File

@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getOne = void 0;
const connect_1 = require("./connect");
const getOne = (username, password) => {
const sql = 'SELECT * FROM accounts WHERE username = ? and password = ?';
return new Promise((resolve, reject) => {
connect_1.db.get(sql, [username, password], (err, row) => {
if (err)
reject(err);
if (!err)
resolve(row);
});
});
};
exports.getOne = getOne;
//# sourceMappingURL=loginmanager.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"loginmanager.js","sourceRoot":"","sources":["../../src/db/loginmanager.ts"],"names":[],"mappings":";;;AAAA,uCAA6B;AAEtB,MAAM,MAAM,GAAG,CAAC,QAAe,EAAE,QAAe,EAAE,EAAE;IACvD,MAAM,GAAG,GAAG,6DAA6D,CAAC;IAE1E,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACnC,YAAE,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC,GAAQ,EAAE,GAAY,EAAE,EAAE;YACzD,IAAI,GAAG;gBACH,MAAM,CAAC,GAAG,CAAC,CAAC;YAEhB,IAAI,CAAC,GAAG;gBAAE,OAAO,CAAC,GAAG,CAAC,CAAC;QAC3B,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;AACP,CAAC,CAAC;AAXW,QAAA,MAAM,UAWjB"}

1
server/development.d.ts vendored Normal file
View File

@ -0,0 +1 @@
export {};

24
server/development.js Normal file
View File

@ -0,0 +1,24 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const server = __importStar(require("./server"));
new server.App;
//# sourceMappingURL=development.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"development.js","sourceRoot":"","sources":["../src/development.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA,iDAAmC;AACnC,IAAI,MAAM,CAAC,GAAG,CAAA"}

2
server/es/development.d.ts vendored Normal file
View File

@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=development.d.ts.map

View File

@ -0,0 +1 @@
{"version":3,"file":"development.d.ts","sourceRoot":"","sources":["../../src/development.ts"],"names":[],"mappings":""}

3
server/es/development.js Normal file
View File

@ -0,0 +1,3 @@
import * as server from "./server";
new server.App;
//# sourceMappingURL=development.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"development.js","sourceRoot":"","sources":["../../src/development.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,UAAU,CAAC;AACnC,IAAI,MAAM,CAAC,GAAG,CAAA"}

7
server/es/server.d.ts vendored Normal file
View File

@ -0,0 +1,7 @@
import 'dotenv';
import express from 'express';
export declare class App {
protected app: express.Application;
constructor(NODE_ENV?: string, PORT?: number);
}
//# sourceMappingURL=server.d.ts.map

View File

@ -0,0 +1 @@
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,CAAC;AAEhB,OAAO,OAAO,MAAM,SAAS,CAAC;AAQ9B,qBAAa,GAAG;IACd,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,WAAW,CAAC;gBAEvB,QAAQ,GAAE,MAAsB,EAAE,IAAI,GAAE,MAAa;CAqBlE"}

14
server/es/server.js Normal file
View File

@ -0,0 +1,14 @@
import 'dotenv';
import express from 'express';
import helmet from 'helmet';
export class App {
constructor(NODE_ENV = 'development', PORT = 8080) {
const serverPort = process.env.PORT || PORT;
this.app = express();
this.app.use(helmet());
this.app.listen(serverPort, function () {
console.log('The server is running in port localhost: ', serverPort);
});
}
}
//# sourceMappingURL=server.js.map

1
server/es/server.js.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,CAAC;AAEhB,OAAO,OAAO,MAAM,SAAS,CAAC;AAG9B,OAAO,MAAM,MAAM,QAAQ,CAAC;AAK5B,MAAM,OAAO,GAAG;IAGd,YAAY,WAAmB,aAAa,EAAE,OAAe,IAAI;QAC/D,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC;QAE5C,IAAI,CAAC,GAAG,GAAG,OAAO,EAAE,CAAC;QACrB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QAIvB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,EAAE;YAC1B,OAAO,CAAC,GAAG,CAAC,2CAA2C,EAAE,UAAU,CAAC,CAAC;QACvE,CAAC,CAAC,CAAC;IACL,CAAC;CAUF"}

3
server/handlers/LoginHandler.d.ts vendored Normal file
View File

@ -0,0 +1,3 @@
import express from 'express';
export declare const ProcessLogin: (req: express.Request, res: express.Response) => express.Response<any, Record<string, any>> | Promise<express.Response<any, Record<string, any>> | undefined>;
export declare const authenticate: (req: express.Request, res: express.Response, next: express.NextFunction) => void;

View File

@ -0,0 +1,79 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.authenticate = exports.ProcessLogin = void 0;
const loginManager = __importStar(require("../db/loginmanager"));
const authenticator_1 = require("../lib/authenticator");
const ProcessLogin = (req, res) => {
console.log('request.body', req.body);
const username = req.body.username;
const password = req.body.password;
console.log('username', username);
console.log('password', password);
if (username && password) {
console.log('>> can try to login');
return loginManager
.getOne(username, password)
.then((data) => {
if (!data) {
console.warn('No data!');
return res.sendStatus(401);
}
else {
console.log('>> WE have data!', data);
const token = authenticator_1.generateAccessToken(username);
console.log(token);
}
})
.catch((err) => {
console.error(err);
return res.status(500).send({
message: err.message || 'Some error occurred while querying the database.',
});
});
}
else {
console.log('No shit');
return res.sendStatus(401);
}
};
exports.ProcessLogin = ProcessLogin;
async function processLoginV2(username, password) {
console.log('>> LoginHandler::processLoginV2');
console.log('username', username);
console.log('password', password);
const user = await loginManager.getOne(username, password);
if (!user)
throw 'Username or password is incorrect';
const id = user.id;
const token = authenticator_1.generateAccessToken(username);
console.log('>> LoginHandler::processLoginV2 : return ', { id: id, token });
return { id: id, token };
}
const authenticate = (req, res, next) => {
console.log('>> LoginHandler::authenticate');
const { username, password } = req.body;
processLoginV2(username, password)
.then((user) => res.json(user))
.catch(next);
};
exports.authenticate = authenticate;
//# sourceMappingURL=LoginHandler.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"LoginHandler.js","sourceRoot":"","sources":["../../src/handlers/LoginHandler.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAEA,iEAAmD;AAEnD,wDAA2D;AAEpD,MAAM,YAAY,GAAG,CAAC,GAAoB,EAAE,GAAqB,EAAE,EAAE;IAE1E,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;IAEtC,MAAM,QAAQ,GAAW,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC;IAC3C,MAAM,QAAQ,GAAW,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC;IAE3C,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAClC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAClC,IAAI,QAAQ,IAAI,QAAQ,EAAE;QACxB,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;QACnC,OAAO,YAAY;aAChB,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC;aAC1B,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;YACb,IAAI,CAAC,IAAI,EAAE;gBAET,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;gBACzB,OAAO,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;aAC5B;iBAAM;gBACL,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,IAAI,CAAC,CAAC;gBACtC,MAAM,KAAK,GAAG,mCAAmB,CAAC,QAAQ,CAAC,CAAC;gBAC5C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;aAIpB;QACH,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YACb,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACnB,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBAC1B,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,kDAAkD;aAC3E,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;KACN;SAAM;QACL,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAEvB,OAAO,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;KAC5B;AAGH,CAAC,CAAC;AAxCW,QAAA,YAAY,gBAwCvB;AAEF,KAAK,UAAU,cAAc,CAAC,QAAgB,EAAE,QAAgB;IAC9D,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;IAG/C,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAClC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAElC,MAAM,IAAI,GAAQ,MAAM,YAAY,CAAC,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAEhE,IAAI,CAAC,IAAI;QAAE,MAAM,mCAAmC,CAAC;IAErD,MAAM,EAAE,GAAG,IAAI,CAAC,EAAG,CAAC;IAGpB,MAAM,KAAK,GAAG,mCAAmB,CAAC,QAAQ,CAAC,CAAC;IAE5C,OAAO,CAAC,GAAG,CAAC,2CAA2C,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IAE5E,OAAO,EAAE,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;AAC3B,CAAC;AAEM,MAAM,YAAY,GAAG,CAAC,GAAoB,EAAE,GAAqB,EAAE,IAA0B,EAAE,EAAE;IACtG,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC;IAC7C,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC;IACxC,cAAc,CAAC,QAAQ,EAAE,QAAQ,CAAC;SAC/B,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;SAC9B,KAAK,CAAC,IAAI,CAAC,CAAC;AACjB,CAAC,CAAC;AANW,QAAA,YAAY,gBAMvB"}

3
server/lib/ValidateRequest.d.ts vendored Normal file
View File

@ -0,0 +1,3 @@
import express from 'express';
import Joi from 'joi';
export declare function validateRequest(req: express.Request, next: express.NextFunction, schema: Joi.Schema): void;

View File

@ -0,0 +1,20 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateRequest = void 0;
function validateRequest(req, next, schema) {
const options = {
abortEarly: false,
allowUnknown: true,
stripUnknown: true
};
const { error, value } = schema.validate(req.body, options);
if (error) {
next(`Validation error: ${error.details.map(x => x.message).join(', ')}`);
}
else {
req.body = value;
next();
}
}
exports.validateRequest = validateRequest;
//# sourceMappingURL=ValidateRequest.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"ValidateRequest.js","sourceRoot":"","sources":["../../src/lib/ValidateRequest.ts"],"names":[],"mappings":";;;AAGA,SAAgB,eAAe,CAAC,GAAmB,EAAE,IAAyB,EAAE,MAAiB;IAC7F,MAAM,OAAO,GAAG;QACZ,UAAU,EAAE,KAAK;QACjB,YAAY,EAAE,IAAI;QAClB,YAAY,EAAE,IAAI;KACrB,CAAC;IACF,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC5D,IAAI,KAAK,EAAE;QACP,IAAI,CAAC,qBAAqB,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;KAC7E;SAAM;QACH,GAAG,CAAC,IAAI,GAAG,KAAK,CAAC;QACjB,IAAI,EAAE,CAAC;KACV;AACL,CAAC;AAbD,0CAaC"}

3
server/lib/authenticator.d.ts vendored Normal file
View File

@ -0,0 +1,3 @@
import express from "express";
export declare function authenticateToken(req: any, res: express.Response, next: express.NextFunction): express.Response<any, Record<string, any>> | undefined;
export declare function generateAccessToken(username: string): string;

View File

@ -0,0 +1,47 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateAccessToken = exports.authenticateToken = void 0;
const jwt = __importStar(require("jsonwebtoken"));
function authenticateToken(req, res, next) {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (!token)
return res.sendStatus(401);
console.log("token", token);
jwt.verify(token, process.env.TOKEN_SECRET, (err, user) => {
console.error(err);
if (err)
return res.sendStatus(403);
req.user = user;
next();
});
}
exports.authenticateToken = authenticateToken;
function generateAccessToken(username) {
const payload = {
username
};
const tokenSecret = process.env.TOKEN_SECRET;
return jwt.sign(payload, tokenSecret, { expiresIn: '3h' });
}
exports.generateAccessToken = generateAccessToken;
//# sourceMappingURL=authenticator.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"authenticator.js","sourceRoot":"","sources":["../../src/lib/authenticator.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;AACA,kDAAoC;AAEpC,SAAgB,iBAAiB,CAAC,GAAQ,EAAG,GAAqB,EAAE,IAA0B;IAC1F,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IAEhD,MAAM,KAAK,GACP,UAAU,IAAI,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAE3C,IAAI,CAAC,KAAK;QAAE,OAAO,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IAEvC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAE5B,GAAG,CAAC,MAAM,CACN,KAAe,EACf,OAAO,CAAC,GAAG,CAAC,YAAsB,EAClC,CAAC,GAAQ,EAAE,IAAS,EAAE,EAAE;QACpB,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACnB,IAAI,GAAG;YAAE,OAAO,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QACpC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;QAChB,IAAI,EAAE,CAAC;IACX,CAAC,CACJ,CAAC;AAEN,CAAC;AArBD,8CAqBC;AAED,SAAgB,mBAAmB,CAAC,QAAe;IAE/C,MAAM,OAAO,GAAG;QACZ,QAAQ;KACX,CAAC;IACF,MAAM,WAAW,GAAW,OAAO,CAAC,GAAG,CAAC,YAAa,CAAC;IACtD,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAC/D,CAAC;AAPD,kDAOC"}

1
server/routes/login.d.ts vendored Normal file
View File

@ -0,0 +1 @@
export declare const Login: (app: any) => void;

21
server/routes/login.js Normal file
View File

@ -0,0 +1,21 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Login = void 0;
const LoginHandler_1 = require("../handlers/LoginHandler");
const joi_1 = __importDefault(require("joi"));
const ValidateRequest_1 = require("../lib/ValidateRequest");
function loginSchema(req, res, next) {
const schema = joi_1.default.object({
username: joi_1.default.string().required(),
password: joi_1.default.string().required(),
});
ValidateRequest_1.validateRequest(req, next, schema);
}
const Login = (app) => {
app.route('/login').post(loginSchema, LoginHandler_1.authenticate);
};
exports.Login = Login;
//# sourceMappingURL=login.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/routes/login.ts"],"names":[],"mappings":";;;;;;AACA,2DAAsE;AAEtE,8CAAsB;AAEtB,4DAAyD;AAEzD,SAAS,WAAW,CAAC,GAAoB,EAAE,GAAqB,EAAE,IAA0B;IAC1F,MAAM,MAAM,GAAG,aAAG,CAAC,MAAM,CAAC;QACxB,QAAQ,EAAE,aAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QACjC,QAAQ,EAAE,aAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;KAClC,CAAC,CAAC;IACH,iCAAe,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;AACrC,CAAC;AAEM,MAAM,KAAK,GAAG,CAAC,GAAQ,EAAE,EAAE;IAChC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,2BAAY,CAAC,CAAC;AACtD,CAAC,CAAC;AAFW,QAAA,KAAK,SAEhB"}

5
server/server.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
import express from 'express';
export declare class App {
protected app: express.Application;
constructor(NODE_ENV?: string, PORT?: number);
}

59
server/server.js Normal file
View File

@ -0,0 +1,59 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.App = void 0;
const dotenv = __importStar(require("dotenv"));
const express_1 = __importDefault(require("express"));
const helmet_1 = __importDefault(require("helmet"));
const cors_1 = __importDefault(require("cors"));
const morgan_1 = __importDefault(require("morgan"));
const authenticator_1 = require("./lib/authenticator");
const path = __importStar(require("path"));
const login_1 = require("./routes/login");
dotenv.config();
class App {
constructor(NODE_ENV = 'development', PORT = 8080) {
const serverPort = process.env.PORT || PORT;
const sitePath = 'public';
this.app = express_1.default();
this.app.use(morgan_1.default('dev'));
this.app.use(express_1.default.json());
this.app.use(cors_1.default());
this.app.use(helmet_1.default());
this.app.set('trust proxy', 1);
this.app.post('/test', authenticator_1.authenticateToken, (req, res) => {
res.sendStatus(200);
});
const login = login_1.Login(this.app);
this.app.get('/', (req, res) => {
console.log('p', path.join(process.cwd(), sitePath));
res.sendFile('index.html', { root: path.join(process.cwd(), sitePath) });
});
this.app.listen(serverPort, function () {
console.log('The server is running in port localhost: ', serverPort);
});
}
}
exports.App = App;
//# sourceMappingURL=server.js.map

1
server/server.js.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+CAAiC;AAEjC,sDAA8B;AAC9B,oDAA4B;AAC5B,gDAAwB;AACxB,oDAA4B;AAI5B,uDAAwD;AACxD,2CAA6B;AAE7B,0CAAqC;AAErC,MAAM,CAAC,MAAM,EAAE,CAAC;AAEhB,MAAa,GAAG;IAGd,YAAY,WAAmB,aAAa,EAAE,OAAe,IAAI;QAC/D,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC;QAC5C,MAAM,QAAQ,GAAG,QAAQ,CAAC;QAE1B,IAAI,CAAC,GAAG,GAAG,iBAAO,EAAE,CAAC;QACrB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,gBAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAE5B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,iBAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QAE7B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,cAAI,EAAE,CAAC,CAAC;QACrB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,gBAAM,EAAE,CAAC,CAAC;QAEvB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;QAE/B,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,iCAAiB,EAAE,CAAC,GAAoB,EAAE,GAAqB,EAAE,EAAE;YACxF,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QACtB,CAAC,CAAC,CAAC;QAGH,MAAM,KAAK,GAAG,aAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAE9B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAoB,EAAE,GAAqB,EAAE,EAAE;YAChE,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAC;YACrD,GAAG,CAAC,QAAQ,CAAC,YAAY,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;QAC3E,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,EAAE;YAC1B,OAAO,CAAC,GAAG,CAAC,2CAA2C,EAAE,UAAU,CAAC,CAAC;QACvE,CAAC,CAAC,CAAC;IACL,CAAC;CA2BF;AA3DD,kBA2DC"}

3
src/db/connect.ts Normal file
View File

@ -0,0 +1,3 @@
const sqlite3 = require('sqlite3').verbose();
console.log(`${__dirname}/../../db/users.db`);
export const db = new sqlite3.Database(`${__dirname}/../../db/users.db`);

14
src/db/loginmanager.ts Normal file
View File

@ -0,0 +1,14 @@
import {db} from './connect';
export const getOne = (username:string, password:string) => {
const sql = 'SELECT * FROM accounts WHERE username = ? and password = ?';
return new Promise((resolve, reject) => {
db.get(sql, [username, password], (err: any, row: unknown) => {
if (err)
reject(err);
if (!err) resolve(row);
});
});
};

2
src/development.ts Normal file
View File

@ -0,0 +1,2 @@
import * as server from "./server";
new server.App

View File

@ -0,0 +1,76 @@
import express from 'express';
import * as loginManager from '../db/loginmanager';
import { generateAccessToken } from '../lib/authenticator';
export const ProcessLogin = (req: express.Request, res: express.Response) => {
// console.log('processLogin', req);
console.log('request.body', req.body);
const username: string = req.body.username;
const password: string = req.body.password;
console.log('username', username);
console.log('password', password);
if (username && password) {
console.log('>> can try to login');
return loginManager
.getOne(username, password)
.then((data) => {
if (!data) {
// response.redirect('/');
console.warn('No data!');
return res.sendStatus(401);
} else {
console.log('>> WE have data!', data);
const token = generateAccessToken(username);
console.log(token);
/* request.session.username = username;
request.session.auth = 'jhgkjgkjhgkjhgjkhgjkhgfhghfjgfjhgf';
response.redirect('/menu');*/
}
})
.catch((err) => {
console.error(err);
return res.status(500).send({
message: err.message || 'Some error occurred while querying the database.',
});
});
} else {
console.log('No shit');
// can't try to login
return res.sendStatus(401);
}
// return res.sendStatus(418);
};
async function processLoginV2(username: string, password: string) {
console.log('>> LoginHandler::processLoginV2');
// console.log('request.body', req.body);
console.log('username', username);
console.log('password', password);
const user: any = await loginManager.getOne(username, password);
if (!user) throw 'Username or password is incorrect';
const id = user.id!;
// authentication successful
const token = generateAccessToken(username);
console.log('>> LoginHandler::processLoginV2 : return ', { id: id, token });
return { id: id, token };
}
export const authenticate = (req: express.Request, res: express.Response, next: express.NextFunction) => {
console.log('>> LoginHandler::authenticate');
const { username, password } = req.body;
processLoginV2(username, password)
.then((user) => res.json(user))
.catch(next);
};

View File

@ -0,0 +1,17 @@
import express from 'express';
import Joi from 'joi'
export function validateRequest(req:express.Request, next:express.NextFunction, schema:Joi.Schema):void {
const options = {
abortEarly: false, // include all errors
allowUnknown: true, // ignore unknown props
stripUnknown: true // remove unknown props
};
const { error, value } = schema.validate(req.body, options);
if (error) {
next(`Validation error: ${error.details.map(x => x.message).join(', ')}`);
} else {
req.body = value;
next();
}
}

34
src/lib/authenticator.ts Normal file
View File

@ -0,0 +1,34 @@
import express from "express";
import * as jwt from "jsonwebtoken";
export function authenticateToken(req: any, res: express.Response, next: express.NextFunction,) {
const authHeader = req.headers['authorization'];
const token: '' | undefined | string =
authHeader && authHeader.split(' ')[1];
if (!token) return res.sendStatus(401);
console.log("token", token);
jwt.verify(
token as string,
process.env.TOKEN_SECRET as string,
(err: any, user: any) => {
console.error(err);
if (err) return res.sendStatus(403);
req.user = user;
next();
},
);
}
export function generateAccessToken(username:string) {
// expires after half and hour (1800 seconds = 30 minutes)
const payload = {
username
};
const tokenSecret: string = process.env.TOKEN_SECRET!;
return jwt.sign(payload, tokenSecret, { expiresIn: '3h' });
}

18
src/routes/login.ts Normal file
View File

@ -0,0 +1,18 @@
import express from 'express';
import { ProcessLogin, authenticate } from '../handlers/LoginHandler';
import Joi from 'joi';
import { validateRequest } from '../lib/ValidateRequest';
function loginSchema(req: express.Request, res: express.Response, next: express.NextFunction) {
const schema = Joi.object({
username: Joi.string().required(),
password: Joi.string().required(),
});
validateRequest(req, next, schema);
}
export const Login = (app: any) => {
app.route('/login').post(loginSchema, authenticate);
};

76
src/server.ts Normal file
View File

@ -0,0 +1,76 @@
import * as dotenv from 'dotenv';
import express from 'express';
import helmet from 'helmet';
import cors from 'cors';
import logger from 'morgan';
import * as jwt from 'jsonwebtoken';
import { authenticateToken } from './lib/authenticator';
import * as path from 'path';
import {Login} from "./routes/login";
dotenv.config();
export class App {
protected app: express.Application;
constructor(NODE_ENV: string = 'development', PORT: number = 8080) {
const serverPort = process.env.PORT || PORT;
const sitePath = 'public';
this.app = express();
this.app.use(logger('dev'));
this.app.use(express.json());
this.app.use(cors());
this.app.use(helmet());
this.app.set('trust proxy', 1);
this.app.post('/test', authenticateToken, (req: express.Request, res: express.Response) => {
res.sendStatus(200);
});
// ///
const login = Login(this.app);
this.app.get('/', (req: express.Request, res: express.Response) => {
console.log('p', path.join(process.cwd(), sitePath));
res.sendFile('index.html', { root: path.join(process.cwd(), sitePath) });
});
this.app.listen(serverPort, function () {
console.log('The server is running in port localhost: ', serverPort);
});
}
/* authenticateToken(
req: any,
res: express.Response,
next: express.NextFunction,
) {
const authHeader = req.headers['authorization'];
const token: '' | undefined | string =
authHeader && authHeader.split(' ')[1];
if (!token) return res.sendStatus(401);
console.log("token", token);
jwt.verify(
token as string,
process.env.TOKEN_SECRET as string,
(err: any, user: any) => {
console.error(err);
if (err) return res.sendStatus(403);
req.user = user;
next();
},
);
}*/
}

4
testing/postLogin.sh Executable file
View File

@ -0,0 +1,4 @@
#!/bin/sh
curl -X POST http://localhost:8080/login \
-H "Content-Type: application/json" \
-d "{\"username\":\"my_login\",\"password\":\"my_password\"}"

3
testing/postLoginFail.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
curl -X POST http://localhost:8080/login \
-H "Content-Type: application/json"

18
tsconfig.json Executable file
View File

@ -0,0 +1,18 @@
{
"compilerOptions": {
"strict": true,
"declaration": true,
"target": "ES2018",
"module": "commonjs",
"noImplicitAny": true,
"removeComments": true,
"preserveConstEnums": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"sourceMap": true,
"esModuleInterop": true,
"outDir": "./server"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "test/**/*.ts"]
}

149
tslint.json Normal file
View File

@ -0,0 +1,149 @@
{
"extends": "tslint:recommended",
"rules": {
"align": {
"options": [
"parameters",
"statements"
]
},
"array-type": false,
"arrow-return-shorthand": true,
"curly": true,
"deprecation": {
"severity": "warning"
},
"component-class-suffix": [true, "Page", "Component"],
"contextual-lifecycle": true,
"directive-class-suffix": true,
"directive-selector": [
true,
"attribute",
"app",
"camelCase"
],
"component-selector": [
true,
"element",
"app",
"kebab-case"
],
"eofline": true,
"import-blacklist": [
true,
"rxjs/Rx"
],
"import-spacing": true,
"indent": {
"options": [
"spaces"
]
},
"max-classes-per-file": false,
"max-line-length": [
true,
140
],
"member-ordering": [
true,
{
"order": [
"static-field",
"instance-field",
"static-method",
"instance-method"
]
}
],
"no-console": [
true,
"debug",
"info",
"time",
"timeEnd",
"trace"
],
"no-empty": false,
"no-inferrable-types": [
true,
"ignore-params"
],
"no-non-null-assertion": true,
"no-redundant-jsdoc": true,
"no-switch-case-fall-through": true,
"no-var-requires": false,
"object-literal-key-quotes": [
true,
"as-needed"
],
"quotemark": [
true,
"single"
],
"semicolon": {
"options": [
"always"
]
},
"space-before-function-paren": {
"options": {
"anonymous": "never",
"asyncArrow": "always",
"constructor": "never",
"method": "never",
"named": "never"
}
},
"typedef-whitespace": {
"options": [
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
},
{
"call-signature": "onespace",
"index-signature": "onespace",
"parameter": "onespace",
"property-declaration": "onespace",
"variable-declaration": "onespace"
}
]
},
"variable-name": {
"options": [
"ban-keywords",
"check-format",
"allow-pascal-case"
]
},
"whitespace": {
"options": [
"check-branch",
"check-decl",
"check-operator",
"check-separator",
"check-type",
"check-typecast"
]
},
"no-conflicting-lifecycle": true,
"no-host-metadata-property": true,
"no-input-rename": true,
"no-inputs-metadata-property": true,
"no-output-native": true,
"no-output-on-prefix": true,
"no-output-rename": true,
"no-outputs-metadata-property": true,
"template-banana-in-box": true,
"template-no-negated-async": true,
"use-lifecycle-interface": true,
"use-pipe-transform-interface": true,
"object-literal-sort-keys": false
},
"rulesDirectory": [
"codelyzer"
]
}