@andrewcaires/api 2.0.2 → 2.0.3
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/README.md +9 -7
- package/dist/index.cjs.js +3 -3
- package/dist/index.d.ts +75 -34
- package/dist/index.esm.js +3 -3
- package/package.json +21 -21
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ The module is now available on npm! `npm i @andrewcaires/api`
|
|
|
19
19
|
NODE_ENV=development
|
|
20
20
|
|
|
21
21
|
API_DB_TYPE=mariadb
|
|
22
|
-
API_DB_DATABASE=
|
|
22
|
+
API_DB_DATABASE=database
|
|
23
23
|
API_DB_HOST=localhost
|
|
24
24
|
API_DB_USERNAME=root
|
|
25
25
|
API_DB_PASSWORD=
|
|
@@ -30,11 +30,11 @@ API_HTTP_PORT=3000
|
|
|
30
30
|
API_HTTP_PUBLIC=/public
|
|
31
31
|
API_HTTP_CROSS=true
|
|
32
32
|
|
|
33
|
-
API_HTTP_CRT
|
|
34
|
-
API_HTTP_KEY
|
|
33
|
+
API_HTTP_CRT=http.crt
|
|
34
|
+
API_HTTP_KEY=http.key
|
|
35
35
|
|
|
36
|
-
API_TOKEN_CRT
|
|
37
|
-
API_TOKEN_KEY
|
|
36
|
+
API_TOKEN_CRT=token.crt
|
|
37
|
+
API_TOKEN_KEY=token.key
|
|
38
38
|
API_TOKEN_LIFETIME=3000
|
|
39
39
|
|
|
40
40
|
API_WEBSOCKET_START=false
|
|
@@ -57,7 +57,7 @@ import {
|
|
|
57
57
|
|
|
58
58
|
} from "@andrewcaires/api";
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
const main = async () => {
|
|
61
61
|
|
|
62
62
|
const app = new App(
|
|
63
63
|
[
|
|
@@ -75,7 +75,9 @@ import {
|
|
|
75
75
|
|
|
76
76
|
await app.listen();
|
|
77
77
|
|
|
78
|
-
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
main().catch(console.log);
|
|
79
81
|
```
|
|
80
82
|
|
|
81
83
|
### Links
|
package/dist/index.cjs.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @andrewcaires/api v2.0.
|
|
2
|
+
* @andrewcaires/api v2.0.3
|
|
3
3
|
* Simple api for small applications using express, jsonwebtoken, sequelize and websocket
|
|
4
|
-
* (c)
|
|
4
|
+
* (c) 2023 Andrew Caires
|
|
5
5
|
* @license: MIT
|
|
6
6
|
*/
|
|
7
|
-
"use strict";var e=require("@andrewcaires/utils.js"),t=require("cors"),r=require("express"),s=require("fs"),i=require("http"),o=require("https"),n=require("net"),a=require("ws"),d=require("dotenv"),u=require("sequelize"),l=require("jsonwebtoken"),c=require("mime-types"),h=require("multer"),p=require("path"),m=require("crypto-js");function v(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 g=v(i),f=v(o);function y(e,t,r,s){return new(r||(r=Promise))((function(i,o){function n(e){try{d(s.next(e))}catch(e){o(e)}}function a(e){try{d(s.throw(e))}catch(e){o(e)}}function d(e){var t;e.done?i(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())}))}d.config();const _=parseInt(process.env.API_AUTH_SLEEP||"1000"),I=process.env.API_DB_DATABASE||"",T=process.env.API_DB_HOST||"127.0.0.1",A=process.env.API_DB_PASSWORD||"",w=parseInt(process.env.API_DB_PORT||"3306"),S=process.env.API_DB_TYPE||"",b=process.env.API_DB_USERNAME||"root",P=e.toBool(process.env.API_DB_LOG||"false"),x=process.env.API_HTTP_CRT||"",E=process.env.API_HTTP_KEY||"",O=parseInt(process.env.API_HTTP_PORT||"3000"),q=process.env.API_HTTP_PUBLIC||"",D=e.toBool(process.env.API_HTTP_CROSS||"false"),R=e.toBool(process.env.API_HTTP_HYBRID||"false"),N=process.env.API_TOKEN_CRT||"",k=process.env.API_TOKEN_KEY||"",B=process.env.API_TOKEN_HEADER||"authorization",C=parseInt(process.env.API_TOKEN_LIFETIME||"15"),z=parseInt(process.env.API_UPLOAD_COUNT||"1"),j=process.env.API_UPLOAD_FIELD||"upload",G=parseInt(process.env.API_UPLOAD_SIZE||"2"),V=process.env.API_UPLOAD_TEMP||"./temp",M=e.toBool(process.env.API_WEBSOCKET_START||"false");class L{static connect(e){const t=S.toLowerCase();if("connect_"+t in L)return L["connect_"+t](e);throw new Error("No database is connected to this API")}static connect_mariadb(e){return new u.Sequelize(e.database,e.username,e.password,{host:e.hostname,port:e.hostport,dialect:"mariadb",logging:P,define:{timestamps:!1}})}static connect_memory(){return new u.Sequelize("sqlite::memory:",{logging:P,define:{timestamps:!1}})}static connect_mysql(e){return new u.Sequelize(e.database,e.username,e.password,{host:e.hostname,port:e.hostport,dialect:"mysql",logging:P,define:{timestamps:!1}})}static connect_postgres(e){return new u.Sequelize(e.database,e.username,e.password,{host:e.hostname,port:e.hostport,dialect:"postgres",logging:P,define:{timestamps:!1}})}static connect_sqlite(e){return new u.Sequelize({dialect:"sqlite",storage:e.database,logging:P,define:{timestamps:!1}})}}const U=L.connect({database:I,username:b,password:A,hostname:T,hostport:w});class H extends u.Model{}H.init({login:u.DataTypes.BIGINT,logout:u.DataTypes.BIGINT,secret:u.DataTypes.STRING,timestamp:u.DataTypes.BIGINT,useragent:u.DataTypes.STRING},{sequelize:U,modelName:"auth"});class K extends u.Model{}K.init({name:u.DataTypes.STRING,description:u.DataTypes.TEXT,state:u.DataTypes.BOOLEAN},{sequelize:U,modelName:"group"});class F extends u.Model{}F.init({name:u.DataTypes.STRING,description:u.DataTypes.TEXT,state:u.DataTypes.BOOLEAN},{sequelize:U,modelName:"route"});class Y extends u.Model{}Y.init({},{sequelize:U,modelName:"groups_routes"}),Y.removeAttribute("id");class W extends u.Model{}W.init({name:u.DataTypes.STRING,email:u.DataTypes.STRING,username:u.DataTypes.STRING,password:u.DataTypes.STRING,description:u.DataTypes.TEXT,state:u.DataTypes.BOOLEAN},{sequelize:U,modelName:"user"});class X extends u.Model{}X.init({},{sequelize:U,modelName:"users_groups"}),X.removeAttribute("id");class J extends u.Model{}J.init({key:u.DataTypes.STRING,value:u.DataTypes.STRING},{sequelize:U,modelName:"configs",timestamps:!0,createdAt:"created",updatedAt:"updated"}),J.removeAttribute("id");class Z extends u.Model{}var $;Z.init({type:u.DataTypes.STRING,source:u.DataTypes.STRING,message:u.DataTypes.TEXT},{sequelize:U,modelName:"logs",timestamps:!0,createdAt:"created",updatedAt:!1}),W.hasMany(H),H.belongsTo(W),K.hasMany(Y),Y.belongsTo(K),F.hasMany(Y),Y.belongsTo(F),W.hasMany(X),X.belongsTo(W),K.hasMany(X),X.belongsTo(K),function(e){e.ERROR="[31m",e.INFO="[36m",e.NONE="[37m",e.SUCCESS="[32m",e.WARNING="[33m"}($||($={}));class Q{static write(e,t,r){return y(this,void 0,void 0,(function*(){yield Q.writeRaw($.NONE,"",e,t,r)}))}static error(e,t,r){return y(this,void 0,void 0,(function*(){yield Q.writeRaw($.ERROR,"error",e,t,r)}))}static info(e,t,r){return y(this,void 0,void 0,(function*(){yield Q.writeRaw($.INFO,"info",e,t,r)}))}static success(e,t,r){return y(this,void 0,void 0,(function*(){yield Q.writeRaw($.ERROR,"success",e,t,r)}))}static warning(e,t,r){return y(this,void 0,void 0,(function*(){yield Q.writeRaw($.WARNING,"warning",e,t,r)}))}static writeConsole(t,r,s){const i=e.dateFormat(new Date,"%H:%M:%S");console.log(">",t,r+" ".repeat(10-r.length),"[37m","|",i,"|",s)}static writeRaw(e,t,r,s,i){return y(this,void 0,void 0,(function*(){i&&Q.writeConsole(e,t,r),U&&(yield Z.create({type:t,source:s,message:r}).catch((()=>null)))}))}}class ee{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){return e.status(400).json({message:t})}static unauthorized(e,t){return e.status(401).json({message:t})}}const te=e=>s.existsSync(e)?s.readFileSync(e):void 0,re={http:te(x),token:te(N)},se={http:te(E),token:te(k)};class ie{static sign(e){return se.token?{token:l.sign(e,se.token,{algorithm:"RS256"})}:{error:"Invalid Secret"}}static user(e){return y(this,void 0,void 0,(function*(){const{error:t,decode:r}=ie.verify(e);if(t)return{error:t};if(r){const{id:e,secret:t}=r;if(e&&r){const r=yield W.findOne({where:{id:e,state:!0}}).catch((e=>{Q.error(e.message,"api.token",!0)}));if(r){const e=yield H.findOne({where:{secret:t,userId:r.id}}).catch((e=>{Q.error(e.message,"api.token",!0)}));if(e){const t=Date.now();if(t>e.timestamp)return{error:"Expired token"};if(e.timestamp=t+6e4*C,yield e.save(),!e.logout)return{auth:e,user:r}}}return{error:"Access denied"}}}return{error:"Invalid token"}}))}static verify(e){if(!re.token)return{error:"Invalid Secret"};if(!e||e.split(".").length<3)return{error:"Invalid Token"};try{return{decode:l.verify(e,re.token)}}catch(e){return{error:"Invalid Token"}}}}class oe extends e.EventEmitter{constructor(e){super(),this.app=r(),this.router=r.Router(),this.middlewares(),this.controllers(e)}controllers(e){e.forEach((e=>{e.intialize(),this.router.use(e.path(),e.router)}))}listen(){return y(this,void 0,void 0,(function*(){if(yield U.sync(),re.http&&se.http||(this._server=g.createServer(this.app),this._server.listen(O,(()=>Q.info("Server started on port "+O,"api.server",!0)))),!this._server){const e=g.createServer(((e,t)=>{const r=80==O?":80":"";t.writeHead(301,{Location:"https://"+e.headers.host+r+e.url}),t.end()})),t=f.createServer({key:se.http,cert:re.http},this.app);if(R){new n.Server((r=>{r.once("data",(s=>{r.pause(),r.unshift(s),(22===s[0]?t:e).emit("connection",r),process.nextTick((()=>r.resume()))}))})).listen(O,(()=>Q.info("Server started on port "+O,"api.server",!0))),this._server=t}this._server||(443==O&&e.listen(80,(()=>Q.info("Server started on port 80","api.server",!0))),t.listen(O,(()=>Q.info("Server started on port "+O,"api.server",!0))),this._server=t)}M&&this._server&&(this._webSocket=new a.Server({server:this._server,verifyClient:(e,t)=>t(M)}),this._webSocket.on("connection",((t,r)=>y(this,void 0,void 0,(function*(){r.url||(r.url="");const s=r.url.length<=1?"":r.url.replace(/\//g,".");let i;t.on("message",(e=>y(this,void 0,void 0,(function*(){if(i)try{const o=JSON.parse(e);this.emit("ws.message"+s,{data:o,message:e,req:r,user:i,ws:t})}catch(o){this.emit("ws.message"+s,{message:e,req:r,user:i,ws:t})}else{const{user:o}=yield ie.user(e.toString());o&&(i=o,this.emit("ws.connection"+s,{req:r,user:i,ws:t}))}i||t.close()})))),t.on("close",(()=>{i&&this.emit("ws.close"+s,{user:i,ws:t})})),yield e.sleep(2e3),i||t.close()})))))}))}middlewares(){this.app.use(r.json()),this.app.use(((e,t,r,s)=>e?(Q.error(e.message,"api.express",!0),ee.error(r,"Internal Server Error")):s())),this.app.use(r.urlencoded({extended:!0})),this.app.disable("x-powered-by"),D&&this.app.use(t()),this.app.use("/api",this.router),this.app.all("/api/*",((e,t)=>ee.notfound(t,"Invalid API"))),q&&(s.existsSync(q)&&this.app.use(r.static(q)),this.app.get("*",((e,t)=>{if(!s.existsSync(q))return ee.notfound(t,'File "index.html" not found');t.sendFile(q+"/index.html")})))}server(){return this._server}websocket(){return this._webSocket}}class ne{static all(e,t){return y(this,void 0,void 0,(function*(){return yield F.findAll({where:Object.assign(Object.assign({},t),{state:!0}),include:[{model:Y,required:!0,include:[{model:K,required:!0,where:{state:!0},include:[{model:X,required:!0,where:{userId:e.id}}]}]}]}).catch((e=>{Q.error(e.message,"api.permission",!0)}))}))}static get(e){return y(this,void 0,void 0,(function*(){const t=yield ne.all(e);return t?t.map((e=>e.name)):[]}))}static is(e,t){return y(this,void 0,void 0,(function*(){const r=yield ne.all(e,{name:t});return r&&!!r.length}))}}const ae=(t,r)=>{const i=e.uuidv4()+"."+r;return s.existsSync(p.join(t,i))?ae(t,r):i};class de{constructor(e){this.router=r.Router(),this._path=e}auth(e,t,r){return y(this,void 0,void 0,(function*(){const s=e.get(B)||"",{auth:i,error:o,user:n}=yield ie.user(s);if(o)return ee.error(t,o);if(i&&n){const t=e.get("User-Agent");return t&&(i.useragent=t),yield i.save(),e.auth=i,e.user=n,r()}return ee.error(t,"Internal Server Error")}))}intialize(){}name(){return"api"}path(){return this._path}permission(e){return(t,r,s)=>y(this,void 0,void 0,(function*(){const i=t.user;return i?(yield ne.is(i,e))?s():ee.error(r,"Unauthorized access"):ee.unauthorized(r,"Access denied")}))}read(e=""){return this.permission((e||this.name())+".read")}upload(e){const t=(null==e?void 0:e.path)||V,r=h.diskStorage({destination:(e,r,s)=>s(null,t),filename:(e,r,s)=>y(this,void 0,void 0,(function*(){return s(null,ae(t,c.extension(r.mimetype)||"bin"))}))}),s=1e6*((null==e?void 0:e.size)||G),i=h({storage:r,fileFilter(t,r,s){var i;return y(this,void 0,void 0,(function*(){const t=null===(i=null==e?void 0:e.types)||void 0===i?void 0:i.indexOf(r.mimetype);return void 0!==t&&t<0?s(new Error("File type not allowed")):s(null,!0)}))},limits:{fileSize:s}}),o=(null==e?void 0:e.count)||z,n=(null==e?void 0:e.field)||j,a=i.array(n,o);return(e,t,r)=>{a(e,t,(function(e){return e?ee.error(t,e.message):r()}))}}validation(t){return(r,s,i)=>y(this,void 0,void 0,(function*(){const{error:o,value:n}=yield e.Validation.object(t).validateAsync(r.body);return o?ee.validation(s,o):(r.body=n,i())}))}write(e=""){return this.permission((e||this.name())+".write")}}class ue extends de{add(){return(e,t)=>y(this,void 0,void 0,(function*(){if(!this._model)return ee.error(t,"Internal Server Error");const r=yield this._model.create(e.body).catch((e=>{Q.error(e.message,"api.controller."+this.name(),!0)}));return r?ee.data(t,{id:r.id}):ee.error(t,"Internal Server Error")}))}all(t,r){return(s,i)=>y(this,void 0,void 0,(function*(){var o,n,a,d,l;if(!this._model)return ee.error(i,"Internal Server Error");const c=Object.assign({},t||{});c.where=Object.assign({},c.where||{});const h=null===(o=s.query.limit)||void 0===o?void 0:o.toString();h&&(c.limit=parseInt(h));const p=null===(n=s.query.offset)||void 0===n?void 0:n.toString();p&&(c.offset=parseInt(p));const m=Object.keys(this._model.getAttributes()),v=[],g=null===(a=s.query.asc)||void 0===a?void 0:a.toString();g&&g.length&&g.split(",").forEach((e=>{m.indexOf(e)>=0&&v.push([e,"ASC"])}));const f=null===(d=s.query.desc)||void 0===d?void 0:d.toString();f&&f.length&&f.split(",").forEach((e=>{m.indexOf(e)>=0&&v.push([e,"DESC"])})),v.length&&(c.order=v);const y=[],_=e.isArray(c.attributes)?c.attributes:m,I=null===(l=s.query.search)||void 0===l?void 0:l.toString();_.forEach((t=>{var r;if(e.isString(t)&&(I&&I.length&&y.push({[t]:{[u.Op.like]:`%${I}%`}}),"search_"+t in s.query)){const e=null===(r=s.query["search_"+t])||void 0===r?void 0:r.toString();e&&e.length&&y.push({[t]:{[u.Op.like]:`%${e}%`}})}})),y.length&&(c.where=Object.assign(Object.assign({},c.where),{[u.Op.or]:[...y]}));const T=yield this._model.findAll(c).catch((e=>{Q.error(e.message,"api.controller."+this.name(),!0)})),A=yield this._model.count(c).catch(e.noop);return T?ee.data(i,{count:A,records:r?r(T):T}):ee.error(i,"Internal Server Error")}))}del(){return(e,t)=>y(this,void 0,void 0,(function*(){if(!this._model)return ee.error(t,"Internal Server Error");const{id:r}=e.params;return(yield this._model.destroy({where:{id:r}}).catch((e=>{Q.error(e.message,"api.controller."+this.name(),!0)})))?ee.success(t,"OK"):ee.notfound(t,"Record not found")}))}get(e,t){return(r,s)=>y(this,void 0,void 0,(function*(){if(!this._model)return ee.error(s,"Internal Server Error");e||(e={});const i=Object.assign({},e);i.where=i.where?Object.assign({},i.where):{};const{id:o}=r.params,n=yield this._model.findByPk(o,i).catch((e=>{Q.error(e.message,"api.controller."+this.name(),!0)}));return n?ee.data(s,t?t(n):n.toJSON()):null===n?ee.notfound(s,"Record not found"):ee.error(s,"Internal Server Error")}))}name(){var e;return this._model?null===(e=this._model)||void 0===e?void 0:e.tableName:super.name()}set(){return(e,t)=>y(this,void 0,void 0,(function*(){if(!this._model)return ee.error(t,"Internal Server Error");const{id:r}=e.params,[s]=(yield this._model.update(e.body,{where:{id:r}}).catch((e=>{Q.error(e.message,"api.controller."+this.name(),!0)})))||[];return s?ee.success(t,"OK"):ee.success(t,"Record not changed")}))}getModel(){return this._model}setModel(e){this._model=e}}class le extends ue{intialize(){const e=this.model();e&&this.setModel(e),this.router.use(this.auth),this.router.get("/",this.read(),this.all().bind(this)),this.router.post("/",this.write(),this.validation(this.create()),this.add().bind(this)),this.router.route("/:id").get(this.read(),this.get().bind(this)).put(this.write(),this.validation(this.update()),this.set().bind(this)).delete(this.write(),this.del().bind(this))}}exports.API_AUTH_SLEEP=_,exports.API_DB_DATABASE=I,exports.API_DB_HOST=T,exports.API_DB_LOG=P,exports.API_DB_PASSWORD=A,exports.API_DB_PORT=w,exports.API_DB_TYPE=S,exports.API_DB_USERNAME=b,exports.API_HTTP_CROSS=D,exports.API_HTTP_CRT=x,exports.API_HTTP_HYBRID=R,exports.API_HTTP_KEY=E,exports.API_HTTP_PORT=O,exports.API_HTTP_PUBLIC=q,exports.API_TOKEN_CRT=N,exports.API_TOKEN_HEADER=B,exports.API_TOKEN_KEY=k,exports.API_TOKEN_LIFETIME=C,exports.API_UPLOAD_COUNT=z,exports.API_UPLOAD_FIELD=j,exports.API_UPLOAD_SIZE=G,exports.API_UPLOAD_TEMP=V,exports.API_WEBSOCKET_START=M,exports.App=oe,exports.Auth=H,exports.AuthController=class extends de{constructor(){super(...arguments),this.attributes=["id","name","email","username"],this.query={username:e.Validation.string().min(4).required(),password:e.Validation.string().min(5).required()}}intialize(){this.router.get("/",this.auth,this.user.bind(this)),this.router.post("/login",this.validation(this.query),this.login.bind(this)),this.router.get("/logout",this.auth,this.logout.bind(this))}login(t,r){return y(this,void 0,void 0,(function*(){yield e.sleep(_);const{username:s,password:i}=t.body,o=yield W.findOne({where:{username:s}}).catch((e=>{Q.error(e.message,"api.controller."+this.name(),!0)}));if(!o)return ee.notfound(r,"Username not found");if(!o.state)return ee.error(r,"Username is disabled");const n=m.SHA256(i).toString();if(o.password!=n)return ee.error(r,"Invalid password");const a=o.id,d=e.uniqueID(),{error:u,token:l}=ie.sign({id:a,secret:d});if(u)return ee.error(r,u);if(l){const e=Date.now(),s=e+6e4*C,i=t.get("User-Agent"),o=yield H.create({login:e,secret:d,timestamp:s,useragent:i,userId:a}).catch((e=>{Q.error(e.message,"api.controller."+this.name(),!0)}));if(o)return ee.data(r,{token:l})}return ee.error(r,"Internal Server Error")}))}logout(e,t){return y(this,void 0,void 0,(function*(){const r=e.auth;return r?(r.logout=Date.now(),r.timestamp=r.logout,yield r.save(),ee.success(t,"Disconcerted")):ee.unauthorized(t,"Access denied")}))}user(t,r){return y(this,void 0,void 0,(function*(){const s=t.user;if(!s)return ee.unauthorized(r,"Access denied");const i=yield ne.all(s);if(i){const t=e.allowedObject(this.attributes,s.toJSON()),o=i.map((e=>e.name));return ee.data(r,Object.assign(Object.assign({},t),{permissions:o}))}return ee.error(r,"Internal Server Error")}))}},exports.Config=class{static all(){return y(this,void 0,void 0,(function*(){const e=yield J.findAll().catch((e=>{Q.error(e.message,"api.config",!0)})),t={};return e&&e.forEach((e=>{t[e.key]=e.value})),t}))}static del(e){return y(this,void 0,void 0,(function*(){return((yield J.destroy({where:{key:e}}).catch((e=>{Q.error(e.message,"api.config",!0)})))||0)>0}))}static get(e){return y(this,void 0,void 0,(function*(){const t=yield J.findOne({where:{key:e}}).catch((e=>{Q.error(e.message,"api.config",!0)}));return t&&t.value||""}))}static set(e,t){return y(this,void 0,void 0,(function*(){const[r]=(yield J.findOrCreate({where:{key:e}}).catch((e=>{Q.error(e.message,"api.config",!0)})))||[];r&&(r.value=t,yield r.save().catch((e=>{Q.error(e.message,"api.config",!0)})))}))}},exports.Configs=J,exports.Controller=de,exports.CrudController=le,exports.Database=L,exports.Group=K,exports.GroupController=class extends le{create(){return{name:e.Validation.string().required(),description:e.Validation.string().empty(""),state:e.Validation.boolean().required()}}model(){return K}update(){return{name:e.Validation.string().empty(),description:e.Validation.string().empty(),state:e.Validation.boolean().empty()}}},exports.GroupRoute=Y,exports.GroupRouteController=class extends ue{constructor(){super(...arguments),this.groups={groups:e.Validation.array().items(e.Validation.number())}}intialize(){this.setModel(Y),this.router.use(this.auth),this.router.route("/:id/groups").get(this.read("users"),this.groupRouteAll.bind(this)).put(this.write("users"),this.validation(this.groups),this.groupRouteSet.bind(this))}groupRouteAll(e,t){return y(this,void 0,void 0,(function*(){const{id:r}=e.params;return this.all({where:{groupId:r},include:[{model:F,required:!0}]},(e=>e.map((e=>e.route))))(e,t)}))}groupRouteSet(e,t){return y(this,void 0,void 0,(function*(){const{id:r}=e.params,{routes:s}=e.body,i=yield K.findByPk(r,{attributes:["id"]}).catch((e=>{Q.error(e.message,"api.controller."+this.name(),!0)}));if(i){const e=i.id;if(yield Y.destroy({where:{groupId:e}}),s){let t=0;for(let r=0;r<s.length;r++)t=yield F.count({where:{id:s[r]}}),t&&(yield Y.create({groupId:e,routeId:s[r]}))}return ee.success(t,"OK")}return null===i?ee.notfound(t,"Record not found"):ee.error(t,"Internal Server Error")}))}},exports.Log=Q,exports.Logs=Z,exports.LogsController=class extends ue{intialize(){this.setModel(Z),this.router.use(this.auth),this.router.get("/",this.read("logs"),this.logsAll.bind(this))}logsAll(e,t){return y(this,void 0,void 0,(function*(){const{source:r,type:s}=e.query,i=r&&s?{source:r,type:s}:r?{source:r}:s?{type:s}:{};return this.all({where:i,order:[["created","DESC"]]})(e,t)}))}},exports.ModelController=ue,exports.Permission=ne,exports.Responses=ee,exports.Route=F,exports.RouteController=class extends le{create(){return{name:e.Validation.string().required(),description:e.Validation.string().empty(""),state:e.Validation.boolean().required()}}model(){return F}update(){return{name:e.Validation.string().empty(),description:e.Validation.string().empty(),state:e.Validation.boolean().empty()}}},exports.Token=ie,exports.User=W,exports.UserController=class extends ue{constructor(){super(...arguments),this.attributes=["id","name","email","username","description","state"],this.create={name:e.Validation.string().required(),email:e.Validation.string().email().required(),username:e.Validation.string().min(4).required(),password:e.Validation.string().min(5).required(),description:e.Validation.string().required(),state:e.Validation.boolean().required()},this.update={name:e.Validation.string().empty(),email:e.Validation.string().email().empty(),username:e.Validation.string().min(4).empty(),password:e.Validation.string().min(5).empty(),description:e.Validation.string().empty(),state:e.Validation.boolean().empty()}}intialize(){this.setModel(W),this.router.use(this.auth),this.router.get("/",this.read(),this.userAll.bind(this)),this.router.post("/",this.write(),this.validation(this.create),this.userAdd.bind(this)),this.router.route("/:id").get(this.read(),this.userGet.bind(this)).put(this.write(),this.validation(this.update),this.userSet.bind(this)).delete(this.write(),this.userDel.bind(this))}userAdd(e,t){return y(this,void 0,void 0,(function*(){return e.body.password=m.SHA256(e.body.password).toString(),yield this.add()(e,t)}))}userAll(e,t){return y(this,void 0,void 0,(function*(){return this.all({attributes:this.attributes})(e,t)}))}userDel(e,t){return y(this,void 0,void 0,(function*(){const r=e.user;if(r){const{id:s}=e.params;if(r.id.toString()!=s)return this.del()(e,t)}return ee.error(t,"Internal Server Error")}))}userGet(e,t){return y(this,void 0,void 0,(function*(){return this.get({attributes:this.attributes})(e,t)}))}userSet(e,t){return y(this,void 0,void 0,(function*(){return e.body.password&&(e.body.password=m.SHA256(e.body.password).toString()),this.set()(e,t)}))}},exports.UserGroup=X,exports.UserGroupController=class extends ue{constructor(){super(...arguments),this.groups={groups:e.Validation.array(e.Validation.number())}}intialize(){this.setModel(X),this.router.use(this.auth),this.router.route("/:id/groups").get(this.read("groups"),this.userGroupsAll.bind(this)).put(this.write("groups"),this.validation(this.groups),this.userGroupsSet.bind(this))}userGroupsAll(e,t){return y(this,void 0,void 0,(function*(){const{id:r}=e.params;return this.all({where:{userId:r},include:[{model:K,required:!0}]},(e=>e.map((e=>e.group))))(e,t)}))}userGroupsSet(e,t){return y(this,void 0,void 0,(function*(){const{id:r}=e.params,{groups:s}=e.body,i=yield W.findByPk(r,{attributes:["id"]}).catch((e=>{Q.error(e.message,"api.controller."+this.name(),!0)}));if(i){if(yield X.destroy({where:{userId:i.id}}),s){let e=0;for(let t=0;t<s.length;t++)e=yield K.count({where:{id:s[t]}}),e&&(yield X.create({userId:i.id,groupId:s[t]}))}return ee.success(t,"OK")}return ee.notfound(t,"Record not found")}))}},exports.crt=re,exports.key=se,exports.sequelize=U;
|
|
7
|
+
"use strict";var e=require("@andrewcaires/utils.js"),t=require("cors"),r=require("express"),s=require("fs"),i=require("http"),o=require("https"),n=require("net"),a=require("ws"),d=require("dotenv"),u=require("sequelize"),l=require("jsonwebtoken"),c=require("mime-types"),h=require("multer"),p=require("path"),m=require("crypto-js");function v(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 g=v(i),f=v(o);function y(e,t,r,s){return new(r||(r=Promise))((function(i,o){function n(e){try{d(s.next(e))}catch(e){o(e)}}function a(e){try{d(s.throw(e))}catch(e){o(e)}}function d(e){var t;e.done?i(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())}))}d.config();const I=e.toBool(process.env.API_CONSOLE_ERROR||"false"),_=process.env.API_DB_DATABASE||"",A=process.env.API_DB_HOST||"127.0.0.1",T=process.env.API_DB_PASSWORD||"",b=parseInt(process.env.API_DB_PORT||"3306"),S=process.env.API_DB_TYPE||"",w=process.env.API_DB_USERNAME||"root",O=e.toBool(process.env.API_DB_LOG||"false"),E=process.env.API_TABLE_PREFIX||"",P=process.env.API_HTTP_CRT||"",x=process.env.API_HTTP_KEY||"",q=parseInt(process.env.API_HTTP_PORT||"3000"),R=process.env.API_HTTP_PUBLIC||"",D=e.toBool(process.env.API_HTTP_CROSS||"false"),N=e.toBool(process.env.API_HTTP_HYBRID||"false"),k=parseInt(process.env.API_SLEEP_AUTH||"1000"),B=parseInt(process.env.API_SLEEP_FORGOT||"5000"),C=parseInt(process.env.API_SLEEP_REGISTRY||"5000"),G=process.env.API_TOKEN_CRT||"",V=process.env.API_TOKEN_KEY||"",j=process.env.API_TOKEN_HEADER||"authorization",z=parseInt(process.env.API_TOKEN_LIFETIME||"15"),L=parseInt(process.env.API_UPLOAD_COUNT||"1"),M=process.env.API_UPLOAD_FIELD||"upload",U=parseInt(process.env.API_UPLOAD_SIZE||"2"),H=process.env.API_UPLOAD_TEMP||"./temp",K=e.toBool(process.env.API_WEBSOCKET_START||"false");class F{static connect(e){const t=S.toLowerCase();if("connect_"+t in F)return F["connect_"+t](e);throw new Error("No database is connected to this API")}static connect_mariadb(e){return new u.Sequelize(e.database,e.username,e.password,{host:e.hostname,port:e.hostport,dialect:"mariadb",logging:O,define:{timestamps:!1}})}static connect_memory(){return new u.Sequelize("sqlite::memory:",{logging:O,define:{timestamps:!1}})}static connect_mysql(e){return new u.Sequelize(e.database,e.username,e.password,{host:e.hostname,port:e.hostport,dialect:"mysql",logging:O,define:{timestamps:!1}})}static connect_postgres(e){return new u.Sequelize(e.database,e.username,e.password,{host:e.hostname,port:e.hostport,dialect:"postgres",logging:O,define:{timestamps:!1}})}static connect_sqlite(e){return new u.Sequelize({dialect:"sqlite",storage:e.database,logging:O,define:{timestamps:!1}})}}const Y=F.connect({database:_,username:w,password:T,hostname:A,hostport:b});class W extends u.Model{}W.init({login:u.DataTypes.BIGINT,logout:u.DataTypes.BIGINT,secret:u.DataTypes.STRING,timestamp:u.DataTypes.BIGINT,useragent:u.DataTypes.STRING},{sequelize:Y,modelName:E+"auth",timestamps:!0,createdAt:"created",updatedAt:"updated"});class X extends u.Model{}X.init({token:u.DataTypes.STRING,timestamp:u.DataTypes.BIGINT,state:u.DataTypes.BOOLEAN},{sequelize:Y,modelName:E+"forgot",timestamps:!0,createdAt:"created",updatedAt:"updated"});class J extends u.Model{}J.init({name:u.DataTypes.STRING,description:u.DataTypes.TEXT,state:u.DataTypes.BOOLEAN},{sequelize:Y,modelName:E+"group",timestamps:!0,createdAt:"created",updatedAt:"updated"});class Z extends u.Model{}Z.init({name:u.DataTypes.STRING,description:u.DataTypes.TEXT,state:u.DataTypes.BOOLEAN},{sequelize:Y,modelName:E+"route",timestamps:!0,createdAt:"created",updatedAt:"updated"});class $ extends u.Model{}$.init({},{sequelize:Y,modelName:E+"groups_routes",timestamps:!0,createdAt:"created",updatedAt:!1}),$.removeAttribute("id");class Q extends u.Model{}Q.init({name:u.DataTypes.STRING,email:u.DataTypes.STRING,username:u.DataTypes.STRING,password:u.DataTypes.STRING,avatar:u.DataTypes.STRING,description:u.DataTypes.TEXT,state:u.DataTypes.BOOLEAN},{sequelize:Y,modelName:E+"user",timestamps:!0,createdAt:"created",updatedAt:"updated"});class ee extends u.Model{}ee.init({},{sequelize:Y,modelName:E+"users_groups",timestamps:!0,createdAt:"created",updatedAt:!1}),ee.removeAttribute("id");class te extends u.Model{}te.init({key:u.DataTypes.STRING,value:u.DataTypes.STRING},{sequelize:Y,modelName:E+"configs",timestamps:!0,createdAt:"created",updatedAt:"updated"}),te.removeAttribute("id");class re extends u.Model{}var se;re.init({type:u.DataTypes.STRING,source:u.DataTypes.STRING,message:u.DataTypes.TEXT},{sequelize:Y,modelName:E+"logs",timestamps:!0,createdAt:"created",updatedAt:!1}),Q.hasMany(W),W.belongsTo(Q),Q.hasMany(X),X.belongsTo(Q),J.hasMany($),$.belongsTo(J),Z.hasMany($),$.belongsTo(Z),Q.hasMany(ee),ee.belongsTo(Q),J.hasMany(ee),ee.belongsTo(J),function(e){e.ERROR="[31m",e.INFO="[36m",e.NONE="[37m",e.SUCCESS="[32m",e.WARNING="[33m"}(se||(se={}));class ie{static write(e,t,r){return y(this,void 0,void 0,(function*(){yield ie.writeRaw(se.NONE,"",e,t,r)}))}static error(e,t,r){return y(this,void 0,void 0,(function*(){yield ie.writeRaw(se.ERROR,"error",e,t,r)}))}static info(e,t,r){return y(this,void 0,void 0,(function*(){yield ie.writeRaw(se.INFO,"info",e,t,r)}))}static success(e,t,r){return y(this,void 0,void 0,(function*(){yield ie.writeRaw(se.ERROR,"success",e,t,r)}))}static warning(e,t,r){return y(this,void 0,void 0,(function*(){yield ie.writeRaw(se.WARNING,"warning",e,t,r)}))}static writeConsole(t,r,s){const i=e.dateFormat(new Date,"%H:%M:%S");console.log(">",t,r+" ".repeat(10-r.length),"[37m","|",i,"|",s)}static writeRaw(e,t,r,s,i){return y(this,void 0,void 0,(function*(){i&&ie.writeConsole(e,t,r),Y&&(yield re.create({type:t,source:s,message:r}).catch((()=>null)))}))}}class oe{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){return e.status(400).json({message:t})}static unauthorized(e,t){return e.status(401).json({message:t})}}const ne=e=>s.existsSync(e)?s.readFileSync(e):void 0,ae={http:ne(P),token:ne(G)},de={http:ne(x),token:ne(V)};class ue{static error(e){ie.error(e.message,"api.token",I)}static sign(e){return de.token?{token:l.sign(e,de.token,{algorithm:"RS256"})}:{error:"Invalid Secret"}}static user(e){return y(this,void 0,void 0,(function*(){const{error:t,decode:r}=ue.verify(e);if(t)return{error:t};if(r){const{id:e,secret:t}=r;if(e&&r){const r=yield Q.findOne({where:{id:e,state:!0}}).catch(ue.error);if(r){const e=yield W.findOne({where:{secret:t,userId:r.id}}).catch(ue.error);if(e){const t=Date.now();if(t>e.timestamp)return e.logout=t,yield e.save(),{error:"Expired token"};if(e.timestamp=t+6e4*z,!e.logout)return yield e.save(),{auth:e,user:r}}}return{error:"Access denied"}}}return{error:"Invalid token"}}))}static verify(e){if(!ae.token)return{error:"Invalid Secret"};if(!e||e.split(".").length<3)return{error:"Invalid Token"};try{return{decode:l.verify(e,ae.token)}}catch(e){return{error:"Invalid Token"}}}}class le extends e.EventEmitter{constructor(e){super(),this.app=r(),this.router=r.Router(),this.middlewares(),this.controllers(e)}controllers(e){e.forEach((e=>{e.intialize(this),this.router.use(e.path(),e.router)}))}listen(){return y(this,void 0,void 0,(function*(){if(yield Y.sync(),ae.http&&de.http||(this._server=g.createServer(this.app),this._server.listen(q,(()=>ie.info("Server started on port "+q,"api.server",!0)))),!this._server){const e=g.createServer(((e,t)=>{const r=80==q?":80":"";t.writeHead(301,{Location:"https://"+e.headers.host+r+e.url}),t.end()})),t=f.createServer({key:de.http,cert:ae.http},this.app);if(N){new n.Server((r=>{r.once("data",(s=>{r.pause(),r.unshift(s),(22===s[0]?t:e).emit("connection",r),process.nextTick((()=>r.resume()))}))})).listen(q,(()=>ie.info("Server started on port "+q,"api.server",!0))),this._server=t}this._server||(443==q&&e.listen(80,(()=>ie.info("Server started on port 80","api.server",!0))),t.listen(q,(()=>ie.info("Server started on port "+q,"api.server",!0))),this._server=t)}K&&this._server&&(this._webSocket=new a.Server({server:this._server,verifyClient:(e,t)=>t(K)}),this._webSocket.on("connection",((t,r)=>y(this,void 0,void 0,(function*(){r.url||(r.url="");const s=r.url.length<=1?"":r.url.replace(/\//g,".");let i;t.on("message",(e=>y(this,void 0,void 0,(function*(){if(i)try{const o=JSON.parse(e);this.emit("ws.message"+s,{data:o,message:e,req:r,user:i,ws:t})}catch(o){this.emit("ws.message"+s,{message:e,req:r,user:i,ws:t})}else{const{user:o}=yield ue.user(e.toString());o&&(i=o,this.emit("ws.connection"+s,{req:r,user:i,ws:t}))}i||t.close()})))),t.on("close",(()=>{i&&this.emit("ws.close"+s,{user:i,ws:t})})),yield e.sleep(2e3),i||t.close()})))))}))}middlewares(){this.app.use(r.json()),this.app.use(((e,t,r,s)=>e?(ie.error(e.message,"api.express",I),oe.error(r,"Internal Server Error")):s())),this.app.use(r.urlencoded({extended:!0})),this.app.disable("x-powered-by"),D&&this.app.use(t()),this.app.use("/api",this.router),this.app.all("/api/*",((e,t)=>oe.notfound(t,"Invalid API"))),R&&(s.existsSync(R)&&this.app.use(r.static(R)),this.app.get("*",((e,t)=>{if(!s.existsSync(R))return oe.notfound(t,'File "index.html" not found');t.sendFile(R+"/index.html")})))}server(){return this._server}websocket(){return this._webSocket}}class ce{static all(){return y(this,void 0,void 0,(function*(){const e=yield te.findAll().catch(ce.error),t={};return e&&e.forEach((e=>{t[e.key]=e.value})),t}))}static del(e){return y(this,void 0,void 0,(function*(){return((yield te.destroy({where:{key:e}}).catch(ce.error))||0)>0}))}static error(e){ie.error(e.message,"api.config",I)}static get(e){return y(this,void 0,void 0,(function*(){const t=yield te.findOne({where:{key:e}}).catch(ce.error);return t&&t.value||""}))}static set(e,t){return y(this,void 0,void 0,(function*(){const[r]=(yield te.findOrCreate({where:{key:e}}).catch(ce.error))||[];r&&(r.value=t,yield r.save().catch(ce.error))}))}}class he{static all(e,t){return y(this,void 0,void 0,(function*(){return yield Z.findAll({where:Object.assign(Object.assign({},t),{state:!0}),include:[{model:$,required:!0,include:[{model:J,required:!0,where:{state:!0},include:[{model:ee,required:!0,where:{userId:e.id}}]}]}]}).catch((e=>{ie.error(e.message,"api.permission",I)}))}))}static get(e){return y(this,void 0,void 0,(function*(){const t=yield he.all(e);return t?t.map((e=>e.name)):[]}))}static is(e,t){return y(this,void 0,void 0,(function*(){const r=yield he.all(e,{name:t});return!!r&&r.length>0}))}}const pe=(t,r)=>{const i=e.uuidv4()+"."+r;return s.existsSync(p.join(t,i))?pe(t,r):i};class me extends e.EventEmitter{constructor(e){super(),this.router=r.Router(),this._path=e}auth(){return(e,t,r)=>y(this,void 0,void 0,(function*(){const s=e.get(j)||"",{auth:i,error:o,user:n}=yield ue.user(s);if(o)return oe.error(t,o);if(i&&n){const t=e.get("User-Agent");return t&&(i.useragent=t),yield i.save(),e.auth=i,e.user=n,r()}return oe.error(t,"Internal Server Error")}))}error(e){ie.error(e.message,"api.controller."+this.name(),I)}name(){return"api"}path(){return this._path}permission(e){return(t,r,s)=>y(this,void 0,void 0,(function*(){const i=t.user;return i?(yield he.is(i,e))?s():oe.error(r,"Unauthorized access"):oe.unauthorized(r,"Access denied")}))}read(e=""){return this.permission((e||this.name())+".read")}upload(e){const t=(null==e?void 0:e.path)||H,r=h.diskStorage({destination:(e,r,s)=>s(null,t),filename:(e,r,s)=>y(this,void 0,void 0,(function*(){return s(null,pe(t,c.extension(r.mimetype)||"bin"))}))}),s=1e6*((null==e?void 0:e.size)||U),i=h({storage:r,fileFilter(t,r,s){var i;return y(this,void 0,void 0,(function*(){const t=null===(i=null==e?void 0:e.types)||void 0===i?void 0:i.indexOf(r.mimetype);return void 0!==t&&t<0?s(new Error("File type not allowed")):s(null,!0)}))},limits:{fileSize:s}}),o=(null==e?void 0:e.count)||L,n=(null==e?void 0:e.field)||M,a=i.array(n,o);return(e,t,r)=>{a(e,t,(function(e){return e?oe.error(t,e.message):r()}))}}validation(t){return(r,s,i)=>y(this,void 0,void 0,(function*(){const{error:o,value:n}=yield e.Validation.object(t).validateAsync(r.body);return o?oe.validation(s,o):(r.body=n,i())}))}write(e=""){return this.permission((e||this.name())+".write")}}class ve extends me{add(){return(e,t)=>y(this,void 0,void 0,(function*(){if(!this._model)return oe.error(t,"Internal Server Error");const r=yield this._model.create(e.body).catch(this.error);return r?(this.emit("add",{req:e,record:r}),oe.data(t,{id:r.id})):oe.error(t,"Internal Server Error")}))}all(t,r){return(s,i)=>y(this,void 0,void 0,(function*(){var o,n,a,d,l;if(!this._model)return oe.error(i,"Internal Server Error");const c=Object.assign({},t||{});c.where=Object.assign({},c.where||{});const h=null===(o=s.query.limit)||void 0===o?void 0:o.toString();h&&(c.limit=parseInt(h));const p=null===(n=s.query.offset)||void 0===n?void 0:n.toString();p&&(c.offset=parseInt(p));const m=Object.keys(this._model.getAttributes()),v=[],g=null===(a=s.query.asc)||void 0===a?void 0:a.toString();g&&g.length&&g.split(",").forEach((e=>{m.indexOf(e)>=0&&v.push([e,"ASC"])}));const f=null===(d=s.query.desc)||void 0===d?void 0:d.toString();f&&f.length&&f.split(",").forEach((e=>{m.indexOf(e)>=0&&v.push([e,"DESC"])})),v.length&&(c.order=v);const y=[],I=e.isArray(c.attributes)?c.attributes:m,_=null===(l=s.query.search)||void 0===l?void 0:l.toString();I.forEach((t=>{var r;if(e.isString(t)&&(_&&_.length&&y.push({[t]:{[u.Op.like]:`%${_}%`}}),"search_"+t in s.query)){const e=null===(r=s.query["search_"+t])||void 0===r?void 0:r.toString();e&&e.length&&y.push({[t]:{[u.Op.like]:`%${e}%`}})}})),y.length&&(c.where=Object.assign(Object.assign({},c.where),{[u.Op.or]:[...y]}));const A=yield this._model.findAll(c).catch(this.error),T=yield this._model.count(c).catch(e.noop);return A?(this.emit("all",{req:s,records:A}),oe.data(i,{count:T,records:r?r(A):A})):oe.error(i,"Internal Server Error")}))}del(){return(e,t)=>y(this,void 0,void 0,(function*(){if(!this._model)return oe.error(t,"Internal Server Error");const{id:r}=e.params;return(yield this._model.destroy({where:{id:r}}).catch(this.error))?(this.emit("del",{req:e,id:r}),oe.success(t,"OK")):oe.notfound(t,"Record not found")}))}get(e,t){return(r,s)=>y(this,void 0,void 0,(function*(){if(!this._model)return oe.error(s,"Internal Server Error");e||(e={});const i=Object.assign({},e);i.where=i.where?Object.assign({},i.where):{};const{id:o}=r.params,n=yield this._model.findByPk(o,i).catch(this.error);return n?(this.emit("get",{req:r,record:n}),oe.data(s,t?t(n):n.toJSON())):null===n?oe.notfound(s,"Record not found"):oe.error(s,"Internal Server Error")}))}name(){var e;return this._model?null===(e=this._model)||void 0===e?void 0:e.tableName:super.name()}set(){return(e,t)=>y(this,void 0,void 0,(function*(){if(!this._model)return oe.error(t,"Internal Server Error");const{id:r}=e.params,[s]=(yield this._model.update(e.body,{where:{id:r}}).catch(this.error))||[];return s?(this.emit("set",{req:e,id:r}),oe.success(t,"OK")):oe.success(t,"Record not changed")}))}getModel(){return this._model}setModel(e){this._model=e}}class ge extends ve{intialize(){const e=this.model();e&&this.setModel(e),this.router.use(this.auth()),this.router.get("/",this.read(),this.all().bind(this)),this.router.post("/",this.write(),this.validation(this.create()),this.add().bind(this)),this.router.route("/:id").get(this.read(),this.get().bind(this)).put(this.write(),this.validation(this.update()),this.set().bind(this)).delete(this.write(),this.del().bind(this))}}class fe extends u.Model{}fe.init({token:u.DataTypes.STRING,timestamp:u.DataTypes.BIGINT,state:u.DataTypes.BOOLEAN},{sequelize:Y,modelName:E+"registry",timestamps:!0,createdAt:"created",updatedAt:"updated"});exports.API_CONSOLE_ERROR=I,exports.API_DB_DATABASE=_,exports.API_DB_HOST=A,exports.API_DB_LOG=O,exports.API_DB_PASSWORD=T,exports.API_DB_PORT=b,exports.API_DB_TYPE=S,exports.API_DB_USERNAME=w,exports.API_HTTP_CROSS=D,exports.API_HTTP_CRT=P,exports.API_HTTP_HYBRID=N,exports.API_HTTP_KEY=x,exports.API_HTTP_PORT=q,exports.API_HTTP_PUBLIC=R,exports.API_SLEEP_AUTH=k,exports.API_SLEEP_FORGOT=B,exports.API_SLEEP_REGISTRY=C,exports.API_TABLE_PREFIX=E,exports.API_TOKEN_CRT=G,exports.API_TOKEN_HEADER=j,exports.API_TOKEN_KEY=V,exports.API_TOKEN_LIFETIME=z,exports.API_UPLOAD_COUNT=L,exports.API_UPLOAD_FIELD=M,exports.API_UPLOAD_SIZE=U,exports.API_UPLOAD_TEMP=H,exports.API_WEBSOCKET_START=K,exports.Application=le,exports.Auth=W,exports.AuthController=class extends me{constructor(){super(...arguments),this.attributes=["id","name","email","username","avatar"],this.query={username:e.Validation.string().min(4).required(),password:e.Validation.string().min(5).required()}}intialize(){this.router.get("/",this.auth(),this.user.bind(this)),this.router.post("/login",this.validation(this.query),this.login.bind(this)),this.router.get("/logout",this.auth(),this.logout.bind(this))}login(t,r){return y(this,void 0,void 0,(function*(){yield e.sleep(k);const{username:s,password:i}=t.body,o=yield Q.findOne({where:{username:s}}).catch(this.error);if(!o)return oe.notfound(r,"Username not found");if(!o.state)return oe.error(r,"Username is disabled");const n=m.SHA256(i).toString();if(o.password!=n)return oe.error(r,"Invalid password");const a=o.id,d=e.uniqueID(),{error:u,token:l}=ue.sign({id:a,secret:d});if(u)return oe.error(r,u);if(l){const e=Date.now(),s=e+6e4*z,i=t.get("User-Agent"),n=yield W.create({login:e,secret:d,timestamp:s,useragent:i,userId:a}).catch(this.error);if(n)return this.emit("login",{auth:n,req:t,user:o}),oe.data(r,{token:l})}return oe.error(r,"Internal Server Error")}))}logout(e,t){return y(this,void 0,void 0,(function*(){const r=e.auth,s=e.user;return r&&s&&!r.logout?(r.logout=Date.now(),r.timestamp=r.logout,yield r.save(),this.emit("logout",{auth:r,req:e,user:s}),oe.success(t,"Disconcerted")):oe.unauthorized(t,"Access denied")}))}user(t,r){return y(this,void 0,void 0,(function*(){const s=t.user;if(!s)return oe.unauthorized(r,"Access denied");const i=yield he.all(s);if(i){const o=e.allowedObject(this.attributes,s.toJSON()),n=i.map((e=>e.name));return this.emit("user",{req:t,user:s}),oe.data(r,Object.assign(Object.assign({},o),{permissions:n}))}return oe.error(r,"Internal Server Error")}))}},exports.Config=ce,exports.Configs=te,exports.Controller=me,exports.CrudController=ge,exports.Database=F,exports.Forgot=X,exports.ForgotController=class extends me{constructor(){super(...arguments),this.username={username:e.Validation.string().min(4).required()},this.password={token:e.Validation.string().required(),password:e.Validation.string().min(5).required()},this.query={token:e.Validation.string().required()}}intialize(){this.router.post("/",this.validation(this.username),this.forgot.bind(this)),this.router.post("/check",this.validation(this.query),this.check.bind(this)),this.router.post("/reset",this.validation(this.password),this.reset.bind(this))}check(t,r){return y(this,void 0,void 0,(function*(){const{token:s}=t.body,i=yield this.findOne(s);return i&&i.user?(i.token=e.uniqueID(),yield i.save(),oe.data(r,{token:i.token})):oe.notfound(r,"User not found")}))}forgot(t,r){return y(this,void 0,void 0,(function*(){const{username:s}=t.body;yield e.sleep(B);const i=yield Q.findOne({where:{username:s}}).catch(this.error);if(!i)return oe.notfound(r,"User not found");const o=e.uniqueID(),n=Date.now()+6e4*z,a=yield X.create({token:o,timestamp:n,state:!0,userId:i.id});return this.emit("forgot",{forgot:a,req:t,user:i}),oe.success(r,"OK")}))}findOne(e){return y(this,void 0,void 0,(function*(){return yield X.findOne({where:{token:e,state:!0},include:[{model:Q,required:!0}]}).catch(this.error)}))}reset(e,t){return y(this,void 0,void 0,(function*(){const{token:r,password:s}=e.body,i=yield this.findOne(r);return i?(i.state=!1,yield i.save().catch(this.error),i.user.password=m.SHA256(s).toString(),yield i.user.save().catch(this.error),this.emit("reset",{req:e,user:i.user}),oe.success(t,"OK")):oe.notfound(t,"User not found")}))}},exports.Group=J,exports.GroupController=class extends ge{create(){return{name:e.Validation.string().required(),description:e.Validation.string().empty(""),state:e.Validation.boolean().parse().required()}}model(){return J}update(){return{name:e.Validation.string().empty(),description:e.Validation.string().empty(),state:e.Validation.boolean().parse().empty()}}},exports.GroupRoute=$,exports.GroupRouteController=class extends ve{constructor(){super(...arguments),this.groups={groups:e.Validation.array().items(e.Validation.number())}}intialize(){this.setModel($),this.router.use(this.auth()),this.router.route("/:id/groups").get(this.read("users"),this.groupRouteAll.bind(this)).put(this.write("users"),this.validation(this.groups),this.groupRouteSet.bind(this))}groupRouteAll(e,t){return y(this,void 0,void 0,(function*(){const{id:r}=e.params;return this.all({where:{groupId:r},include:[{model:Z,required:!0}]},(e=>e.map((e=>e.route))))(e,t)}))}groupRouteSet(t,r){return y(this,void 0,void 0,(function*(){const{id:s}=t.params,{routes:i}=t.body,o=yield J.findByPk(s,{attributes:["id"]}).catch(this.error);if(o){const e=o.id;if(yield $.destroy({where:{groupId:e}}),i){let t=0;for(let r=0;r<i.length;r++)t=yield Z.count({where:{id:i[r]}}),t&&(yield $.create({groupId:e,routeId:i[r]}))}return oe.success(r,"OK")}return e.isNull(o)?oe.notfound(r,"Record not found"):oe.error(r,"Internal Server Error")}))}},exports.Log=ie,exports.Logs=re,exports.LogsController=class extends ve{intialize(){this.setModel(re),this.router.use(this.auth()),this.router.get("/",this.read("logs"),this.logsAll.bind(this))}logsAll(e,t){return y(this,void 0,void 0,(function*(){const{source:r,type:s}=e.query,i=r&&s?{source:r,type:s}:r?{source:r}:s?{type:s}:{};return this.all({where:i,order:[["created","DESC"]]})(e,t)}))}},exports.ModelController=ve,exports.Permission=he,exports.RegisterController=class extends me{constructor(){super(...arguments),this.create={name:e.Validation.string().required(),email:e.Validation.string().email().required(),username:e.Validation.string().min(4).required(),password:e.Validation.string().min(5).required()},this.query={token:e.Validation.string().required()}}intialize(){this.router.post("/",this.validation(this.create),this.register.bind(this)),this.router.post("/confirm",this.validation(this.query),this.confirm.bind(this))}confirm(e,t){return y(this,void 0,void 0,(function*(){const{token:r}=e.body,s=yield fe.findOne({where:{token:r,state:!0},include:[{model:Q,required:!0}]}).catch(this.error);return s?(s.user.state=!0,yield s.user.save().catch(this.error),this.emit("confirm",{req:e,user:s.user}),oe.success(t,"OK")):oe.notfound(t,"User not found")}))}register(t,r){return y(this,void 0,void 0,(function*(){const{username:s}=t.body;yield e.sleep(B);const i=yield Q.findOne({where:{username:s}}).catch(this.error);if(i)return oe.error(r,"Invalid Username");if(!e.isNull(i))return oe.error(r,"Internal Server Error");const o=yield Q.create(Object.assign(Object.assign({},t.body),{state:!1}));return this.emit("register",{req:t,user:o}),oe.success(r,"OK")}))}},exports.Responses=oe,exports.Route=Z,exports.RouteController=class extends ge{create(){return{name:e.Validation.string().required(),description:e.Validation.string().empty(""),state:e.Validation.boolean().parse().required()}}model(){return Z}update(){return{name:e.Validation.string().empty(),description:e.Validation.string().empty(),state:e.Validation.boolean().empty()}}},exports.SetupController=class extends me{intialize(){this.router.get("/",this.setup.bind(this))}setup(t,r){return y(this,void 0,void 0,(function*(){if(0==(yield Q.count())){const t={description:"",state:!0},r=yield Q.create(Object.assign({name:"Admin",email:"admin@localhost",username:"admin",password:"8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918",avatar:""},t)),s=yield J.create(Object.assign({name:"admin"},t));yield ee.create({userId:r.id,groupId:s.id});const i=["read","write"],o=["users","groups","routes"];yield e.forEachSeries(o,(r=>y(this,void 0,void 0,(function*(){yield e.forEachSeries(i,(e=>y(this,void 0,void 0,(function*(){const i=r+"."+e,o=yield Z.create(Object.assign({name:i},t));yield $.create({groupId:s.id,routeId:o.id})}))))}))));const n=yield Z.create(Object.assign({name:"logs.read"},t));yield $.create({groupId:s.id,routeId:n.id})}return oe.success(r,"OK")}))}},exports.Token=ue,exports.User=Q,exports.UserController=class extends ve{constructor(){super(...arguments),this.attributes=["id","name","email","username","avatar","description","state","created","updated"],this.create={name:e.Validation.string().required(),email:e.Validation.string().email().required(),username:e.Validation.string().min(4).required(),password:e.Validation.string().min(5).required(),description:e.Validation.string().required(),state:e.Validation.boolean().parse().required()},this.update={name:e.Validation.string().empty(),email:e.Validation.string().email().empty(),username:e.Validation.string().min(4).empty(),password:e.Validation.string().min(5).empty(),description:e.Validation.string().empty(),state:e.Validation.boolean().parse().empty()}}intialize(){this.setModel(Q),this.router.use(this.auth()),this.router.get("/",this.read(),this.userAll.bind(this)),this.router.post("/",this.write(),this.validation(this.create),this.userAdd.bind(this)),this.router.route("/:id").get(this.read(),this.userGet.bind(this)).put(this.write(),this.validation(this.update),this.userSet.bind(this)).delete(this.write(),this.userDel.bind(this))}userAdd(e,t){return y(this,void 0,void 0,(function*(){return e.body.password=m.SHA256(e.body.password).toString(),yield this.add()(e,t)}))}userAll(e,t){return y(this,void 0,void 0,(function*(){return this.all({attributes:this.attributes})(e,t)}))}userDel(e,t){return y(this,void 0,void 0,(function*(){const r=e.user;if(r){const{id:s}=e.params;if(r.id.toString()!=s)return this.del()(e,t)}return oe.error(t,"Internal Server Error")}))}userGet(e,t){return y(this,void 0,void 0,(function*(){return this.get({attributes:this.attributes})(e,t)}))}userSet(e,t){return y(this,void 0,void 0,(function*(){return e.body.password&&(e.body.password=m.SHA256(e.body.password).toString()),this.set()(e,t)}))}},exports.UserGroup=ee,exports.UserGroupController=class extends ve{constructor(){super(...arguments),this.groups={groups:e.Validation.array(e.Validation.number())}}intialize(){this.setModel(ee),this.router.use(this.auth()),this.router.route("/:id/groups").get(this.read("groups"),this.userGroupsAll.bind(this)).put(this.write("groups"),this.validation(this.groups),this.userGroupsSet.bind(this))}userGroupsAll(e,t){return y(this,void 0,void 0,(function*(){const{id:r}=e.params;return this.all({where:{userId:r},include:[{model:J,required:!0}]},(e=>e.map((e=>e.group))))(e,t)}))}userGroupsSet(t,r){return y(this,void 0,void 0,(function*(){const{id:s}=t.params,{groups:i}=t.body,o=yield Q.findByPk(s,{attributes:["id"]}).catch(this.error);if(o){if(yield ee.destroy({where:{userId:o.id}}),i){let e=0;for(let t=0;t<i.length;t++)e=yield J.count({where:{id:i[t]}}),e&&(yield ee.create({userId:o.id,groupId:i[t]}))}return oe.success(r,"OK")}return e.isNull(o),oe.notfound(r,"Record not found")}))}},exports.crt=ae,exports.key=de,exports.sequelize=Y;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @andrewcaires/api v2.0.
|
|
2
|
+
* @andrewcaires/api v2.0.3
|
|
3
3
|
* Simple api for small applications using express, jsonwebtoken, sequelize and websocket
|
|
4
|
-
* (c)
|
|
4
|
+
* (c) 2023 Andrew Caires
|
|
5
5
|
* @license: MIT
|
|
6
6
|
*/
|
|
7
7
|
import * as express_serve_static_core from 'express-serve-static-core';
|
|
8
|
-
import { TypeObject, ValidationBase,
|
|
8
|
+
import { EventEmitter, TypeObject, ValidationBase, TypeObjectString } from '@andrewcaires/utils.js';
|
|
9
9
|
import * as http from 'http';
|
|
10
10
|
import * as https from 'https';
|
|
11
11
|
import WebSocket from 'ws';
|
|
12
|
-
import
|
|
13
|
-
import { Request, Response, NextFunction } from 'express';
|
|
12
|
+
import { RequestHandler, Request, Response } from 'express';
|
|
14
13
|
import { Model, FindOptions, Attributes, ModelStatic, Sequelize } from 'sequelize';
|
|
15
14
|
import { WhereOptions } from 'sequelize/types';
|
|
16
15
|
|
|
@@ -51,6 +50,7 @@ declare class User extends Model {
|
|
|
51
50
|
email: string;
|
|
52
51
|
username: string;
|
|
53
52
|
password: string;
|
|
53
|
+
avatar: string;
|
|
54
54
|
description: string;
|
|
55
55
|
state: boolean;
|
|
56
56
|
users_groups: UserGroup[];
|
|
@@ -66,6 +66,15 @@ declare class Auth extends Model {
|
|
|
66
66
|
user: User;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
declare class Forgot extends Model {
|
|
70
|
+
id: number;
|
|
71
|
+
token: string;
|
|
72
|
+
timestamp: number;
|
|
73
|
+
state: boolean;
|
|
74
|
+
userId: number;
|
|
75
|
+
user: User;
|
|
76
|
+
}
|
|
77
|
+
|
|
69
78
|
declare class Configs extends Model {
|
|
70
79
|
key: string;
|
|
71
80
|
value: string;
|
|
@@ -92,22 +101,23 @@ interface UploadOptions {
|
|
|
92
101
|
size?: number;
|
|
93
102
|
types?: string[];
|
|
94
103
|
}
|
|
95
|
-
declare abstract class Controller {
|
|
104
|
+
declare abstract class Controller extends EventEmitter {
|
|
96
105
|
private _path;
|
|
97
106
|
readonly router: express_serve_static_core.Router;
|
|
98
107
|
constructor(path: string);
|
|
99
|
-
protected auth(
|
|
100
|
-
|
|
108
|
+
protected auth(): RequestHandler;
|
|
109
|
+
protected error(error: any): void;
|
|
110
|
+
abstract intialize(app: Application): void;
|
|
101
111
|
protected name(): string;
|
|
102
112
|
path(): string;
|
|
103
|
-
protected permission(name: string):
|
|
104
|
-
protected read(name?: string):
|
|
105
|
-
protected upload(options: UploadOptions):
|
|
106
|
-
protected validation(options: TypeObject<ValidationBase>):
|
|
107
|
-
protected write(name?: string):
|
|
113
|
+
protected permission(name: string): RequestHandler;
|
|
114
|
+
protected read(name?: string): RequestHandler;
|
|
115
|
+
protected upload(options: UploadOptions): RequestHandler;
|
|
116
|
+
protected validation(options: TypeObject<ValidationBase>): RequestHandler;
|
|
117
|
+
protected write(name?: string): RequestHandler;
|
|
108
118
|
}
|
|
109
119
|
|
|
110
|
-
declare class
|
|
120
|
+
declare class Application extends EventEmitter {
|
|
111
121
|
private _server?;
|
|
112
122
|
private _webSocket?;
|
|
113
123
|
readonly app: express_serve_static_core.Express;
|
|
@@ -123,11 +133,12 @@ declare class App extends EventEmitter {
|
|
|
123
133
|
declare class Config {
|
|
124
134
|
static all(): Promise<TypeObjectString>;
|
|
125
135
|
static del(key: string): Promise<boolean>;
|
|
136
|
+
private static error;
|
|
126
137
|
static get(key: string): Promise<string>;
|
|
127
138
|
static set(key: string, value: string): Promise<void>;
|
|
128
139
|
}
|
|
129
140
|
|
|
130
|
-
declare const
|
|
141
|
+
declare const API_CONSOLE_ERROR: boolean;
|
|
131
142
|
declare const API_DB_DATABASE: string;
|
|
132
143
|
declare const API_DB_HOST: string;
|
|
133
144
|
declare const API_DB_PASSWORD: string;
|
|
@@ -135,12 +146,16 @@ declare const API_DB_PORT: number;
|
|
|
135
146
|
declare const API_DB_TYPE: string;
|
|
136
147
|
declare const API_DB_USERNAME: string;
|
|
137
148
|
declare const API_DB_LOG: boolean;
|
|
149
|
+
declare const API_TABLE_PREFIX: string;
|
|
138
150
|
declare const API_HTTP_CRT: string;
|
|
139
151
|
declare const API_HTTP_KEY: string;
|
|
140
152
|
declare const API_HTTP_PORT: number;
|
|
141
153
|
declare const API_HTTP_PUBLIC: string;
|
|
142
154
|
declare const API_HTTP_CROSS: boolean;
|
|
143
155
|
declare const API_HTTP_HYBRID: boolean;
|
|
156
|
+
declare const API_SLEEP_AUTH: number;
|
|
157
|
+
declare const API_SLEEP_FORGOT: number;
|
|
158
|
+
declare const API_SLEEP_REGISTRY: number;
|
|
144
159
|
declare const API_TOKEN_CRT: string;
|
|
145
160
|
declare const API_TOKEN_KEY: string;
|
|
146
161
|
declare const API_TOKEN_HEADER: string;
|
|
@@ -153,15 +168,26 @@ declare const API_WEBSOCKET_START: boolean;
|
|
|
153
168
|
|
|
154
169
|
declare class AuthController extends Controller {
|
|
155
170
|
readonly attributes: string[];
|
|
156
|
-
private query;
|
|
171
|
+
private readonly query;
|
|
157
172
|
intialize(): void;
|
|
158
173
|
protected login(req: Request, res: Response): Promise<Response<any, Record<string, any>>>;
|
|
159
174
|
protected logout(req: Request, res: Response): Promise<Response<any, Record<string, any>>>;
|
|
160
175
|
protected user(req: Request, res: Response): Promise<Response<any, Record<string, any>>>;
|
|
161
176
|
}
|
|
162
177
|
|
|
163
|
-
declare
|
|
164
|
-
|
|
178
|
+
declare class ForgotController extends Controller {
|
|
179
|
+
private readonly username;
|
|
180
|
+
private readonly password;
|
|
181
|
+
private readonly query;
|
|
182
|
+
intialize(): void;
|
|
183
|
+
protected check(req: Request, res: Response): Promise<Response<any, Record<string, any>>>;
|
|
184
|
+
protected forgot(req: Request, res: Response): Promise<Response<any, Record<string, any>>>;
|
|
185
|
+
private findOne;
|
|
186
|
+
protected reset(req: Request, res: Response): Promise<Response<any, Record<string, any>>>;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
type FnRecord<M> = (records: M) => any;
|
|
190
|
+
type FnRecords<M> = (records: Array<M>) => Array<any>;
|
|
165
191
|
declare abstract class ModelController<M extends Model<M>> extends Controller {
|
|
166
192
|
private _model?;
|
|
167
193
|
protected add(): (req: Request, res: Response) => Promise<Response<any, Record<string, any>>>;
|
|
@@ -188,7 +214,7 @@ declare class GroupController extends CrudController<Group> {
|
|
|
188
214
|
}
|
|
189
215
|
|
|
190
216
|
declare class GroupRouteController extends ModelController<GroupRoute> {
|
|
191
|
-
private groups;
|
|
217
|
+
private readonly groups;
|
|
192
218
|
intialize(): void;
|
|
193
219
|
protected groupRouteAll(req: Request, res: Response): Promise<Response<any, Record<string, any>>>;
|
|
194
220
|
protected groupRouteSet(req: Request, res: Response): Promise<Response<any, Record<string, any>>>;
|
|
@@ -199,16 +225,29 @@ declare class LogsController extends ModelController<Logs> {
|
|
|
199
225
|
protected logsAll(req: Request, res: Response): Promise<Response<any, Record<string, any>>>;
|
|
200
226
|
}
|
|
201
227
|
|
|
228
|
+
declare class RegisterController extends Controller {
|
|
229
|
+
private readonly create;
|
|
230
|
+
private readonly query;
|
|
231
|
+
intialize(): void;
|
|
232
|
+
confirm(req: Request, res: Response): Promise<Response<any, Record<string, any>>>;
|
|
233
|
+
register(req: Request, res: Response): Promise<Response<any, Record<string, any>>>;
|
|
234
|
+
}
|
|
235
|
+
|
|
202
236
|
declare class RouteController extends CrudController<Route> {
|
|
203
237
|
protected create(): TypeObject<ValidationBase>;
|
|
204
238
|
protected model(): ModelStatic<Route>;
|
|
205
239
|
protected update(): TypeObject<ValidationBase>;
|
|
206
240
|
}
|
|
207
241
|
|
|
242
|
+
declare class SetupController extends Controller {
|
|
243
|
+
intialize(): void;
|
|
244
|
+
protected setup(req: Request, res: Response): Promise<Response<any, Record<string, any>>>;
|
|
245
|
+
}
|
|
246
|
+
|
|
208
247
|
declare class UserController extends ModelController<User> {
|
|
209
|
-
private attributes;
|
|
210
|
-
private create;
|
|
211
|
-
private update;
|
|
248
|
+
private readonly attributes;
|
|
249
|
+
private readonly create;
|
|
250
|
+
private readonly update;
|
|
212
251
|
intialize(): void;
|
|
213
252
|
protected userAdd(req: Request, res: Response): Promise<Response<any, Record<string, any>>>;
|
|
214
253
|
protected userAll(req: Request, res: Response): Promise<Response<any, Record<string, any>>>;
|
|
@@ -218,7 +257,7 @@ declare class UserController extends ModelController<User> {
|
|
|
218
257
|
}
|
|
219
258
|
|
|
220
259
|
declare class UserGroupController extends ModelController<UserGroup> {
|
|
221
|
-
private groups;
|
|
260
|
+
private readonly groups;
|
|
222
261
|
intialize(): void;
|
|
223
262
|
protected userGroupsAll(req: Request, res: Response): Promise<Response<any, Record<string, any>>>;
|
|
224
263
|
protected userGroupsSet(req: Request, res: Response): Promise<Response<any, Record<string, any>>>;
|
|
@@ -252,19 +291,20 @@ declare class Log {
|
|
|
252
291
|
}
|
|
253
292
|
|
|
254
293
|
declare class Permission {
|
|
255
|
-
static all(user: User, where?: WhereOptions): Promise<void | Route
|
|
256
|
-
static get(user: User): Promise<string
|
|
257
|
-
static is(user: User, name: string): Promise<boolean
|
|
294
|
+
static all(user: User, where?: WhereOptions): Promise<void | Array<Route>>;
|
|
295
|
+
static get(user: User): Promise<Array<string>>;
|
|
296
|
+
static is(user: User, name: string): Promise<boolean>;
|
|
258
297
|
}
|
|
259
298
|
|
|
299
|
+
type ResponseJson = Response<any, Record<string, any>>;
|
|
260
300
|
declare class Responses {
|
|
261
|
-
static success(res: Response, message: string):
|
|
262
|
-
static data(res: Response, obj: object):
|
|
263
|
-
static error(res: Response, message: string):
|
|
264
|
-
static list(res: Response, arr: Array<any>):
|
|
265
|
-
static notfound(res: Response, message: string):
|
|
266
|
-
static validation(res: Response, message: string):
|
|
267
|
-
static unauthorized(res: Response, message: string):
|
|
301
|
+
static success(res: Response, message: string): ResponseJson;
|
|
302
|
+
static data(res: Response, obj: object): ResponseJson;
|
|
303
|
+
static error(res: Response, message: string): ResponseJson;
|
|
304
|
+
static list(res: Response, arr: Array<any>): ResponseJson;
|
|
305
|
+
static notfound(res: Response, message: string): ResponseJson;
|
|
306
|
+
static validation(res: Response, message: string): ResponseJson;
|
|
307
|
+
static unauthorized(res: Response, message: string): ResponseJson;
|
|
268
308
|
}
|
|
269
309
|
|
|
270
310
|
declare const crt: {
|
|
@@ -290,9 +330,10 @@ interface TokenVerify {
|
|
|
290
330
|
decode?: TypeObject<string | number | boolean>;
|
|
291
331
|
}
|
|
292
332
|
declare class Token {
|
|
333
|
+
private static error;
|
|
293
334
|
static sign(payload: TypeObject<string | number>): TokenSign;
|
|
294
335
|
static user(token: string): Promise<TokenUser>;
|
|
295
336
|
static verify(token: string): TokenVerify;
|
|
296
337
|
}
|
|
297
338
|
|
|
298
|
-
export {
|
|
339
|
+
export { API_CONSOLE_ERROR, 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_SLEEP_AUTH, API_SLEEP_FORGOT, API_SLEEP_REGISTRY, API_TABLE_PREFIX, 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, Application, Auth, AuthController, Config, Configs, Controller, CrudController, Database, Forgot, ForgotController, Group, GroupController, GroupRoute, GroupRouteController, Log, Logs, LogsController, ModelController, Permission, RegisterController, Responses, Route, RouteController, SetupController, Token, User, UserController, UserGroup, UserGroupController, crt, key, sequelize };
|
package/dist/index.esm.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @andrewcaires/api v2.0.
|
|
2
|
+
* @andrewcaires/api v2.0.3
|
|
3
3
|
* Simple api for small applications using express, jsonwebtoken, sequelize and websocket
|
|
4
|
-
* (c)
|
|
4
|
+
* (c) 2023 Andrew Caires
|
|
5
5
|
* @license: MIT
|
|
6
6
|
*/
|
|
7
|
-
import{toBool as e,dateFormat as t,EventEmitter as r,sleep as s,Validation as i,uuidv4 as n,uniqueID as o,allowedObject as a,isArray as d,isString as u,noop as c}from"@andrewcaires/utils.js";import l from"cors";import h,{Router as p,json as m,urlencoded as v}from"express";import{existsSync as g,readFileSync as f}from"fs";import*as y from"http";import*as w from"https";import{Server as I}from"net";import b from"ws";import{config as _}from"dotenv";import{Sequelize as S,DataTypes as A,Model as T,Op as E}from"sequelize";import{sign as O,verify as R}from"jsonwebtoken";import N from"mime-types";import P from"multer";import{join as q}from"path";import{SHA256 as k}from"crypto-js";function x(e,t,r,s){return new(r||(r=Promise))((function(i,n){function o(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?i(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(o,a)}d((s=s.apply(e,t||[])).next())}))}_();const z=parseInt(process.env.API_AUTH_SLEEP||"1000"),D=process.env.API_DB_DATABASE||"",G=process.env.API_DB_HOST||"127.0.0.1",j=process.env.API_DB_PASSWORD||"",B=parseInt(process.env.API_DB_PORT||"3306"),C=process.env.API_DB_TYPE||"",M=process.env.API_DB_USERNAME||"root",L=e(process.env.API_DB_LOG||"false"),U=process.env.API_HTTP_CRT||"",H=process.env.API_HTTP_KEY||"",K=parseInt(process.env.API_HTTP_PORT||"3000"),F=process.env.API_HTTP_PUBLIC||"",W=e(process.env.API_HTTP_CROSS||"false"),X=e(process.env.API_HTTP_HYBRID||"false"),Y=process.env.API_TOKEN_CRT||"",J=process.env.API_TOKEN_KEY||"",$=process.env.API_TOKEN_HEADER||"authorization",Z=parseInt(process.env.API_TOKEN_LIFETIME||"15"),Q=parseInt(process.env.API_UPLOAD_COUNT||"1"),V=process.env.API_UPLOAD_FIELD||"upload",ee=parseInt(process.env.API_UPLOAD_SIZE||"2"),te=process.env.API_UPLOAD_TEMP||"./temp",re=e(process.env.API_WEBSOCKET_START||"false");class se{static connect(e){const t=C.toLowerCase();if("connect_"+t in se)return se["connect_"+t](e);throw new Error("No database is connected to this API")}static connect_mariadb(e){return new S(e.database,e.username,e.password,{host:e.hostname,port:e.hostport,dialect:"mariadb",logging:L,define:{timestamps:!1}})}static connect_memory(){return new S("sqlite::memory:",{logging:L,define:{timestamps:!1}})}static connect_mysql(e){return new S(e.database,e.username,e.password,{host:e.hostname,port:e.hostport,dialect:"mysql",logging:L,define:{timestamps:!1}})}static connect_postgres(e){return new S(e.database,e.username,e.password,{host:e.hostname,port:e.hostport,dialect:"postgres",logging:L,define:{timestamps:!1}})}static connect_sqlite(e){return new S({dialect:"sqlite",storage:e.database,logging:L,define:{timestamps:!1}})}}const ie=se.connect({database:D,username:M,password:j,hostname:G,hostport:B});class ne extends T{}ne.init({login:A.BIGINT,logout:A.BIGINT,secret:A.STRING,timestamp:A.BIGINT,useragent:A.STRING},{sequelize:ie,modelName:"auth"});class oe extends T{}oe.init({name:A.STRING,description:A.TEXT,state:A.BOOLEAN},{sequelize:ie,modelName:"group"});class ae extends T{}ae.init({name:A.STRING,description:A.TEXT,state:A.BOOLEAN},{sequelize:ie,modelName:"route"});class de extends T{}de.init({},{sequelize:ie,modelName:"groups_routes"}),de.removeAttribute("id");class ue extends T{}ue.init({name:A.STRING,email:A.STRING,username:A.STRING,password:A.STRING,description:A.TEXT,state:A.BOOLEAN},{sequelize:ie,modelName:"user"});class ce extends T{}ce.init({},{sequelize:ie,modelName:"users_groups"}),ce.removeAttribute("id");class le extends T{}le.init({key:A.STRING,value:A.STRING},{sequelize:ie,modelName:"configs",timestamps:!0,createdAt:"created",updatedAt:"updated"}),le.removeAttribute("id");class he extends T{}var pe;he.init({type:A.STRING,source:A.STRING,message:A.TEXT},{sequelize:ie,modelName:"logs",timestamps:!0,createdAt:"created",updatedAt:!1}),ue.hasMany(ne),ne.belongsTo(ue),oe.hasMany(de),de.belongsTo(oe),ae.hasMany(de),de.belongsTo(ae),ue.hasMany(ce),ce.belongsTo(ue),oe.hasMany(ce),ce.belongsTo(oe),function(e){e.ERROR="[31m",e.INFO="[36m",e.NONE="[37m",e.SUCCESS="[32m",e.WARNING="[33m"}(pe||(pe={}));class me{static write(e,t,r){return x(this,void 0,void 0,(function*(){yield me.writeRaw(pe.NONE,"",e,t,r)}))}static error(e,t,r){return x(this,void 0,void 0,(function*(){yield me.writeRaw(pe.ERROR,"error",e,t,r)}))}static info(e,t,r){return x(this,void 0,void 0,(function*(){yield me.writeRaw(pe.INFO,"info",e,t,r)}))}static success(e,t,r){return x(this,void 0,void 0,(function*(){yield me.writeRaw(pe.ERROR,"success",e,t,r)}))}static warning(e,t,r){return x(this,void 0,void 0,(function*(){yield me.writeRaw(pe.WARNING,"warning",e,t,r)}))}static writeConsole(e,r,s){const i=t(new Date,"%H:%M:%S");console.log(">",e,r+" ".repeat(10-r.length),"[37m","|",i,"|",s)}static writeRaw(e,t,r,s,i){return x(this,void 0,void 0,(function*(){i&&me.writeConsole(e,t,r),ie&&(yield he.create({type:t,source:s,message:r}).catch((()=>null)))}))}}class ve{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){return e.status(400).json({message:t})}static unauthorized(e,t){return e.status(401).json({message:t})}}const ge=e=>g(e)?f(e):void 0,fe={http:ge(U),token:ge(Y)},ye={http:ge(H),token:ge(J)};class we{static sign(e){return ye.token?{token:O(e,ye.token,{algorithm:"RS256"})}:{error:"Invalid Secret"}}static user(e){return x(this,void 0,void 0,(function*(){const{error:t,decode:r}=we.verify(e);if(t)return{error:t};if(r){const{id:e,secret:t}=r;if(e&&r){const r=yield ue.findOne({where:{id:e,state:!0}}).catch((e=>{me.error(e.message,"api.token",!0)}));if(r){const e=yield ne.findOne({where:{secret:t,userId:r.id}}).catch((e=>{me.error(e.message,"api.token",!0)}));if(e){const t=Date.now();if(t>e.timestamp)return{error:"Expired token"};if(e.timestamp=t+6e4*Z,yield e.save(),!e.logout)return{auth:e,user:r}}}return{error:"Access denied"}}}return{error:"Invalid token"}}))}static verify(e){if(!fe.token)return{error:"Invalid Secret"};if(!e||e.split(".").length<3)return{error:"Invalid Token"};try{return{decode:R(e,fe.token)}}catch(e){return{error:"Invalid Token"}}}}class Ie extends r{constructor(e){super(),this.app=h(),this.router=p(),this.middlewares(),this.controllers(e)}controllers(e){e.forEach((e=>{e.intialize(),this.router.use(e.path(),e.router)}))}listen(){return x(this,void 0,void 0,(function*(){if(yield ie.sync(),fe.http&&ye.http||(this._server=y.createServer(this.app),this._server.listen(K,(()=>me.info("Server started on port "+K,"api.server",!0)))),!this._server){const e=y.createServer(((e,t)=>{const r=80==K?":80":"";t.writeHead(301,{Location:"https://"+e.headers.host+r+e.url}),t.end()})),t=w.createServer({key:ye.http,cert:fe.http},this.app);if(X){new I((r=>{r.once("data",(s=>{r.pause(),r.unshift(s),(22===s[0]?t:e).emit("connection",r),process.nextTick((()=>r.resume()))}))})).listen(K,(()=>me.info("Server started on port "+K,"api.server",!0))),this._server=t}this._server||(443==K&&e.listen(80,(()=>me.info("Server started on port 80","api.server",!0))),t.listen(K,(()=>me.info("Server started on port "+K,"api.server",!0))),this._server=t)}re&&this._server&&(this._webSocket=new b.Server({server:this._server,verifyClient:(e,t)=>t(re)}),this._webSocket.on("connection",((e,t)=>x(this,void 0,void 0,(function*(){t.url||(t.url="");const r=t.url.length<=1?"":t.url.replace(/\//g,".");let i;e.on("message",(s=>x(this,void 0,void 0,(function*(){if(i)try{const n=JSON.parse(s);this.emit("ws.message"+r,{data:n,message:s,req:t,user:i,ws:e})}catch(n){this.emit("ws.message"+r,{message:s,req:t,user:i,ws:e})}else{const{user:n}=yield we.user(s.toString());n&&(i=n,this.emit("ws.connection"+r,{req:t,user:i,ws:e}))}i||e.close()})))),e.on("close",(()=>{i&&this.emit("ws.close"+r,{user:i,ws:e})})),yield s(2e3),i||e.close()})))))}))}middlewares(){this.app.use(m()),this.app.use(((e,t,r,s)=>e?(me.error(e.message,"api.express",!0),ve.error(r,"Internal Server Error")):s())),this.app.use(v({extended:!0})),this.app.disable("x-powered-by"),W&&this.app.use(l()),this.app.use("/api",this.router),this.app.all("/api/*",((e,t)=>ve.notfound(t,"Invalid API"))),F&&(g(F)&&this.app.use(h.static(F)),this.app.get("*",((e,t)=>{if(!g(F))return ve.notfound(t,'File "index.html" not found');t.sendFile(F+"/index.html")})))}server(){return this._server}websocket(){return this._webSocket}}class be{static all(){return x(this,void 0,void 0,(function*(){const e=yield le.findAll().catch((e=>{me.error(e.message,"api.config",!0)})),t={};return e&&e.forEach((e=>{t[e.key]=e.value})),t}))}static del(e){return x(this,void 0,void 0,(function*(){return((yield le.destroy({where:{key:e}}).catch((e=>{me.error(e.message,"api.config",!0)})))||0)>0}))}static get(e){return x(this,void 0,void 0,(function*(){const t=yield le.findOne({where:{key:e}}).catch((e=>{me.error(e.message,"api.config",!0)}));return t&&t.value||""}))}static set(e,t){return x(this,void 0,void 0,(function*(){const[r]=(yield le.findOrCreate({where:{key:e}}).catch((e=>{me.error(e.message,"api.config",!0)})))||[];r&&(r.value=t,yield r.save().catch((e=>{me.error(e.message,"api.config",!0)})))}))}}class _e{static all(e,t){return x(this,void 0,void 0,(function*(){return yield ae.findAll({where:Object.assign(Object.assign({},t),{state:!0}),include:[{model:de,required:!0,include:[{model:oe,required:!0,where:{state:!0},include:[{model:ce,required:!0,where:{userId:e.id}}]}]}]}).catch((e=>{me.error(e.message,"api.permission",!0)}))}))}static get(e){return x(this,void 0,void 0,(function*(){const t=yield _e.all(e);return t?t.map((e=>e.name)):[]}))}static is(e,t){return x(this,void 0,void 0,(function*(){const r=yield _e.all(e,{name:t});return r&&!!r.length}))}}const Se=(e,t)=>{const r=n()+"."+t;return g(q(e,r))?Se(e,t):r};class Ae{constructor(e){this.router=p(),this._path=e}auth(e,t,r){return x(this,void 0,void 0,(function*(){const s=e.get($)||"",{auth:i,error:n,user:o}=yield we.user(s);if(n)return ve.error(t,n);if(i&&o){const t=e.get("User-Agent");return t&&(i.useragent=t),yield i.save(),e.auth=i,e.user=o,r()}return ve.error(t,"Internal Server Error")}))}intialize(){}name(){return"api"}path(){return this._path}permission(e){return(t,r,s)=>x(this,void 0,void 0,(function*(){const i=t.user;return i?(yield _e.is(i,e))?s():ve.error(r,"Unauthorized access"):ve.unauthorized(r,"Access denied")}))}read(e=""){return this.permission((e||this.name())+".read")}upload(e){const t=(null==e?void 0:e.path)||te,r=P.diskStorage({destination:(e,r,s)=>s(null,t),filename:(e,r,s)=>x(this,void 0,void 0,(function*(){return s(null,Se(t,N.extension(r.mimetype)||"bin"))}))}),s=1e6*((null==e?void 0:e.size)||ee),i=P({storage:r,fileFilter(t,r,s){var i;return x(this,void 0,void 0,(function*(){const t=null===(i=null==e?void 0:e.types)||void 0===i?void 0:i.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)||Q,o=(null==e?void 0:e.field)||V,a=i.array(o,n);return(e,t,r)=>{a(e,t,(function(e){return e?ve.error(t,e.message):r()}))}}validation(e){return(t,r,s)=>x(this,void 0,void 0,(function*(){const{error:n,value:o}=yield i.object(e).validateAsync(t.body);return n?ve.validation(r,n):(t.body=o,s())}))}write(e=""){return this.permission((e||this.name())+".write")}}class Te extends Ae{constructor(){super(...arguments),this.attributes=["id","name","email","username"],this.query={username:i.string().min(4).required(),password:i.string().min(5).required()}}intialize(){this.router.get("/",this.auth,this.user.bind(this)),this.router.post("/login",this.validation(this.query),this.login.bind(this)),this.router.get("/logout",this.auth,this.logout.bind(this))}login(e,t){return x(this,void 0,void 0,(function*(){yield s(z);const{username:r,password:i}=e.body,n=yield ue.findOne({where:{username:r}}).catch((e=>{me.error(e.message,"api.controller."+this.name(),!0)}));if(!n)return ve.notfound(t,"Username not found");if(!n.state)return ve.error(t,"Username is disabled");const a=k(i).toString();if(n.password!=a)return ve.error(t,"Invalid password");const d=n.id,u=o(),{error:c,token:l}=we.sign({id:d,secret:u});if(c)return ve.error(t,c);if(l){const r=Date.now(),s=r+6e4*Z,i=e.get("User-Agent"),n=yield ne.create({login:r,secret:u,timestamp:s,useragent:i,userId:d}).catch((e=>{me.error(e.message,"api.controller."+this.name(),!0)}));if(n)return ve.data(t,{token:l})}return ve.error(t,"Internal Server Error")}))}logout(e,t){return x(this,void 0,void 0,(function*(){const r=e.auth;return r?(r.logout=Date.now(),r.timestamp=r.logout,yield r.save(),ve.success(t,"Disconcerted")):ve.unauthorized(t,"Access denied")}))}user(e,t){return x(this,void 0,void 0,(function*(){const r=e.user;if(!r)return ve.unauthorized(t,"Access denied");const s=yield _e.all(r);if(s){const e=a(this.attributes,r.toJSON()),i=s.map((e=>e.name));return ve.data(t,Object.assign(Object.assign({},e),{permissions:i}))}return ve.error(t,"Internal Server Error")}))}}class Ee extends Ae{add(){return(e,t)=>x(this,void 0,void 0,(function*(){if(!this._model)return ve.error(t,"Internal Server Error");const r=yield this._model.create(e.body).catch((e=>{me.error(e.message,"api.controller."+this.name(),!0)}));return r?ve.data(t,{id:r.id}):ve.error(t,"Internal Server Error")}))}all(e,t){return(r,s)=>x(this,void 0,void 0,(function*(){var i,n,o,a,l;if(!this._model)return ve.error(s,"Internal Server Error");const h=Object.assign({},e||{});h.where=Object.assign({},h.where||{});const p=null===(i=r.query.limit)||void 0===i?void 0:i.toString();p&&(h.limit=parseInt(p));const m=null===(n=r.query.offset)||void 0===n?void 0:n.toString();m&&(h.offset=parseInt(m));const v=Object.keys(this._model.getAttributes()),g=[],f=null===(o=r.query.asc)||void 0===o?void 0:o.toString();f&&f.length&&f.split(",").forEach((e=>{v.indexOf(e)>=0&&g.push([e,"ASC"])}));const y=null===(a=r.query.desc)||void 0===a?void 0:a.toString();y&&y.length&&y.split(",").forEach((e=>{v.indexOf(e)>=0&&g.push([e,"DESC"])})),g.length&&(h.order=g);const w=[],I=d(h.attributes)?h.attributes:v,b=null===(l=r.query.search)||void 0===l?void 0:l.toString();I.forEach((e=>{var t;if(u(e)&&(b&&b.length&&w.push({[e]:{[E.like]:`%${b}%`}}),"search_"+e in r.query)){const s=null===(t=r.query["search_"+e])||void 0===t?void 0:t.toString();s&&s.length&&w.push({[e]:{[E.like]:`%${s}%`}})}})),w.length&&(h.where=Object.assign(Object.assign({},h.where),{[E.or]:[...w]}));const _=yield this._model.findAll(h).catch((e=>{me.error(e.message,"api.controller."+this.name(),!0)})),S=yield this._model.count(h).catch(c);return _?ve.data(s,{count:S,records:t?t(_):_}):ve.error(s,"Internal Server Error")}))}del(){return(e,t)=>x(this,void 0,void 0,(function*(){if(!this._model)return ve.error(t,"Internal Server Error");const{id:r}=e.params;return(yield this._model.destroy({where:{id:r}}).catch((e=>{me.error(e.message,"api.controller."+this.name(),!0)})))?ve.success(t,"OK"):ve.notfound(t,"Record not found")}))}get(e,t){return(r,s)=>x(this,void 0,void 0,(function*(){if(!this._model)return ve.error(s,"Internal Server Error");e||(e={});const i=Object.assign({},e);i.where=i.where?Object.assign({},i.where):{};const{id:n}=r.params,o=yield this._model.findByPk(n,i).catch((e=>{me.error(e.message,"api.controller."+this.name(),!0)}));return o?ve.data(s,t?t(o):o.toJSON()):null===o?ve.notfound(s,"Record not found"):ve.error(s,"Internal Server Error")}))}name(){var e;return this._model?null===(e=this._model)||void 0===e?void 0:e.tableName:super.name()}set(){return(e,t)=>x(this,void 0,void 0,(function*(){if(!this._model)return ve.error(t,"Internal Server Error");const{id:r}=e.params,[s]=(yield this._model.update(e.body,{where:{id:r}}).catch((e=>{me.error(e.message,"api.controller."+this.name(),!0)})))||[];return s?ve.success(t,"OK"):ve.success(t,"Record not changed")}))}getModel(){return this._model}setModel(e){this._model=e}}class Oe extends Ee{intialize(){const e=this.model();e&&this.setModel(e),this.router.use(this.auth),this.router.get("/",this.read(),this.all().bind(this)),this.router.post("/",this.write(),this.validation(this.create()),this.add().bind(this)),this.router.route("/:id").get(this.read(),this.get().bind(this)).put(this.write(),this.validation(this.update()),this.set().bind(this)).delete(this.write(),this.del().bind(this))}}class Re extends Oe{create(){return{name:i.string().required(),description:i.string().empty(""),state:i.boolean().required()}}model(){return oe}update(){return{name:i.string().empty(),description:i.string().empty(),state:i.boolean().empty()}}}class Ne extends Ee{constructor(){super(...arguments),this.groups={groups:i.array().items(i.number())}}intialize(){this.setModel(de),this.router.use(this.auth),this.router.route("/:id/groups").get(this.read("users"),this.groupRouteAll.bind(this)).put(this.write("users"),this.validation(this.groups),this.groupRouteSet.bind(this))}groupRouteAll(e,t){return x(this,void 0,void 0,(function*(){const{id:r}=e.params;return this.all({where:{groupId:r},include:[{model:ae,required:!0}]},(e=>e.map((e=>e.route))))(e,t)}))}groupRouteSet(e,t){return x(this,void 0,void 0,(function*(){const{id:r}=e.params,{routes:s}=e.body,i=yield oe.findByPk(r,{attributes:["id"]}).catch((e=>{me.error(e.message,"api.controller."+this.name(),!0)}));if(i){const e=i.id;if(yield de.destroy({where:{groupId:e}}),s){let t=0;for(let r=0;r<s.length;r++)t=yield ae.count({where:{id:s[r]}}),t&&(yield de.create({groupId:e,routeId:s[r]}))}return ve.success(t,"OK")}return null===i?ve.notfound(t,"Record not found"):ve.error(t,"Internal Server Error")}))}}class Pe extends Ee{intialize(){this.setModel(he),this.router.use(this.auth),this.router.get("/",this.read("logs"),this.logsAll.bind(this))}logsAll(e,t){return x(this,void 0,void 0,(function*(){const{source:r,type:s}=e.query,i=r&&s?{source:r,type:s}:r?{source:r}:s?{type:s}:{};return this.all({where:i,order:[["created","DESC"]]})(e,t)}))}}class qe extends Oe{create(){return{name:i.string().required(),description:i.string().empty(""),state:i.boolean().required()}}model(){return ae}update(){return{name:i.string().empty(),description:i.string().empty(),state:i.boolean().empty()}}}class ke extends Ee{constructor(){super(...arguments),this.attributes=["id","name","email","username","description","state"],this.create={name:i.string().required(),email:i.string().email().required(),username:i.string().min(4).required(),password:i.string().min(5).required(),description:i.string().required(),state:i.boolean().required()},this.update={name:i.string().empty(),email:i.string().email().empty(),username:i.string().min(4).empty(),password:i.string().min(5).empty(),description:i.string().empty(),state:i.boolean().empty()}}intialize(){this.setModel(ue),this.router.use(this.auth),this.router.get("/",this.read(),this.userAll.bind(this)),this.router.post("/",this.write(),this.validation(this.create),this.userAdd.bind(this)),this.router.route("/:id").get(this.read(),this.userGet.bind(this)).put(this.write(),this.validation(this.update),this.userSet.bind(this)).delete(this.write(),this.userDel.bind(this))}userAdd(e,t){return x(this,void 0,void 0,(function*(){return e.body.password=k(e.body.password).toString(),yield this.add()(e,t)}))}userAll(e,t){return x(this,void 0,void 0,(function*(){return this.all({attributes:this.attributes})(e,t)}))}userDel(e,t){return x(this,void 0,void 0,(function*(){const r=e.user;if(r){const{id:s}=e.params;if(r.id.toString()!=s)return this.del()(e,t)}return ve.error(t,"Internal Server Error")}))}userGet(e,t){return x(this,void 0,void 0,(function*(){return this.get({attributes:this.attributes})(e,t)}))}userSet(e,t){return x(this,void 0,void 0,(function*(){return e.body.password&&(e.body.password=k(e.body.password).toString()),this.set()(e,t)}))}}class xe extends Ee{constructor(){super(...arguments),this.groups={groups:i.array(i.number())}}intialize(){this.setModel(ce),this.router.use(this.auth),this.router.route("/:id/groups").get(this.read("groups"),this.userGroupsAll.bind(this)).put(this.write("groups"),this.validation(this.groups),this.userGroupsSet.bind(this))}userGroupsAll(e,t){return x(this,void 0,void 0,(function*(){const{id:r}=e.params;return this.all({where:{userId:r},include:[{model:oe,required:!0}]},(e=>e.map((e=>e.group))))(e,t)}))}userGroupsSet(e,t){return x(this,void 0,void 0,(function*(){const{id:r}=e.params,{groups:s}=e.body,i=yield ue.findByPk(r,{attributes:["id"]}).catch((e=>{me.error(e.message,"api.controller."+this.name(),!0)}));if(i){if(yield ce.destroy({where:{userId:i.id}}),s){let e=0;for(let t=0;t<s.length;t++)e=yield oe.count({where:{id:s[t]}}),e&&(yield ce.create({userId:i.id,groupId:s[t]}))}return ve.success(t,"OK")}return ve.notfound(t,"Record not found")}))}}export{z as API_AUTH_SLEEP,D as API_DB_DATABASE,G as API_DB_HOST,L as API_DB_LOG,j as API_DB_PASSWORD,B as API_DB_PORT,C as API_DB_TYPE,M as API_DB_USERNAME,W as API_HTTP_CROSS,U as API_HTTP_CRT,X as API_HTTP_HYBRID,H as API_HTTP_KEY,K as API_HTTP_PORT,F as API_HTTP_PUBLIC,Y as API_TOKEN_CRT,$ as API_TOKEN_HEADER,J as API_TOKEN_KEY,Z as API_TOKEN_LIFETIME,Q as API_UPLOAD_COUNT,V as API_UPLOAD_FIELD,ee as API_UPLOAD_SIZE,te as API_UPLOAD_TEMP,re as API_WEBSOCKET_START,Ie as App,ne as Auth,Te as AuthController,be as Config,le as Configs,Ae as Controller,Oe as CrudController,se as Database,oe as Group,Re as GroupController,de as GroupRoute,Ne as GroupRouteController,me as Log,he as Logs,Pe as LogsController,Ee as ModelController,_e as Permission,ve as Responses,ae as Route,qe as RouteController,we as Token,ue as User,ke as UserController,ce as UserGroup,xe as UserGroupController,fe as crt,ye as key,ie as sequelize};
|
|
7
|
+
import{toBool as e,dateFormat as t,EventEmitter as r,sleep as s,Validation as i,uuidv4 as n,uniqueID as o,allowedObject as a,isArray as d,isString as u,noop as c,isNull as l,forEachSeries as h}from"@andrewcaires/utils.js";import p from"cors";import m,{Router as v,json as g,urlencoded as f}from"express";import{existsSync as y,readFileSync as w}from"fs";import*as I from"http";import*as b from"https";import{Server as A}from"net";import _ from"ws";import{config as S}from"dotenv";import{Sequelize as O,DataTypes as q,Model as E,Op as T}from"sequelize";import{sign as R,verify as N}from"jsonwebtoken";import P from"mime-types";import k from"multer";import{join as x}from"path";import{SHA256 as G}from"crypto-js";function j(e,t,r,s){return new(r||(r=Promise))((function(i,n){function o(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?i(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(o,a)}d((s=s.apply(e,t||[])).next())}))}S();const z=e(process.env.API_CONSOLE_ERROR||"false"),D=process.env.API_DB_DATABASE||"",B=process.env.API_DB_HOST||"127.0.0.1",L=process.env.API_DB_PASSWORD||"",U=parseInt(process.env.API_DB_PORT||"3306"),C=process.env.API_DB_TYPE||"",M=process.env.API_DB_USERNAME||"root",K=e(process.env.API_DB_LOG||"false"),H=process.env.API_TABLE_PREFIX||"",F=process.env.API_HTTP_CRT||"",X=process.env.API_HTTP_KEY||"",Y=parseInt(process.env.API_HTTP_PORT||"3000"),W=process.env.API_HTTP_PUBLIC||"",J=e(process.env.API_HTTP_CROSS||"false"),$=e(process.env.API_HTTP_HYBRID||"false"),Z=parseInt(process.env.API_SLEEP_AUTH||"1000"),Q=parseInt(process.env.API_SLEEP_FORGOT||"5000"),V=parseInt(process.env.API_SLEEP_REGISTRY||"5000"),ee=process.env.API_TOKEN_CRT||"",te=process.env.API_TOKEN_KEY||"",re=process.env.API_TOKEN_HEADER||"authorization",se=parseInt(process.env.API_TOKEN_LIFETIME||"15"),ie=parseInt(process.env.API_UPLOAD_COUNT||"1"),ne=process.env.API_UPLOAD_FIELD||"upload",oe=parseInt(process.env.API_UPLOAD_SIZE||"2"),ae=process.env.API_UPLOAD_TEMP||"./temp",de=e(process.env.API_WEBSOCKET_START||"false");class ue{static connect(e){const t=C.toLowerCase();if("connect_"+t in ue)return ue["connect_"+t](e);throw new Error("No database is connected to this API")}static connect_mariadb(e){return new O(e.database,e.username,e.password,{host:e.hostname,port:e.hostport,dialect:"mariadb",logging:K,define:{timestamps:!1}})}static connect_memory(){return new O("sqlite::memory:",{logging:K,define:{timestamps:!1}})}static connect_mysql(e){return new O(e.database,e.username,e.password,{host:e.hostname,port:e.hostport,dialect:"mysql",logging:K,define:{timestamps:!1}})}static connect_postgres(e){return new O(e.database,e.username,e.password,{host:e.hostname,port:e.hostport,dialect:"postgres",logging:K,define:{timestamps:!1}})}static connect_sqlite(e){return new O({dialect:"sqlite",storage:e.database,logging:K,define:{timestamps:!1}})}}const ce=ue.connect({database:D,username:M,password:L,hostname:B,hostport:U});class le extends E{}le.init({login:q.BIGINT,logout:q.BIGINT,secret:q.STRING,timestamp:q.BIGINT,useragent:q.STRING},{sequelize:ce,modelName:H+"auth",timestamps:!0,createdAt:"created",updatedAt:"updated"});class he extends E{}he.init({token:q.STRING,timestamp:q.BIGINT,state:q.BOOLEAN},{sequelize:ce,modelName:H+"forgot",timestamps:!0,createdAt:"created",updatedAt:"updated"});class pe extends E{}pe.init({name:q.STRING,description:q.TEXT,state:q.BOOLEAN},{sequelize:ce,modelName:H+"group",timestamps:!0,createdAt:"created",updatedAt:"updated"});class me extends E{}me.init({name:q.STRING,description:q.TEXT,state:q.BOOLEAN},{sequelize:ce,modelName:H+"route",timestamps:!0,createdAt:"created",updatedAt:"updated"});class ve extends E{}ve.init({},{sequelize:ce,modelName:H+"groups_routes",timestamps:!0,createdAt:"created",updatedAt:!1}),ve.removeAttribute("id");class ge extends E{}ge.init({name:q.STRING,email:q.STRING,username:q.STRING,password:q.STRING,avatar:q.STRING,description:q.TEXT,state:q.BOOLEAN},{sequelize:ce,modelName:H+"user",timestamps:!0,createdAt:"created",updatedAt:"updated"});class fe extends E{}fe.init({},{sequelize:ce,modelName:H+"users_groups",timestamps:!0,createdAt:"created",updatedAt:!1}),fe.removeAttribute("id");class ye extends E{}ye.init({key:q.STRING,value:q.STRING},{sequelize:ce,modelName:H+"configs",timestamps:!0,createdAt:"created",updatedAt:"updated"}),ye.removeAttribute("id");class we extends E{}var Ie;we.init({type:q.STRING,source:q.STRING,message:q.TEXT},{sequelize:ce,modelName:H+"logs",timestamps:!0,createdAt:"created",updatedAt:!1}),ge.hasMany(le),le.belongsTo(ge),ge.hasMany(he),he.belongsTo(ge),pe.hasMany(ve),ve.belongsTo(pe),me.hasMany(ve),ve.belongsTo(me),ge.hasMany(fe),fe.belongsTo(ge),pe.hasMany(fe),fe.belongsTo(pe),function(e){e.ERROR="[31m",e.INFO="[36m",e.NONE="[37m",e.SUCCESS="[32m",e.WARNING="[33m"}(Ie||(Ie={}));class be{static write(e,t,r){return j(this,void 0,void 0,(function*(){yield be.writeRaw(Ie.NONE,"",e,t,r)}))}static error(e,t,r){return j(this,void 0,void 0,(function*(){yield be.writeRaw(Ie.ERROR,"error",e,t,r)}))}static info(e,t,r){return j(this,void 0,void 0,(function*(){yield be.writeRaw(Ie.INFO,"info",e,t,r)}))}static success(e,t,r){return j(this,void 0,void 0,(function*(){yield be.writeRaw(Ie.ERROR,"success",e,t,r)}))}static warning(e,t,r){return j(this,void 0,void 0,(function*(){yield be.writeRaw(Ie.WARNING,"warning",e,t,r)}))}static writeConsole(e,r,s){const i=t(new Date,"%H:%M:%S");console.log(">",e,r+" ".repeat(10-r.length),"[37m","|",i,"|",s)}static writeRaw(e,t,r,s,i){return j(this,void 0,void 0,(function*(){i&&be.writeConsole(e,t,r),ce&&(yield we.create({type:t,source:s,message:r}).catch((()=>null)))}))}}class Ae{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){return e.status(400).json({message:t})}static unauthorized(e,t){return e.status(401).json({message:t})}}const _e=e=>y(e)?w(e):void 0,Se={http:_e(F),token:_e(ee)},Oe={http:_e(X),token:_e(te)};class qe{static error(e){be.error(e.message,"api.token",z)}static sign(e){return Oe.token?{token:R(e,Oe.token,{algorithm:"RS256"})}:{error:"Invalid Secret"}}static user(e){return j(this,void 0,void 0,(function*(){const{error:t,decode:r}=qe.verify(e);if(t)return{error:t};if(r){const{id:e,secret:t}=r;if(e&&r){const r=yield ge.findOne({where:{id:e,state:!0}}).catch(qe.error);if(r){const e=yield le.findOne({where:{secret:t,userId:r.id}}).catch(qe.error);if(e){const t=Date.now();if(t>e.timestamp)return e.logout=t,yield e.save(),{error:"Expired token"};if(e.timestamp=t+6e4*se,!e.logout)return yield e.save(),{auth:e,user:r}}}return{error:"Access denied"}}}return{error:"Invalid token"}}))}static verify(e){if(!Se.token)return{error:"Invalid Secret"};if(!e||e.split(".").length<3)return{error:"Invalid Token"};try{return{decode:N(e,Se.token)}}catch(e){return{error:"Invalid Token"}}}}class Ee extends r{constructor(e){super(),this.app=m(),this.router=v(),this.middlewares(),this.controllers(e)}controllers(e){e.forEach((e=>{e.intialize(this),this.router.use(e.path(),e.router)}))}listen(){return j(this,void 0,void 0,(function*(){if(yield ce.sync(),Se.http&&Oe.http||(this._server=I.createServer(this.app),this._server.listen(Y,(()=>be.info("Server started on port "+Y,"api.server",!0)))),!this._server){const e=I.createServer(((e,t)=>{const r=80==Y?":80":"";t.writeHead(301,{Location:"https://"+e.headers.host+r+e.url}),t.end()})),t=b.createServer({key:Oe.http,cert:Se.http},this.app);if($){new A((r=>{r.once("data",(s=>{r.pause(),r.unshift(s),(22===s[0]?t:e).emit("connection",r),process.nextTick((()=>r.resume()))}))})).listen(Y,(()=>be.info("Server started on port "+Y,"api.server",!0))),this._server=t}this._server||(443==Y&&e.listen(80,(()=>be.info("Server started on port 80","api.server",!0))),t.listen(Y,(()=>be.info("Server started on port "+Y,"api.server",!0))),this._server=t)}de&&this._server&&(this._webSocket=new _.Server({server:this._server,verifyClient:(e,t)=>t(de)}),this._webSocket.on("connection",((e,t)=>j(this,void 0,void 0,(function*(){t.url||(t.url="");const r=t.url.length<=1?"":t.url.replace(/\//g,".");let i;e.on("message",(s=>j(this,void 0,void 0,(function*(){if(i)try{const n=JSON.parse(s);this.emit("ws.message"+r,{data:n,message:s,req:t,user:i,ws:e})}catch(n){this.emit("ws.message"+r,{message:s,req:t,user:i,ws:e})}else{const{user:n}=yield qe.user(s.toString());n&&(i=n,this.emit("ws.connection"+r,{req:t,user:i,ws:e}))}i||e.close()})))),e.on("close",(()=>{i&&this.emit("ws.close"+r,{user:i,ws:e})})),yield s(2e3),i||e.close()})))))}))}middlewares(){this.app.use(g()),this.app.use(((e,t,r,s)=>e?(be.error(e.message,"api.express",z),Ae.error(r,"Internal Server Error")):s())),this.app.use(f({extended:!0})),this.app.disable("x-powered-by"),J&&this.app.use(p()),this.app.use("/api",this.router),this.app.all("/api/*",((e,t)=>Ae.notfound(t,"Invalid API"))),W&&(y(W)&&this.app.use(m.static(W)),this.app.get("*",((e,t)=>{if(!y(W))return Ae.notfound(t,'File "index.html" not found');t.sendFile(W+"/index.html")})))}server(){return this._server}websocket(){return this._webSocket}}class Te{static all(){return j(this,void 0,void 0,(function*(){const e=yield ye.findAll().catch(Te.error),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 ye.destroy({where:{key:e}}).catch(Te.error))||0)>0}))}static error(e){be.error(e.message,"api.config",z)}static get(e){return j(this,void 0,void 0,(function*(){const t=yield ye.findOne({where:{key:e}}).catch(Te.error);return t&&t.value||""}))}static set(e,t){return j(this,void 0,void 0,(function*(){const[r]=(yield ye.findOrCreate({where:{key:e}}).catch(Te.error))||[];r&&(r.value=t,yield r.save().catch(Te.error))}))}}class Re{static all(e,t){return j(this,void 0,void 0,(function*(){return yield me.findAll({where:Object.assign(Object.assign({},t),{state:!0}),include:[{model:ve,required:!0,include:[{model:pe,required:!0,where:{state:!0},include:[{model:fe,required:!0,where:{userId:e.id}}]}]}]}).catch((e=>{be.error(e.message,"api.permission",z)}))}))}static get(e){return j(this,void 0,void 0,(function*(){const t=yield Re.all(e);return t?t.map((e=>e.name)):[]}))}static is(e,t){return j(this,void 0,void 0,(function*(){const r=yield Re.all(e,{name:t});return!!r&&r.length>0}))}}const Ne=(e,t)=>{const r=n()+"."+t;return y(x(e,r))?Ne(e,t):r};class Pe extends r{constructor(e){super(),this.router=v(),this._path=e}auth(){return(e,t,r)=>j(this,void 0,void 0,(function*(){const s=e.get(re)||"",{auth:i,error:n,user:o}=yield qe.user(s);if(n)return Ae.error(t,n);if(i&&o){const t=e.get("User-Agent");return t&&(i.useragent=t),yield i.save(),e.auth=i,e.user=o,r()}return Ae.error(t,"Internal Server Error")}))}error(e){be.error(e.message,"api.controller."+this.name(),z)}name(){return"api"}path(){return this._path}permission(e){return(t,r,s)=>j(this,void 0,void 0,(function*(){const i=t.user;return i?(yield Re.is(i,e))?s():Ae.error(r,"Unauthorized access"):Ae.unauthorized(r,"Access denied")}))}read(e=""){return this.permission((e||this.name())+".read")}upload(e){const t=(null==e?void 0:e.path)||ae,r=k.diskStorage({destination:(e,r,s)=>s(null,t),filename:(e,r,s)=>j(this,void 0,void 0,(function*(){return s(null,Ne(t,P.extension(r.mimetype)||"bin"))}))}),s=1e6*((null==e?void 0:e.size)||oe),i=k({storage:r,fileFilter(t,r,s){var i;return j(this,void 0,void 0,(function*(){const t=null===(i=null==e?void 0:e.types)||void 0===i?void 0:i.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)||ie,o=(null==e?void 0:e.field)||ne,a=i.array(o,n);return(e,t,r)=>{a(e,t,(function(e){return e?Ae.error(t,e.message):r()}))}}validation(e){return(t,r,s)=>j(this,void 0,void 0,(function*(){const{error:n,value:o}=yield i.object(e).validateAsync(t.body);return n?Ae.validation(r,n):(t.body=o,s())}))}write(e=""){return this.permission((e||this.name())+".write")}}class ke extends Pe{constructor(){super(...arguments),this.attributes=["id","name","email","username","avatar"],this.query={username:i.string().min(4).required(),password:i.string().min(5).required()}}intialize(){this.router.get("/",this.auth(),this.user.bind(this)),this.router.post("/login",this.validation(this.query),this.login.bind(this)),this.router.get("/logout",this.auth(),this.logout.bind(this))}login(e,t){return j(this,void 0,void 0,(function*(){yield s(Z);const{username:r,password:i}=e.body,n=yield ge.findOne({where:{username:r}}).catch(this.error);if(!n)return Ae.notfound(t,"Username not found");if(!n.state)return Ae.error(t,"Username is disabled");const a=G(i).toString();if(n.password!=a)return Ae.error(t,"Invalid password");const d=n.id,u=o(),{error:c,token:l}=qe.sign({id:d,secret:u});if(c)return Ae.error(t,c);if(l){const r=Date.now(),s=r+6e4*se,i=e.get("User-Agent"),o=yield le.create({login:r,secret:u,timestamp:s,useragent:i,userId:d}).catch(this.error);if(o)return this.emit("login",{auth:o,req:e,user:n}),Ae.data(t,{token:l})}return Ae.error(t,"Internal Server Error")}))}logout(e,t){return j(this,void 0,void 0,(function*(){const r=e.auth,s=e.user;return r&&s&&!r.logout?(r.logout=Date.now(),r.timestamp=r.logout,yield r.save(),this.emit("logout",{auth:r,req:e,user:s}),Ae.success(t,"Disconcerted")):Ae.unauthorized(t,"Access denied")}))}user(e,t){return j(this,void 0,void 0,(function*(){const r=e.user;if(!r)return Ae.unauthorized(t,"Access denied");const s=yield Re.all(r);if(s){const i=a(this.attributes,r.toJSON()),n=s.map((e=>e.name));return this.emit("user",{req:e,user:r}),Ae.data(t,Object.assign(Object.assign({},i),{permissions:n}))}return Ae.error(t,"Internal Server Error")}))}}class xe extends Pe{constructor(){super(...arguments),this.username={username:i.string().min(4).required()},this.password={token:i.string().required(),password:i.string().min(5).required()},this.query={token:i.string().required()}}intialize(){this.router.post("/",this.validation(this.username),this.forgot.bind(this)),this.router.post("/check",this.validation(this.query),this.check.bind(this)),this.router.post("/reset",this.validation(this.password),this.reset.bind(this))}check(e,t){return j(this,void 0,void 0,(function*(){const{token:r}=e.body,s=yield this.findOne(r);return s&&s.user?(s.token=o(),yield s.save(),Ae.data(t,{token:s.token})):Ae.notfound(t,"User not found")}))}forgot(e,t){return j(this,void 0,void 0,(function*(){const{username:r}=e.body;yield s(Q);const i=yield ge.findOne({where:{username:r}}).catch(this.error);if(!i)return Ae.notfound(t,"User not found");const n=o(),a=Date.now()+6e4*se,d=yield he.create({token:n,timestamp:a,state:!0,userId:i.id});return this.emit("forgot",{forgot:d,req:e,user:i}),Ae.success(t,"OK")}))}findOne(e){return j(this,void 0,void 0,(function*(){return yield he.findOne({where:{token:e,state:!0},include:[{model:ge,required:!0}]}).catch(this.error)}))}reset(e,t){return j(this,void 0,void 0,(function*(){const{token:r,password:s}=e.body,i=yield this.findOne(r);return i?(i.state=!1,yield i.save().catch(this.error),i.user.password=G(s).toString(),yield i.user.save().catch(this.error),this.emit("reset",{req:e,user:i.user}),Ae.success(t,"OK")):Ae.notfound(t,"User not found")}))}}class Ge extends Pe{add(){return(e,t)=>j(this,void 0,void 0,(function*(){if(!this._model)return Ae.error(t,"Internal Server Error");const r=yield this._model.create(e.body).catch(this.error);return r?(this.emit("add",{req:e,record:r}),Ae.data(t,{id:r.id})):Ae.error(t,"Internal Server Error")}))}all(e,t){return(r,s)=>j(this,void 0,void 0,(function*(){var i,n,o,a,l;if(!this._model)return Ae.error(s,"Internal Server Error");const h=Object.assign({},e||{});h.where=Object.assign({},h.where||{});const p=null===(i=r.query.limit)||void 0===i?void 0:i.toString();p&&(h.limit=parseInt(p));const m=null===(n=r.query.offset)||void 0===n?void 0:n.toString();m&&(h.offset=parseInt(m));const v=Object.keys(this._model.getAttributes()),g=[],f=null===(o=r.query.asc)||void 0===o?void 0:o.toString();f&&f.length&&f.split(",").forEach((e=>{v.indexOf(e)>=0&&g.push([e,"ASC"])}));const y=null===(a=r.query.desc)||void 0===a?void 0:a.toString();y&&y.length&&y.split(",").forEach((e=>{v.indexOf(e)>=0&&g.push([e,"DESC"])})),g.length&&(h.order=g);const w=[],I=d(h.attributes)?h.attributes:v,b=null===(l=r.query.search)||void 0===l?void 0:l.toString();I.forEach((e=>{var t;if(u(e)&&(b&&b.length&&w.push({[e]:{[T.like]:`%${b}%`}}),"search_"+e in r.query)){const s=null===(t=r.query["search_"+e])||void 0===t?void 0:t.toString();s&&s.length&&w.push({[e]:{[T.like]:`%${s}%`}})}})),w.length&&(h.where=Object.assign(Object.assign({},h.where),{[T.or]:[...w]}));const A=yield this._model.findAll(h).catch(this.error),_=yield this._model.count(h).catch(c);return A?(this.emit("all",{req:r,records:A}),Ae.data(s,{count:_,records:t?t(A):A})):Ae.error(s,"Internal Server Error")}))}del(){return(e,t)=>j(this,void 0,void 0,(function*(){if(!this._model)return Ae.error(t,"Internal Server Error");const{id:r}=e.params;return(yield this._model.destroy({where:{id:r}}).catch(this.error))?(this.emit("del",{req:e,id:r}),Ae.success(t,"OK")):Ae.notfound(t,"Record not found")}))}get(e,t){return(r,s)=>j(this,void 0,void 0,(function*(){if(!this._model)return Ae.error(s,"Internal Server Error");e||(e={});const i=Object.assign({},e);i.where=i.where?Object.assign({},i.where):{};const{id:n}=r.params,o=yield this._model.findByPk(n,i).catch(this.error);return o?(this.emit("get",{req:r,record:o}),Ae.data(s,t?t(o):o.toJSON())):null===o?Ae.notfound(s,"Record not found"):Ae.error(s,"Internal Server Error")}))}name(){var e;return this._model?null===(e=this._model)||void 0===e?void 0:e.tableName:super.name()}set(){return(e,t)=>j(this,void 0,void 0,(function*(){if(!this._model)return Ae.error(t,"Internal Server Error");const{id:r}=e.params,[s]=(yield this._model.update(e.body,{where:{id:r}}).catch(this.error))||[];return s?(this.emit("set",{req:e,id:r}),Ae.success(t,"OK")):Ae.success(t,"Record not changed")}))}getModel(){return this._model}setModel(e){this._model=e}}class je extends Ge{intialize(){const e=this.model();e&&this.setModel(e),this.router.use(this.auth()),this.router.get("/",this.read(),this.all().bind(this)),this.router.post("/",this.write(),this.validation(this.create()),this.add().bind(this)),this.router.route("/:id").get(this.read(),this.get().bind(this)).put(this.write(),this.validation(this.update()),this.set().bind(this)).delete(this.write(),this.del().bind(this))}}class ze extends je{create(){return{name:i.string().required(),description:i.string().empty(""),state:i.boolean().parse().required()}}model(){return pe}update(){return{name:i.string().empty(),description:i.string().empty(),state:i.boolean().parse().empty()}}}class De extends Ge{constructor(){super(...arguments),this.groups={groups:i.array().items(i.number())}}intialize(){this.setModel(ve),this.router.use(this.auth()),this.router.route("/:id/groups").get(this.read("users"),this.groupRouteAll.bind(this)).put(this.write("users"),this.validation(this.groups),this.groupRouteSet.bind(this))}groupRouteAll(e,t){return j(this,void 0,void 0,(function*(){const{id:r}=e.params;return this.all({where:{groupId:r},include:[{model:me,required:!0}]},(e=>e.map((e=>e.route))))(e,t)}))}groupRouteSet(e,t){return j(this,void 0,void 0,(function*(){const{id:r}=e.params,{routes:s}=e.body,i=yield pe.findByPk(r,{attributes:["id"]}).catch(this.error);if(i){const e=i.id;if(yield ve.destroy({where:{groupId:e}}),s){let t=0;for(let r=0;r<s.length;r++)t=yield me.count({where:{id:s[r]}}),t&&(yield ve.create({groupId:e,routeId:s[r]}))}return Ae.success(t,"OK")}return l(i)?Ae.notfound(t,"Record not found"):Ae.error(t,"Internal Server Error")}))}}class Be extends Ge{intialize(){this.setModel(we),this.router.use(this.auth()),this.router.get("/",this.read("logs"),this.logsAll.bind(this))}logsAll(e,t){return j(this,void 0,void 0,(function*(){const{source:r,type:s}=e.query,i=r&&s?{source:r,type:s}:r?{source:r}:s?{type:s}:{};return this.all({where:i,order:[["created","DESC"]]})(e,t)}))}}class Le extends E{}Le.init({token:q.STRING,timestamp:q.BIGINT,state:q.BOOLEAN},{sequelize:ce,modelName:H+"registry",timestamps:!0,createdAt:"created",updatedAt:"updated"});class Ue extends Pe{constructor(){super(...arguments),this.create={name:i.string().required(),email:i.string().email().required(),username:i.string().min(4).required(),password:i.string().min(5).required()},this.query={token:i.string().required()}}intialize(){this.router.post("/",this.validation(this.create),this.register.bind(this)),this.router.post("/confirm",this.validation(this.query),this.confirm.bind(this))}confirm(e,t){return j(this,void 0,void 0,(function*(){const{token:r}=e.body,s=yield Le.findOne({where:{token:r,state:!0},include:[{model:ge,required:!0}]}).catch(this.error);return s?(s.user.state=!0,yield s.user.save().catch(this.error),this.emit("confirm",{req:e,user:s.user}),Ae.success(t,"OK")):Ae.notfound(t,"User not found")}))}register(e,t){return j(this,void 0,void 0,(function*(){const{username:r}=e.body;yield s(Q);const i=yield ge.findOne({where:{username:r}}).catch(this.error);if(i)return Ae.error(t,"Invalid Username");if(!l(i))return Ae.error(t,"Internal Server Error");const n=yield ge.create(Object.assign(Object.assign({},e.body),{state:!1}));return this.emit("register",{req:e,user:n}),Ae.success(t,"OK")}))}}class Ce extends je{create(){return{name:i.string().required(),description:i.string().empty(""),state:i.boolean().parse().required()}}model(){return me}update(){return{name:i.string().empty(),description:i.string().empty(),state:i.boolean().empty()}}}class Me extends Pe{intialize(){this.router.get("/",this.setup.bind(this))}setup(e,t){return j(this,void 0,void 0,(function*(){if(0==(yield ge.count())){const e={description:"",state:!0},t=yield ge.create(Object.assign({name:"Admin",email:"admin@localhost",username:"admin",password:"8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918",avatar:""},e)),r=yield pe.create(Object.assign({name:"admin"},e));yield fe.create({userId:t.id,groupId:r.id});const s=["read","write"],i=["users","groups","routes"];yield h(i,(t=>j(this,void 0,void 0,(function*(){yield h(s,(s=>j(this,void 0,void 0,(function*(){const i=t+"."+s,n=yield me.create(Object.assign({name:i},e));yield ve.create({groupId:r.id,routeId:n.id})}))))}))));const n=yield me.create(Object.assign({name:"logs.read"},e));yield ve.create({groupId:r.id,routeId:n.id})}return Ae.success(t,"OK")}))}}class Ke extends Ge{constructor(){super(...arguments),this.attributes=["id","name","email","username","avatar","description","state","created","updated"],this.create={name:i.string().required(),email:i.string().email().required(),username:i.string().min(4).required(),password:i.string().min(5).required(),description:i.string().required(),state:i.boolean().parse().required()},this.update={name:i.string().empty(),email:i.string().email().empty(),username:i.string().min(4).empty(),password:i.string().min(5).empty(),description:i.string().empty(),state:i.boolean().parse().empty()}}intialize(){this.setModel(ge),this.router.use(this.auth()),this.router.get("/",this.read(),this.userAll.bind(this)),this.router.post("/",this.write(),this.validation(this.create),this.userAdd.bind(this)),this.router.route("/:id").get(this.read(),this.userGet.bind(this)).put(this.write(),this.validation(this.update),this.userSet.bind(this)).delete(this.write(),this.userDel.bind(this))}userAdd(e,t){return j(this,void 0,void 0,(function*(){return e.body.password=G(e.body.password).toString(),yield this.add()(e,t)}))}userAll(e,t){return j(this,void 0,void 0,(function*(){return this.all({attributes:this.attributes})(e,t)}))}userDel(e,t){return j(this,void 0,void 0,(function*(){const r=e.user;if(r){const{id:s}=e.params;if(r.id.toString()!=s)return this.del()(e,t)}return Ae.error(t,"Internal Server Error")}))}userGet(e,t){return j(this,void 0,void 0,(function*(){return this.get({attributes:this.attributes})(e,t)}))}userSet(e,t){return j(this,void 0,void 0,(function*(){return e.body.password&&(e.body.password=G(e.body.password).toString()),this.set()(e,t)}))}}class He extends Ge{constructor(){super(...arguments),this.groups={groups:i.array(i.number())}}intialize(){this.setModel(fe),this.router.use(this.auth()),this.router.route("/:id/groups").get(this.read("groups"),this.userGroupsAll.bind(this)).put(this.write("groups"),this.validation(this.groups),this.userGroupsSet.bind(this))}userGroupsAll(e,t){return j(this,void 0,void 0,(function*(){const{id:r}=e.params;return this.all({where:{userId:r},include:[{model:pe,required:!0}]},(e=>e.map((e=>e.group))))(e,t)}))}userGroupsSet(e,t){return j(this,void 0,void 0,(function*(){const{id:r}=e.params,{groups:s}=e.body,i=yield ge.findByPk(r,{attributes:["id"]}).catch(this.error);if(i){if(yield fe.destroy({where:{userId:i.id}}),s){let e=0;for(let t=0;t<s.length;t++)e=yield pe.count({where:{id:s[t]}}),e&&(yield fe.create({userId:i.id,groupId:s[t]}))}return Ae.success(t,"OK")}return l(i),Ae.notfound(t,"Record not found")}))}}export{z as API_CONSOLE_ERROR,D as API_DB_DATABASE,B as API_DB_HOST,K as API_DB_LOG,L as API_DB_PASSWORD,U as API_DB_PORT,C as API_DB_TYPE,M as API_DB_USERNAME,J as API_HTTP_CROSS,F as API_HTTP_CRT,$ as API_HTTP_HYBRID,X as API_HTTP_KEY,Y as API_HTTP_PORT,W as API_HTTP_PUBLIC,Z as API_SLEEP_AUTH,Q as API_SLEEP_FORGOT,V as API_SLEEP_REGISTRY,H as API_TABLE_PREFIX,ee as API_TOKEN_CRT,re as API_TOKEN_HEADER,te as API_TOKEN_KEY,se as API_TOKEN_LIFETIME,ie as API_UPLOAD_COUNT,ne as API_UPLOAD_FIELD,oe as API_UPLOAD_SIZE,ae as API_UPLOAD_TEMP,de as API_WEBSOCKET_START,Ee as Application,le as Auth,ke as AuthController,Te as Config,ye as Configs,Pe as Controller,je as CrudController,ue as Database,he as Forgot,xe as ForgotController,pe as Group,ze as GroupController,ve as GroupRoute,De as GroupRouteController,be as Log,we as Logs,Be as LogsController,Ge as ModelController,Re as Permission,Ue as RegisterController,Ae as Responses,me as Route,Ce as RouteController,Me as SetupController,qe as Token,ge as User,Ke as UserController,fe as UserGroup,He as UserGroupController,Se as crt,Oe as key,ce as sequelize};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@andrewcaires/api",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.3",
|
|
4
4
|
"description": "Simple api for small applications using express, jsonwebtoken, sequelize and websocket",
|
|
5
5
|
"main": "./dist/index.cjs.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -45,38 +45,38 @@
|
|
|
45
45
|
},
|
|
46
46
|
"homepage": "https://github.com/andrewcaires/npm/tree/main/api#readme",
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@andrewcaires/utils.js": "^0.2.
|
|
48
|
+
"@andrewcaires/utils.js": "^0.2.9",
|
|
49
49
|
"cors": "^2.8.5",
|
|
50
50
|
"crypto-js": "^4.1.1",
|
|
51
51
|
"dotenv": "^16.0.3",
|
|
52
52
|
"express": "^4.18.2",
|
|
53
|
-
"jsonwebtoken": "^
|
|
54
|
-
"mariadb": "^3.0
|
|
53
|
+
"jsonwebtoken": "^9.0.0",
|
|
54
|
+
"mariadb": "^3.1.0",
|
|
55
55
|
"mime-types": "^2.1.35",
|
|
56
56
|
"multer": "^1.4.5-lts.1",
|
|
57
|
-
"mysql2": "^
|
|
58
|
-
"sequelize": "^6.
|
|
59
|
-
"ws": "^8.
|
|
57
|
+
"mysql2": "^3.1.2",
|
|
58
|
+
"sequelize": "^6.29.0",
|
|
59
|
+
"ws": "^8.12.1"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
|
-
"@rollup/plugin-commonjs": "^
|
|
63
|
-
"@rollup/plugin-terser": "^0.
|
|
64
|
-
"@rollup/plugin-typescript": "^
|
|
65
|
-
"@types/cors": "^2.8.
|
|
62
|
+
"@rollup/plugin-commonjs": "^24.0.1",
|
|
63
|
+
"@rollup/plugin-terser": "^0.4.0",
|
|
64
|
+
"@rollup/plugin-typescript": "^11.0.0",
|
|
65
|
+
"@types/cors": "^2.8.13",
|
|
66
66
|
"@types/crypto-js": "^4.1.1",
|
|
67
|
-
"@types/express": "^4.17.
|
|
68
|
-
"@types/jsonwebtoken": "^
|
|
67
|
+
"@types/express": "^4.17.17",
|
|
68
|
+
"@types/jsonwebtoken": "^9.0.1",
|
|
69
69
|
"@types/mime-types": "^2.1.1",
|
|
70
70
|
"@types/multer": "^1.4.7",
|
|
71
|
-
"@types/node": "^18.
|
|
72
|
-
"@types/ws": "^8.5.
|
|
73
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
74
|
-
"@typescript-eslint/parser": "^5.
|
|
75
|
-
"eslint": "^8.
|
|
76
|
-
"rollup": "^3.
|
|
77
|
-
"rollup-plugin-dts": "^5.
|
|
71
|
+
"@types/node": "^18.14.4",
|
|
72
|
+
"@types/ws": "^8.5.4",
|
|
73
|
+
"@typescript-eslint/eslint-plugin": "^5.54.0",
|
|
74
|
+
"@typescript-eslint/parser": "^5.54.0",
|
|
75
|
+
"eslint": "^8.35.0",
|
|
76
|
+
"rollup": "^3.18.0",
|
|
77
|
+
"rollup-plugin-dts": "^5.2.0",
|
|
78
78
|
"ts-node": "^10.9.1",
|
|
79
79
|
"ts-node-dev": "^2.0.0",
|
|
80
|
-
"tslib": "^2.
|
|
80
|
+
"tslib": "^2.5.0"
|
|
81
81
|
}
|
|
82
82
|
}
|