@andrewcaires/api 1.0.2 → 1.0.5

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 CHANGED
@@ -1,16 +1,21 @@
1
- /// <reference types="node" />
2
- import * as https from 'https';
3
- import * as http from 'http';
1
+ /*!
2
+ * @andrewcaires/api v1.0.5
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 WebSocket from 'ws';
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 const startSocket: (server: http.Server | https.Server) => WebSocket.Server;
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(log: string, model: ModelStatic<M>);
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
- declare global {
160
- namespace Express {
161
- interface Request {
162
- auth: Auth | undefined;
163
- user: User | undefined;
164
- }
165
- }
195
+ interface TokenSign {
196
+ error?: string;
197
+ token?: string;
166
198
  }
167
- declare const auth: (req: Request, res: Response, next: NextFunction) => Promise<void | Response<any, Record<string, any>>>;
168
-
169
- declare const permission: (name: string) => (req: Request, res: Response, next: NextFunction) => Promise<void | Response<any, Record<string, any>>>;
170
-
171
- interface UploadOptions {
172
- count?: number;
173
- field?: string;
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 validation: (schema: ObjectSchema) => (req: Request, res: Response, next: NextFunction) => void | Response<any, Record<string, any>>;
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, app, auth, crt, initialize, key, permission, router, sequelize, server, startSocket, upload, uuid, validation };
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
2
+ * @andrewcaires/api v1.0.5
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 w,readFileSync as y}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="",e.INFO="",e.NONE="",e.SUCCESS="",e.WARNING=""}(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),"","|",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(w(e))return y(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")})),we=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()}},ye={username:S.string().min(5).required(),password:S.string().min(5).required()},Ie=we(S.object(ye)),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 w=yield this.model.findAll(c).catch((e=>{ce.error(e.message,this.log+".all")})),y=yield this.model.count(c).catch(i);return w?le.data(s,{count:y,records:t?t(w):w}):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=we(S.object(je)),ke={routes:S.array().items(S.number())},De=we(S.object(ke)),xe={name:S.string().min(3).empty(""),description:S.string().allow(null,""),state:S.boolean().empty("")},Be=we(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(),description:S.string().allow(null,""),state:S.boolean().required()},Fe=we(S.object(Me)),We={name:S.string().min(5).empty(""),description:S.string().allow(null,""),state:S.boolean().empty("")},Xe=we(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=we(S.object(Qe)),tt={groups:S.array().items(S.number())},rt=we(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=we(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&&(w(L)&&at.use(f.static(L)),at.get("*",((e,t)=>{if(!w(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 w(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,we as validation};
7
+ import{toBool as e,dateFormat as t,isArray as r,isString as o,noop as s,sleep as i,uniqueID as n,allowedObject as a,uuidv4 as d}from"@andrewcaires/utils.js";import{config as u}from"dotenv";import{UUID as c,UUIDV4 as l,Sequelize as m,DataTypes as p,Model as v,Op as g}from"sequelize";import*as f from"http";import*as h from"https";import{Server as y}from"net";import w from"cors";import I,{Router as b}from"express";import{existsSync as S,readFileSync as T}from"fs";import{SHA256 as A}from"crypto-js";import{sign as N,verify as O}from"jsonwebtoken";import E from"mime-types";import _ from"multer";import{join as P}from"path";import R from"joi";import q from"ws";function j(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())}))}u();const k=parseInt(process.env.API_AUTH_SLEEP||"1000"),D=process.env.API_DB_DATABASE||"",x=process.env.API_DB_HOST||"127.0.0.1",B=process.env.API_DB_PASSWORD||"",G=parseInt(process.env.API_DB_PORT||"3306"),z=process.env.API_DB_TYPE||"",U=process.env.API_DB_USERNAME||"root",C=e(process.env.API_DB_LOG||"false"),L=process.env.API_HTTP_CRT||"",H=process.env.API_HTTP_KEY||"",K=parseInt(process.env.API_HTTP_PORT||"3000"),M=process.env.API_HTTP_PUBLIC||"",F=e(process.env.API_HTTP_CROSS||"false"),W=e(process.env.API_HTTP_HYBRID||"false"),X=process.env.API_TOKEN_CRT||"",Y=process.env.API_TOKEN_KEY||"",J=process.env.API_TOKEN_HEADER||"authorization",V=parseInt(process.env.API_TOKEN_LIFETIME||"15"),$=parseInt(process.env.API_UPLOAD_COUNT||"1"),Z=process.env.API_UPLOAD_FIELD||"upload",Q=parseInt(process.env.API_UPLOAD_SIZE||"2"),ee=process.env.API_UPLOAD_TEMP||"./temp",te=e(process.env.API_WEBSOCKET_START||"false"),re={type:c,defaultValue:l,allowNull:!1,primaryKey:!0},oe=(()=>{switch(z){case"mariadb":return new m(D,U,B,{host:x,port:G,dialect:"mariadb",logging:C,define:{timestamps:!1}});case"mysql":return new m(D,U,B,{host:x,port:G,dialect:"mysql",logging:C,define:{timestamps:!1}});case"postgres":return new m(D,U,B,{host:x,port:G,dialect:"postgres",logging:C,define:{timestamps:!1}})}throw new Error("No database selected")})();class se extends v{}se.init({login:p.BIGINT,logout:p.BIGINT,secret:p.STRING,timestamp:p.BIGINT,useragent:p.STRING},{sequelize:oe,modelName:"auth"});class ie extends v{}ie.init({name:p.STRING,description:p.TEXT,state:p.BOOLEAN},{sequelize:oe,modelName:"group"});class ne extends v{}ne.init({name:p.STRING,description:p.TEXT,state:p.BOOLEAN},{sequelize:oe,modelName:"route"});class ae extends v{}ae.init({},{sequelize:oe,modelName:"groups_routes"}),ae.removeAttribute("id");class de extends v{}de.init({name:p.STRING,email:p.STRING,username:p.STRING,password:p.STRING,description:p.TEXT,state:p.BOOLEAN},{sequelize:oe,modelName:"user"});class ue extends v{}ue.init({},{sequelize:oe,modelName:"users_groups"}),ue.removeAttribute("id");class ce extends v{}ce.init({key:p.STRING,value:p.STRING},{sequelize:oe,modelName:"configs",timestamps:!0,createdAt:"created",updatedAt:"updated"}),ce.removeAttribute("id");class le extends v{}var me;le.init({type:p.STRING,source:p.STRING,message:p.TEXT},{sequelize:oe,modelName:"logs",timestamps:!0,createdAt:"created",updatedAt:!1}),de.hasMany(se),se.belongsTo(de),ie.hasMany(ae),ae.belongsTo(ie),ne.hasMany(ae),ae.belongsTo(ne),de.hasMany(ue),ue.belongsTo(de),ie.hasMany(ue),ue.belongsTo(ie),function(e){e.ERROR="",e.INFO="",e.NONE="",e.SUCCESS="",e.WARNING=""}(me||(me={}));class pe{static write(e,t,r){return j(this,void 0,void 0,(function*(){yield pe.writeRaw(me.NONE,"",e,t,r)}))}static error(e,t,r){return j(this,void 0,void 0,(function*(){yield pe.writeRaw(me.ERROR,"error",e,t,r)}))}static info(e,t,r){return j(this,void 0,void 0,(function*(){yield pe.writeRaw(me.INFO,"info",e,t,r)}))}static success(e,t,r){return j(this,void 0,void 0,(function*(){yield pe.writeRaw(me.ERROR,"success",e,t,r)}))}static warning(e,t,r){return j(this,void 0,void 0,(function*(){yield pe.writeRaw(me.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),"","|",s,"|",o)}static writeRaw(e,t,r,o,s){return j(this,void 0,void 0,(function*(){s&&pe.writeConsole(e,t,r),yield le.create({type:t,source:o,message:r}).catch((()=>null))}))}}class ve{static all(){return j(this,void 0,void 0,(function*(){const e=yield ce.findAll().catch((e=>{pe.error(e.message,"api.config",!0)})),t={};return e&&e.forEach((e=>{t[e.key]=e.value})),t}))}static del(e){return j(this,void 0,void 0,(function*(){return((yield ce.destroy({where:{key:e}}).catch((e=>{pe.error(e.message,"api.config",!0)})))||0)>0}))}static get(e){return j(this,void 0,void 0,(function*(){const t=yield ce.findOne({where:{key:e}}).catch((e=>{pe.error(e.message,"api.config",!0)}));return t&&t.value||""}))}static set(e,t){return j(this,void 0,void 0,(function*(){const[r]=(yield ce.findOrCreate({where:{key:e}}).catch((e=>{pe.error(e.message,"api.config",!0)})))||[];r&&(r.value=t,yield r.save().catch((e=>{pe.error(e.message,"api.config",!0)})))}))}}class ge{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 fe{constructor(e){this.model=e}add(){return(e,t)=>j(this,void 0,void 0,(function*(){const r=yield this.model.create(e.body).catch((e=>{pe.error(e.message,"api.controller."+this.model.tableName,!0)}));return r?ge.data(t,{id:r.id}):ge.error(t,"Internal Server Error")}))}all(e,t){return(i,n)=>j(this,void 0,void 0,(function*(){var a,d,u,c,l;const m=Object.assign({},e||{});m.where=Object.assign({},m.where||{});const p=null===(a=i.query.limit)||void 0===a?void 0:a.toString();p&&(m.limit=parseInt(p));const v=null===(d=i.query.offset)||void 0===d?void 0:d.toString();v&&(m.offset=parseInt(v));const f=[],h=null===(u=i.query.asc)||void 0===u?void 0:u.toString();h&&h.length&&h.split(",").forEach((e=>{f.push([e,"ASC"])}));const y=null===(c=i.query.desc)||void 0===c?void 0:c.toString();y&&y.length&&y.split(",").forEach((e=>{f.push([e,"DESC"])})),f.length&&(m.order=f);const w=[],I=Object.keys(this.model.getAttributes()),b=r(m.attributes)?m.attributes:I,S=null===(l=i.query.search)||void 0===l?void 0:l.toString();b.forEach((e=>{var t;if(o(e)&&(S&&S.length&&w.push({[e]:{[g.like]:`%${S}%`}}),"search_"+e in i.query)){const r=null===(t=i.query["search_"+e])||void 0===t?void 0:t.toString();r&&r.length&&w.push({[e]:{[g.like]:`%${r}%`}})}})),w.length&&(m.where=Object.assign(Object.assign({},m.where),{[g.or]:[...w]}));const T=yield this.model.findAll(m).catch((e=>{pe.error(e.message,"api.controller."+this.model.tableName,!0)})),A=yield this.model.count(m).catch(s);return T?ge.data(n,{count:A,records:t?t(T):T}):ge.error(n,"Internal Server Error")}))}del(){return(e,t)=>j(this,void 0,void 0,(function*(){const{id:r}=e.params;return(yield this.model.destroy({where:{id:r}}).catch((e=>{pe.error(e.message,"api.controller."+this.model.tableName,!0)})))?ge.success(t,"OK"):ge.notfound(t,"Record not found")}))}get(e,t){return(r,o)=>j(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=>{pe.error(e.message,"api.controller."+this.model.tableName,!0)}));return n?ge.data(o,t?t(n):n.toJSON()):null===n?ge.notfound(o,"Record not found"):ge.error(o,"Internal Server Error")}))}set(){return(e,t)=>j(this,void 0,void 0,(function*(){const{id:r}=e.params,[o]=(yield this.model.update(e.body,{where:{id:r}}).catch((e=>{pe.error(e.message,"api.controller."+this.model.tableName,!0)})))||[];return o?ge.success(t,"OK"):ge.success(t,"Record not changed")}))}}class he{static all(e,t){return j(this,void 0,void 0,(function*(){return yield ne.findAll({where:Object.assign(Object.assign({},t),{state:!0}),include:[{model:ae,required:!0,include:[{model:ie,required:!0,where:{state:!0},include:[{model:ue,required:!0,where:{userId:e.id}}]}]}]}).catch((e=>{pe.error(e.message,"api.permission",!0)}))}))}static get(e){return j(this,void 0,void 0,(function*(){const t=yield he.all(e);return t?t.map((e=>e.name)):[]}))}static is(e,t){return j(this,void 0,void 0,(function*(){const r=yield he.all(e,{name:t});return r&&!!r.length}))}}const ye=e=>{if(S(e))return T(e)},we={http:ye(L),token:ye(X)},Ie={http:ye(H),token:ye(Y)};class be{static sign(e){return Ie.token?{token:N(e,Ie.token,{algorithm:"RS256"})}:{error:"Invalid Secret"}}static verify(e){if(!we.token)return{error:"Invalid Secret"};if(!e||e.split(".").length<3)return{error:"Invalid Token"};try{return{decode:O(e,we.token)}}catch(e){return{error:"Invalid Token"}}}}const Se=["id","name","email","username"],Te=(e,t,r)=>j(void 0,void 0,void 0,(function*(){const o=e.get(J)||"",{error:s,decode:i}=be.verify(o);if(s)return ge.error(t,s);if(i){const{id:o,secret:s}=i;if(o&&i){const i=yield de.findOne({where:{id:o,state:!0}}).catch((e=>{pe.error(e.message,"api.auth",!0)}));if(i){const o=yield se.findOne({where:{secret:s,userId:i.id}}).catch((e=>{pe.error(e.message,"api.auth",!0)}));if(o){const s=Date.now();if(s>o.timestamp)return ge.error(t,"Expired token");if(!o.logout){o.timestamp=s+6e4*V;const t=e.get("User-Agent");return t&&(o.useragent=t),yield o.save(),e.auth=o,e.user=i,r()}}}return ge.error(t,"Access denied")}}return ge.error(t,"Invalid token")})),Ae=e=>(t,r,o)=>j(void 0,void 0,void 0,(function*(){const s=t.user;return s?(yield he.is(s,e))?o():ge.error(r,"Unauthorized access"):ge.unauthorized(r,"Access denied")})),Ne=(e,t)=>{const r=d()+"."+t;return S(P(e,r))?Ne(e,t):r},Oe=e=>{const t=(null==e?void 0:e.path)||ee,r=_.diskStorage({destination:(e,r,o)=>o(null,t),filename:(e,r,o)=>j(void 0,void 0,void 0,(function*(){return o(null,Ne(t,E.extension(r.mimetype)||"bin"))}))}),o=1e6*((null==e?void 0:e.size)||Q),s=_({storage:r,fileFilter(t,r,o){var s;return j(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)||$,n=(null==e?void 0:e.field)||Z,a=s.array(n,i);return(e,t,r)=>{a(e,t,(function(e){return e?ge.error(t,e.message):r()}))}},Ee=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})})),ge.validation(o,"Validation error: "+e,t)}return r.body=n,s()}},_e={username:R.string().min(5).required(),password:R.string().min(5).required()},Pe=Ee(R.object(_e)),Re=b();Re.get("/",Te,((e,t)=>j(void 0,void 0,void 0,(function*(){const r=e.user;if(!r)return ge.unauthorized(t,"Access denied");const o=yield he.all(r);if(o){const e=a(Se,r.toJSON()),s=o.map((e=>e.name));return ge.data(t,Object.assign(Object.assign({},e),{permissions:s}))}return ge.error(t,"Internal Server Error")})))),Re.post("/login",Pe,((e,t)=>j(void 0,void 0,void 0,(function*(){const{username:r,password:o}=e.body;if(!r||!o)return ge.error(t,"Invalid parameters");yield i(k);const s=yield de.findOne({where:{username:r}}).catch((e=>{pe.error(e.message,"api.controller."+de.tableName,!0)}));if(!s)return ge.notfound(t,"Username not found");if(!s.state)return ge.error(t,"Username is disabled");const a=A(o).toString();if(s.password!=a)return ge.error(t,"Invalid password");const d=s.id,u=n(),{error:c,token:l}=be.sign({id:d,secret:u});if(c)return ge.error(t,c);if(l){const r=Date.now(),o=r+6e4*V,s=e.get("User-Agent"),i=yield se.create({login:r,secret:u,timestamp:o,useragent:s,userId:d}).catch((e=>{pe.error(e.message,"api.controller."+se.tableName,!0)}));if(i)return ge.data(t,{token:l})}return ge.error(t,"Internal Server Error")})))),Re.get("/logout",Te,((e,t)=>j(void 0,void 0,void 0,(function*(){const r=e.auth;return r?(r.logout=Date.now(),r.timestamp=r.logout,yield r.save(),ge.success(t,"Disconcerted")):ge.unauthorized(t,"Access denied")}))));const qe=new fe(ie),je=new fe(ae),ke=qe.add(),De=qe.all(),xe=qe.del(),Be=qe.get(),Ge=qe.set(),ze={name:R.string().min(3).required(),description:R.string().allow(null,""),state:R.boolean().required()},Ue=Ee(R.object(ze)),Ce={routes:R.array().items(R.number())},Le=Ee(R.object(Ce)),He={name:R.string().min(3).empty(""),description:R.string().allow(null,""),state:R.boolean().empty("")},Ke=Ee(R.object(He)),Me=b();Me.use(Te),Me.get("/",Ae("groups.read"),De),Me.post("/",Ae("groups.write"),Ue,ke),Me.route("/:id").get(Ae("groups.read"),Be).put(Ae("groups.write"),Ke,Ge).delete(Ae("groups.write"),xe),Me.route("/:id/routes").get(Ae("groups.read"),Le,((e,t)=>j(void 0,void 0,void 0,(function*(){const{id:r}=e.params;return je.all({where:{groupId:r},include:[{model:ne,required:!0}]},(e=>e.map((e=>e.route))))(e,t)})))).put(Ae("groups.write"),Le,((e,t)=>j(void 0,void 0,void 0,(function*(){const{id:r}=e.params,{routes:o}=e.body,s=yield ie.findByPk(r,{attributes:["id"]}).catch((e=>{pe.error(e.message,"api.controller."+ie.tableName,!0)}));if(s){const e=s.id;if(yield ae.destroy({where:{groupId:e}}),o){let t=0;for(let r=0;r<o.length;r++)t=yield ne.count({where:{id:o[r]}}),t&&(yield ae.create({groupId:e,routeId:o[r]}))}return ge.success(t,"OK")}return null===s?ge.notfound(t,"Record not found"):ge.error(t,"Internal Server Error")}))));const Fe=new fe(le),We=b();We.use(Te),We.get("/",Ae("logs.read"),((e,t)=>j(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 Fe.all({where:s,order:[["created","DESC"]]})(e,t)}))));const Xe=new fe(ne),Ye=Xe.add(),Je=Xe.all(),Ve=Xe.del(),$e=Xe.get(),Ze=Xe.set(),Qe={name:R.string().min(5).required(),description:R.string().allow(null,""),state:R.boolean().required()},et=Ee(R.object(Qe)),tt={name:R.string().min(5).empty(""),description:R.string().allow(null,""),state:R.boolean().empty("")},rt=Ee(R.object(tt)),ot=b();ot.use(Te),ot.get("/",Ae("routes.read"),Je),ot.post("/",Ae("routes.write"),et,Ye),ot.route("/:id").get(Ae("routes.read"),$e).put(Ae("routes.write"),rt,Ze).delete(Ae("routes.write"),Ve);const st=new fe(de),it=new fe(ue),nt=["id","name","email","username","description","state"],at=st.del(),dt={name:R.string().min(5).required(),email:R.string().email().required(),username:R.string().min(5).required(),password:R.string().min(5).required(),description:R.string().allow(null,""),state:R.boolean().required()},ut=Ee(R.object(dt)),ct={groups:R.array().items(R.number())},lt=Ee(R.object(ct)),mt={name:R.string().min(5).empty(""),email:R.string().email().empty(""),username:R.string().min(5).empty(""),password:R.string().min(5).empty(""),description:R.string().allow(null,""),state:R.boolean().empty("")},pt=Ee(R.object(mt)),vt=b();vt.use(Te),vt.get("/",Ae("users.read"),((e,t)=>j(void 0,void 0,void 0,(function*(){return st.all({attributes:nt})(e,t)})))),vt.post("/",Ae("users.write"),ut,((e,t)=>j(void 0,void 0,void 0,(function*(){return e.body.password=A(e.body.password).toString(),yield st.add()(e,t)})))),vt.route("/:id").get(Ae("users.read"),((e,t)=>j(void 0,void 0,void 0,(function*(){return st.get({attributes:nt})(e,t)})))).put(Ae("users.write"),pt,((e,t)=>j(void 0,void 0,void 0,(function*(){return e.body.password&&(e.body.password=A(e.body.password).toString()),st.set()(e,t)})))).delete(Ae("users.write"),at),vt.route("/:id/groups").get(Ae("users.read"),((e,t)=>j(void 0,void 0,void 0,(function*(){const{id:r}=e.params;return it.all({where:{userId:r},include:[{model:ie,required:!0}]},(e=>e.map((e=>e.group))))(e,t)})))).put(Ae("users.write"),lt,((e,t)=>j(void 0,void 0,void 0,(function*(){const{id:r}=e.params,{groups:o}=e.body,s=yield de.findByPk(r,{attributes:["id"]}).catch((e=>{pe.error(e.message,"api.controller."+de.tableName,!0)}));if(s){if(yield ue.destroy({where:{userId:s.id}}),o){let e=0;for(let t=0;t<o.length;t++)e=yield ie.count({where:{id:o[t]}}),e&&(yield ue.create({userId:s.id,groupId:o[t]}))}return ge.success(t,"OK")}return ge.notfound(t,"Record not found")}))));const gt=b();let ft;gt.use("/auth",Re),gt.use("/groups",Me),gt.use("/logs",We),gt.use("/routes",ot),gt.use("/users",vt);const ht=b(),yt=()=>{var e;return ft||(ft=I(),(e=ft).use(I.json()),e.use(((e,t,r,o)=>e?(pe.error(e.message,"api.express",!0),ge.error(r,"Internal Server Error")):o())),e.use(I.urlencoded({extended:!0})),e.disable("x-powered-by"),F&&e.use(w()),e.use("/api",ht),e.use("/api",gt),e.all("/api/*",((e,t)=>ge.notfound(t,"Invalid API"))),M&&(S(M)&&e.use(I.static(M)),e.get("*",((e,t)=>{if(!S(M))return ge.notfound(t,'File "index.html" not found');t.sendFile(M+"/index.html")})))),ft};let wt;const It=()=>(wt||(wt=(e=>{if(!we.http||!Ie.http){const t=f.createServer(e);return t.listen(K,(()=>pe.info("Server started on port "+K,"api.server",!0))),t}const t=f.createServer(((e,t)=>{const r=80==K?":80":"";t.writeHead(301,{Location:"https://"+e.headers.host+r+e.url}),t.end()})),r=h.createServer({key:Ie.http,cert:we.http},e);if(W)return new y((e=>{e.once("data",(o=>{e.pause(),e.unshift(o),(22===o[0]?r:t).emit("connection",e),process.nextTick((()=>e.resume()))}))})).listen(K,(()=>pe.info("Server started on port "+K,"api.server",!0))),r;return 443==K&&t.listen(80,(()=>pe.info("Server started on port 80","api.server",!0))),r.listen(K,(()=>pe.info("Server started on port "+K,"api.server",!0))),r})(yt())),wt),bt=e=>{const t=new q.Server({server:e,verifyClient:St});return t.on("connection",(e=>{e.on("message",(t=>j(void 0,void 0,void 0,(function*(){be.verify(t.toString()),e.close()})))),setTimeout((()=>{e.close()}),2e3),e.on("close",(()=>{t.emit("close",e)}))})),t},St=(e,t)=>t(te),Tt=()=>j(void 0,void 0,void 0,(function*(){yield oe.sync();const e=It();te&&bt(e)}));export{k as API_AUTH_SLEEP,D as API_DB_DATABASE,x as API_DB_HOST,C as API_DB_LOG,B as API_DB_PASSWORD,G as API_DB_PORT,z as API_DB_TYPE,U as API_DB_USERNAME,F as API_HTTP_CROSS,L as API_HTTP_CRT,W as API_HTTP_HYBRID,H as API_HTTP_KEY,K as API_HTTP_PORT,M as API_HTTP_PUBLIC,X as API_TOKEN_CRT,J as API_TOKEN_HEADER,Y as API_TOKEN_KEY,V as API_TOKEN_LIFETIME,$ as API_UPLOAD_COUNT,Z as API_UPLOAD_FIELD,Q as API_UPLOAD_SIZE,ee as API_UPLOAD_TEMP,te as API_WEBSOCKET_START,se as Auth,ve as Config,ce as Configs,fe as Controller,ie as Group,ae as GroupRoute,pe as Log,le as Logs,he as Permission,ge as Responses,ne as Route,be as Token,de as User,ue as UserGroup,Te as auth,we as crt,Tt as initialize,Ie as key,Ae as permission,ht as router,oe as sequelize,bt as startSocket,Oe as upload,yt as useExpress,re as uuid,Ee as validation};
package/dist/index.umd.js CHANGED
@@ -1,6 +1,7 @@
1
1
  /*!
2
- * @andrewcaires/api v1.0.2
2
+ * @andrewcaires/api v1.0.5
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="",e.INFO="",e.NONE="",e.SUCCESS="",e.WARNING=""}(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),"","|",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(),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(""),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),_=g(c),A=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="",e.INFO="",e.NONE="",e.SUCCESS="",e.WARNING=""}(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),"","|",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;const c=Object.assign({},t||{});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=[],v=null===(d=o.query.asc)||void 0===d?void 0:d.toString();v&&v.length&&v.split(",").forEach((e=>{m.push([e,"ASC"])}));const g=null===(u=o.query.desc)||void 0===u?void 0:u.toString();g&&g.length&&g.split(",").forEach((e=>{m.push([e,"DESC"])})),m.length&&(c.order=m);const y=[],h=Object.keys(this.model.getAttributes()),I=e.isArray(c.attributes)?c.attributes:h,T=null===(l=o.query.search)||void 0===l?void 0:l.toString();I.forEach((t=>{var s;if(e.isString(t)&&(T&&T.length&&y.push({[t]:{[r.Op.like]:`%${T}%`}}),"search_"+t in o.query)){const e=null===(s=o.query["search_"+t])||void 0===s?void 0:s.toString();e&&e.length&&y.push({[t]:{[r.Op.like]:`%${e}%`}})}})),y.length&&(c.where=Object.assign(Object.assign({},c.where),{[r.Op.or]:[...y]}));const w=yield this.model.findAll(c).catch((e=>{ae.error(e.message,"api.controller."+this.model.tableName,!0)})),_=yield this.model.count(c).catch(e.noop);return w?de.data(i,{count:_,records:s?s(w):w}):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)})))||[];return s?de.success(t,"OK"):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");if(!s.logout){s.timestamp=o+6e4*K;const t=e.get("User-Agent");return t&&(s.useragent=t),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)),_e=a.Router();_e.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")})))),_e.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")})))),_e.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 Ae=new ue(Q),Pe=new ue(te),Se=Ae.add(),be=Ae.all(),Oe=Ae.del(),xe=Ae.get(),Ee=Ae.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",_e),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=A.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,_.default.extension(r.mimetype)||"bin"))}))}),s=1e6*((null==e?void 0:e.size)||W),o=A.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.2",
3
+ "version": "1.0.5",
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.0",
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.0",
46
+ "mariadb": "^3.0.1",
46
47
  "mime-types": "^2.1.35",
47
- "multer": "^1.4.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.19.1",
52
- "ws": "^8.6.0"
52
+ "sequelize": "^6.21.4",
53
+ "ws": "^8.8.1"
53
54
  },
54
55
  "devDependencies": {
55
- "@rollup/plugin-typescript": "^8.3.2",
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": "^17.0.34",
64
+ "@types/node": "^18.7.6",
63
65
  "@types/ws": "^8.5.3",
64
- "@typescript-eslint/eslint-plugin": "^5.24.0",
65
- "@typescript-eslint/parser": "^5.24.0",
66
- "eslint": "^8.15.0",
67
- "rollup": "^2.73.0",
68
- "rollup-plugin-dts": "^4.2.1",
66
+ "@typescript-eslint/eslint-plugin": "^5.33.1",
67
+ "@typescript-eslint/parser": "^5.33.1",
68
+ "eslint": "^8.22.0",
69
+ "rollup": "^2.78.1",
70
+ "rollup-plugin-dts": "^4.2.2",
69
71
  "rollup-plugin-terser": "^7.0.2",
70
- "ts-node": "^10.7.0",
71
- "typescript": "^4.6.4"
72
+ "ts-node": "^10.9.1",
73
+ "ts-node-dev": "^2.0.0",
74
+ "typescript": "^4.7.4"
72
75
  }
73
76
  }