create-tinny-backend 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +107 -0
- package/package.json +38 -0
- package/template/admin/auth.ts +85 -0
- package/template/admin/monitor.ts +102 -0
- package/template/admin/routes.ts +192 -0
- package/template/app/index.ts +6 -0
- package/template/lib/CreateSrv.ts +9 -0
- package/template/package.json +48 -0
- package/template/public/admin/index.html +2012 -0
- package/template/public/doc/index.html +1651 -0
- package/template/public/example/default.html +437 -0
- package/template/public/imgs/logo-square.png +0 -0
- package/template/public/imgs/logo.png +0 -0
- package/template/public/imgs/no-bg-logo.png +0 -0
- package/template/public/login/css/style.css +109 -0
- package/template/public/login/index.html +883 -0
- package/template/public/login/new-password.html +1173 -0
- package/template/public/status/401.html +649 -0
- package/template/public/status/404.html +668 -0
- package/template/tsconfig.json +44 -0
package/index.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs-extra');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { execSync } = require('child_process');
|
|
6
|
+
const prompts = require('prompts');
|
|
7
|
+
const { cyan, green, bold, yellow, red, gray } = require('kolorist');
|
|
8
|
+
const ora = require('ora');
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
const args = process.argv.slice(2);
|
|
12
|
+
const projectName = args[0] || 'myapp';
|
|
13
|
+
const targetDir = path.join(process.cwd(), projectName);
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
if (fs.existsSync(targetDir)) {
|
|
17
|
+
console.error(red(`✖ Directory "${projectName}" already exists.`));
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
(async function main() {
|
|
23
|
+
console.log(cyan('\nWelcome to create-tinny-backend\n'));
|
|
24
|
+
|
|
25
|
+
const response = await prompts([
|
|
26
|
+
{
|
|
27
|
+
type: 'text',
|
|
28
|
+
name: 'description',
|
|
29
|
+
message: 'Project description',
|
|
30
|
+
initial: 'A tinny-backend application'
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
type: 'text',
|
|
34
|
+
name: 'author',
|
|
35
|
+
message: 'Author name',
|
|
36
|
+
initial: 'Yassine Ajagrou'
|
|
37
|
+
}
|
|
38
|
+
]);
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
const templateDir = path.join(__dirname, 'template');
|
|
42
|
+
if (!fs.existsSync(templateDir)) {
|
|
43
|
+
console.error(red(`✖ Template folder not found at ${templateDir}`));
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const spinner = ora('Copying template files...').start();
|
|
48
|
+
try {
|
|
49
|
+
fs.copySync(templateDir, targetDir);
|
|
50
|
+
spinner.succeed(green('Template copied successfully'));
|
|
51
|
+
} catch (err) {
|
|
52
|
+
spinner.fail(red('Failed to copy template'));
|
|
53
|
+
console.error(err);
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
const pkgPath = path.join(targetDir, 'package.json');
|
|
59
|
+
if (fs.existsSync(pkgPath)) {
|
|
60
|
+
const pkg = fs.readJsonSync(pkgPath);
|
|
61
|
+
pkg.name = projectName;
|
|
62
|
+
pkg.description = response.description || pkg.description;
|
|
63
|
+
pkg.author = response.author || pkg.author;
|
|
64
|
+
fs.writeJsonSync(pkgPath, pkg, { spaces: 2 });
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const installSpinner = ora('Installing dependencies (npm install)...').start();
|
|
68
|
+
try {
|
|
69
|
+
execSync(`cd "${targetDir}" && npm install`, { stdio: 'pipe' });
|
|
70
|
+
installSpinner.succeed(green('Dependencies installed'));
|
|
71
|
+
} catch (err) {
|
|
72
|
+
installSpinner.fail(red('npm install failed'));
|
|
73
|
+
console.error(err);
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const buildSpinner = ora('Building project (npm run build)...').start();
|
|
78
|
+
try {
|
|
79
|
+
execSync(`cd "${targetDir}" && npm run build`, { stdio: 'pipe' });
|
|
80
|
+
buildSpinner.succeed(green('Build completed'));
|
|
81
|
+
} catch (err) {
|
|
82
|
+
buildSpinner.fail(red('Build failed'));
|
|
83
|
+
console.error(err);
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
console.log(cyan('\n▶ Starting the server (npm run start)...\n'));
|
|
88
|
+
console.log(gray('Press Ctrl+C to stop the server when done.\n'));
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
execSync(`cd "${targetDir}" && npm run start`, { stdio: 'inherit' });
|
|
92
|
+
} catch (err) {
|
|
93
|
+
console.log(yellow('\nServer stopped.'));
|
|
94
|
+
process.exit(0);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
console.log(green(`\n✅ Project "${bold(projectName)}" is ready!`));
|
|
98
|
+
console.log(cyan(` cd ${projectName}`));
|
|
99
|
+
console.log(cyan(' npm run dev # for development with hot-reload'));
|
|
100
|
+
console.log(cyan(' npm start # for production (already running)'));
|
|
101
|
+
console.log(gray('\n--------------------------------------------------'));
|
|
102
|
+
console.log(gray('Created by Yassine Ajagrou - https://github.com/iaceene'));
|
|
103
|
+
console.log(gray('--------------------------------------------------\n'));
|
|
104
|
+
})().catch((err) => {
|
|
105
|
+
console.error(red('Unexpected error:'), err);
|
|
106
|
+
process.exit(1);
|
|
107
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-tinny-backend",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Scaffold a new tinny-backend project",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"create-tinny-backend": "./index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
11
|
+
},
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/iaceene/create-tinny-backend.git"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"tinny-backend",
|
|
18
|
+
"scaffold",
|
|
19
|
+
"starter",
|
|
20
|
+
"backend"
|
|
21
|
+
],
|
|
22
|
+
"author": "Yassine Ajagrou",
|
|
23
|
+
"license": "ISC",
|
|
24
|
+
"type": "commonjs",
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/iaceene/create-tinny-backend/issues"
|
|
27
|
+
},
|
|
28
|
+
"homepage": "https://github.com/iaceene/create-tinny-backend#readme",
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"fs-extra": "^11.2.0",
|
|
31
|
+
"prompts": "^2.4.2",
|
|
32
|
+
"kolorist": "^1.8.0",
|
|
33
|
+
"ora": "^8.0.1"
|
|
34
|
+
},
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=18.0.0"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import * as JWT from "jsonwebtoken"
|
|
2
|
+
import * as DOTENV from "dotenv"
|
|
3
|
+
import Server from "tinny-backend";
|
|
4
|
+
import type {
|
|
5
|
+
AdminSessions,
|
|
6
|
+
ServerReq,
|
|
7
|
+
ServerRes
|
|
8
|
+
} from "tinny-backend"
|
|
9
|
+
|
|
10
|
+
export type auth_t = {
|
|
11
|
+
Auth: (req: ServerReq, res: ServerRes) => Promise<void>;
|
|
12
|
+
sessions: AdminSessions[];
|
|
13
|
+
key: string;
|
|
14
|
+
SetUsername: (userName: string) => void;
|
|
15
|
+
SetPassword: (passWord: string) => void;
|
|
16
|
+
GetPasswd: () => string;
|
|
17
|
+
GetUser: () => string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default function Authen(server: Server): auth_t{
|
|
21
|
+
DOTENV.config()
|
|
22
|
+
|
|
23
|
+
let username: string = process.env.ADMIN_USERNAME || ""
|
|
24
|
+
let password: string = process.env.ADMIN_PASSWORD || ""
|
|
25
|
+
const key: string = process.env.ADMIN_KEY || ""
|
|
26
|
+
const sessions: AdminSessions[] = []
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
const isAuthed = (res: ServerRes): boolean =>{
|
|
30
|
+
const TOKEN = res.getCookie("token")
|
|
31
|
+
if (!TOKEN)
|
|
32
|
+
return false
|
|
33
|
+
try {
|
|
34
|
+
const decoded: any = JWT.default.verify(TOKEN.value, key);
|
|
35
|
+
|
|
36
|
+
if (typeof decoded.id === undefined)
|
|
37
|
+
throw new Error("None valid token");
|
|
38
|
+
for (let i = 0; i < sessions.length; i++){
|
|
39
|
+
if (sessions[i]?.id === decoded.id){
|
|
40
|
+
if (!sessions[i]?.isValid)
|
|
41
|
+
throw new Error("None valid token");
|
|
42
|
+
(sessions[i] as AdminSessions).request += 1;
|
|
43
|
+
(res as any).currentID = decoded.id;
|
|
44
|
+
return true
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
throw new Error("None valid UUID");
|
|
48
|
+
} catch {
|
|
49
|
+
server.log("a user try to login to admin panel using none valid token", "error")
|
|
50
|
+
return false
|
|
51
|
+
}
|
|
52
|
+
return true
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const Auth = async (req: ServerReq, res: ServerRes)=>{
|
|
56
|
+
if (!isAuthed(res)){
|
|
57
|
+
if (req.ReqUrl?.pathname == "/")
|
|
58
|
+
return await server.SendFile(res, "public/login/index.html", 401)
|
|
59
|
+
return await server.SendFile(res, "public/status/401.html", 401)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (req.ReqUrl?.pathname == "/")
|
|
63
|
+
return await server.SendFile(res, "public/admin/index.html", 200)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const SetUsername = (userName: string)=>{
|
|
67
|
+
console.log("old pwd ", username)
|
|
68
|
+
username = userName
|
|
69
|
+
console.log("new pwd ", username)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const SetPassword = (passWord: string)=>{
|
|
73
|
+
password = passWord
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const GetPasswd = ()=>{
|
|
77
|
+
return password
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const GetUser = ()=>{
|
|
81
|
+
return username
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return {Auth, sessions, key, SetUsername, SetPassword, GetPasswd, GetUser}
|
|
85
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import Server from "tinny-backend";
|
|
2
|
+
import type {
|
|
3
|
+
ServerReq,
|
|
4
|
+
ServerRes
|
|
5
|
+
} from "tinny-backend"
|
|
6
|
+
import Authen from "./auth.js";
|
|
7
|
+
import Routes from "./routes.js";
|
|
8
|
+
|
|
9
|
+
export default function monitor(server: Server){
|
|
10
|
+
const {Auth, sessions, key, SetUsername, SetPassword, GetPasswd, GetUser} = Authen(server)
|
|
11
|
+
const { ChangeUser, LogoutSession, ChangePasswd, ChangePasswdAuth, CheckUsername, Status, Logout, Login } = Routes(server, {Auth, sessions, key, SetUsername, SetPassword, GetPasswd, GetUser})
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
server.add({
|
|
15
|
+
method: "POST",
|
|
16
|
+
handler: Login,
|
|
17
|
+
path: "/api/login"
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
server.add({
|
|
21
|
+
method: "GET",
|
|
22
|
+
middelWares: [Auth],
|
|
23
|
+
handler: async (req, res)=>{
|
|
24
|
+
return await server.SendFile(res, "public/login/index.html", 200)
|
|
25
|
+
},
|
|
26
|
+
path: "/"
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
server.add({
|
|
30
|
+
method: "GET",
|
|
31
|
+
middelWares: [Auth],
|
|
32
|
+
handler: Logout,
|
|
33
|
+
path: "/api/logout"
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
server.add({
|
|
37
|
+
method: "GET",
|
|
38
|
+
middelWares: [Auth],
|
|
39
|
+
path: "/admin/status",
|
|
40
|
+
handler: Status
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
server.add({
|
|
44
|
+
method: "GET",
|
|
45
|
+
middelWares: [Auth],
|
|
46
|
+
path: "/messages",
|
|
47
|
+
handler: async (req: ServerReq, res: ServerRes) => {
|
|
48
|
+
res.send(200, {
|
|
49
|
+
"logs" : server.getLogs()
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
server.add({
|
|
55
|
+
method: "GET",
|
|
56
|
+
path: "/passwd",
|
|
57
|
+
handler: async (req: ServerReq, res: ServerRes) => {
|
|
58
|
+
return await server.SendFile(res, "./public/login/new-password.html", 200)
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
server.add({
|
|
63
|
+
method: "GET",
|
|
64
|
+
path: "/api/passwd/:username",
|
|
65
|
+
handler: CheckUsername
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
server.add({
|
|
69
|
+
method: "POST",
|
|
70
|
+
path: "/api/passwd/change",
|
|
71
|
+
handler: ChangePasswd
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
server.add({
|
|
75
|
+
method: "POST",
|
|
76
|
+
middelWares: [Auth],
|
|
77
|
+
path: "/api/logout/:SessionId",
|
|
78
|
+
handler: LogoutSession
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
server.add({
|
|
82
|
+
method: "POST",
|
|
83
|
+
middelWares: [Auth],
|
|
84
|
+
path: "/passwd/change/auth",
|
|
85
|
+
handler: ChangePasswdAuth
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
server.add({
|
|
89
|
+
method: "POST",
|
|
90
|
+
middelWares: [Auth],
|
|
91
|
+
path: "/api/user/change",
|
|
92
|
+
handler: ChangeUser
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
server.servDir("./public/doc", "docs")
|
|
96
|
+
server.servDir("./public/imgs", "imgs")
|
|
97
|
+
server.servDir("./public/login", "/", [Auth])
|
|
98
|
+
server.servDir("./public/admin", "admin", [Auth])
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
server.listen(false)
|
|
102
|
+
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import * as os from "node:os";
|
|
2
|
+
import * as JWT from "jsonwebtoken"
|
|
3
|
+
import Server from "tinny-backend";
|
|
4
|
+
import type {
|
|
5
|
+
AdminSessions,
|
|
6
|
+
ServerReq,
|
|
7
|
+
ServerRes
|
|
8
|
+
} from "tinny-backend"
|
|
9
|
+
|
|
10
|
+
import { type auth_t} from "./auth.js";
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
export default function Routes(server: Server, obj: auth_t){
|
|
15
|
+
|
|
16
|
+
const {sessions, key, SetUsername, SetPassword, GetPasswd, GetUser} = obj
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
const Login = async (req: ServerReq, res: ServerRes) => {
|
|
20
|
+
let token
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
if (!req.body.username || req.body.username !== GetUser() || !req.body.password || req.body.password !== GetPasswd())
|
|
24
|
+
throw new Error("User has entred a none valid cridentials")
|
|
25
|
+
const SESSION_ID = crypto.randomUUID()
|
|
26
|
+
token = JWT.default.sign({ id: SESSION_ID }, key, { expiresIn: "1h" });
|
|
27
|
+
res.addCookie("token", token)
|
|
28
|
+
sessions.push({
|
|
29
|
+
id: SESSION_ID,
|
|
30
|
+
isValid: true,
|
|
31
|
+
creation: Date.now(),
|
|
32
|
+
userAgent: req.headers["user-agent"] ?? "DEVICE",
|
|
33
|
+
ip: (req as ServerReq).ip ?? "UNKNOWN",
|
|
34
|
+
request: 0
|
|
35
|
+
})
|
|
36
|
+
res.send(200, "./public/admin/index.html", { "set-cookie" : `token=${token}; Path=/; SameSite=Lax; HttpOnly` });
|
|
37
|
+
}
|
|
38
|
+
catch(err: any) {
|
|
39
|
+
res.server.log(err.message, "error")
|
|
40
|
+
res.server.log("A user entred a none valid cridentionl", "error")
|
|
41
|
+
res.send(403, {"Error" : "Access Denied"})
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const Logout = async (req: ServerReq, res: ServerRes) => {
|
|
46
|
+
let payloud: any
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
const TOKEN = res.getCookie("token")
|
|
50
|
+
if (!TOKEN)
|
|
51
|
+
return server.SendFile(res, "public/login/index.html", 401)
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
payloud = JWT.default.verify(TOKEN.value, key);
|
|
55
|
+
if (typeof payloud.id === "undefined")
|
|
56
|
+
throw new Error("an Error is happens");
|
|
57
|
+
for (let i = 0; i < sessions.length; i++){
|
|
58
|
+
if (sessions[i]?.id === payloud.id){
|
|
59
|
+
if (!sessions[i]?.isValid)
|
|
60
|
+
throw new Error("None valid token");
|
|
61
|
+
(sessions[i] as AdminSessions).request += 1;
|
|
62
|
+
(sessions[i] as AdminSessions).isValid = false;
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return await server.SendFile(res, "public/login/index.html", 200)
|
|
67
|
+
}
|
|
68
|
+
catch(err: any) {
|
|
69
|
+
server.log(err.message, "error")
|
|
70
|
+
res.send(403, {"Error" : "Access Denied"})
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const Status = async (req: ServerReq, res: ServerRes) => {
|
|
75
|
+
const now: number = Date.now()
|
|
76
|
+
res.send(200, {
|
|
77
|
+
"Machin uptime": `${Math.floor(os.uptime() / 86400)}d ${Math.floor((os.uptime() % 86400) / 3600)}h ${Math.floor((os.uptime() % 3600) / 60)}m`,
|
|
78
|
+
"Server uptime": `${Math.floor((now - server.getUpTime()) / (1000 * 60 * 60 * 24)) % 60}D ${Math.floor((now - server.getUpTime()) / (1000 * 60 * 60)) % 60}H ${Math.floor((now - server.getUpTime()) / (1000 * 60)) % 60}M ${Math.floor((now - server.getUpTime()) / 1000) % 60}S`,
|
|
79
|
+
"Arch" : os.arch(),
|
|
80
|
+
"Platform" : os.platform(),
|
|
81
|
+
"Memory" : `${(os.totalmem() / (1024 ** 3)).toFixed(2)} GB`,
|
|
82
|
+
"Used Memory" : `${((os.totalmem() - os.freemem()) / (1024 ** 3)).toFixed(2)} GB`,
|
|
83
|
+
"Free Memory" : `${(os.freemem() / (1024 ** 3)).toFixed(2)} GB`,
|
|
84
|
+
"Cpu" : os.cpus()[0],
|
|
85
|
+
"Connected clients" : "0",
|
|
86
|
+
"Total requests" : server.getReqCount(),
|
|
87
|
+
"Currnet-session": (res as any).currentID,
|
|
88
|
+
"sessions": sessions,
|
|
89
|
+
"routes" : server.getMethodHandlers(),
|
|
90
|
+
"logs" : server.getLogs()
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const CheckUsername = async (req: ServerReq, res: ServerRes) => {
|
|
95
|
+
let userName = req.params.username
|
|
96
|
+
|
|
97
|
+
if (typeof userName === undefined)
|
|
98
|
+
return res.send(404, {"user": userName, status: "not found"})
|
|
99
|
+
|
|
100
|
+
if (userName === GetUser())
|
|
101
|
+
return res.send(200, {"user": userName, status: "found"})
|
|
102
|
+
|
|
103
|
+
return res.send(404, {"user": userName, status: "not found"})
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const ChangePasswd = async (req: ServerReq, res: ServerRes) => {
|
|
107
|
+
try {
|
|
108
|
+
|
|
109
|
+
const { userName, oldpwd, newpwd } = req.body;
|
|
110
|
+
|
|
111
|
+
if (!userName || !oldpwd || !newpwd)
|
|
112
|
+
return res.send(400, { "user": userName || 'unknown', status: 'missing fields', message: 'Username, old password, and new password are required' });
|
|
113
|
+
|
|
114
|
+
if (userName !== GetUser())
|
|
115
|
+
return res.send(404, {"user": userName, status: 'this username not found', message: `${userName} not found` });
|
|
116
|
+
|
|
117
|
+
if (oldpwd !== GetPasswd())
|
|
118
|
+
return res.send(401, {"user": userName, status: 'password not corect', message: `Password not corect for ${userName}` });
|
|
119
|
+
|
|
120
|
+
if (newpwd.length < 8)
|
|
121
|
+
return res.send(400, { "user": userName, status: 'password must be 8 char +' });
|
|
122
|
+
|
|
123
|
+
if (oldpwd === newpwd || newpwd === GetPasswd())
|
|
124
|
+
return res.send(400, {"user": userName, status: 'new password must be different', message: 'New password must be different from current password' });
|
|
125
|
+
SetPassword(newpwd)
|
|
126
|
+
return res.send(200, { "user": userName, status: 'password changed', message: 'Password updated successfully'})
|
|
127
|
+
|
|
128
|
+
} catch(error: any) {
|
|
129
|
+
server.log(`Password change error: ${error}`, "error");
|
|
130
|
+
return res.send(500, { "user": req.body?.username || 'unknown', status: 'error', message: 'Internal server error'});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const LogoutSession = async (req: ServerReq, res: ServerRes) => {
|
|
135
|
+
let SessionID = req.params.SessionId
|
|
136
|
+
|
|
137
|
+
if (typeof SessionID === undefined)
|
|
138
|
+
return res.send(404, {status: "not found"})
|
|
139
|
+
|
|
140
|
+
for (let i = 0; i < sessions.length; i++){
|
|
141
|
+
if (SessionID === sessions[i]?.id){
|
|
142
|
+
(sessions[i] as any).isValid = false;
|
|
143
|
+
return res.send(200, {status: `session ${SessionID} logouted`})
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return res.send(404, {status: "not found"})
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const ChangePasswdAuth = async (req: ServerReq, res: ServerRes) => {
|
|
150
|
+
try {
|
|
151
|
+
const { oldpwd, newpwd } = req.body
|
|
152
|
+
if (!oldpwd || !newpwd)
|
|
153
|
+
return res.send(401, {status: "all field are required !"})
|
|
154
|
+
|
|
155
|
+
if (oldpwd !== GetPasswd())
|
|
156
|
+
return res.send(401, {status: "incorect password"})
|
|
157
|
+
|
|
158
|
+
if (oldpwd === newpwd)
|
|
159
|
+
return res.send(400, {status: "old pwd must be defrent from new one"})
|
|
160
|
+
|
|
161
|
+
SetPassword(newpwd)
|
|
162
|
+
return res.send(200, {status: "password changed with secc"})
|
|
163
|
+
|
|
164
|
+
} catch {
|
|
165
|
+
res.send(500, {status: "internal server error"})
|
|
166
|
+
}
|
|
167
|
+
return res.send(401, {status: "?"})
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const ChangeUser = async (req: ServerReq, res: ServerRes) => {
|
|
171
|
+
try {
|
|
172
|
+
const { userName } = req.body
|
|
173
|
+
|
|
174
|
+
if (!userName)
|
|
175
|
+
return res.send(401, {status: "all field are required !"})
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
if (userName.length <= 3 || userName.length >= 20)
|
|
179
|
+
return res.send(400, {status: "username must be between 4-19"})
|
|
180
|
+
|
|
181
|
+
SetUsername(userName)
|
|
182
|
+
return res.send(200, {status: "username changed with secc"})
|
|
183
|
+
|
|
184
|
+
} catch {
|
|
185
|
+
res.send(500, {status: "internal server error"})
|
|
186
|
+
}
|
|
187
|
+
return res.send(401, {status: "?"})
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return {ChangeUser, LogoutSession, ChangePasswd, ChangePasswdAuth, CheckUsername, Status, Logout, Login}
|
|
191
|
+
}
|
|
192
|
+
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import monitor from "../admin/monitor.js"
|
|
2
|
+
import Server from "tinny-backend"
|
|
3
|
+
|
|
4
|
+
export default function CreateServer(monitoring: boolean, PORT: number){
|
|
5
|
+
const server = new Server({port: PORT});
|
|
6
|
+
if (monitoring)
|
|
7
|
+
monitor(new Server({port: (PORT + 1)}))
|
|
8
|
+
return server;
|
|
9
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "startup-tinny-backend",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Backend starter using tinny-backend framework",
|
|
5
|
+
"private": false,
|
|
6
|
+
"main": "dist/app/index.js",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "tsc",
|
|
10
|
+
"start": "node dist/app/index.js",
|
|
11
|
+
"dev": "nodemon dist/app/index.js",
|
|
12
|
+
"dev:watch": "ts-node-dev --respawn --transpile-only app/index.ts"
|
|
13
|
+
},
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=24.13.1",
|
|
16
|
+
"npm": ">=11.10.0"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"backend",
|
|
20
|
+
"starter",
|
|
21
|
+
"tinny-backend",
|
|
22
|
+
"typescript"
|
|
23
|
+
],
|
|
24
|
+
"author": "Yassine Ajagrou",
|
|
25
|
+
"license": "ISC",
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "git+https://github.com/iaceene/startup-tinny-backend.git"
|
|
29
|
+
},
|
|
30
|
+
"bugs": {
|
|
31
|
+
"url": "https://github.com/iaceene/startup-tinny-backend/issues"
|
|
32
|
+
},
|
|
33
|
+
"homepage": "https://github.com/iaceene/startup-tinny-backend#readme",
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"dotenv": "^17.4.2",
|
|
36
|
+
"jsonwebtoken": "^9.0.3",
|
|
37
|
+
"tinny-backend": "^1.0.3"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/jsonwebtoken": "^9.0.10",
|
|
41
|
+
"nodemon": "^3.1.14",
|
|
42
|
+
"ts-node-dev": "^2.0.0"
|
|
43
|
+
},
|
|
44
|
+
"directories": {
|
|
45
|
+
"lib": "lib"
|
|
46
|
+
},
|
|
47
|
+
"types": "./dist/app/index.d.ts"
|
|
48
|
+
}
|