aloux-iam 0.0.145 → 0.0.146
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 +277 -238
- package/index.js +12 -6
- package/lib/config/utils.js +40 -10
- package/lib/controllers/auth.js +33 -1
- package/lib/controllers/business.js +25 -51
- package/lib/controllers/company.js +7 -7
- package/lib/controllers/functions.js +38 -62
- package/lib/controllers/label.js +26 -25
- package/lib/controllers/log.js +24 -24
- package/lib/controllers/menu.js +47 -74
- package/lib/controllers/permission.js +52 -72
- package/lib/controllers/user.js +124 -175
- package/lib/middleware.js +11 -17
- package/lib/models/Company.js +0 -1
- package/lib/models/Permission.js +3 -1
- package/lib/models/User.js +11 -8
- package/lib/providers.js +7 -0
- package/lib/router.js +16 -25
- package/lib/services/auth.js +88 -113
- package/lib/services/totp.js +13 -11
- package/lib/services/user.js +55 -38
- package/package.json +12 -16
- package/CONTRIBUTING.md +0 -1
- package/lib/controllers/operationsAWS.js +0 -228
- package/lib/services/bigQuery.js +0 -88
- package/lib/services/s3.js +0 -72
- package/lib/services/ses.js +0 -98
- package/lib/services/sns.js +0 -22
package/README.md
CHANGED
|
@@ -1,272 +1,311 @@
|
|
|
1
|
-
#
|
|
1
|
+
# aloux-iam
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Librería Node.js para gestión de identidad y acceso (IAM) en APIs Express + MongoDB.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Instalación
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
|
|
8
|
+
npm install aloux-iam
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
## Usage
|
|
13
|
-
En archivo `init.js`
|
|
11
|
+
## Configuración básica
|
|
14
12
|
|
|
15
13
|
```js
|
|
16
|
-
|
|
17
|
-
const
|
|
14
|
+
const express = require('express')
|
|
15
|
+
const mongoose = require('mongoose')
|
|
16
|
+
const cookieParser = require('cookie-parser')
|
|
17
|
+
const { IAMRouter } = require('aloux-iam')
|
|
18
18
|
|
|
19
|
+
const app = express()
|
|
19
20
|
|
|
21
|
+
app.use(express.json())
|
|
22
|
+
app.use(cookieParser())
|
|
20
23
|
app.use(IAMRouter)
|
|
21
24
|
|
|
22
|
-
|
|
23
|
-
app.
|
|
24
|
-
"/aloux-iam",
|
|
25
|
-
swaggerUI.serveFiles(IAMswagger, {}),
|
|
26
|
-
swaggerUI.setup(IAMswagger)
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
// URL Swagger
|
|
30
|
-
// [BASE_URL]/docs-iam/#/default/
|
|
31
|
-
|
|
25
|
+
mongoose.connect(process.env.MONGO_URI)
|
|
26
|
+
app.listen(3000)
|
|
32
27
|
```
|
|
33
28
|
|
|
34
|
-
|
|
35
|
-
En archivo `router.js`
|
|
29
|
+
### Proteger tus propias rutas
|
|
36
30
|
|
|
37
31
|
```js
|
|
38
|
-
// Require
|
|
39
32
|
const { IAMAuth } = require('aloux-iam')
|
|
40
33
|
|
|
41
|
-
|
|
42
|
-
|
|
34
|
+
app.get('/api/mi-recurso', IAMAuth, (req, res) => {
|
|
35
|
+
// req.user → usuario autenticado con funciones y permisos
|
|
36
|
+
// req.token → JWT string
|
|
37
|
+
res.json({ user: req.user })
|
|
38
|
+
})
|
|
43
39
|
```
|
|
44
40
|
|
|
45
|
-
|
|
41
|
+
### Swagger
|
|
46
42
|
|
|
47
|
-
Requiere las siguientes variables de entorno (.env)
|
|
48
|
-
|
|
49
|
-
| Variable | Description |
|
|
50
|
-
| ----------------------|---------------|
|
|
51
|
-
| AUTH_SECRET | Required, para cifrar la contraseña |
|
|
52
|
-
| AWS_SECRET_ACCESS_KEY | Required, para acceso a S3 y SES AWS. |
|
|
53
|
-
| AWS_ACCESS_KEY_ID | Required, para acceso a S3 y SES AWS. |
|
|
54
|
-
| AWS_REGION | Required, para acceso a S3 y SES AWS. |
|
|
55
|
-
| AWS_BUCKET | Required, para guardar la foto de perfil en AWS. |
|
|
56
|
-
| AWS_EMAIL_SENDER | Required, para mandar el correo de recuperación de contraseña |
|
|
57
|
-
| DEBUG | Required, para validar si el ambiente es dev o PROD |
|
|
58
|
-
| SWAGGER_SERVER | Required, para acceder al swagger de IAM |
|
|
59
|
-
| MASTER_PWD | Optional, para utilizar contraseña maestra de usuarios en desarrollo |
|
|
60
|
-
| BASE_URL | Optional, para swagger |
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
## Endpoints disponibles
|
|
64
|
-
|
|
65
|
-
### Endpoints user self (no auth)
|
|
66
|
-
|
|
67
|
-
| Method | Endpoint | Description |
|
|
68
|
-
| --------- | --------------------------|---------------|
|
|
69
|
-
| POST | iam/auth/email | Validar correo |
|
|
70
|
-
| POST | iam/auth/login | Iniciar sesión |
|
|
71
|
-
| POST | iam/auth/forgot/password | Enviar código a correo |
|
|
72
|
-
| POST | iam/auth/validate/code | Verificar código |
|
|
73
|
-
| POST | iam/auth/verify/mail | Verificar correo |
|
|
74
|
-
| GET | iam/auth/verify/mail/token/:token | Valida correo (Manda correo de bienvenida) |
|
|
75
|
-
| POST | iam/auth/reset/password | Reestablecer contraseña |
|
|
76
|
-
| POST | iam/auth/signup | Registrarse |
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
### Endpoints user self
|
|
80
|
-
|
|
81
|
-
| Method | Endpoint | Description |
|
|
82
|
-
| --------- | --------------------------|---------------|
|
|
83
|
-
| GET | iam/auth/me | Obtener información de usuario autenticado |
|
|
84
|
-
| PUT | iam/auth/profile | Actualizar perfil |
|
|
85
|
-
| PUT | iam/auth/profile/pictura | Actualizar solo la foto de perfil |
|
|
86
|
-
| PUT | iam/auth/reset/password | Actualizar contraseña |
|
|
87
|
-
| POST | iam/auth/send/verify/phone | Enviar código al teléfono de la cuenta para verificarla |
|
|
88
|
-
| POST | iam/auth/verify/phone | Valida teléfono del usuario de la cuenta |
|
|
89
|
-
| POST | iam/auth/logout | Cerrar sesión |
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
### Endpoints user
|
|
93
|
-
|
|
94
|
-
| Method | Endpoint | Description |
|
|
95
|
-
| --------- | ------------------------------|----------------|
|
|
96
|
-
| POST | iam/user | Crear usuario |
|
|
97
|
-
| GET | iam/user | Obtener todos los usuario |
|
|
98
|
-
| GET | iam/user/:USER_ID | Obtener detalle de usuario |
|
|
99
|
-
| PUT | iam/user/:USER_ID | Actualizar usuario |
|
|
100
|
-
| PUT | iam/user/:USER_ID/status | Activar o desactivar usuario |
|
|
101
|
-
| PUT | iam/user/password/:USER_ID | Actualizar la constraseña de un usuario |
|
|
102
|
-
| DELETE | iam/user/:USER_ID | Eliminar usuario |
|
|
103
|
-
| GET | iam/user/count/all | Obtiene el número de usuarios |
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
### Endpoints funtions
|
|
107
|
-
|
|
108
|
-
| Method | Endpoint | Description |
|
|
109
|
-
| --------- | --------------------------------------|----------------|
|
|
110
|
-
| POST | iam/functions | Crear función |
|
|
111
|
-
| PUT | iam/functions/:FUNCTION_ID | Actualizar función |
|
|
112
|
-
| PUT | iam/functions/:FUNCTION_ID/status | Activar o desactivar función |
|
|
113
|
-
| GET | iam/functions | Obtener todas las funciones |
|
|
114
|
-
| GET | iam/functions/:FUNCTION_ID | Obtener detalle de la función |
|
|
115
|
-
| DELETE | iam/functions/:FUNCTION_ID | Eliminar función |
|
|
116
|
-
| GET | iam/functions/count/all | Obtiene el número de funciones |
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
### Endpoints permission
|
|
120
|
-
|
|
121
|
-
| Method | Endpoint | Description |
|
|
122
|
-
| --------- | ------------------------------------------|---------------|
|
|
123
|
-
| POST | iam/permission | Crear permiso
|
|
124
|
-
| PUT | iam/permission/:PERMISSION_ID | Actualizar permiso |
|
|
125
|
-
| PUT | iam/permission/:PERMISSION_ID/status | Activar o desactivar permiso |
|
|
126
|
-
| GET | iam/permission | Obtener todas los permisos |
|
|
127
|
-
| GET | iam/permission/:PERMISSION_ID | Obtener detalle de la permiso |
|
|
128
|
-
| DELETE | iam/permission/:PERMISSION_ID | Eliminar permiso |
|
|
129
|
-
| GET | iam/permission/count/all | Obtiene el número de permisos |
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
### Endpoints menu
|
|
133
|
-
|
|
134
|
-
| Method | Endpoint | Description |
|
|
135
|
-
| --------- | --------------------------|---------------|
|
|
136
|
-
| POST | /iam/menu | Crea un elemento de menú |
|
|
137
|
-
| PUT | /iam/menu/:MENU_ID | Actualiza un elemento de menú |
|
|
138
|
-
| PUT | /iam/menu/:MENU_ID/status | Activa o desactiva un menú |
|
|
139
|
-
| GET | /iam/menu | Obtiene todos los elementos de menú |
|
|
140
|
-
| GET | /iam/menu/:MENU_ID | Obtiene el detalle de un elemento de menú |
|
|
141
|
-
| DELETE | /iam/menu/:MENU_ID | Elimina un elemento de menú |
|
|
142
|
-
| POST | /iam/menu/order | Ordena los elementos de menú |
|
|
143
|
-
| GET | iam/menu/count | Obtiene el número de menús |
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
## Aloux-AWS
|
|
147
|
-
#### Aggregate file
|
|
148
43
|
```js
|
|
149
|
-
|
|
150
|
-
const {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
// variables
|
|
154
|
-
/*
|
|
155
|
-
* AWS_REGION
|
|
156
|
-
* AWS_BUCKET
|
|
157
|
-
*/
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* pathFile = folder/file_name-file_id
|
|
161
|
-
* file = req.files.property
|
|
162
|
-
*/
|
|
163
|
-
// a constant is created to save the new element
|
|
164
|
-
const result = await AlouxAWS.upload('folder/file_name', req.files.data)
|
|
44
|
+
const swaggerUI = require('swagger-ui-express')
|
|
45
|
+
const { IAMSwagger } = require('aloux-iam')
|
|
165
46
|
|
|
47
|
+
app.use('/docs-iam', swaggerUI.serveFiles(IAMSwagger, {}), swaggerUI.setup(IAMSwagger))
|
|
166
48
|
```
|
|
167
49
|
|
|
168
|
-
|
|
169
|
-
```js
|
|
170
|
-
// Require
|
|
171
|
-
const { AlouxAWS } = require('aloux-iam')
|
|
50
|
+
## Integración con aloux-cloud
|
|
172
51
|
|
|
173
|
-
|
|
174
|
-
// variables
|
|
175
|
-
/*
|
|
176
|
-
* AWS_REGION
|
|
177
|
-
* AWS_BUCKET
|
|
178
|
-
*/
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* files = [{key: 'folder/file1'},{key: 'folder/file1'}]
|
|
182
|
-
*/
|
|
183
|
-
// delete selected files
|
|
184
|
-
const files = [{key: 'folder/file1.png'},{key: 'folder/file1.png'}]
|
|
185
|
-
const deleteFiles = await AlouxAWS.deleteMany(files)
|
|
186
|
-
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
#### Eliminate file
|
|
190
52
|
```js
|
|
191
|
-
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* file = folder/file_name
|
|
203
|
-
*/
|
|
204
|
-
// delete the file
|
|
205
|
-
const file = 'folder/file_name.png'
|
|
206
|
-
const deleteFile = await AlouxAWS.delete(file)
|
|
207
|
-
|
|
53
|
+
const iam = require('aloux-iam')
|
|
54
|
+
const cloud = require('aloux-cloud')
|
|
55
|
+
|
|
56
|
+
iam.init({
|
|
57
|
+
email: cloud.ses,
|
|
58
|
+
sms: cloud.sns,
|
|
59
|
+
storage: cloud.s3,
|
|
60
|
+
analytics: cloud.bigQuery,
|
|
61
|
+
})
|
|
208
62
|
```
|
|
209
63
|
|
|
210
|
-
|
|
211
|
-
#### Send email
|
|
212
|
-
```js
|
|
213
|
-
// Require
|
|
214
|
-
const { AlouxAWS } = require('aloux-iam')
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
// variables
|
|
218
|
-
/*
|
|
219
|
-
* AWS_REGION
|
|
220
|
-
* AWS_EMAIL_SENDER
|
|
221
|
-
*/
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* email: Destination email
|
|
225
|
-
* message: Mail body
|
|
226
|
-
* subject: Mail subject
|
|
227
|
-
*/
|
|
228
|
-
// a constant is created to request the data from the req.body.
|
|
229
|
-
const { email, message, subject } = req.body
|
|
230
|
-
const sendEmail = await AlouxAWS.sendCustom(email, message, subject)
|
|
231
|
-
|
|
232
|
-
// example of the messages variable
|
|
233
|
-
// this variable must be sent as a string if you want to send modified HTML
|
|
234
|
-
/*
|
|
235
|
-
|
|
236
|
-
message: "<!DOCTYPE html><html lang='en'><head><meta charset='UTF-8'><meta name='viewport' content='width=device-width, initial-scale=1.0'><title>Document</title></head><body><h1>Information</h1></body></html>"
|
|
237
|
-
|
|
238
|
-
*/
|
|
64
|
+
Cada provider es opcional. Si no se configura, el IAM funciona sin ese servicio.
|
|
239
65
|
|
|
66
|
+
## Variables de entorno
|
|
240
67
|
|
|
68
|
+
### Requeridas
|
|
69
|
+
|
|
70
|
+
| Variable | Descripción |
|
|
71
|
+
|----------|-------------|
|
|
72
|
+
| `AUTH_SECRET` | Clave secreta para firmar JWT |
|
|
73
|
+
| `MONGO_URI` | URI de conexión a MongoDB |
|
|
74
|
+
|
|
75
|
+
### Sesión y autenticación
|
|
76
|
+
|
|
77
|
+
| Variable | Default | Descripción |
|
|
78
|
+
|----------|---------|-------------|
|
|
79
|
+
| `SESSION_TIME` | — | Duración del token en minutos |
|
|
80
|
+
| `MAX_TOKENS` | `5` | Sesiones activas simultáneas por usuario |
|
|
81
|
+
| `FAILED_ATTEMPS` | `5` | Intentos fallidos antes de bloquear la cuenta |
|
|
82
|
+
| `SESSION_INTERRUPTOR` | — | Si `true`, valida expiración en cada request |
|
|
83
|
+
| `SERVICE_ACCOUNT_TTL_DAYS` | permanente | Días de vida del token de cuentas de servicio |
|
|
84
|
+
| `DEBUG` | — | Si `true`, activa `MASTER_PWD` y URL de Swagger |
|
|
85
|
+
| `MASTER_PWD` | — | Contraseña maestra que omite bcrypt (requiere `DEBUG=true`) |
|
|
86
|
+
| `SWAGGER_SERVER` | — | URL del servidor en Swagger cuando `DEBUG=true` |
|
|
87
|
+
|
|
88
|
+
### Emails (requiere provider `email`)
|
|
89
|
+
|
|
90
|
+
| Variable | Descripción |
|
|
91
|
+
|----------|-------------|
|
|
92
|
+
| `SEND_EMAIL_USER` | Si `true`, envía credenciales al crear usuario admin |
|
|
93
|
+
| `SUBJECT_EMAIL` | Asunto por defecto de los emails |
|
|
94
|
+
| `CHANGE_PWD` | Si `true`, fuerza cambio de contraseña en primer login |
|
|
95
|
+
| `VERIFY_ACCOUNT_URL` | URL base para verificación de cuenta |
|
|
96
|
+
| `URL_VERIFY_EMAIL` | URL para confirmar cambio de email |
|
|
97
|
+
| `TEMPLATE_ACCOUNT` | Path al template HTML de credenciales |
|
|
98
|
+
| `TEMPLATE_RECOVER_PASSWORD` | Path al template HTML de recuperación |
|
|
99
|
+
| `TEMPLATE_VERIFY_EMAIL` | Path al template HTML de verificación |
|
|
100
|
+
| `TEMPLATE_WELCOME` | Path al template HTML de bienvenida |
|
|
101
|
+
| `TEMPLATE_CHANGE_MAIL` | Path al template HTML de cambio de email |
|
|
102
|
+
|
|
103
|
+
### Branding y multi-app
|
|
104
|
+
|
|
105
|
+
| Variable | Descripción |
|
|
106
|
+
|----------|-------------|
|
|
107
|
+
| `APP` | Identificador de app para templates con sufijo |
|
|
108
|
+
| `PROJECT_NAME` | Nombre de la app en templates y SMS |
|
|
109
|
+
| `PROJECT_URL` | URL del proyecto en SMS de verificación |
|
|
110
|
+
| `BRAND_COLOR` | Color principal para templates de email |
|
|
111
|
+
| `BRAND_LOGO` | URL del logo para templates de email |
|
|
112
|
+
| `FUNCTION_NAME` | Función asignada por defecto al hacer signup |
|
|
113
|
+
|
|
114
|
+
### Historial
|
|
115
|
+
|
|
116
|
+
| Variable | Descripción |
|
|
117
|
+
|----------|-------------|
|
|
118
|
+
| `HISTORY` | Si `true`, registra historial de acciones |
|
|
119
|
+
| `HISTORY_ENDPOINTS` | Paths separados por coma a registrar |
|
|
120
|
+
|
|
121
|
+
### Analytics (requiere provider `analytics`)
|
|
122
|
+
|
|
123
|
+
| Variable | Descripción |
|
|
124
|
+
|----------|-------------|
|
|
125
|
+
| `UPLOAD_CUSTOMER` | Si `true`, inserta nuevos usuarios en BigQuery |
|
|
126
|
+
| `UPLOAD_CUSTOMER_TABLE` | Tabla de BigQuery donde insertar |
|
|
127
|
+
|
|
128
|
+
## Exportaciones
|
|
129
|
+
|
|
130
|
+
| Export | Tipo | Descripción |
|
|
131
|
+
|--------|------|-------------|
|
|
132
|
+
| `IAMRouter` | Express Router | Monta todos los endpoints `/iam/*` |
|
|
133
|
+
| `IAMAuth` | Middleware | Autenticación JWT para tus rutas |
|
|
134
|
+
| `IAMSwagger` | Object | Spec OpenAPI lista para swagger-ui-express |
|
|
135
|
+
| `IAMUserModel` | Mongoose Model | Modelo User |
|
|
136
|
+
| `IAMUserBusiness` | Mongoose Model | Modelo Business |
|
|
137
|
+
| `IAMFunctionsModel` | Mongoose Model | Modelo Functions |
|
|
138
|
+
| `IAMPermissionModel` | Mongoose Model | Modelo Permission |
|
|
139
|
+
| `IAMMenuModel` | Mongoose Model | Modelo Menu |
|
|
140
|
+
| `AlouxHistory` | Service | Controlador de historial |
|
|
141
|
+
| `init` | Function | Registra providers de aloux-cloud |
|
|
142
|
+
|
|
143
|
+
## Flujos de creación de usuarios
|
|
144
|
+
|
|
145
|
+
### Signup público — `POST /iam/auth/signup`
|
|
146
|
+
El usuario se registra solo. Requiere `email` y `pwd`. Se le asigna la función definida en `FUNCTION_NAME`.
|
|
147
|
+
|
|
148
|
+
### Usuario administrado — `POST /iam/user`
|
|
149
|
+
Un admin crea el usuario. Requiere `email` y `pwd`. Permite asignar funciones, empresas y negocios.
|
|
150
|
+
|
|
151
|
+
### Cuenta de servicio — `POST /iam/user/service`
|
|
152
|
+
Sin `email` ni contraseña. Para comunicación machine-to-machine. Devuelve un API token permanente una sola vez en la respuesta.
|
|
153
|
+
|
|
154
|
+
## Endpoints
|
|
155
|
+
|
|
156
|
+
### Autenticación (sin token)
|
|
157
|
+
|
|
158
|
+
| Método | Endpoint | Descripción |
|
|
159
|
+
|--------|----------|-------------|
|
|
160
|
+
| `POST` | `/iam/auth/email` | Verificar si un email existe |
|
|
161
|
+
| `POST` | `/iam/auth/login` | Iniciar sesión |
|
|
162
|
+
| `POST` | `/iam/auth/logo` | Logo de empresa por email |
|
|
163
|
+
| `POST` | `/iam/auth/forgot/password` | Enviar código de recuperación |
|
|
164
|
+
| `POST` | `/iam/auth/validate/code` | Validar código de recuperación |
|
|
165
|
+
| `POST` | `/iam/auth/reset/password` | Resetear contraseña con código |
|
|
166
|
+
| `POST` | `/iam/auth/verify/mail` | Enviar email de verificación de cuenta |
|
|
167
|
+
| `GET` | `/iam/auth/verify/mail/token/:token` | Activar cuenta por token |
|
|
168
|
+
| `POST` | `/iam/auth/signup` | Registro público (requiere `pwd`) |
|
|
169
|
+
| `GET` | `/iam/generatePassword` | Generar contraseña segura aleatoria |
|
|
170
|
+
|
|
171
|
+
### Autenticación (con token)
|
|
172
|
+
|
|
173
|
+
| Método | Endpoint | Descripción |
|
|
174
|
+
|--------|----------|-------------|
|
|
175
|
+
| `GET` | `/iam/auth/me` | Perfil del usuario autenticado |
|
|
176
|
+
| `PATCH` | `/iam/auth/profile` | Actualizar perfil |
|
|
177
|
+
| `PUT` | `/iam/auth/profile/pictura` | Actualizar foto de perfil |
|
|
178
|
+
| `PUT` | `/iam/auth/reset/password` | Cambiar contraseña |
|
|
179
|
+
| `POST` | `/iam/auth/send/verify/phone` | Enviar código SMS |
|
|
180
|
+
| `POST` | `/iam/auth/verify/phone` | Validar código de teléfono |
|
|
181
|
+
| `POST` | `/iam/auth/logout` | Cerrar sesión |
|
|
182
|
+
| `PATCH` | `/iam/auth/mail` | Iniciar cambio de email |
|
|
183
|
+
| `POST` | `/iam/auth/validate/mail` | Confirmar nuevo email |
|
|
184
|
+
|
|
185
|
+
### 2FA / TOTP
|
|
186
|
+
|
|
187
|
+
| Método | Endpoint | Descripción |
|
|
188
|
+
|--------|----------|-------------|
|
|
189
|
+
| `GET` | `/iam/totp/setup` | Genera QR y secreto TOTP |
|
|
190
|
+
| `POST` | `/iam/totp/activate` | Activa 2FA tras escanear QR |
|
|
191
|
+
| `POST` | `/iam/totp/verify` | Verifica código TOTP en el login |
|
|
192
|
+
|
|
193
|
+
### Usuarios
|
|
194
|
+
|
|
195
|
+
| Método | Endpoint | Descripción |
|
|
196
|
+
|--------|----------|-------------|
|
|
197
|
+
| `POST` | `/iam/user` | Crear usuario administrado |
|
|
198
|
+
| `POST` | `/iam/user/service` | Crear cuenta de servicio |
|
|
199
|
+
| `GET` | `/iam/user` | Listar usuarios `?page&itemsPerPage&search` |
|
|
200
|
+
| `GET` | `/iam/user/:USER_ID` | Obtener usuario |
|
|
201
|
+
| `PATCH` | `/iam/user/:USER_ID` | Actualizar usuario |
|
|
202
|
+
| `PUT` | `/iam/user/:USER_ID/status` | Cambiar estado |
|
|
203
|
+
| `PUT` | `/iam/user/password/:USER_ID` | Cambiar contraseña |
|
|
204
|
+
| `DELETE` | `/iam/user/:USER_ID` | Eliminar usuario |
|
|
205
|
+
| `GET` | `/iam/user/count/all` | Contar usuarios |
|
|
206
|
+
| `GET` | `/iam/business/user` | Usuarios del negocio actual |
|
|
207
|
+
| `GET` | `/iam/user/by/my/companies` | Usuarios de mis empresas |
|
|
208
|
+
|
|
209
|
+
### Funciones
|
|
210
|
+
|
|
211
|
+
| Método | Endpoint | Descripción |
|
|
212
|
+
|--------|----------|-------------|
|
|
213
|
+
| `POST` | `/iam/functions` | Crear función |
|
|
214
|
+
| `GET` | `/iam/functions` | Listar funciones |
|
|
215
|
+
| `GET` | `/iam/functions/:FUNCTION_ID` | Obtener función |
|
|
216
|
+
| `PATCH` | `/iam/functions/:FUNCTION_ID` | Actualizar función |
|
|
217
|
+
| `PUT` | `/iam/functions/:FUNCTION_ID/status` | Cambiar estado |
|
|
218
|
+
| `DELETE` | `/iam/functions/:FUNCTION_ID` | Eliminar función |
|
|
219
|
+
| `GET` | `/iam/functions/count/all` | Contar funciones |
|
|
220
|
+
|
|
221
|
+
### Permisos
|
|
222
|
+
|
|
223
|
+
| Método | Endpoint | Descripción |
|
|
224
|
+
|--------|----------|-------------|
|
|
225
|
+
| `POST` | `/iam/permission` | Crear permiso |
|
|
226
|
+
| `GET` | `/iam/permission` | Listar permisos |
|
|
227
|
+
| `GET` | `/iam/permission/:PERMISSION_ID` | Obtener permiso |
|
|
228
|
+
| `PATCH` | `/iam/permission/:PERMISSION_ID` | Actualizar permiso |
|
|
229
|
+
| `PUT` | `/iam/permission/:PERMISSION_ID/status` | Cambiar estado |
|
|
230
|
+
| `DELETE` | `/iam/permission/:PERMISSION_ID` | Eliminar permiso |
|
|
231
|
+
| `GET` | `/iam/permission/count/all` | Contar permisos |
|
|
232
|
+
|
|
233
|
+
### Menús
|
|
234
|
+
|
|
235
|
+
| Método | Endpoint | Descripción |
|
|
236
|
+
|--------|----------|-------------|
|
|
237
|
+
| `POST` | `/iam/menu` | Crear elemento |
|
|
238
|
+
| `GET` | `/iam/menu` | Listar menús |
|
|
239
|
+
| `GET` | `/iam/menu/:MENU_ID` | Obtener elemento |
|
|
240
|
+
| `PATCH` | `/iam/menu/:MENU_ID` | Actualizar elemento |
|
|
241
|
+
| `PUT` | `/iam/menu/:MENU_ID/status` | Cambiar estado |
|
|
242
|
+
| `POST` | `/iam/menu/order` | Reordenar |
|
|
243
|
+
| `DELETE` | `/iam/menu/:MENU_ID` | Eliminar elemento |
|
|
244
|
+
| `GET` | `/iam/menu/count/all` | Contar menús |
|
|
245
|
+
|
|
246
|
+
### Empresas
|
|
247
|
+
|
|
248
|
+
| Método | Endpoint | Descripción |
|
|
249
|
+
|--------|----------|-------------|
|
|
250
|
+
| `POST` | `/iam/company` | Crear empresa |
|
|
251
|
+
| `GET` | `/iam/company` | Listar empresas |
|
|
252
|
+
| `GET` | `/iam/company/my` | Mis empresas |
|
|
253
|
+
| `GET` | `/iam/company/:COMPANY_ID` | Detalle |
|
|
254
|
+
| `PATCH` | `/iam/company/:COMPANY_ID` | Actualizar |
|
|
255
|
+
| `PATCH` | `/iam/company/:COMPANY_ID/picture` | Actualizar logo |
|
|
256
|
+
| `PATCH` | `/iam/company/:COMPANY_ID/favicon` | Actualizar favicon |
|
|
257
|
+
| `GET` | `/iam/company/:ID/identity` | Identidad pública |
|
|
258
|
+
| `PUT` | `/iam/company/:COMPANY_ID/gkey` | Configurar Google Key |
|
|
259
|
+
| `DELETE` | `/iam/company/:COMPANY_ID/gkey` | Eliminar Google Key |
|
|
260
|
+
| `DELETE` | `/iam/company/:COMPANY_ID` | Eliminar empresa |
|
|
261
|
+
|
|
262
|
+
### Negocios
|
|
263
|
+
|
|
264
|
+
| Método | Endpoint | Descripción |
|
|
265
|
+
|--------|----------|-------------|
|
|
266
|
+
| `POST` | `/iam/business` | Crear negocio |
|
|
267
|
+
| `GET` | `/iam/business` | Listar negocios |
|
|
268
|
+
| `POST` | `/iam/business/company` | Negocios de una empresa |
|
|
269
|
+
| `GET` | `/iam/business/my` | Mis negocios |
|
|
270
|
+
| `GET` | `/iam/business/my/company/:COMPANY_ID` | Mis negocios por empresa |
|
|
271
|
+
| `GET` | `/iam/business/:BUSINESS_ID` | Detalle |
|
|
272
|
+
| `PUT` | `/iam/business/:BUSINESS_ID` | Actualizar |
|
|
273
|
+
| `PATCH` | `/iam/business/:BUSINESS_ID/picture` | Actualizar logo |
|
|
274
|
+
| `PATCH` | `/iam/business/:BUSINESS_ID/favicon` | Actualizar favicon |
|
|
275
|
+
| `GET` | `/iam/business/:ID/identity` | Identidad pública |
|
|
276
|
+
| `PATCH` | `/iam/business/:BUSINESS_ID/useCompanyKey` | Usar clave de empresa |
|
|
277
|
+
| `POST` | `/iam/business/:BUSINESS_ID/inheritKey` | Heredar clave de empresa |
|
|
278
|
+
| `DELETE` | `/iam/business/:BUSINESS_ID` | Eliminar negocio |
|
|
279
|
+
|
|
280
|
+
### Logs, Etiquetas e Historial
|
|
281
|
+
|
|
282
|
+
| Método | Endpoint | Descripción |
|
|
283
|
+
|--------|----------|-------------|
|
|
284
|
+
| `POST` | `/iam/log` | Crear log |
|
|
285
|
+
| `POST` | `/iam/log/retrieve` | Recuperar logs con filtros y analytics |
|
|
286
|
+
| `GET` | `/iam/log/:LOG_ID` | Obtener log |
|
|
287
|
+
| `PATCH` | `/iam/log/:LOG_ID` | Actualizar log |
|
|
288
|
+
| `PUT` | `/iam/log/:LOG_ID/status` | Cambiar estado |
|
|
289
|
+
| `DELETE` | `/iam/log/:LOG_ID` | Eliminar log |
|
|
290
|
+
| `GET` | `/iam/log/count/all` | Contar logs |
|
|
291
|
+
| `POST` | `/iam/label` | Crear etiqueta |
|
|
292
|
+
| `GET` | `/iam/label` | Listar etiquetas |
|
|
293
|
+
| `POST` | `/iam/retrieve/history` | Listar historial |
|
|
294
|
+
| `GET` | `/iam/history/:HISTORY_ID` | Detalle de historial |
|
|
295
|
+
|
|
296
|
+
## Respuesta de error estándar
|
|
297
|
+
|
|
298
|
+
Todos los errores del IAM devuelven siempre la misma estructura:
|
|
299
|
+
|
|
300
|
+
```json
|
|
301
|
+
{
|
|
302
|
+
"code": 400,
|
|
303
|
+
"title": "Título del error",
|
|
304
|
+
"detail": "Descripción detallada",
|
|
305
|
+
"suggestion": "Qué hacer para resolverlo"
|
|
306
|
+
}
|
|
241
307
|
```
|
|
242
308
|
|
|
243
|
-
|
|
244
|
-
#### Send sns
|
|
245
|
-
```js
|
|
246
|
-
// Require
|
|
247
|
-
const { AlouxAWS } = require('aloux-iam')
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
// variables
|
|
251
|
-
/*
|
|
252
|
-
* AWS_REGION
|
|
253
|
-
*/
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* phoneNumber: Destination number
|
|
257
|
-
* message: Message body
|
|
258
|
-
*/
|
|
259
|
-
// a constant is created to request the data from the req.body.
|
|
260
|
-
const { phoneNumber, message } = req.body
|
|
261
|
-
const sendSns = await AlouxAWS.sendMessagePhone(phoneNumber, message)
|
|
262
|
-
|
|
263
|
-
// example of the phoneNumber variable
|
|
264
|
-
// this variable must be sent as a string and taking into account the telephone prefix
|
|
265
|
-
|
|
266
|
-
/*
|
|
267
|
-
|
|
268
|
-
phoneNumber: "+52244-------"
|
|
269
|
-
|
|
270
|
-
*/
|
|
309
|
+
## Licencia
|
|
271
310
|
|
|
272
|
-
|
|
311
|
+
MIT
|
package/index.js
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
|
+
const REQUIRED_ENV = ['AUTH_SECRET', 'SESSION_TIME'];
|
|
2
|
+
const missingEnv = REQUIRED_ENV.filter(k => !process.env[k]);
|
|
3
|
+
if (missingEnv.length > 0) {
|
|
4
|
+
throw new Error(`[aloux-iam] Variables de entorno requeridas faltantes: ${missingEnv.join(', ')}`);
|
|
5
|
+
}
|
|
6
|
+
|
|
1
7
|
const IAMrouter = require("./lib/router");
|
|
2
8
|
const IAMauth = require("./lib/middleware");
|
|
3
|
-
const awsAloux = require("./lib/controllers/operationsAWS");
|
|
4
9
|
const historyAloux = require("./lib/controllers/history");
|
|
5
|
-
const
|
|
6
|
-
const
|
|
10
|
+
const providers = require("./lib/providers");
|
|
11
|
+
const jsyaml = require("js-yaml");
|
|
7
12
|
const path = require("path");
|
|
13
|
+
const fs = require("fs");
|
|
8
14
|
|
|
9
15
|
const User = require("./lib/models/User");
|
|
10
16
|
const Functions = require("./lib/models/Functions");
|
|
@@ -14,7 +20,7 @@ const Business = require("./lib/models/Business");
|
|
|
14
20
|
|
|
15
21
|
// swagger
|
|
16
22
|
const swagger_path = path.resolve(__dirname, "./lib/swagger.yaml");
|
|
17
|
-
const swagger =
|
|
23
|
+
const swagger = jsyaml.load(fs.readFileSync(swagger_path, "utf8"));
|
|
18
24
|
|
|
19
25
|
if (process.env.DEBUG === "true") {
|
|
20
26
|
swagger["servers"] = [];
|
|
@@ -32,7 +38,7 @@ module.exports = {
|
|
|
32
38
|
IAMPermissionModel: Permission,
|
|
33
39
|
IAMMenuModel: Menu,
|
|
34
40
|
|
|
35
|
-
AlouxAWS: awsAloux,
|
|
36
|
-
AlouxBQ: awsBQ,
|
|
37
41
|
AlouxHistory: historyAloux,
|
|
42
|
+
|
|
43
|
+
init: (p = {}) => providers.set(p),
|
|
38
44
|
};
|
package/lib/config/utils.js
CHANGED
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
const fs = require("fs");
|
|
2
2
|
const self = module.exports;
|
|
3
3
|
|
|
4
|
-
self.responseError =
|
|
5
|
-
let
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
title
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
4
|
+
self.responseError = (res, error, defaultCode, defaultTitle, defaultSuggestion) => {
|
|
5
|
+
let code, title, detail, suggestion;
|
|
6
|
+
|
|
7
|
+
if (error && typeof error.code === "number") {
|
|
8
|
+
code = error.code;
|
|
9
|
+
title = error.title || "Error";
|
|
10
|
+
detail = typeof error.detail === "string" ? error.detail : "";
|
|
11
|
+
suggestion = error.suggestion || "Revisa el detalle";
|
|
12
|
+
} else {
|
|
13
|
+
code = defaultCode || 400;
|
|
14
|
+
title = defaultTitle || "Error";
|
|
15
|
+
detail = error?.message || "";
|
|
16
|
+
suggestion = defaultSuggestion || "Revisa el detalle";
|
|
13
17
|
}
|
|
14
|
-
|
|
18
|
+
|
|
19
|
+
res.status(code).send({ code, title, detail, suggestion });
|
|
15
20
|
};
|
|
16
21
|
|
|
17
22
|
self.generatePaginationResponse = async (count, page, itemsPerPage, items) => {
|
|
@@ -69,6 +74,31 @@ self.brand = {
|
|
|
69
74
|
},
|
|
70
75
|
};
|
|
71
76
|
|
|
77
|
+
self.escapeRegex = (str) => {
|
|
78
|
+
if (typeof str !== 'string') return '';
|
|
79
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
self.hashToken = (token) => {
|
|
83
|
+
const crypto = require('crypto');
|
|
84
|
+
return crypto.createHash('sha256').update(String(token)).digest('hex');
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
self.hashCode = (code) => {
|
|
88
|
+
const crypto = require('crypto');
|
|
89
|
+
return crypto.createHash('sha256').update(String(code)).digest('hex');
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
self.sanitizeSort = (sort, allowedFields) => {
|
|
93
|
+
if (!sort || typeof sort !== 'object' || Array.isArray(sort)) return null;
|
|
94
|
+
const safe = {};
|
|
95
|
+
for (const [key, val] of Object.entries(sort)) {
|
|
96
|
+
const n = Number(val);
|
|
97
|
+
if (allowedFields.includes(key) && (n === 1 || n === -1)) safe[key] = n;
|
|
98
|
+
}
|
|
99
|
+
return Object.keys(safe).length > 0 ? safe : null;
|
|
100
|
+
};
|
|
101
|
+
|
|
72
102
|
// Gkey
|
|
73
103
|
self.resolveGkey = (business) => {
|
|
74
104
|
const businessGkey = business.gkey || null;
|