@andrewcaires/api 1.0.1 → 1.0.4
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/dist/index.d.ts +66 -38
- package/dist/index.esm.js +3 -2
- package/dist/index.umd.js +3 -2
- package/package.json +19 -16
package/dist/index.d.ts
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/*!
|
|
2
|
+
* @andrewcaires/api v1.0.4
|
|
3
|
+
* Simple api for small applications using express, jsonwebtoken, sequelize and websocket
|
|
4
|
+
* (c) 2022 Andrew Caires
|
|
5
|
+
* @license: MIT
|
|
6
|
+
*/
|
|
4
7
|
import * as _sequelize from 'sequelize';
|
|
5
8
|
import { Model, Sequelize, ModelStatic, FindOptions, Attributes } from 'sequelize';
|
|
6
9
|
import * as express_serve_static_core from 'express-serve-static-core';
|
|
7
|
-
import
|
|
8
|
-
import { Request, Response, NextFunction } from 'express';
|
|
9
|
-
import { WhereOptions } from 'sequelize/types';
|
|
10
|
+
import { Express, Request, Response, NextFunction } from 'express';
|
|
10
11
|
import { ObjectSchema } from 'joi';
|
|
12
|
+
import { TypeObjectString, TypeObject } from '@andrewcaires/utils.js';
|
|
13
|
+
import { WhereOptions } from 'sequelize/types';
|
|
14
|
+
import * as http from 'http';
|
|
15
|
+
import * as https from 'https';
|
|
16
|
+
import WebSocket from 'ws';
|
|
11
17
|
|
|
12
|
-
declare const initialize: () => void
|
|
13
|
-
declare const server: http.Server | https.Server;
|
|
18
|
+
declare const initialize: () => Promise<void>;
|
|
14
19
|
|
|
15
20
|
declare const API_AUTH_SLEEP: number;
|
|
16
21
|
declare const API_DB_DATABASE: string;
|
|
@@ -88,15 +93,42 @@ declare class Auth extends Model {
|
|
|
88
93
|
user: User;
|
|
89
94
|
}
|
|
90
95
|
|
|
96
|
+
declare class Configs extends Model {
|
|
97
|
+
key: string;
|
|
98
|
+
value: string;
|
|
99
|
+
}
|
|
100
|
+
|
|
91
101
|
declare class Logs extends Model {
|
|
92
102
|
type: string;
|
|
93
103
|
source: string;
|
|
94
104
|
message: string;
|
|
95
105
|
}
|
|
96
106
|
|
|
97
|
-
declare const app: express_serve_static_core.Express;
|
|
98
|
-
|
|
99
107
|
declare const router: express_serve_static_core.Router;
|
|
108
|
+
declare const useExpress: () => Express;
|
|
109
|
+
|
|
110
|
+
declare global {
|
|
111
|
+
namespace Express {
|
|
112
|
+
interface Request {
|
|
113
|
+
auth?: Auth;
|
|
114
|
+
user?: User;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
declare const auth: (req: Request, res: Response, next: NextFunction) => Promise<void | Response<any, Record<string, any>>>;
|
|
119
|
+
|
|
120
|
+
declare const permission: (name: string) => (req: Request, res: Response, next: NextFunction) => Promise<void | Response<any, Record<string, any>>>;
|
|
121
|
+
|
|
122
|
+
interface UploadOptions {
|
|
123
|
+
count?: number;
|
|
124
|
+
field?: string;
|
|
125
|
+
path?: string;
|
|
126
|
+
size?: number;
|
|
127
|
+
types?: string[];
|
|
128
|
+
}
|
|
129
|
+
declare const upload: (options?: UploadOptions) => (req: Request, res: Response, next: NextFunction) => void;
|
|
130
|
+
|
|
131
|
+
declare const validation: (schema: ObjectSchema) => (req: Request, res: Response, next: NextFunction) => void | Response<any, Record<string, any>>;
|
|
100
132
|
|
|
101
133
|
declare const uuid: {
|
|
102
134
|
type: _sequelize.AbstractDataTypeConstructor;
|
|
@@ -115,14 +147,18 @@ declare const key: {
|
|
|
115
147
|
token: Buffer | undefined;
|
|
116
148
|
};
|
|
117
149
|
|
|
118
|
-
declare
|
|
150
|
+
declare class Config {
|
|
151
|
+
static all(): Promise<TypeObjectString>;
|
|
152
|
+
static del(key: string): Promise<boolean>;
|
|
153
|
+
static get(key: string): Promise<string>;
|
|
154
|
+
static set(key: string, value: string): Promise<void>;
|
|
155
|
+
}
|
|
119
156
|
|
|
120
157
|
declare type FnRecord<M> = (records: M) => any;
|
|
121
158
|
declare type FnRecords<M> = (records: Array<M>) => Array<any>;
|
|
122
159
|
declare class Controller<M extends Model<M>> {
|
|
123
|
-
private log;
|
|
124
160
|
private model;
|
|
125
|
-
constructor(
|
|
161
|
+
constructor(model: ModelStatic<M>);
|
|
126
162
|
add(): (req: Request, res: Response) => Promise<Response<any, Record<string, any>>>;
|
|
127
163
|
all(options?: FindOptions<Attributes<M>>, fn?: FnRecords<M>): (req: Request, res: Response) => Promise<Response<any, Record<string, any>>>;
|
|
128
164
|
del(): (req: Request, res: Response) => Promise<Response<any, Record<string, any>>>;
|
|
@@ -131,11 +167,11 @@ declare class Controller<M extends Model<M>> {
|
|
|
131
167
|
}
|
|
132
168
|
|
|
133
169
|
declare class Log {
|
|
134
|
-
static write(message: string, source?: string): void
|
|
135
|
-
static error(message: string, source?: string): void
|
|
136
|
-
static info(message: string, source?: string): void
|
|
137
|
-
static success(message: string, source?: string): void
|
|
138
|
-
static warning(message: string, source?: string): void
|
|
170
|
+
static write(message: string, source?: string, console?: boolean): Promise<void>;
|
|
171
|
+
static error(message: string, source?: string, console?: boolean): Promise<void>;
|
|
172
|
+
static info(message: string, source?: string, console?: boolean): Promise<void>;
|
|
173
|
+
static success(message: string, source?: string, console?: boolean): Promise<void>;
|
|
174
|
+
static warning(message: string, source?: string, console?: boolean): Promise<void>;
|
|
139
175
|
private static writeConsole;
|
|
140
176
|
private static writeRaw;
|
|
141
177
|
}
|
|
@@ -156,27 +192,19 @@ declare class Responses {
|
|
|
156
192
|
static unauthorized(res: Response, message: string): Response<any, Record<string, any>>;
|
|
157
193
|
}
|
|
158
194
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
auth: Auth | undefined;
|
|
163
|
-
user: User | undefined;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
195
|
+
interface TokenSign {
|
|
196
|
+
error?: string;
|
|
197
|
+
token?: string;
|
|
166
198
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
path?: string;
|
|
175
|
-
size?: number;
|
|
176
|
-
types?: string[];
|
|
199
|
+
interface TokenVerify {
|
|
200
|
+
error?: string;
|
|
201
|
+
decode?: TypeObject<string | number | boolean>;
|
|
202
|
+
}
|
|
203
|
+
declare class Token {
|
|
204
|
+
static sign(payload: TypeObject<string | number>): TokenSign;
|
|
205
|
+
static verify(token: string): TokenVerify;
|
|
177
206
|
}
|
|
178
|
-
declare const upload: (options?: UploadOptions | undefined) => (req: Request, res: Response, next: NextFunction) => void;
|
|
179
207
|
|
|
180
|
-
declare const
|
|
208
|
+
declare const startSocket: (server: http.Server | https.Server) => WebSocket.Server;
|
|
181
209
|
|
|
182
|
-
export { API_AUTH_SLEEP, API_DB_DATABASE, API_DB_HOST, API_DB_LOG, API_DB_PASSWORD, API_DB_PORT, API_DB_TYPE, API_DB_USERNAME, API_HTTP_CROSS, API_HTTP_CRT, API_HTTP_HYBRID, API_HTTP_KEY, API_HTTP_PORT, API_HTTP_PUBLIC, API_TOKEN_CRT, API_TOKEN_HEADER, API_TOKEN_KEY, API_TOKEN_LIFETIME, API_UPLOAD_COUNT, API_UPLOAD_FIELD, API_UPLOAD_SIZE, API_UPLOAD_TEMP, API_WEBSOCKET_START, Auth, Controller, Group, GroupRoute, Log, Logs, Permission, Responses, Route, User, UserGroup,
|
|
210
|
+
export { API_AUTH_SLEEP, API_DB_DATABASE, API_DB_HOST, API_DB_LOG, API_DB_PASSWORD, API_DB_PORT, API_DB_TYPE, API_DB_USERNAME, API_HTTP_CROSS, API_HTTP_CRT, API_HTTP_HYBRID, API_HTTP_KEY, API_HTTP_PORT, API_HTTP_PUBLIC, API_TOKEN_CRT, API_TOKEN_HEADER, API_TOKEN_KEY, API_TOKEN_LIFETIME, API_UPLOAD_COUNT, API_UPLOAD_FIELD, API_UPLOAD_SIZE, API_UPLOAD_TEMP, API_WEBSOCKET_START, Auth, Config, Configs, Controller, Group, GroupRoute, Log, Logs, Permission, Responses, Route, Token, User, UserGroup, auth, crt, initialize, key, permission, router, sequelize, startSocket, upload, useExpress, uuid, validation };
|
package/dist/index.esm.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @andrewcaires/api v1.0.
|
|
2
|
+
* @andrewcaires/api v1.0.4
|
|
3
|
+
* Simple api for small applications using express, jsonwebtoken, sequelize and websocket
|
|
3
4
|
* (c) 2022 Andrew Caires
|
|
4
5
|
* @license: MIT
|
|
5
6
|
*/
|
|
6
|
-
import{toBool as e,forEachSeries as t,dateFormat as r,sleep as s,uniqueID as o,allowedObject as n,noop as i,uuidv4 as a}from"@andrewcaires/utils.js";import{config as d}from"dotenv";import{Sequelize as u,UUID as c,UUIDV4 as l,DataTypes as m,Model as p,Op as g}from"sequelize";import v from"cors";import f,{Router as h}from"express";import{existsSync as y,readFileSync as w}from"fs";import{SHA256 as I}from"crypto-js";import b from"jsonwebtoken";import S from"joi";import*as T from"http";import*as A from"https";import{Server as O}from"net";import E from"ws";import _ from"mime-types";import P from"multer";import{join as N}from"path";d();const R=parseInt(process.env.API_AUTH_SLEEP||"1000"),j=process.env.API_DB_DATABASE||"",q=process.env.API_DB_HOST||"127.0.0.1",k=process.env.API_DB_PASSWORD||"",D=parseInt(process.env.API_DB_PORT||"3306"),x=process.env.API_DB_TYPE||"",B=process.env.API_DB_USERNAME||"root",z=e(process.env.API_DB_LOG||"false"),G=process.env.API_HTTP_CRT||"",U=process.env.API_HTTP_KEY||"",C=parseInt(process.env.API_HTTP_PORT||"3000"),L=process.env.API_HTTP_PUBLIC||"",H=e(process.env.API_HTTP_CROSS||"false"),K=e(process.env.API_HTTP_HYBRID||"false"),M=process.env.API_TOKEN_CRT||"",F=process.env.API_TOKEN_KEY||"",W=process.env.API_TOKEN_HEADER||"authorization",X=parseInt(process.env.API_TOKEN_LIFETIME||"15"),Y=parseInt(process.env.API_UPLOAD_COUNT||"1"),$=process.env.API_UPLOAD_FIELD||"upload",J=parseInt(process.env.API_UPLOAD_SIZE||"2"),V=process.env.API_UPLOAD_TEMP||"./temp",Z=e(process.env.API_WEBSOCKET_START||"false");function Q(e,t,r,s){return new(r||(r=Promise))((function(o,n){function i(e){try{d(s.next(e))}catch(e){n(e)}}function a(e){try{d(s.throw(e))}catch(e){n(e)}}function d(e){var t;e.done?o(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(i,a)}d((s=s.apply(e,t||[])).next())}))}const ee={type:c,defaultValue:l,allowNull:!1,primaryKey:!0},te=(()=>{switch(x){case"mariadb":return new u(j,B,k,{host:q,port:D,dialect:"mariadb",logging:z,define:{timestamps:!1}});case"mysql":return new u(j,B,k,{host:q,port:D,dialect:"mysql",logging:z,define:{timestamps:!1}});case"postgres":return new u(j,B,k,{host:q,port:D,dialect:"postgres",logging:z,define:{timestamps:!1}})}throw new Error("No database selected")})();class re extends p{}re.init({login:m.BIGINT,logout:m.BIGINT,secret:m.STRING,timestamp:m.BIGINT,useragent:m.STRING},{sequelize:te,modelName:"auth"});class se extends p{}se.init({name:m.STRING,description:m.TEXT,state:m.BOOLEAN},{sequelize:te,modelName:"group"});class oe extends p{}oe.init({type:m.STRING,source:m.STRING,message:m.TEXT},{sequelize:te,modelName:"logs",timestamps:!0,createdAt:"created",updatedAt:!1});class ne extends p{}ne.init({name:m.STRING,description:m.TEXT,state:m.BOOLEAN},{sequelize:te,modelName:"route"});class ie extends p{}ie.init({},{sequelize:te,modelName:"groups_routes"}),ie.removeAttribute("id");class ae extends p{}ae.init({name:m.STRING,email:m.STRING,username:m.STRING,password:m.STRING,description:m.TEXT,state:m.BOOLEAN},{sequelize:te,modelName:"user"});class de extends p{}de.init({},{sequelize:te,modelName:"users_groups"}),de.removeAttribute("id"),ae.hasMany(re),re.belongsTo(ae),se.hasMany(ie),ie.belongsTo(se),ne.hasMany(ie),ie.belongsTo(ne),ae.hasMany(de),de.belongsTo(ae),se.hasMany(de),de.belongsTo(se);var ue;!function(e){e.ERROR="[31m",e.INFO="[36m",e.NONE="[37m",e.SUCCESS="[32m",e.WARNING="[33m"}(ue||(ue={}));class ce{static write(e,t){ce.writeRaw(ue.NONE,"",e,t)}static error(e,t){ce.writeRaw(ue.ERROR,"error",e,t)}static info(e,t){ce.writeRaw(ue.INFO,"info",e,t)}static success(e,t){ce.writeRaw(ue.ERROR,"success",e,t)}static warning(e,t){ce.writeRaw(ue.WARNING,"warning",e,t)}static writeConsole(e,t,s){const o=r(new Date,"%H:%M:%S");console.log(">",e,t+" ".repeat(10-t.length),"[37m","|",o,"|",s)}static writeRaw(e,t,r,s){ce.writeConsole(e,t,r),oe.create({type:t,source:s,message:r}).catch((()=>null))}}class le{static success(e,t){return e.status(200).json({message:t})}static data(e,t){return e.status(200).json(Object.assign({},t))}static error(e,t){return e.status(500).json({message:t})}static list(e,t){return e.status(200).json([...t])}static notfound(e,t){return e.status(404).json({message:t})}static validation(e,t,r){return e.status(400).json({message:t,details:r})}static unauthorized(e,t){return e.status(401).json({message:t})}}const me=e=>{if(y(e))return w(e)},pe={http:me(G),token:me(M)},ge={http:me(U),token:me(F)};class ve{static all(e,t){return Q(this,void 0,void 0,(function*(){return yield ne.findAll({where:Object.assign(Object.assign({},t),{state:!0}),include:[{model:ie,required:!0,include:[{model:se,required:!0,where:{state:!0},include:[{model:de,required:!0,where:{userId:e.id}}]}]}]}).catch((e=>{ce.error(e.message,"permission")}))}))}static get(e){return Q(this,void 0,void 0,(function*(){const t=yield ve.all(e);return t?t.map((e=>e.name)):[]}))}static is(e,t){return Q(this,void 0,void 0,(function*(){const r=yield ve.all(e,{name:t});return r&&!!r.length}))}}const fe=["id","name","email","username"],he=(e,t,r)=>Q(void 0,void 0,void 0,(function*(){const s=e.get(W)||"";if(!pe.token)return le.error(t,"Invalid Secret");if(!s||s.split(".").length<3)return le.error(t,"Invalid token");let o;try{o=b.verify(s,pe.token)}catch(e){return le.error(t,"Invalid token")}if(o&&o.id&&o.secret){const s=yield ae.findOne({where:{id:o.id}}).catch((e=>{ce.error(e.message,"token.check")}));if(s&&s.state){const n=yield re.findOne({where:{logout:null,secret:o.secret,userId:s.id}}).catch((e=>{ce.error(e.message,"token.check")}));if(n){const o=Date.now();if(o>n.timestamp)return le.error(t,"Expired token");n.timestamp=o+6e4*X;const i=e.get("User-Agent");return i&&(n.useragent=i),yield n.save(),e.auth=n,e.user=s,r()}}return le.error(t,"Access denied")}return le.error(t,"Invalid token")})),ye=e=>{const t={abortEarly:!1,allowUnknown:!0,stripUnknown:!0};return(r,s,o)=>{const{error:n,value:i}=e.validate(r.body,t);if(n){const e=n.details.map((e=>e.message)).join(", "),t=[];return n.details.forEach((e=>{var r;t.push({key:(null===(r=e.context)||void 0===r?void 0:r.key)||"",type:e.type})})),le.validation(s,"Validation error: "+e,t)}return r.body=i,o()}},we={username:S.string().min(5).required(),password:S.string().min(5).required()},Ie=ye(S.object(we)),be=h();be.get("/",he,((e,t)=>Q(void 0,void 0,void 0,(function*(){const r=e.user;if(!r)return le.unauthorized(t,"Access denied");const s=yield ve.all(r);if(s){const e=n(fe,r.toJSON()),o=s.map((e=>e.name));return le.data(t,Object.assign(Object.assign({},e),{permissions:o}))}return le.error(t,"Internal Server Error")})))),be.post("/login",Ie,((e,t)=>Q(void 0,void 0,void 0,(function*(){const{username:r,password:n}=e.body;if(!r||!n)return le.error(t,"Invalid parameters");yield s(R);const i=yield ae.findOne({where:{username:r}}).catch((e=>{ce.error(e.message,"auth.login")}));if(!i)return le.notfound(t,"User not found");if(!i.state)return le.error(t,"User is disabled");const a=I(n).toString();if(i.password!=a)return le.error(t,"Invalid password");if(!ge.token)return le.error(t,"Invalid Secret");const d=i.id,u=o(),c=b.sign({id:d,secret:u},ge.token,{algorithm:"RS256"});if(c){const r=Date.now(),s=r+6e4*X,o=e.get("User-Agent");if(yield re.create({login:r,secret:u,timestamp:s,useragent:o,userId:d}).catch((e=>{ce.error(e.message,"auth.login")})))return le.data(t,{token:c})}return le.error(t,"Internal Server Error")})))),be.get("/logout",he,((e,t)=>Q(void 0,void 0,void 0,(function*(){const r=e.auth;return r?(r.logout=Date.now(),r.timestamp=r.logout,yield r.save(),le.success(t,"Disconcerted")):le.unauthorized(t,"Access denied")}))));class Se{constructor(e,t){this.log=e,this.model=t}add(){return(e,t)=>Q(this,void 0,void 0,(function*(){const r=yield this.model.create(e.body).catch((e=>{ce.error(e.message,this.log+".add")}));return r?le.data(t,{id:r.id}):le.error(t,"Internal Server Error")}))}all(e,t){return(r,s)=>Q(this,void 0,void 0,(function*(){var o,n,a,d,u;e||(e={});const c=Object.assign({},e);c.where=c.where?Object.assign({},c.where):{};const l=null===(o=r.query.limit)||void 0===o?void 0:o.toString();l&&(c.limit=parseInt(l));const m=null===(n=r.query.offset)||void 0===n?void 0:n.toString();m&&(c.offset=parseInt(m));const p=null===(a=r.query.asc)||void 0===a?void 0:a.toString();p&&(c.order=[[p,"ASC"]]);const v=null===(d=r.query.desc)||void 0===d?void 0:d.toString();v&&(c.order=[[v,"DESC"]]);const f=[],h=null===(u=r.query.search)||void 0===u?void 0:u.toString();h&&(Object.keys(this.model.getAttributes()).forEach((e=>{f.push({[e]:{[g.like]:`%${h}%`}})})),f.length&&(c.where=Object.assign(Object.assign({},c.where),{[g.or]:[...f]})));const y=yield this.model.findAll(c).catch((e=>{ce.error(e.message,this.log+".all")})),w=yield this.model.count(c).catch(i);return y?le.data(s,{count:w,records:t?t(y):y}):le.error(s,"Internal Server Error")}))}del(){return(e,t)=>Q(this,void 0,void 0,(function*(){const{id:r}=e.params;return(yield this.model.destroy({where:{id:r}}).catch((e=>{ce.error(e.message,this.log+".del")})))?le.success(t,"OK"):le.notfound(t,"Record not found")}))}get(e,t){return(r,s)=>Q(this,void 0,void 0,(function*(){e||(e={});const o=Object.assign({},e);o.where=o.where?Object.assign({},o.where):{};const{id:n}=r.params,i=yield this.model.findByPk(n,o).catch((e=>{ce.error(e.message,this.log+".get")}));return i?le.data(s,t?t(i):i.toJSON()):null===i?le.notfound(s,"Record not found"):le.error(s,"Internal Server Error")}))}set(){return(e,t)=>Q(this,void 0,void 0,(function*(){const{id:r}=e.params,s=yield this.model.update(e.body,{where:{id:r}}).catch((e=>{ce.error(e.message,this.log+".set")}));if(s){const[e]=s;if(e)return le.success(t,"OK")}return le.success(t,"Record not changed")}))}}const Te=new Se("groups",se),Ae=new Se("groups.route",ie),Oe=Te.add(),Ee=Te.all(),_e=Te.del(),Pe=Te.get(),Ne=Te.set(),Re=e=>(t,r,s)=>Q(void 0,void 0,void 0,(function*(){const o=t.user;return o?(yield ve.is(o,e))?s():le.error(r,"Unauthorized access"):le.unauthorized(r,"Access denied")})),je={name:S.string().min(3).required(),description:S.string().allow(null,""),state:S.boolean().required()},qe=ye(S.object(je)),ke={routes:S.array().items(S.number())},De=ye(S.object(ke)),xe={name:S.string().min(3).empty(""),description:S.string().allow(null,""),state:S.boolean().empty("")},Be=ye(S.object(xe)),ze=h();ze.use(he),ze.get("/",Re("groups.read"),Ee),ze.post("/",Re("groups.write"),qe,Oe),ze.route("/:id").get(Re("groups.read"),Pe).put(Re("groups.write"),Be,Ne).delete(Re("groups.write"),_e),ze.route("/:id/routes").get(Re("groups.read"),De,((e,t)=>Q(void 0,void 0,void 0,(function*(){const{id:r}=e.params;return Ae.all({where:{groupId:r},include:[{model:ne,required:!0}]},(e=>e.map((e=>e.route))))(e,t)})))).put(Re("groups.write"),De,((e,t)=>Q(void 0,void 0,void 0,(function*(){const{id:r}=e.params,{routes:s}=e.body,o=yield se.findByPk(r,{attributes:["id"]}).catch((e=>{ce.error(e.message,"groups.routesSet")}));if(o){const e=o.id;if(yield ie.destroy({where:{groupId:e}}),s){let t=0;for(let r=0;r<s.length;r++)t=yield ne.count({where:{id:s[r]}}),t&&(yield ie.create({groupId:e,routeId:s[r]}))}return le.success(t,"OK")}return null===o?le.notfound(t,"Record not found"):le.error(t,"Internal Server Error")}))));const Ge=new Se("route",ne),Ue=Ge.add(),Ce=Ge.all(),Le=Ge.del(),He=Ge.get(),Ke=Ge.set(),Me={name:S.string().min(5).required(),permission:S.string().required(),description:S.string().allow(null,""),state:S.boolean().required()},Fe=ye(S.object(Me)),We={name:S.string().min(5).empty(""),permission:S.string().empty(""),description:S.string().allow(null,""),state:S.boolean().empty("")},Xe=ye(S.object(We)),Ye=h();Ye.use(he),Ye.get("/",Re("routes.read"),Ce),Ye.post("/",Re("routes.write"),Fe,Ue),Ye.route("/:id").get(Re("routes.read"),He).put(Re("routes.write"),Xe,Ke).delete(Re("routes.write"),Le);const $e=new Se("user",ae),Je=new Se("user.groups",de),Ve=["id","name","email","username","description","state"],Ze=$e.del(),Qe={name:S.string().min(5).required(),email:S.string().email().required(),username:S.string().min(5).required(),password:S.string().min(5).required(),description:S.string().allow(null,""),state:S.boolean().required()},et=ye(S.object(Qe)),tt={groups:S.array().items(S.number())},rt=ye(S.object(tt)),st={name:S.string().min(5).empty(""),email:S.string().email().empty(""),username:S.string().min(5).empty(""),password:S.string().min(5).empty(""),description:S.string().allow(null,""),state:S.boolean().empty("")},ot=ye(S.object(st)),nt=h();nt.use(he),nt.get("/",Re("users.read"),((e,t)=>Q(void 0,void 0,void 0,(function*(){return $e.all({attributes:Ve})(e,t)})))),nt.post("/",Re("users.write"),et,((e,t)=>Q(void 0,void 0,void 0,(function*(){return e.body.password=I(e.body.password).toString(),yield $e.add()(e,t)})))),nt.route("/:id").get(Re("users.read"),((e,t)=>Q(void 0,void 0,void 0,(function*(){return $e.get({attributes:Ve})(e,t)})))).put(Re("users.write"),ot,((e,t)=>Q(void 0,void 0,void 0,(function*(){return e.body.password&&(e.body.password=I(e.body.password).toString()),$e.set()(e,t)})))).delete(Re("users.write"),Ze),nt.route("/:id/groups").get(Re("users.read"),((e,t)=>Q(void 0,void 0,void 0,(function*(){const{id:r}=e.params;return Je.all({where:{userId:r},include:[{model:se,required:!0}]},(e=>e.map((e=>e.group))))(e,t)})))).put(Re("users.write"),rt,((e,t)=>Q(void 0,void 0,void 0,(function*(){const{id:r}=e.params,{groups:s}=e.body,o=yield ae.findByPk(r,{attributes:["id"]}).catch((e=>{ce.error(e.message,"user.groups.set")}));if(o){if(yield de.destroy({where:{userId:o.id}}),s){let e=0;for(let t=0;t<s.length;t++)e=yield se.count({where:{id:s[t]}}),e&&(yield de.create({userId:o.id,groupId:s[t]}))}return le.success(t,"OK")}return le.notfound(t,"Record not found")}))));const it=h();it.use("/v1/auth",be),it.use("/v1/groups",ze),it.use("/v1/routes",Ye),it.use("/v1/users",nt);const at=f();at.use(f.json()),at.use(((e,t,r,s)=>e?(ce.error(e.message,"express"),le.error(r,"Internal Server Error")):s())),at.use(f.urlencoded({extended:!0})),at.disable("x-powered-by"),H&&at.use(v()),at.use("/api",it),at.all("/api/*",((e,t)=>le.notfound(t,"Invalid API"))),L&&(y(L)&&at.use(f.static(L)),at.get("*",((e,t)=>{if(!y(L))return le.notfound(t,'File "index.html" not found');t.sendFile(L+"/index.html")})));const dt=e=>{const t=new E.Server({server:e,verifyClient:ut});return t.on("connection",(e=>{e.on("message",(t=>{e.close()})),setTimeout((()=>{e.close()}),2e3),e.on("close",(()=>{t.emit("close",e)}))})),t},ut=(e,t)=>t(Z),ct=()=>{te.sync().then((()=>{Q(void 0,void 0,void 0,(function*(){if(0==(yield ae.count())){const e=yield ae.create({name:"Admin",email:"admin@localhost",username:"admin",password:"8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918",description:"",state:!0});if(0==(yield se.count())){const r=yield se.create({name:"admin",description:"",state:!0});if(yield de.create({userId:e.id,groupId:r.id}),0==(yield ne.count())){const e=["read","write"];t(["users","groups","permission"],(s=>Q(void 0,void 0,void 0,(function*(){t(e,(e=>Q(void 0,void 0,void 0,(function*(){const t=s.toLowerCase()+"."+e.toLowerCase(),o=yield ne.create({name:t,description:"",state:!0});yield ie.create({groupId:r.id,routeId:o.id})}))))}))))}}}})),Z&&dt(lt)}))},lt=(e=>{if(!pe.http||!ge.http){const t=T.createServer(e);return t.listen(C,(()=>ce.info(`Server started on port ${C}`))),t}const t=T.createServer(((e,t)=>{const r=80==C?":80":"";t.writeHead(301,{Location:"https://"+e.headers.host+r+e.url}),t.end()})),r=A.createServer({key:ge.http,cert:pe.http},e);if(K){return new O((e=>{e.once("data",(s=>{e.pause(),e.unshift(s),(22===s[0]?r:t).emit("connection",e),process.nextTick((()=>e.resume()))}))})).listen(C,(()=>ce.info(`Server started on port ${C}`))),r}return 443==C&&t.listen(80,(()=>ce.info("Server started on port 80"))),r.listen(C,(()=>ce.info(`Server started on port ${C}`))),r})(at),mt=(e,t)=>{const r=a()+"."+t;return y(N(e,r))?mt(e,t):r},pt=e=>{const t=(null==e?void 0:e.path)||V,r=P.diskStorage({destination:(e,r,s)=>s(null,t),filename:(e,r,s)=>Q(void 0,void 0,void 0,(function*(){return s(null,mt(t,_.extension(r.mimetype)||"bin"))}))}),s=1e6*((null==e?void 0:e.size)||J),o=P({storage:r,fileFilter(t,r,s){var o;return Q(this,void 0,void 0,(function*(){const t=null===(o=null==e?void 0:e.types)||void 0===o?void 0:o.indexOf(r.mimetype);return void 0!==t&&t<0?s(new Error("File type not allowed")):s(null,!0)}))},limits:{fileSize:s}}),n=(null==e?void 0:e.count)||Y,i=(null==e?void 0:e.field)||$,a=o.array(i,n);return(e,t,r)=>{a(e,t,(function(e){return e?le.error(t,e.message):r()}))}};export{R as API_AUTH_SLEEP,j as API_DB_DATABASE,q as API_DB_HOST,z as API_DB_LOG,k as API_DB_PASSWORD,D as API_DB_PORT,x as API_DB_TYPE,B as API_DB_USERNAME,H as API_HTTP_CROSS,G as API_HTTP_CRT,K as API_HTTP_HYBRID,U as API_HTTP_KEY,C as API_HTTP_PORT,L as API_HTTP_PUBLIC,M as API_TOKEN_CRT,W as API_TOKEN_HEADER,F as API_TOKEN_KEY,X as API_TOKEN_LIFETIME,Y as API_UPLOAD_COUNT,$ as API_UPLOAD_FIELD,J as API_UPLOAD_SIZE,V as API_UPLOAD_TEMP,Z as API_WEBSOCKET_START,re as Auth,Se as Controller,se as Group,ie as GroupRoute,ce as Log,oe as Logs,ve as Permission,le as Responses,ne as Route,ae as User,de as UserGroup,at as app,he as auth,pe as crt,ct as initialize,ge as key,Re as permission,it as router,te as sequelize,lt as server,dt as startSocket,pt as upload,ee as uuid,ye as validation};
|
|
7
|
+
import{toBool as e,dateFormat as t,noop as r,sleep as o,uniqueID as s,allowedObject as i,uuidv4 as n}from"@andrewcaires/utils.js";import{config as a}from"dotenv";import{UUID as d,UUIDV4 as u,Sequelize as c,DataTypes as l,Model as m,Op as p}from"sequelize";import*as v from"http";import*as g from"https";import{Server as f}from"net";import h from"cors";import y,{Router as w}from"express";import{existsSync as I,readFileSync as b}from"fs";import{SHA256 as T}from"crypto-js";import{sign as S,verify as A}from"jsonwebtoken";import N from"mime-types";import O from"multer";import{join as E}from"path";import _ from"joi";import P from"ws";function R(e,t,r,o){return new(r||(r=Promise))((function(s,i){function n(e){try{d(o.next(e))}catch(e){i(e)}}function a(e){try{d(o.throw(e))}catch(e){i(e)}}function d(e){var t;e.done?s(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(n,a)}d((o=o.apply(e,t||[])).next())}))}a();const j=parseInt(process.env.API_AUTH_SLEEP||"1000"),q=process.env.API_DB_DATABASE||"",k=process.env.API_DB_HOST||"127.0.0.1",D=process.env.API_DB_PASSWORD||"",x=parseInt(process.env.API_DB_PORT||"3306"),B=process.env.API_DB_TYPE||"",G=process.env.API_DB_USERNAME||"root",z=e(process.env.API_DB_LOG||"false"),U=process.env.API_HTTP_CRT||"",C=process.env.API_HTTP_KEY||"",L=parseInt(process.env.API_HTTP_PORT||"3000"),H=process.env.API_HTTP_PUBLIC||"",K=e(process.env.API_HTTP_CROSS||"false"),M=e(process.env.API_HTTP_HYBRID||"false"),F=process.env.API_TOKEN_CRT||"",W=process.env.API_TOKEN_KEY||"",X=process.env.API_TOKEN_HEADER||"authorization",Y=parseInt(process.env.API_TOKEN_LIFETIME||"15"),J=parseInt(process.env.API_UPLOAD_COUNT||"1"),V=process.env.API_UPLOAD_FIELD||"upload",Z=parseInt(process.env.API_UPLOAD_SIZE||"2"),$=process.env.API_UPLOAD_TEMP||"./temp",Q=e(process.env.API_WEBSOCKET_START||"false"),ee={type:d,defaultValue:u,allowNull:!1,primaryKey:!0},te=(()=>{switch(B){case"mariadb":return new c(q,G,D,{host:k,port:x,dialect:"mariadb",logging:z,define:{timestamps:!1}});case"mysql":return new c(q,G,D,{host:k,port:x,dialect:"mysql",logging:z,define:{timestamps:!1}});case"postgres":return new c(q,G,D,{host:k,port:x,dialect:"postgres",logging:z,define:{timestamps:!1}})}throw new Error("No database selected")})();class re extends m{}re.init({login:l.BIGINT,logout:l.BIGINT,secret:l.STRING,timestamp:l.BIGINT,useragent:l.STRING},{sequelize:te,modelName:"auth"});class oe extends m{}oe.init({name:l.STRING,description:l.TEXT,state:l.BOOLEAN},{sequelize:te,modelName:"group"});class se extends m{}se.init({name:l.STRING,description:l.TEXT,state:l.BOOLEAN},{sequelize:te,modelName:"route"});class ie extends m{}ie.init({},{sequelize:te,modelName:"groups_routes"}),ie.removeAttribute("id");class ne extends m{}ne.init({name:l.STRING,email:l.STRING,username:l.STRING,password:l.STRING,description:l.TEXT,state:l.BOOLEAN},{sequelize:te,modelName:"user"});class ae extends m{}ae.init({},{sequelize:te,modelName:"users_groups"}),ae.removeAttribute("id");class de extends m{}de.init({key:l.STRING,value:l.STRING},{sequelize:te,modelName:"configs",timestamps:!0,createdAt:"created",updatedAt:"updated"}),de.removeAttribute("id");class ue extends m{}var ce;ue.init({type:l.STRING,source:l.STRING,message:l.TEXT},{sequelize:te,modelName:"logs",timestamps:!0,createdAt:"created",updatedAt:!1}),ne.hasMany(re),re.belongsTo(ne),oe.hasMany(ie),ie.belongsTo(oe),se.hasMany(ie),ie.belongsTo(se),ne.hasMany(ae),ae.belongsTo(ne),oe.hasMany(ae),ae.belongsTo(oe),function(e){e.ERROR="[31m",e.INFO="[36m",e.NONE="[37m",e.SUCCESS="[32m",e.WARNING="[33m"}(ce||(ce={}));class le{static write(e,t,r){return R(this,void 0,void 0,(function*(){yield le.writeRaw(ce.NONE,"",e,t,r)}))}static error(e,t,r){return R(this,void 0,void 0,(function*(){yield le.writeRaw(ce.ERROR,"error",e,t,r)}))}static info(e,t,r){return R(this,void 0,void 0,(function*(){yield le.writeRaw(ce.INFO,"info",e,t,r)}))}static success(e,t,r){return R(this,void 0,void 0,(function*(){yield le.writeRaw(ce.ERROR,"success",e,t,r)}))}static warning(e,t,r){return R(this,void 0,void 0,(function*(){yield le.writeRaw(ce.WARNING,"warning",e,t,r)}))}static writeConsole(e,r,o){const s=t(new Date,"%H:%M:%S");console.log(">",e,r+" ".repeat(10-r.length),"[37m","|",s,"|",o)}static writeRaw(e,t,r,o,s){return R(this,void 0,void 0,(function*(){s&&le.writeConsole(e,t,r),yield ue.create({type:t,source:o,message:r}).catch((()=>null))}))}}class me{static all(){return R(this,void 0,void 0,(function*(){const e=yield de.findAll().catch((e=>{le.error(e.message,"api.config",!0)})),t={};return e&&e.forEach((e=>{t[e.key]=e.value})),t}))}static del(e){return R(this,void 0,void 0,(function*(){return((yield de.destroy({where:{key:e}}).catch((e=>{le.error(e.message,"api.config",!0)})))||0)>0}))}static get(e){return R(this,void 0,void 0,(function*(){const t=yield de.findOne({where:{key:e}}).catch((e=>{le.error(e.message,"api.config",!0)}));return t&&t.value||""}))}static set(e,t){return R(this,void 0,void 0,(function*(){const[r]=(yield de.findOrCreate({where:{key:e}}).catch((e=>{le.error(e.message,"api.config",!0)})))||[];r&&(r.value=t,yield r.save().catch((e=>{le.error(e.message,"api.config",!0)})))}))}}class pe{static success(e,t){return e.status(200).json({message:t})}static data(e,t){return e.status(200).json(Object.assign({},t))}static error(e,t){return e.status(500).json({message:t})}static list(e,t){return e.status(200).json([...t])}static notfound(e,t){return e.status(404).json({message:t})}static validation(e,t,r){return e.status(400).json({message:t,details:r})}static unauthorized(e,t){return e.status(401).json({message:t})}}class ve{constructor(e){this.model=e}add(){return(e,t)=>R(this,void 0,void 0,(function*(){const r=yield this.model.create(e.body).catch((e=>{le.error(e.message,"api.controller."+this.model.tableName,!0)}));return r?pe.data(t,{id:r.id}):pe.error(t,"Internal Server Error")}))}all(e,t){return(o,s)=>R(this,void 0,void 0,(function*(){var i,n,a,d,u;e||(e={});const c=Object.assign({},e);c.where=c.where?Object.assign({},c.where):{};const l=null===(i=o.query.limit)||void 0===i?void 0:i.toString();l&&(c.limit=parseInt(l));const m=null===(n=o.query.offset)||void 0===n?void 0:n.toString();m&&(c.offset=parseInt(m));const v=null===(a=o.query.asc)||void 0===a?void 0:a.toString();v&&(c.order=[[v,"ASC"]]);const g=null===(d=o.query.desc)||void 0===d?void 0:d.toString();g&&(c.order=[[g,"DESC"]]);const f=[],h=null===(u=o.query.search)||void 0===u?void 0:u.toString();h&&(Object.keys(this.model.getAttributes()).forEach((e=>{"password"!=e&&f.push({[e]:{[p.like]:`%${h}%`}})})),f.length&&(c.where=Object.assign(Object.assign({},c.where),{[p.or]:[...f]})));const y=yield this.model.findAll(c).catch((e=>{le.error(e.message,"api.controller."+this.model.tableName,!0)})),w=yield this.model.count(c).catch(r);return y?pe.data(s,{count:w,records:t?t(y):y}):pe.error(s,"Internal Server Error")}))}del(){return(e,t)=>R(this,void 0,void 0,(function*(){const{id:r}=e.params;return(yield this.model.destroy({where:{id:r}}).catch((e=>{le.error(e.message,"api.controller."+this.model.tableName,!0)})))?pe.success(t,"OK"):pe.notfound(t,"Record not found")}))}get(e,t){return(r,o)=>R(this,void 0,void 0,(function*(){e||(e={});const s=Object.assign({},e);s.where=s.where?Object.assign({},s.where):{};const{id:i}=r.params,n=yield this.model.findByPk(i,s).catch((e=>{le.error(e.message,"api.controller."+this.model.tableName,!0)}));return n?pe.data(o,t?t(n):n.toJSON()):null===n?pe.notfound(o,"Record not found"):pe.error(o,"Internal Server Error")}))}set(){return(e,t)=>R(this,void 0,void 0,(function*(){const{id:r}=e.params,o=yield this.model.update(e.body,{where:{id:r}}).catch((e=>{le.error(e.message,"api.controller."+this.model.tableName,!0)}));if(o){const[e]=o;if(e)return pe.success(t,"OK")}return pe.success(t,"Record not changed")}))}}class ge{static all(e,t){return R(this,void 0,void 0,(function*(){return yield se.findAll({where:Object.assign(Object.assign({},t),{state:!0}),include:[{model:ie,required:!0,include:[{model:oe,required:!0,where:{state:!0},include:[{model:ae,required:!0,where:{userId:e.id}}]}]}]}).catch((e=>{le.error(e.message,"api.permission",!0)}))}))}static get(e){return R(this,void 0,void 0,(function*(){const t=yield ge.all(e);return t?t.map((e=>e.name)):[]}))}static is(e,t){return R(this,void 0,void 0,(function*(){const r=yield ge.all(e,{name:t});return r&&!!r.length}))}}const fe=e=>{if(I(e))return b(e)},he={http:fe(U),token:fe(F)},ye={http:fe(C),token:fe(W)};class we{static sign(e){return ye.token?{token:S(e,ye.token,{algorithm:"RS256"})}:{error:"Invalid Secret"}}static verify(e){if(!he.token)return{error:"Invalid Secret"};if(!e||e.split(".").length<3)return{error:"Invalid Token"};try{return{decode:A(e,he.token)}}catch(e){return{error:"Invalid Token"}}}}const Ie=["id","name","email","username"],be=(e,t,r)=>R(void 0,void 0,void 0,(function*(){const o=e.get(X)||"",{error:s,decode:i}=we.verify(o);if(s)return pe.error(t,s);if(i){const{id:o,secret:s}=i;if(o&&i){const i=yield ne.findOne({where:{id:o,state:!0}}).catch((e=>{le.error(e.message,"api.auth",!0)}));if(i){const o=yield re.findOne({where:{secret:s,userId:i.id}}).catch((e=>{le.error(e.message,"api.auth",!0)}));if(o){const s=Date.now();if(s>o.timestamp)return pe.error(t,"Expired token");o.timestamp=s+6e4*Y;const n=e.get("User-Agent");return n&&(o.useragent=n),yield o.save(),e.auth=o,e.user=i,r()}}return pe.error(t,"Access denied")}}return pe.error(t,"Invalid token")})),Te=e=>(t,r,o)=>R(void 0,void 0,void 0,(function*(){const s=t.user;return s?(yield ge.is(s,e))?o():pe.error(r,"Unauthorized access"):pe.unauthorized(r,"Access denied")})),Se=(e,t)=>{const r=n()+"."+t;return I(E(e,r))?Se(e,t):r},Ae=e=>{const t=(null==e?void 0:e.path)||$,r=O.diskStorage({destination:(e,r,o)=>o(null,t),filename:(e,r,o)=>R(void 0,void 0,void 0,(function*(){return o(null,Se(t,N.extension(r.mimetype)||"bin"))}))}),o=1e6*((null==e?void 0:e.size)||Z),s=O({storage:r,fileFilter(t,r,o){var s;return R(this,void 0,void 0,(function*(){const t=null===(s=null==e?void 0:e.types)||void 0===s?void 0:s.indexOf(r.mimetype);return void 0!==t&&t<0?o(new Error("File type not allowed")):o(null,!0)}))},limits:{fileSize:o}}),i=(null==e?void 0:e.count)||J,n=(null==e?void 0:e.field)||V,a=s.array(n,i);return(e,t,r)=>{a(e,t,(function(e){return e?pe.error(t,e.message):r()}))}},Ne=e=>{const t={abortEarly:!1,allowUnknown:!0,stripUnknown:!0};return(r,o,s)=>{const{error:i,value:n}=e.validate(r.body,t);if(i){const e=i.details.map((e=>e.message)).join(", "),t=[];return i.details.forEach((e=>{var r;t.push({key:(null===(r=e.context)||void 0===r?void 0:r.key)||"",type:e.type})})),pe.validation(o,"Validation error: "+e,t)}return r.body=n,s()}},Oe={username:_.string().min(5).required(),password:_.string().min(5).required()},Ee=Ne(_.object(Oe)),_e=w();_e.get("/",be,((e,t)=>R(void 0,void 0,void 0,(function*(){const r=e.user;if(!r)return pe.unauthorized(t,"Access denied");const o=yield ge.all(r);if(o){const e=i(Ie,r.toJSON()),s=o.map((e=>e.name));return pe.data(t,Object.assign(Object.assign({},e),{permissions:s}))}return pe.error(t,"Internal Server Error")})))),_e.post("/login",Ee,((e,t)=>R(void 0,void 0,void 0,(function*(){const{username:r,password:i}=e.body;if(!r||!i)return pe.error(t,"Invalid parameters");yield o(j);const n=yield ne.findOne({where:{username:r}}).catch((e=>{le.error(e.message,"api.controller."+ne.tableName,!0)}));if(!n)return pe.notfound(t,"Username not found");if(!n.state)return pe.error(t,"Username is disabled");const a=T(i).toString();if(n.password!=a)return pe.error(t,"Invalid password");const d=n.id,u=s(),{error:c,token:l}=we.sign({id:d,secret:u});if(c)return pe.error(t,c);if(l){const r=Date.now(),o=r+6e4*Y,s=e.get("User-Agent"),i=yield re.create({login:r,secret:u,timestamp:o,useragent:s,userId:d}).catch((e=>{le.error(e.message,"api.controller."+re.tableName,!0)}));if(i)return pe.data(t,{token:l})}return pe.error(t,"Internal Server Error")})))),_e.get("/logout",be,((e,t)=>R(void 0,void 0,void 0,(function*(){const r=e.auth;return r?(r.logout=Date.now(),r.timestamp=r.logout,yield r.save(),pe.success(t,"Disconcerted")):pe.unauthorized(t,"Access denied")}))));const Pe=new ve(oe),Re=new ve(ie),je=Pe.add(),qe=Pe.all(),ke=Pe.del(),De=Pe.get(),xe=Pe.set(),Be={name:_.string().min(3).required(),description:_.string().allow(null,""),state:_.boolean().required()},Ge=Ne(_.object(Be)),ze={routes:_.array().items(_.number())},Ue=Ne(_.object(ze)),Ce={name:_.string().min(3).empty(""),description:_.string().allow(null,""),state:_.boolean().empty("")},Le=Ne(_.object(Ce)),He=w();He.use(be),He.get("/",Te("groups.read"),qe),He.post("/",Te("groups.write"),Ge,je),He.route("/:id").get(Te("groups.read"),De).put(Te("groups.write"),Le,xe).delete(Te("groups.write"),ke),He.route("/:id/routes").get(Te("groups.read"),Ue,((e,t)=>R(void 0,void 0,void 0,(function*(){const{id:r}=e.params;return Re.all({where:{groupId:r},include:[{model:se,required:!0}]},(e=>e.map((e=>e.route))))(e,t)})))).put(Te("groups.write"),Ue,((e,t)=>R(void 0,void 0,void 0,(function*(){const{id:r}=e.params,{routes:o}=e.body,s=yield oe.findByPk(r,{attributes:["id"]}).catch((e=>{le.error(e.message,"api.controller."+oe.tableName,!0)}));if(s){const e=s.id;if(yield ie.destroy({where:{groupId:e}}),o){let t=0;for(let r=0;r<o.length;r++)t=yield se.count({where:{id:o[r]}}),t&&(yield ie.create({groupId:e,routeId:o[r]}))}return pe.success(t,"OK")}return null===s?pe.notfound(t,"Record not found"):pe.error(t,"Internal Server Error")}))));const Ke=new ve(ue),Me=w();Me.use(be),Me.get("/",Te("logs.read"),((e,t)=>R(void 0,void 0,void 0,(function*(){const{source:r,type:o}=e.query,s=r&&o?{source:r,type:o}:r?{source:r}:o?{type:o}:{};return Ke.all({where:s,order:[["created","DESC"]]})(e,t)}))));const Fe=new ve(se),We=Fe.add(),Xe=Fe.all(),Ye=Fe.del(),Je=Fe.get(),Ve=Fe.set(),Ze={name:_.string().min(5).required(),description:_.string().allow(null,""),state:_.boolean().required()},$e=Ne(_.object(Ze)),Qe={name:_.string().min(5).empty(""),description:_.string().allow(null,""),state:_.boolean().empty("")},et=Ne(_.object(Qe)),tt=w();tt.use(be),tt.get("/",Te("routes.read"),Xe),tt.post("/",Te("routes.write"),$e,We),tt.route("/:id").get(Te("routes.read"),Je).put(Te("routes.write"),et,Ve).delete(Te("routes.write"),Ye);const rt=new ve(ne),ot=new ve(ae),st=["id","name","email","username","description","state"],it=rt.del(),nt={name:_.string().min(5).required(),email:_.string().email().required(),username:_.string().min(5).required(),password:_.string().min(5).required(),description:_.string().allow(null,""),state:_.boolean().required()},at=Ne(_.object(nt)),dt={groups:_.array().items(_.number())},ut=Ne(_.object(dt)),ct={name:_.string().min(5).empty(""),email:_.string().email().empty(""),username:_.string().min(5).empty(""),password:_.string().min(5).empty(""),description:_.string().allow(null,""),state:_.boolean().empty("")},lt=Ne(_.object(ct)),mt=w();mt.use(be),mt.get("/",Te("users.read"),((e,t)=>R(void 0,void 0,void 0,(function*(){return rt.all({attributes:st})(e,t)})))),mt.post("/",Te("users.write"),at,((e,t)=>R(void 0,void 0,void 0,(function*(){return e.body.password=T(e.body.password).toString(),yield rt.add()(e,t)})))),mt.route("/:id").get(Te("users.read"),((e,t)=>R(void 0,void 0,void 0,(function*(){return rt.get({attributes:st})(e,t)})))).put(Te("users.write"),lt,((e,t)=>R(void 0,void 0,void 0,(function*(){return e.body.password&&(e.body.password=T(e.body.password).toString()),rt.set()(e,t)})))).delete(Te("users.write"),it),mt.route("/:id/groups").get(Te("users.read"),((e,t)=>R(void 0,void 0,void 0,(function*(){const{id:r}=e.params;return ot.all({where:{userId:r},include:[{model:oe,required:!0}]},(e=>e.map((e=>e.group))))(e,t)})))).put(Te("users.write"),ut,((e,t)=>R(void 0,void 0,void 0,(function*(){const{id:r}=e.params,{groups:o}=e.body,s=yield ne.findByPk(r,{attributes:["id"]}).catch((e=>{le.error(e.message,"api.controller."+ne.tableName,!0)}));if(s){if(yield ae.destroy({where:{userId:s.id}}),o){let e=0;for(let t=0;t<o.length;t++)e=yield oe.count({where:{id:o[t]}}),e&&(yield ae.create({userId:s.id,groupId:o[t]}))}return pe.success(t,"OK")}return pe.notfound(t,"Record not found")}))));const pt=w();let vt;pt.use("/auth",_e),pt.use("/groups",He),pt.use("/logs",Me),pt.use("/routes",tt),pt.use("/users",mt);const gt=w(),ft=()=>{var e;return vt||(vt=y(),(e=vt).use(y.json()),e.use(((e,t,r,o)=>e?(le.error(e.message,"api.express",!0),pe.error(r,"Internal Server Error")):o())),e.use(y.urlencoded({extended:!0})),e.disable("x-powered-by"),K&&e.use(h()),e.use("/api",gt),e.use("/api",pt),e.all("/api/*",((e,t)=>pe.notfound(t,"Invalid API"))),H&&(I(H)&&e.use(y.static(H)),e.get("*",((e,t)=>{if(!I(H))return pe.notfound(t,'File "index.html" not found');t.sendFile(H+"/index.html")})))),vt};let ht;const yt=()=>(ht||(ht=(e=>{if(!he.http||!ye.http){const t=v.createServer(e);return t.listen(L,(()=>le.info("Server started on port "+L,"api.server",!0))),t}const t=v.createServer(((e,t)=>{const r=80==L?":80":"";t.writeHead(301,{Location:"https://"+e.headers.host+r+e.url}),t.end()})),r=g.createServer({key:ye.http,cert:he.http},e);if(M)return new f((e=>{e.once("data",(o=>{e.pause(),e.unshift(o),(22===o[0]?r:t).emit("connection",e),process.nextTick((()=>e.resume()))}))})).listen(L,(()=>le.info("Server started on port "+L,"api.server",!0))),r;return 443==L&&t.listen(80,(()=>le.info("Server started on port 80","api.server",!0))),r.listen(L,(()=>le.info("Server started on port "+L,"api.server",!0))),r})(ft())),ht),wt=e=>{const t=new P.Server({server:e,verifyClient:It});return t.on("connection",(e=>{e.on("message",(t=>R(void 0,void 0,void 0,(function*(){we.verify(t.toString()),e.close()})))),setTimeout((()=>{e.close()}),2e3),e.on("close",(()=>{t.emit("close",e)}))})),t},It=(e,t)=>t(Q),bt=()=>R(void 0,void 0,void 0,(function*(){yield te.sync();const e=yt();Q&&wt(e)}));export{j as API_AUTH_SLEEP,q as API_DB_DATABASE,k as API_DB_HOST,z as API_DB_LOG,D as API_DB_PASSWORD,x as API_DB_PORT,B as API_DB_TYPE,G as API_DB_USERNAME,K as API_HTTP_CROSS,U as API_HTTP_CRT,M as API_HTTP_HYBRID,C as API_HTTP_KEY,L as API_HTTP_PORT,H as API_HTTP_PUBLIC,F as API_TOKEN_CRT,X as API_TOKEN_HEADER,W as API_TOKEN_KEY,Y as API_TOKEN_LIFETIME,J as API_UPLOAD_COUNT,V as API_UPLOAD_FIELD,Z as API_UPLOAD_SIZE,$ as API_UPLOAD_TEMP,Q as API_WEBSOCKET_START,re as Auth,me as Config,de as Configs,ve as Controller,oe as Group,ie as GroupRoute,le as Log,ue as Logs,ge as Permission,pe as Responses,se as Route,we as Token,ne as User,ae as UserGroup,be as auth,he as crt,bt as initialize,ye as key,Te as permission,gt as router,te as sequelize,wt as startSocket,Ae as upload,ft as useExpress,ee as uuid,Ne as validation};
|
package/dist/index.umd.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @andrewcaires/api v1.0.
|
|
2
|
+
* @andrewcaires/api v1.0.4
|
|
3
|
+
* Simple api for small applications using express, jsonwebtoken, sequelize and websocket
|
|
3
4
|
* (c) 2022 Andrew Caires
|
|
4
5
|
* @license: MIT
|
|
5
6
|
*/
|
|
6
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("@andrewcaires/utils.js"),t=require("dotenv"),r=require("sequelize"),s=require("cors"),o=require("express"),n=require("fs"),i=require("crypto-js"),a=require("jsonwebtoken"),d=require("joi"),u=require("http"),l=require("https"),c=require("net"),p=require("ws"),f=require("mime-types"),m=require("multer"),g=require("path");function v(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function y(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var s=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,s.get?s:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}var h=v(s),I=v(o),T=v(a),w=v(d),_=y(u),A=y(l),P=v(p),S=v(f),b=v(m);t.config();const O=parseInt(process.env.API_AUTH_SLEEP||"1000"),x=process.env.API_DB_DATABASE||"",E=process.env.API_DB_HOST||"127.0.0.1",D=process.env.API_DB_PASSWORD||"",R=parseInt(process.env.API_DB_PORT||"3306"),q=process.env.API_DB_TYPE||"",N=process.env.API_DB_USERNAME||"root",j=e.toBool(process.env.API_DB_LOG||"false"),B=process.env.API_HTTP_CRT||"",k=process.env.API_HTTP_KEY||"",U=parseInt(process.env.API_HTTP_PORT||"3000"),L=process.env.API_HTTP_PUBLIC||"",H=e.toBool(process.env.API_HTTP_CROSS||"false"),z=e.toBool(process.env.API_HTTP_HYBRID||"false"),C=process.env.API_TOKEN_CRT||"",M=process.env.API_TOKEN_KEY||"",G=process.env.API_TOKEN_HEADER||"authorization",K=parseInt(process.env.API_TOKEN_LIFETIME||"15"),F=parseInt(process.env.API_UPLOAD_COUNT||"1"),Y=process.env.API_UPLOAD_FIELD||"upload",W=parseInt(process.env.API_UPLOAD_SIZE||"2"),X=process.env.API_UPLOAD_TEMP||"./temp",$=e.toBool(process.env.API_WEBSOCKET_START||"false");function V(e,t,r,s){return new(r||(r=Promise))((function(o,n){function i(e){try{d(s.next(e))}catch(e){n(e)}}function a(e){try{d(s.throw(e))}catch(e){n(e)}}function d(e){var t;e.done?o(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(i,a)}d((s=s.apply(e,t||[])).next())}))}const J={type:r.UUID,defaultValue:r.UUIDV4,allowNull:!1,primaryKey:!0},Z=(()=>{switch(q){case"mariadb":return new r.Sequelize(x,N,D,{host:E,port:R,dialect:"mariadb",logging:j,define:{timestamps:!1}});case"mysql":return new r.Sequelize(x,N,D,{host:E,port:R,dialect:"mysql",logging:j,define:{timestamps:!1}});case"postgres":return new r.Sequelize(x,N,D,{host:E,port:R,dialect:"postgres",logging:j,define:{timestamps:!1}})}throw new Error("No database selected")})();class Q extends r.Model{}Q.init({login:r.DataTypes.BIGINT,logout:r.DataTypes.BIGINT,secret:r.DataTypes.STRING,timestamp:r.DataTypes.BIGINT,useragent:r.DataTypes.STRING},{sequelize:Z,modelName:"auth"});class ee extends r.Model{}ee.init({name:r.DataTypes.STRING,description:r.DataTypes.TEXT,state:r.DataTypes.BOOLEAN},{sequelize:Z,modelName:"group"});class te extends r.Model{}te.init({type:r.DataTypes.STRING,source:r.DataTypes.STRING,message:r.DataTypes.TEXT},{sequelize:Z,modelName:"logs",timestamps:!0,createdAt:"created",updatedAt:!1});class re extends r.Model{}re.init({name:r.DataTypes.STRING,description:r.DataTypes.TEXT,state:r.DataTypes.BOOLEAN},{sequelize:Z,modelName:"route"});class se extends r.Model{}se.init({},{sequelize:Z,modelName:"groups_routes"}),se.removeAttribute("id");class oe extends r.Model{}oe.init({name:r.DataTypes.STRING,email:r.DataTypes.STRING,username:r.DataTypes.STRING,password:r.DataTypes.STRING,description:r.DataTypes.TEXT,state:r.DataTypes.BOOLEAN},{sequelize:Z,modelName:"user"});class ne extends r.Model{}ne.init({},{sequelize:Z,modelName:"users_groups"}),ne.removeAttribute("id"),oe.hasMany(Q),Q.belongsTo(oe),ee.hasMany(se),se.belongsTo(ee),re.hasMany(se),se.belongsTo(re),oe.hasMany(ne),ne.belongsTo(oe),ee.hasMany(ne),ne.belongsTo(ee);var ie;!function(e){e.ERROR="[31m",e.INFO="[36m",e.NONE="[37m",e.SUCCESS="[32m",e.WARNING="[33m"}(ie||(ie={}));class ae{static write(e,t){ae.writeRaw(ie.NONE,"",e,t)}static error(e,t){ae.writeRaw(ie.ERROR,"error",e,t)}static info(e,t){ae.writeRaw(ie.INFO,"info",e,t)}static success(e,t){ae.writeRaw(ie.ERROR,"success",e,t)}static warning(e,t){ae.writeRaw(ie.WARNING,"warning",e,t)}static writeConsole(t,r,s){const o=e.dateFormat(new Date,"%H:%M:%S");console.log(">",t,r+" ".repeat(10-r.length),"[37m","|",o,"|",s)}static writeRaw(e,t,r,s){ae.writeConsole(e,t,r),te.create({type:t,source:s,message:r}).catch((()=>null))}}class de{static success(e,t){return e.status(200).json({message:t})}static data(e,t){return e.status(200).json(Object.assign({},t))}static error(e,t){return e.status(500).json({message:t})}static list(e,t){return e.status(200).json([...t])}static notfound(e,t){return e.status(404).json({message:t})}static validation(e,t,r){return e.status(400).json({message:t,details:r})}static unauthorized(e,t){return e.status(401).json({message:t})}}const ue=e=>{if(n.existsSync(e))return n.readFileSync(e)},le={http:ue(B),token:ue(C)},ce={http:ue(k),token:ue(M)};class pe{static all(e,t){return V(this,void 0,void 0,(function*(){return yield re.findAll({where:Object.assign(Object.assign({},t),{state:!0}),include:[{model:se,required:!0,include:[{model:ee,required:!0,where:{state:!0},include:[{model:ne,required:!0,where:{userId:e.id}}]}]}]}).catch((e=>{ae.error(e.message,"permission")}))}))}static get(e){return V(this,void 0,void 0,(function*(){const t=yield pe.all(e);return t?t.map((e=>e.name)):[]}))}static is(e,t){return V(this,void 0,void 0,(function*(){const r=yield pe.all(e,{name:t});return r&&!!r.length}))}}const fe=["id","name","email","username"],me=(e,t,r)=>V(void 0,void 0,void 0,(function*(){const s=e.get(G)||"";if(!le.token)return de.error(t,"Invalid Secret");if(!s||s.split(".").length<3)return de.error(t,"Invalid token");let o;try{o=T.default.verify(s,le.token)}catch(e){return de.error(t,"Invalid token")}if(o&&o.id&&o.secret){const s=yield oe.findOne({where:{id:o.id}}).catch((e=>{ae.error(e.message,"token.check")}));if(s&&s.state){const n=yield Q.findOne({where:{logout:null,secret:o.secret,userId:s.id}}).catch((e=>{ae.error(e.message,"token.check")}));if(n){const o=Date.now();if(o>n.timestamp)return de.error(t,"Expired token");n.timestamp=o+6e4*K;const i=e.get("User-Agent");return i&&(n.useragent=i),yield n.save(),e.auth=n,e.user=s,r()}}return de.error(t,"Access denied")}return de.error(t,"Invalid token")})),ge=e=>{const t={abortEarly:!1,allowUnknown:!0,stripUnknown:!0};return(r,s,o)=>{const{error:n,value:i}=e.validate(r.body,t);if(n){const e=n.details.map((e=>e.message)).join(", "),t=[];return n.details.forEach((e=>{var r;t.push({key:(null===(r=e.context)||void 0===r?void 0:r.key)||"",type:e.type})})),de.validation(s,"Validation error: "+e,t)}return r.body=i,o()}},ve={username:w.default.string().min(5).required(),password:w.default.string().min(5).required()},ye=ge(w.default.object(ve)),he=o.Router();he.get("/",me,((t,r)=>V(void 0,void 0,void 0,(function*(){const s=t.user;if(!s)return de.unauthorized(r,"Access denied");const o=yield pe.all(s);if(o){const t=e.allowedObject(fe,s.toJSON()),n=o.map((e=>e.name));return de.data(r,Object.assign(Object.assign({},t),{permissions:n}))}return de.error(r,"Internal Server Error")})))),he.post("/login",ye,((t,r)=>V(void 0,void 0,void 0,(function*(){const{username:s,password:o}=t.body;if(!s||!o)return de.error(r,"Invalid parameters");yield e.sleep(O);const n=yield oe.findOne({where:{username:s}}).catch((e=>{ae.error(e.message,"auth.login")}));if(!n)return de.notfound(r,"User not found");if(!n.state)return de.error(r,"User is disabled");const a=i.SHA256(o).toString();if(n.password!=a)return de.error(r,"Invalid password");if(!ce.token)return de.error(r,"Invalid Secret");const d=n.id,u=e.uniqueID(),l=T.default.sign({id:d,secret:u},ce.token,{algorithm:"RS256"});if(l){const e=Date.now(),s=e+6e4*K,o=t.get("User-Agent");if(yield Q.create({login:e,secret:u,timestamp:s,useragent:o,userId:d}).catch((e=>{ae.error(e.message,"auth.login")})))return de.data(r,{token:l})}return de.error(r,"Internal Server Error")})))),he.get("/logout",me,((e,t)=>V(void 0,void 0,void 0,(function*(){const r=e.auth;return r?(r.logout=Date.now(),r.timestamp=r.logout,yield r.save(),de.success(t,"Disconcerted")):de.unauthorized(t,"Access denied")}))));class Ie{constructor(e,t){this.log=e,this.model=t}add(){return(e,t)=>V(this,void 0,void 0,(function*(){const r=yield this.model.create(e.body).catch((e=>{ae.error(e.message,this.log+".add")}));return r?de.data(t,{id:r.id}):de.error(t,"Internal Server Error")}))}all(t,s){return(o,n)=>V(this,void 0,void 0,(function*(){var i,a,d,u,l;t||(t={});const c=Object.assign({},t);c.where=c.where?Object.assign({},c.where):{};const p=null===(i=o.query.limit)||void 0===i?void 0:i.toString();p&&(c.limit=parseInt(p));const f=null===(a=o.query.offset)||void 0===a?void 0:a.toString();f&&(c.offset=parseInt(f));const m=null===(d=o.query.asc)||void 0===d?void 0:d.toString();m&&(c.order=[[m,"ASC"]]);const g=null===(u=o.query.desc)||void 0===u?void 0:u.toString();g&&(c.order=[[g,"DESC"]]);const v=[],y=null===(l=o.query.search)||void 0===l?void 0:l.toString();y&&(Object.keys(this.model.getAttributes()).forEach((e=>{v.push({[e]:{[r.Op.like]:`%${y}%`}})})),v.length&&(c.where=Object.assign(Object.assign({},c.where),{[r.Op.or]:[...v]})));const h=yield this.model.findAll(c).catch((e=>{ae.error(e.message,this.log+".all")})),I=yield this.model.count(c).catch(e.noop);return h?de.data(n,{count:I,records:s?s(h):h}):de.error(n,"Internal Server Error")}))}del(){return(e,t)=>V(this,void 0,void 0,(function*(){const{id:r}=e.params;return(yield this.model.destroy({where:{id:r}}).catch((e=>{ae.error(e.message,this.log+".del")})))?de.success(t,"OK"):de.notfound(t,"Record not found")}))}get(e,t){return(r,s)=>V(this,void 0,void 0,(function*(){e||(e={});const o=Object.assign({},e);o.where=o.where?Object.assign({},o.where):{};const{id:n}=r.params,i=yield this.model.findByPk(n,o).catch((e=>{ae.error(e.message,this.log+".get")}));return i?de.data(s,t?t(i):i.toJSON()):null===i?de.notfound(s,"Record not found"):de.error(s,"Internal Server Error")}))}set(){return(e,t)=>V(this,void 0,void 0,(function*(){const{id:r}=e.params,s=yield this.model.update(e.body,{where:{id:r}}).catch((e=>{ae.error(e.message,this.log+".set")}));if(s){const[e]=s;if(e)return de.success(t,"OK")}return de.success(t,"Record not changed")}))}}const Te=new Ie("groups",ee),we=new Ie("groups.route",se),_e=Te.add(),Ae=Te.all(),Pe=Te.del(),Se=Te.get(),be=Te.set(),Oe=e=>(t,r,s)=>V(void 0,void 0,void 0,(function*(){const o=t.user;return o?(yield pe.is(o,e))?s():de.error(r,"Unauthorized access"):de.unauthorized(r,"Access denied")})),xe={name:w.default.string().min(3).required(),description:w.default.string().allow(null,""),state:w.default.boolean().required()},Ee=ge(w.default.object(xe)),De={routes:w.default.array().items(w.default.number())},Re=ge(w.default.object(De)),qe={name:w.default.string().min(3).empty(""),description:w.default.string().allow(null,""),state:w.default.boolean().empty("")},Ne=ge(w.default.object(qe)),je=o.Router();je.use(me),je.get("/",Oe("groups.read"),Ae),je.post("/",Oe("groups.write"),Ee,_e),je.route("/:id").get(Oe("groups.read"),Se).put(Oe("groups.write"),Ne,be).delete(Oe("groups.write"),Pe),je.route("/:id/routes").get(Oe("groups.read"),Re,((e,t)=>V(void 0,void 0,void 0,(function*(){const{id:r}=e.params;return we.all({where:{groupId:r},include:[{model:re,required:!0}]},(e=>e.map((e=>e.route))))(e,t)})))).put(Oe("groups.write"),Re,((e,t)=>V(void 0,void 0,void 0,(function*(){const{id:r}=e.params,{routes:s}=e.body,o=yield ee.findByPk(r,{attributes:["id"]}).catch((e=>{ae.error(e.message,"groups.routesSet")}));if(o){const e=o.id;if(yield se.destroy({where:{groupId:e}}),s){let t=0;for(let r=0;r<s.length;r++)t=yield re.count({where:{id:s[r]}}),t&&(yield se.create({groupId:e,routeId:s[r]}))}return de.success(t,"OK")}return null===o?de.notfound(t,"Record not found"):de.error(t,"Internal Server Error")}))));const Be=new Ie("route",re),ke=Be.add(),Ue=Be.all(),Le=Be.del(),He=Be.get(),ze=Be.set(),Ce={name:w.default.string().min(5).required(),permission:w.default.string().required(),description:w.default.string().allow(null,""),state:w.default.boolean().required()},Me=ge(w.default.object(Ce)),Ge={name:w.default.string().min(5).empty(""),permission:w.default.string().empty(""),description:w.default.string().allow(null,""),state:w.default.boolean().empty("")},Ke=ge(w.default.object(Ge)),Fe=o.Router();Fe.use(me),Fe.get("/",Oe("routes.read"),Ue),Fe.post("/",Oe("routes.write"),Me,ke),Fe.route("/:id").get(Oe("routes.read"),He).put(Oe("routes.write"),Ke,ze).delete(Oe("routes.write"),Le);const Ye=new Ie("user",oe),We=new Ie("user.groups",ne),Xe=["id","name","email","username","description","state"],$e=Ye.del(),Ve={name:w.default.string().min(5).required(),email:w.default.string().email().required(),username:w.default.string().min(5).required(),password:w.default.string().min(5).required(),description:w.default.string().allow(null,""),state:w.default.boolean().required()},Je=ge(w.default.object(Ve)),Ze={groups:w.default.array().items(w.default.number())},Qe=ge(w.default.object(Ze)),et={name:w.default.string().min(5).empty(""),email:w.default.string().email().empty(""),username:w.default.string().min(5).empty(""),password:w.default.string().min(5).empty(""),description:w.default.string().allow(null,""),state:w.default.boolean().empty("")},tt=ge(w.default.object(et)),rt=o.Router();rt.use(me),rt.get("/",Oe("users.read"),((e,t)=>V(void 0,void 0,void 0,(function*(){return Ye.all({attributes:Xe})(e,t)})))),rt.post("/",Oe("users.write"),Je,((e,t)=>V(void 0,void 0,void 0,(function*(){return e.body.password=i.SHA256(e.body.password).toString(),yield Ye.add()(e,t)})))),rt.route("/:id").get(Oe("users.read"),((e,t)=>V(void 0,void 0,void 0,(function*(){return Ye.get({attributes:Xe})(e,t)})))).put(Oe("users.write"),tt,((e,t)=>V(void 0,void 0,void 0,(function*(){return e.body.password&&(e.body.password=i.SHA256(e.body.password).toString()),Ye.set()(e,t)})))).delete(Oe("users.write"),$e),rt.route("/:id/groups").get(Oe("users.read"),((e,t)=>V(void 0,void 0,void 0,(function*(){const{id:r}=e.params;return We.all({where:{userId:r},include:[{model:ee,required:!0}]},(e=>e.map((e=>e.group))))(e,t)})))).put(Oe("users.write"),Qe,((e,t)=>V(void 0,void 0,void 0,(function*(){const{id:r}=e.params,{groups:s}=e.body,o=yield oe.findByPk(r,{attributes:["id"]}).catch((e=>{ae.error(e.message,"user.groups.set")}));if(o){if(yield ne.destroy({where:{userId:o.id}}),s){let e=0;for(let t=0;t<s.length;t++)e=yield ee.count({where:{id:s[t]}}),e&&(yield ne.create({userId:o.id,groupId:s[t]}))}return de.success(t,"OK")}return de.notfound(t,"Record not found")}))));const st=o.Router();st.use("/v1/auth",he),st.use("/v1/groups",je),st.use("/v1/routes",Fe),st.use("/v1/users",rt);const ot=I.default();ot.use(I.default.json()),ot.use(((e,t,r,s)=>e?(ae.error(e.message,"express"),de.error(r,"Internal Server Error")):s())),ot.use(I.default.urlencoded({extended:!0})),ot.disable("x-powered-by"),H&&ot.use(h.default()),ot.use("/api",st),ot.all("/api/*",((e,t)=>de.notfound(t,"Invalid API"))),L&&(n.existsSync(L)&&ot.use(I.default.static(L)),ot.get("*",((e,t)=>{if(!n.existsSync(L))return de.notfound(t,'File "index.html" not found');t.sendFile(L+"/index.html")})));const nt=e=>{const t=new P.default.Server({server:e,verifyClient:it});return t.on("connection",(e=>{e.on("message",(t=>{e.close()})),setTimeout((()=>{e.close()}),2e3),e.on("close",(()=>{t.emit("close",e)}))})),t},it=(e,t)=>t($),at=(e=>{if(!le.http||!ce.http){const t=_.createServer(e);return t.listen(U,(()=>ae.info(`Server started on port ${U}`))),t}const t=_.createServer(((e,t)=>{const r=80==U?":80":"";t.writeHead(301,{Location:"https://"+e.headers.host+r+e.url}),t.end()})),r=A.createServer({key:ce.http,cert:le.http},e);if(z){return new c.Server((e=>{e.once("data",(s=>{e.pause(),e.unshift(s),(22===s[0]?r:t).emit("connection",e),process.nextTick((()=>e.resume()))}))})).listen(U,(()=>ae.info(`Server started on port ${U}`))),r}return 443==U&&t.listen(80,(()=>ae.info("Server started on port 80"))),r.listen(U,(()=>ae.info(`Server started on port ${U}`))),r})(ot),dt=(t,r)=>{const s=e.uuidv4()+"."+r;return n.existsSync(g.join(t,s))?dt(t,r):s};exports.API_AUTH_SLEEP=O,exports.API_DB_DATABASE=x,exports.API_DB_HOST=E,exports.API_DB_LOG=j,exports.API_DB_PASSWORD=D,exports.API_DB_PORT=R,exports.API_DB_TYPE=q,exports.API_DB_USERNAME=N,exports.API_HTTP_CROSS=H,exports.API_HTTP_CRT=B,exports.API_HTTP_HYBRID=z,exports.API_HTTP_KEY=k,exports.API_HTTP_PORT=U,exports.API_HTTP_PUBLIC=L,exports.API_TOKEN_CRT=C,exports.API_TOKEN_HEADER=G,exports.API_TOKEN_KEY=M,exports.API_TOKEN_LIFETIME=K,exports.API_UPLOAD_COUNT=F,exports.API_UPLOAD_FIELD=Y,exports.API_UPLOAD_SIZE=W,exports.API_UPLOAD_TEMP=X,exports.API_WEBSOCKET_START=$,exports.Auth=Q,exports.Controller=Ie,exports.Group=ee,exports.GroupRoute=se,exports.Log=ae,exports.Logs=te,exports.Permission=pe,exports.Responses=de,exports.Route=re,exports.User=oe,exports.UserGroup=ne,exports.app=ot,exports.auth=me,exports.crt=le,exports.initialize=()=>{Z.sync().then((()=>{V(void 0,void 0,void 0,(function*(){if(0==(yield oe.count())){const t=yield oe.create({name:"Admin",email:"admin@localhost",username:"admin",password:"8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918",description:"",state:!0});if(0==(yield ee.count())){const r=yield ee.create({name:"admin",description:"",state:!0});if(yield ne.create({userId:t.id,groupId:r.id}),0==(yield re.count())){const t=["read","write"],s=["users","groups","permission"];e.forEachSeries(s,(s=>V(void 0,void 0,void 0,(function*(){e.forEachSeries(t,(e=>V(void 0,void 0,void 0,(function*(){const t=s.toLowerCase()+"."+e.toLowerCase(),o=yield re.create({name:t,description:"",state:!0});yield se.create({groupId:r.id,routeId:o.id})}))))}))))}}}})),$&&nt(at)}))},exports.key=ce,exports.permission=Oe,exports.router=st,exports.sequelize=Z,exports.server=at,exports.startSocket=nt,exports.upload=e=>{const t=(null==e?void 0:e.path)||X,r=b.default.diskStorage({destination:(e,r,s)=>s(null,t),filename:(e,r,s)=>V(void 0,void 0,void 0,(function*(){return s(null,dt(t,S.default.extension(r.mimetype)||"bin"))}))}),s=1e6*((null==e?void 0:e.size)||W),o=b.default({storage:r,fileFilter(t,r,s){var o;return V(this,void 0,void 0,(function*(){const t=null===(o=null==e?void 0:e.types)||void 0===o?void 0:o.indexOf(r.mimetype);return void 0!==t&&t<0?s(new Error("File type not allowed")):s(null,!0)}))},limits:{fileSize:s}}),n=(null==e?void 0:e.count)||F,i=(null==e?void 0:e.field)||Y,a=o.array(i,n);return(e,t,r)=>{a(e,t,(function(e){return e?de.error(t,e.message):r()}))}},exports.uuid=J,exports.validation=ge;
|
|
7
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("@andrewcaires/utils.js"),t=require("dotenv"),r=require("sequelize"),s=require("http"),o=require("https"),i=require("net"),n=require("cors"),a=require("express"),d=require("fs"),u=require("crypto-js"),l=require("jsonwebtoken"),c=require("mime-types"),p=require("multer"),f=require("path"),m=require("joi"),v=require("ws");function g(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function y(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var s=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,s.get?s:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}var h=y(s),I=y(o),T=g(n),w=g(a),A=g(c),_=g(p),P=g(m),S=g(v);function b(e,t,r,s){return new(r||(r=Promise))((function(o,i){function n(e){try{d(s.next(e))}catch(e){i(e)}}function a(e){try{d(s.throw(e))}catch(e){i(e)}}function d(e){var t;e.done?o(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(n,a)}d((s=s.apply(e,t||[])).next())}))}t.config();const O=parseInt(process.env.API_AUTH_SLEEP||"1000"),x=process.env.API_DB_DATABASE||"",E=process.env.API_DB_HOST||"127.0.0.1",D=process.env.API_DB_PASSWORD||"",R=parseInt(process.env.API_DB_PORT||"3306"),N=process.env.API_DB_TYPE||"",q=process.env.API_DB_USERNAME||"root",j=e.toBool(process.env.API_DB_LOG||"false"),k=process.env.API_HTTP_CRT||"",B=process.env.API_HTTP_KEY||"",U=parseInt(process.env.API_HTTP_PORT||"3000"),H=process.env.API_HTTP_PUBLIC||"",C=e.toBool(process.env.API_HTTP_CROSS||"false"),L=e.toBool(process.env.API_HTTP_HYBRID||"false"),z=process.env.API_TOKEN_CRT||"",G=process.env.API_TOKEN_KEY||"",M=process.env.API_TOKEN_HEADER||"authorization",K=parseInt(process.env.API_TOKEN_LIFETIME||"15"),F=parseInt(process.env.API_UPLOAD_COUNT||"1"),Y=process.env.API_UPLOAD_FIELD||"upload",W=parseInt(process.env.API_UPLOAD_SIZE||"2"),X=process.env.API_UPLOAD_TEMP||"./temp",V=e.toBool(process.env.API_WEBSOCKET_START||"false"),J={type:r.UUID,defaultValue:r.UUIDV4,allowNull:!1,primaryKey:!0},Z=(()=>{switch(N){case"mariadb":return new r.Sequelize(x,q,D,{host:E,port:R,dialect:"mariadb",logging:j,define:{timestamps:!1}});case"mysql":return new r.Sequelize(x,q,D,{host:E,port:R,dialect:"mysql",logging:j,define:{timestamps:!1}});case"postgres":return new r.Sequelize(x,q,D,{host:E,port:R,dialect:"postgres",logging:j,define:{timestamps:!1}})}throw new Error("No database selected")})();class $ extends r.Model{}$.init({login:r.DataTypes.BIGINT,logout:r.DataTypes.BIGINT,secret:r.DataTypes.STRING,timestamp:r.DataTypes.BIGINT,useragent:r.DataTypes.STRING},{sequelize:Z,modelName:"auth"});class Q extends r.Model{}Q.init({name:r.DataTypes.STRING,description:r.DataTypes.TEXT,state:r.DataTypes.BOOLEAN},{sequelize:Z,modelName:"group"});class ee extends r.Model{}ee.init({name:r.DataTypes.STRING,description:r.DataTypes.TEXT,state:r.DataTypes.BOOLEAN},{sequelize:Z,modelName:"route"});class te extends r.Model{}te.init({},{sequelize:Z,modelName:"groups_routes"}),te.removeAttribute("id");class re extends r.Model{}re.init({name:r.DataTypes.STRING,email:r.DataTypes.STRING,username:r.DataTypes.STRING,password:r.DataTypes.STRING,description:r.DataTypes.TEXT,state:r.DataTypes.BOOLEAN},{sequelize:Z,modelName:"user"});class se extends r.Model{}se.init({},{sequelize:Z,modelName:"users_groups"}),se.removeAttribute("id");class oe extends r.Model{}oe.init({key:r.DataTypes.STRING,value:r.DataTypes.STRING},{sequelize:Z,modelName:"configs",timestamps:!0,createdAt:"created",updatedAt:"updated"}),oe.removeAttribute("id");class ie extends r.Model{}var ne;ie.init({type:r.DataTypes.STRING,source:r.DataTypes.STRING,message:r.DataTypes.TEXT},{sequelize:Z,modelName:"logs",timestamps:!0,createdAt:"created",updatedAt:!1}),re.hasMany($),$.belongsTo(re),Q.hasMany(te),te.belongsTo(Q),ee.hasMany(te),te.belongsTo(ee),re.hasMany(se),se.belongsTo(re),Q.hasMany(se),se.belongsTo(Q),function(e){e.ERROR="[31m",e.INFO="[36m",e.NONE="[37m",e.SUCCESS="[32m",e.WARNING="[33m"}(ne||(ne={}));class ae{static write(e,t,r){return b(this,void 0,void 0,(function*(){yield ae.writeRaw(ne.NONE,"",e,t,r)}))}static error(e,t,r){return b(this,void 0,void 0,(function*(){yield ae.writeRaw(ne.ERROR,"error",e,t,r)}))}static info(e,t,r){return b(this,void 0,void 0,(function*(){yield ae.writeRaw(ne.INFO,"info",e,t,r)}))}static success(e,t,r){return b(this,void 0,void 0,(function*(){yield ae.writeRaw(ne.ERROR,"success",e,t,r)}))}static warning(e,t,r){return b(this,void 0,void 0,(function*(){yield ae.writeRaw(ne.WARNING,"warning",e,t,r)}))}static writeConsole(t,r,s){const o=e.dateFormat(new Date,"%H:%M:%S");console.log(">",t,r+" ".repeat(10-r.length),"[37m","|",o,"|",s)}static writeRaw(e,t,r,s,o){return b(this,void 0,void 0,(function*(){o&&ae.writeConsole(e,t,r),yield ie.create({type:t,source:s,message:r}).catch((()=>null))}))}}class de{static success(e,t){return e.status(200).json({message:t})}static data(e,t){return e.status(200).json(Object.assign({},t))}static error(e,t){return e.status(500).json({message:t})}static list(e,t){return e.status(200).json([...t])}static notfound(e,t){return e.status(404).json({message:t})}static validation(e,t,r){return e.status(400).json({message:t,details:r})}static unauthorized(e,t){return e.status(401).json({message:t})}}class ue{constructor(e){this.model=e}add(){return(e,t)=>b(this,void 0,void 0,(function*(){const r=yield this.model.create(e.body).catch((e=>{ae.error(e.message,"api.controller."+this.model.tableName,!0)}));return r?de.data(t,{id:r.id}):de.error(t,"Internal Server Error")}))}all(t,s){return(o,i)=>b(this,void 0,void 0,(function*(){var n,a,d,u,l;t||(t={});const c=Object.assign({},t);c.where=c.where?Object.assign({},c.where):{};const p=null===(n=o.query.limit)||void 0===n?void 0:n.toString();p&&(c.limit=parseInt(p));const f=null===(a=o.query.offset)||void 0===a?void 0:a.toString();f&&(c.offset=parseInt(f));const m=null===(d=o.query.asc)||void 0===d?void 0:d.toString();m&&(c.order=[[m,"ASC"]]);const v=null===(u=o.query.desc)||void 0===u?void 0:u.toString();v&&(c.order=[[v,"DESC"]]);const g=[],y=null===(l=o.query.search)||void 0===l?void 0:l.toString();y&&(Object.keys(this.model.getAttributes()).forEach((e=>{"password"!=e&&g.push({[e]:{[r.Op.like]:`%${y}%`}})})),g.length&&(c.where=Object.assign(Object.assign({},c.where),{[r.Op.or]:[...g]})));const h=yield this.model.findAll(c).catch((e=>{ae.error(e.message,"api.controller."+this.model.tableName,!0)})),I=yield this.model.count(c).catch(e.noop);return h?de.data(i,{count:I,records:s?s(h):h}):de.error(i,"Internal Server Error")}))}del(){return(e,t)=>b(this,void 0,void 0,(function*(){const{id:r}=e.params;return(yield this.model.destroy({where:{id:r}}).catch((e=>{ae.error(e.message,"api.controller."+this.model.tableName,!0)})))?de.success(t,"OK"):de.notfound(t,"Record not found")}))}get(e,t){return(r,s)=>b(this,void 0,void 0,(function*(){e||(e={});const o=Object.assign({},e);o.where=o.where?Object.assign({},o.where):{};const{id:i}=r.params,n=yield this.model.findByPk(i,o).catch((e=>{ae.error(e.message,"api.controller."+this.model.tableName,!0)}));return n?de.data(s,t?t(n):n.toJSON()):null===n?de.notfound(s,"Record not found"):de.error(s,"Internal Server Error")}))}set(){return(e,t)=>b(this,void 0,void 0,(function*(){const{id:r}=e.params,s=yield this.model.update(e.body,{where:{id:r}}).catch((e=>{ae.error(e.message,"api.controller."+this.model.tableName,!0)}));if(s){const[e]=s;if(e)return de.success(t,"OK")}return de.success(t,"Record not changed")}))}}class le{static all(e,t){return b(this,void 0,void 0,(function*(){return yield ee.findAll({where:Object.assign(Object.assign({},t),{state:!0}),include:[{model:te,required:!0,include:[{model:Q,required:!0,where:{state:!0},include:[{model:se,required:!0,where:{userId:e.id}}]}]}]}).catch((e=>{ae.error(e.message,"api.permission",!0)}))}))}static get(e){return b(this,void 0,void 0,(function*(){const t=yield le.all(e);return t?t.map((e=>e.name)):[]}))}static is(e,t){return b(this,void 0,void 0,(function*(){const r=yield le.all(e,{name:t});return r&&!!r.length}))}}const ce=e=>{if(d.existsSync(e))return d.readFileSync(e)},pe={http:ce(k),token:ce(z)},fe={http:ce(B),token:ce(G)};class me{static sign(e){return fe.token?{token:l.sign(e,fe.token,{algorithm:"RS256"})}:{error:"Invalid Secret"}}static verify(e){if(!pe.token)return{error:"Invalid Secret"};if(!e||e.split(".").length<3)return{error:"Invalid Token"};try{return{decode:l.verify(e,pe.token)}}catch(e){return{error:"Invalid Token"}}}}const ve=["id","name","email","username"],ge=(e,t,r)=>b(void 0,void 0,void 0,(function*(){const s=e.get(M)||"",{error:o,decode:i}=me.verify(s);if(o)return de.error(t,o);if(i){const{id:s,secret:o}=i;if(s&&i){const i=yield re.findOne({where:{id:s,state:!0}}).catch((e=>{ae.error(e.message,"api.auth",!0)}));if(i){const s=yield $.findOne({where:{secret:o,userId:i.id}}).catch((e=>{ae.error(e.message,"api.auth",!0)}));if(s){const o=Date.now();if(o>s.timestamp)return de.error(t,"Expired token");s.timestamp=o+6e4*K;const n=e.get("User-Agent");return n&&(s.useragent=n),yield s.save(),e.auth=s,e.user=i,r()}}return de.error(t,"Access denied")}}return de.error(t,"Invalid token")})),ye=e=>(t,r,s)=>b(void 0,void 0,void 0,(function*(){const o=t.user;return o?(yield le.is(o,e))?s():de.error(r,"Unauthorized access"):de.unauthorized(r,"Access denied")})),he=(t,r)=>{const s=e.uuidv4()+"."+r;return d.existsSync(f.join(t,s))?he(t,r):s},Ie=e=>{const t={abortEarly:!1,allowUnknown:!0,stripUnknown:!0};return(r,s,o)=>{const{error:i,value:n}=e.validate(r.body,t);if(i){const e=i.details.map((e=>e.message)).join(", "),t=[];return i.details.forEach((e=>{var r;t.push({key:(null===(r=e.context)||void 0===r?void 0:r.key)||"",type:e.type})})),de.validation(s,"Validation error: "+e,t)}return r.body=n,o()}},Te={username:P.default.string().min(5).required(),password:P.default.string().min(5).required()},we=Ie(P.default.object(Te)),Ae=a.Router();Ae.get("/",ge,((t,r)=>b(void 0,void 0,void 0,(function*(){const s=t.user;if(!s)return de.unauthorized(r,"Access denied");const o=yield le.all(s);if(o){const t=e.allowedObject(ve,s.toJSON()),i=o.map((e=>e.name));return de.data(r,Object.assign(Object.assign({},t),{permissions:i}))}return de.error(r,"Internal Server Error")})))),Ae.post("/login",we,((t,r)=>b(void 0,void 0,void 0,(function*(){const{username:s,password:o}=t.body;if(!s||!o)return de.error(r,"Invalid parameters");yield e.sleep(O);const i=yield re.findOne({where:{username:s}}).catch((e=>{ae.error(e.message,"api.controller."+re.tableName,!0)}));if(!i)return de.notfound(r,"Username not found");if(!i.state)return de.error(r,"Username is disabled");const n=u.SHA256(o).toString();if(i.password!=n)return de.error(r,"Invalid password");const a=i.id,d=e.uniqueID(),{error:l,token:c}=me.sign({id:a,secret:d});if(l)return de.error(r,l);if(c){const e=Date.now(),s=e+6e4*K,o=t.get("User-Agent"),i=yield $.create({login:e,secret:d,timestamp:s,useragent:o,userId:a}).catch((e=>{ae.error(e.message,"api.controller."+$.tableName,!0)}));if(i)return de.data(r,{token:c})}return de.error(r,"Internal Server Error")})))),Ae.get("/logout",ge,((e,t)=>b(void 0,void 0,void 0,(function*(){const r=e.auth;return r?(r.logout=Date.now(),r.timestamp=r.logout,yield r.save(),de.success(t,"Disconcerted")):de.unauthorized(t,"Access denied")}))));const _e=new ue(Q),Pe=new ue(te),Se=_e.add(),be=_e.all(),Oe=_e.del(),xe=_e.get(),Ee=_e.set(),De={name:P.default.string().min(3).required(),description:P.default.string().allow(null,""),state:P.default.boolean().required()},Re=Ie(P.default.object(De)),Ne={routes:P.default.array().items(P.default.number())},qe=Ie(P.default.object(Ne)),je={name:P.default.string().min(3).empty(""),description:P.default.string().allow(null,""),state:P.default.boolean().empty("")},ke=Ie(P.default.object(je)),Be=a.Router();Be.use(ge),Be.get("/",ye("groups.read"),be),Be.post("/",ye("groups.write"),Re,Se),Be.route("/:id").get(ye("groups.read"),xe).put(ye("groups.write"),ke,Ee).delete(ye("groups.write"),Oe),Be.route("/:id/routes").get(ye("groups.read"),qe,((e,t)=>b(void 0,void 0,void 0,(function*(){const{id:r}=e.params;return Pe.all({where:{groupId:r},include:[{model:ee,required:!0}]},(e=>e.map((e=>e.route))))(e,t)})))).put(ye("groups.write"),qe,((e,t)=>b(void 0,void 0,void 0,(function*(){const{id:r}=e.params,{routes:s}=e.body,o=yield Q.findByPk(r,{attributes:["id"]}).catch((e=>{ae.error(e.message,"api.controller."+Q.tableName,!0)}));if(o){const e=o.id;if(yield te.destroy({where:{groupId:e}}),s){let t=0;for(let r=0;r<s.length;r++)t=yield ee.count({where:{id:s[r]}}),t&&(yield te.create({groupId:e,routeId:s[r]}))}return de.success(t,"OK")}return null===o?de.notfound(t,"Record not found"):de.error(t,"Internal Server Error")}))));const Ue=new ue(ie),He=a.Router();He.use(ge),He.get("/",ye("logs.read"),((e,t)=>b(void 0,void 0,void 0,(function*(){const{source:r,type:s}=e.query,o=r&&s?{source:r,type:s}:r?{source:r}:s?{type:s}:{};return Ue.all({where:o,order:[["created","DESC"]]})(e,t)}))));const Ce=new ue(ee),Le=Ce.add(),ze=Ce.all(),Ge=Ce.del(),Me=Ce.get(),Ke=Ce.set(),Fe={name:P.default.string().min(5).required(),description:P.default.string().allow(null,""),state:P.default.boolean().required()},Ye=Ie(P.default.object(Fe)),We={name:P.default.string().min(5).empty(""),description:P.default.string().allow(null,""),state:P.default.boolean().empty("")},Xe=Ie(P.default.object(We)),Ve=a.Router();Ve.use(ge),Ve.get("/",ye("routes.read"),ze),Ve.post("/",ye("routes.write"),Ye,Le),Ve.route("/:id").get(ye("routes.read"),Me).put(ye("routes.write"),Xe,Ke).delete(ye("routes.write"),Ge);const Je=new ue(re),Ze=new ue(se),$e=["id","name","email","username","description","state"],Qe=Je.del(),et={name:P.default.string().min(5).required(),email:P.default.string().email().required(),username:P.default.string().min(5).required(),password:P.default.string().min(5).required(),description:P.default.string().allow(null,""),state:P.default.boolean().required()},tt=Ie(P.default.object(et)),rt={groups:P.default.array().items(P.default.number())},st=Ie(P.default.object(rt)),ot={name:P.default.string().min(5).empty(""),email:P.default.string().email().empty(""),username:P.default.string().min(5).empty(""),password:P.default.string().min(5).empty(""),description:P.default.string().allow(null,""),state:P.default.boolean().empty("")},it=Ie(P.default.object(ot)),nt=a.Router();nt.use(ge),nt.get("/",ye("users.read"),((e,t)=>b(void 0,void 0,void 0,(function*(){return Je.all({attributes:$e})(e,t)})))),nt.post("/",ye("users.write"),tt,((e,t)=>b(void 0,void 0,void 0,(function*(){return e.body.password=u.SHA256(e.body.password).toString(),yield Je.add()(e,t)})))),nt.route("/:id").get(ye("users.read"),((e,t)=>b(void 0,void 0,void 0,(function*(){return Je.get({attributes:$e})(e,t)})))).put(ye("users.write"),it,((e,t)=>b(void 0,void 0,void 0,(function*(){return e.body.password&&(e.body.password=u.SHA256(e.body.password).toString()),Je.set()(e,t)})))).delete(ye("users.write"),Qe),nt.route("/:id/groups").get(ye("users.read"),((e,t)=>b(void 0,void 0,void 0,(function*(){const{id:r}=e.params;return Ze.all({where:{userId:r},include:[{model:Q,required:!0}]},(e=>e.map((e=>e.group))))(e,t)})))).put(ye("users.write"),st,((e,t)=>b(void 0,void 0,void 0,(function*(){const{id:r}=e.params,{groups:s}=e.body,o=yield re.findByPk(r,{attributes:["id"]}).catch((e=>{ae.error(e.message,"api.controller."+re.tableName,!0)}));if(o){if(yield se.destroy({where:{userId:o.id}}),s){let e=0;for(let t=0;t<s.length;t++)e=yield Q.count({where:{id:s[t]}}),e&&(yield se.create({userId:o.id,groupId:s[t]}))}return de.success(t,"OK")}return de.notfound(t,"Record not found")}))));const at=a.Router();let dt;at.use("/auth",Ae),at.use("/groups",Be),at.use("/logs",He),at.use("/routes",Ve),at.use("/users",nt);const ut=a.Router(),lt=()=>{var e;return dt||(dt=w.default(),(e=dt).use(w.default.json()),e.use(((e,t,r,s)=>e?(ae.error(e.message,"api.express",!0),de.error(r,"Internal Server Error")):s())),e.use(w.default.urlencoded({extended:!0})),e.disable("x-powered-by"),C&&e.use(T.default()),e.use("/api",ut),e.use("/api",at),e.all("/api/*",((e,t)=>de.notfound(t,"Invalid API"))),H&&(d.existsSync(H)&&e.use(w.default.static(H)),e.get("*",((e,t)=>{if(!d.existsSync(H))return de.notfound(t,'File "index.html" not found');t.sendFile(H+"/index.html")})))),dt};let ct;const pt=()=>(ct||(ct=(e=>{if(!pe.http||!fe.http){const t=h.createServer(e);return t.listen(U,(()=>ae.info("Server started on port "+U,"api.server",!0))),t}const t=h.createServer(((e,t)=>{const r=80==U?":80":"";t.writeHead(301,{Location:"https://"+e.headers.host+r+e.url}),t.end()})),r=I.createServer({key:fe.http,cert:pe.http},e);if(L)return new i.Server((e=>{e.once("data",(s=>{e.pause(),e.unshift(s),(22===s[0]?r:t).emit("connection",e),process.nextTick((()=>e.resume()))}))})).listen(U,(()=>ae.info("Server started on port "+U,"api.server",!0))),r;return 443==U&&t.listen(80,(()=>ae.info("Server started on port 80","api.server",!0))),r.listen(U,(()=>ae.info("Server started on port "+U,"api.server",!0))),r})(lt())),ct),ft=e=>{const t=new S.default.Server({server:e,verifyClient:mt});return t.on("connection",(e=>{e.on("message",(t=>b(void 0,void 0,void 0,(function*(){me.verify(t.toString()),e.close()})))),setTimeout((()=>{e.close()}),2e3),e.on("close",(()=>{t.emit("close",e)}))})),t},mt=(e,t)=>t(V);exports.API_AUTH_SLEEP=O,exports.API_DB_DATABASE=x,exports.API_DB_HOST=E,exports.API_DB_LOG=j,exports.API_DB_PASSWORD=D,exports.API_DB_PORT=R,exports.API_DB_TYPE=N,exports.API_DB_USERNAME=q,exports.API_HTTP_CROSS=C,exports.API_HTTP_CRT=k,exports.API_HTTP_HYBRID=L,exports.API_HTTP_KEY=B,exports.API_HTTP_PORT=U,exports.API_HTTP_PUBLIC=H,exports.API_TOKEN_CRT=z,exports.API_TOKEN_HEADER=M,exports.API_TOKEN_KEY=G,exports.API_TOKEN_LIFETIME=K,exports.API_UPLOAD_COUNT=F,exports.API_UPLOAD_FIELD=Y,exports.API_UPLOAD_SIZE=W,exports.API_UPLOAD_TEMP=X,exports.API_WEBSOCKET_START=V,exports.Auth=$,exports.Config=class{static all(){return b(this,void 0,void 0,(function*(){const e=yield oe.findAll().catch((e=>{ae.error(e.message,"api.config",!0)})),t={};return e&&e.forEach((e=>{t[e.key]=e.value})),t}))}static del(e){return b(this,void 0,void 0,(function*(){return((yield oe.destroy({where:{key:e}}).catch((e=>{ae.error(e.message,"api.config",!0)})))||0)>0}))}static get(e){return b(this,void 0,void 0,(function*(){const t=yield oe.findOne({where:{key:e}}).catch((e=>{ae.error(e.message,"api.config",!0)}));return t&&t.value||""}))}static set(e,t){return b(this,void 0,void 0,(function*(){const[r]=(yield oe.findOrCreate({where:{key:e}}).catch((e=>{ae.error(e.message,"api.config",!0)})))||[];r&&(r.value=t,yield r.save().catch((e=>{ae.error(e.message,"api.config",!0)})))}))}},exports.Configs=oe,exports.Controller=ue,exports.Group=Q,exports.GroupRoute=te,exports.Log=ae,exports.Logs=ie,exports.Permission=le,exports.Responses=de,exports.Route=ee,exports.Token=me,exports.User=re,exports.UserGroup=se,exports.auth=ge,exports.crt=pe,exports.initialize=()=>b(void 0,void 0,void 0,(function*(){yield Z.sync();const e=pt();V&&ft(e)})),exports.key=fe,exports.permission=ye,exports.router=ut,exports.sequelize=Z,exports.startSocket=ft,exports.upload=e=>{const t=(null==e?void 0:e.path)||X,r=_.default.diskStorage({destination:(e,r,s)=>s(null,t),filename:(e,r,s)=>b(void 0,void 0,void 0,(function*(){return s(null,he(t,A.default.extension(r.mimetype)||"bin"))}))}),s=1e6*((null==e?void 0:e.size)||W),o=_.default({storage:r,fileFilter(t,r,s){var o;return b(this,void 0,void 0,(function*(){const t=null===(o=null==e?void 0:e.types)||void 0===o?void 0:o.indexOf(r.mimetype);return void 0!==t&&t<0?s(new Error("File type not allowed")):s(null,!0)}))},limits:{fileSize:s}}),i=(null==e?void 0:e.count)||F,n=(null==e?void 0:e.field)||Y,a=o.array(n,i);return(e,t,r)=>{a(e,t,(function(e){return e?de.error(t,e.message):r()}))}},exports.useExpress=lt,exports.uuid=J,exports.validation=Ie;
|
package/package.json
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@andrewcaires/api",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Simple api for small applications using express, jsonwebtoken, sequelize and websocket",
|
|
5
5
|
"main": "dist/index.umd.js",
|
|
6
6
|
"module": "dist/index.esm.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
8
|
"scripts": {
|
|
9
9
|
"serve": "ts-node src/test.ts",
|
|
10
|
-
"build": "rollup -c build/rollup.config.js"
|
|
10
|
+
"build": "rollup -c build/rollup.config.js",
|
|
11
|
+
"dev": "ts-node-dev --respawn --transpile-only ./src/test.ts"
|
|
11
12
|
},
|
|
12
13
|
"repository": {
|
|
13
14
|
"type": "git",
|
|
@@ -34,7 +35,7 @@
|
|
|
34
35
|
},
|
|
35
36
|
"homepage": "https://github.com/andrewcaires/npm/tree/main/api#readme",
|
|
36
37
|
"dependencies": {
|
|
37
|
-
"@andrewcaires/utils.js": "^0.1.
|
|
38
|
+
"@andrewcaires/utils.js": "^0.1.6",
|
|
38
39
|
"cors": "^2.8.5",
|
|
39
40
|
"crypto-js": "^4.1.1",
|
|
40
41
|
"dotenv": "^16.0.1",
|
|
@@ -42,32 +43,34 @@
|
|
|
42
43
|
"fs": "^0.0.1-security",
|
|
43
44
|
"joi": "^17.6.0",
|
|
44
45
|
"jsonwebtoken": "^8.5.1",
|
|
45
|
-
"mariadb": "^3.0.
|
|
46
|
+
"mariadb": "^3.0.1",
|
|
46
47
|
"mime-types": "^2.1.35",
|
|
47
|
-
"multer": "^1.4.
|
|
48
|
+
"multer": "^1.4.5-lts.1",
|
|
48
49
|
"mysql2": "^2.3.3",
|
|
49
50
|
"pg": "^8.7.3",
|
|
50
51
|
"pg-hstore": "^2.3.4",
|
|
51
|
-
"sequelize": "^6.
|
|
52
|
-
"ws": "^8.
|
|
52
|
+
"sequelize": "^6.21.3",
|
|
53
|
+
"ws": "^8.8.1"
|
|
53
54
|
},
|
|
54
55
|
"devDependencies": {
|
|
55
|
-
"@rollup/plugin-
|
|
56
|
+
"@rollup/plugin-commonjs": "^22.0.2",
|
|
57
|
+
"@rollup/plugin-typescript": "^8.3.4",
|
|
56
58
|
"@types/cors": "^2.8.12",
|
|
57
59
|
"@types/crypto-js": "^4.1.1",
|
|
58
60
|
"@types/express": "^4.17.13",
|
|
59
61
|
"@types/jsonwebtoken": "^8.5.8",
|
|
60
62
|
"@types/mime-types": "^2.1.1",
|
|
61
63
|
"@types/multer": "^1.4.7",
|
|
62
|
-
"@types/node": "^
|
|
64
|
+
"@types/node": "^18.6.4",
|
|
63
65
|
"@types/ws": "^8.5.3",
|
|
64
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
65
|
-
"@typescript-eslint/parser": "^5.
|
|
66
|
-
"eslint": "^8.
|
|
67
|
-
"rollup": "^2.
|
|
68
|
-
"rollup-plugin-dts": "^4.2.
|
|
66
|
+
"@typescript-eslint/eslint-plugin": "^5.32.0",
|
|
67
|
+
"@typescript-eslint/parser": "^5.32.0",
|
|
68
|
+
"eslint": "^8.21.0",
|
|
69
|
+
"rollup": "^2.77.2",
|
|
70
|
+
"rollup-plugin-dts": "^4.2.2",
|
|
69
71
|
"rollup-plugin-terser": "^7.0.2",
|
|
70
|
-
"ts-node": "^10.
|
|
71
|
-
"
|
|
72
|
+
"ts-node": "^10.9.1",
|
|
73
|
+
"ts-node-dev": "^2.0.0",
|
|
74
|
+
"typescript": "^4.7.4"
|
|
72
75
|
}
|
|
73
76
|
}
|