ngx-redi-core 0.0.2
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 +24 -0
- package/ng-package.json +7 -0
- package/package.json +12 -0
- package/src/lib/modules/interceptors/secure.interceptor.spec.ts +16 -0
- package/src/lib/modules/interceptors/secure.interceptor.ts +211 -0
- package/src/lib/modules/secure/model/secure-factory.model.spec.ts +7 -0
- package/src/lib/modules/secure/model/secure-factory.model.ts +28 -0
- package/src/lib/modules/secure/model/tipo-operacion.enum.ts +19 -0
- package/src/lib/modules/secure/secure.module.ts +15 -0
- package/src/lib/modules/secure/services/cifrado.service.spec.ts +16 -0
- package/src/lib/modules/secure/services/cifrado.service.ts +32 -0
- package/src/lib/ngx-redi-core.component.spec.ts +23 -0
- package/src/lib/ngx-redi-core.component.ts +15 -0
- package/src/lib/ngx-redi-core.module.ts +16 -0
- package/src/lib/ngx-redi-core.service.spec.ts +16 -0
- package/src/lib/ngx-redi-core.service.ts +9 -0
- package/src/public-api.ts +7 -0
- package/tsconfig.lib.json +14 -0
- package/tsconfig.lib.prod.json +10 -0
- package/tsconfig.spec.json +14 -0
package/README.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# NgxRediCore
|
|
2
|
+
|
|
3
|
+
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 15.2.0.
|
|
4
|
+
|
|
5
|
+
## Code scaffolding
|
|
6
|
+
|
|
7
|
+
Run `ng generate component component-name --project ngx-redi-core` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project ngx-redi-core`.
|
|
8
|
+
> Note: Don't forget to add `--project ngx-redi-core` or else it will be added to the default project in your `angular.json` file.
|
|
9
|
+
|
|
10
|
+
## Build
|
|
11
|
+
|
|
12
|
+
Run `ng build ngx-redi-core` to build the project. The build artifacts will be stored in the `dist/` directory.
|
|
13
|
+
|
|
14
|
+
## Publishing
|
|
15
|
+
|
|
16
|
+
After building your library with `ng build ngx-redi-core`, go to the dist folder `cd dist/ngx-redi-core` and run `npm publish`.
|
|
17
|
+
|
|
18
|
+
## Running unit tests
|
|
19
|
+
|
|
20
|
+
Run `ng test ngx-redi-core` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
|
21
|
+
|
|
22
|
+
## Further help
|
|
23
|
+
|
|
24
|
+
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
|
package/ng-package.json
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { TestBed } from '@angular/core/testing';
|
|
2
|
+
|
|
3
|
+
import { SecureInterceptor } from './secure.interceptor';
|
|
4
|
+
|
|
5
|
+
describe('SecureInterceptor', () => {
|
|
6
|
+
beforeEach(() => TestBed.configureTestingModule({
|
|
7
|
+
providers: [
|
|
8
|
+
SecureInterceptor
|
|
9
|
+
]
|
|
10
|
+
}));
|
|
11
|
+
|
|
12
|
+
it('should be created', () => {
|
|
13
|
+
const interceptor: SecureInterceptor = TestBed.inject(SecureInterceptor);
|
|
14
|
+
expect(interceptor).toBeTruthy();
|
|
15
|
+
});
|
|
16
|
+
});
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { Injectable } from '@angular/core';
|
|
3
|
+
import {
|
|
4
|
+
HttpRequest,
|
|
5
|
+
HttpHandler,
|
|
6
|
+
HttpEvent,
|
|
7
|
+
HttpInterceptor,
|
|
8
|
+
HttpContextToken,
|
|
9
|
+
HttpResponse
|
|
10
|
+
} from '@angular/common/http';
|
|
11
|
+
import { Observable } from 'rxjs';
|
|
12
|
+
import { map } from 'rxjs/operators';
|
|
13
|
+
import { CifradoService } from '../secure/services/cifrado.service';
|
|
14
|
+
import { TOKEN_SECURE } from '../secure/model/secure-factory.model';
|
|
15
|
+
|
|
16
|
+
/** Request token para el contexto Http */
|
|
17
|
+
export const REQUEST_TOKEN = new HttpContextToken<any>(() => { });
|
|
18
|
+
/** Response token para el contexto Http */
|
|
19
|
+
export const RESPONSE_TOKEN = new HttpContextToken<any>(() => { });
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Interceptor de seguridad que cifra y descifra información sensible en las peticiones Web
|
|
23
|
+
* @decorator `@Injectable()`
|
|
24
|
+
*/
|
|
25
|
+
@Injectable()
|
|
26
|
+
export class SecureInterceptor implements HttpInterceptor {
|
|
27
|
+
constructor(private cifradoService: CifradoService) { }
|
|
28
|
+
|
|
29
|
+
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
|
30
|
+
/** Ciframos los datos de la petición */
|
|
31
|
+
return next.handle(this.cifrarRequest(request))
|
|
32
|
+
.pipe(map(event => {
|
|
33
|
+
if (event instanceof HttpResponse) {
|
|
34
|
+
return event.clone({
|
|
35
|
+
body: this.descifrarResponse(request, event)
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return event
|
|
39
|
+
}));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Regresa una respuesta HTTP descifrada
|
|
44
|
+
* @param request - Petición web
|
|
45
|
+
* @param response - Respuesta web a descifrar
|
|
46
|
+
* @returns Respuesta http descifrada
|
|
47
|
+
*/
|
|
48
|
+
private descifrarResponse(request: HttpRequest<any>, response: HttpResponse<any>): any {
|
|
49
|
+
let responseDefinition = request.context.get(RESPONSE_TOKEN);
|
|
50
|
+
if (responseDefinition && response.body) {
|
|
51
|
+
return this.descifrarDatos(response.body, responseDefinition)
|
|
52
|
+
}
|
|
53
|
+
return response.body;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Cifra los datos de la petición interceptada y regresa una nueva petición con los datos cifrados
|
|
58
|
+
* @param request - Petición Http
|
|
59
|
+
* @returns - Petición con datos cifrados
|
|
60
|
+
*/
|
|
61
|
+
private cifrarRequest(request: HttpRequest<any>): HttpRequest<any> {
|
|
62
|
+
let newRequest: HttpRequest<any> = request;
|
|
63
|
+
switch (request.method) {
|
|
64
|
+
case 'POST':
|
|
65
|
+
newRequest = request.clone({ body: this.cifrarDatos(request.body) });
|
|
66
|
+
break;
|
|
67
|
+
default:
|
|
68
|
+
newRequest = request.clone({ url: this.cifrarPeticionUrl(request) });
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
return newRequest;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Realiza el cifrado de la petición cuando los datos a cifrar se mandan en la URL
|
|
76
|
+
* @param request - Petición HTTP
|
|
77
|
+
* @returns StringQueryParams cifrados en URL
|
|
78
|
+
*/
|
|
79
|
+
private cifrarPeticionUrl(request: HttpRequest<any>): string {
|
|
80
|
+
let requestData = request.context.get(REQUEST_TOKEN);
|
|
81
|
+
let queryParams: string[] = [];
|
|
82
|
+
let queryObject = Object.fromEntries(new URL(request.url).searchParams.entries());
|
|
83
|
+
if (typeof requestData === 'object') {
|
|
84
|
+
Object.entries(queryObject).forEach(([key, value]) => {
|
|
85
|
+
if (!requestData[key]) {
|
|
86
|
+
requestData[key] = value;
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
Object.entries(this.cifrarDatos(requestData)).forEach(([key, value]) => {
|
|
90
|
+
if (value && typeof value !== 'object') {
|
|
91
|
+
queryParams.push(`${key}=${encodeURI((value || '') as string)}`);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
return `${(request.url || '').split('?')[0]}${queryParams.length ? '?' + queryParams.join('&') : ''}`
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Valida si la propiedad de un objeto es segura
|
|
100
|
+
* @param data - Objeto a validar
|
|
101
|
+
* @param key - Propiedad del objeto a validar
|
|
102
|
+
* @returns True si es una propiedad segura
|
|
103
|
+
*/
|
|
104
|
+
private isValidDecorator(data: any, key: string): boolean {
|
|
105
|
+
return data != null && this.propertyHasDecorator(data, key);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Valida si la propiedad tiene el decorador de seguridad
|
|
110
|
+
* @param data - Entidad objetivo
|
|
111
|
+
* @param key - Nombre de la propiedad
|
|
112
|
+
*/
|
|
113
|
+
private propertyHasDecorator(data: any, key: string): boolean {
|
|
114
|
+
return Reflect.hasMetadata(TOKEN_SECURE, data, key);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Valida si un objeto es seguro
|
|
119
|
+
* @param data - Objeto a validar
|
|
120
|
+
* @returns True si existe el decorador @Secure
|
|
121
|
+
*/
|
|
122
|
+
private hasDecorator(data: any): boolean {
|
|
123
|
+
return data != null && Reflect.hasMetadata(TOKEN_SECURE, data);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Valida si es un objeto y no esta nulo
|
|
128
|
+
* @param object - Objeto a validar
|
|
129
|
+
* @returns True si es un objeto valido
|
|
130
|
+
*/
|
|
131
|
+
private isValidObject(object: any): boolean {
|
|
132
|
+
return object != null && typeof object === 'object';
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Cifra los datos especificados
|
|
137
|
+
* @param datos - Datos a cifrar
|
|
138
|
+
* @returns Regresa el objeto con los datos cifrados
|
|
139
|
+
*/
|
|
140
|
+
private cifrarDatos(datos: any): any {
|
|
141
|
+
if (this.isValidObject(datos)) {
|
|
142
|
+
const contenedor: any = {};
|
|
143
|
+
Object.entries(datos).forEach(([key, value]) => {
|
|
144
|
+
if (this.isValidObject(value)) {
|
|
145
|
+
contenedor[key] = this.cifrarDatos(value)
|
|
146
|
+
}
|
|
147
|
+
else if (this.isValidDecorator(datos, key)) {
|
|
148
|
+
contenedor[key] = this.cifrarTexto(value as string);
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
contenedor[key] = value;
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
return this.hasDecorator(datos) ? this.cifrarTexto(JSON.stringify(contenedor)) : contenedor;
|
|
155
|
+
}
|
|
156
|
+
return datos;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Descifra los datos a partir de una definición
|
|
161
|
+
* @param datos - Datos a descifrar
|
|
162
|
+
* @param definition - Definición de los datos con los decoradores seguros
|
|
163
|
+
* @returns Datos descifrados
|
|
164
|
+
*/
|
|
165
|
+
private descifrarDatos(datos: any, definition: any): any {
|
|
166
|
+
let contenedor: any = datos;
|
|
167
|
+
if (datos && definition) {
|
|
168
|
+
|
|
169
|
+
if (Array.isArray(datos)) {
|
|
170
|
+
contenedor = [];
|
|
171
|
+
Object.entries(datos).forEach(([, value]) => {
|
|
172
|
+
contenedor.push(this.descifrarDatos(value, definition));
|
|
173
|
+
})
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
contenedor = {};
|
|
177
|
+
Object.entries(datos).forEach(([key, value]) => {
|
|
178
|
+
if (this.isValidObject(value)) {
|
|
179
|
+
contenedor[key] = this.descifrarDatos(value, definition.prototype[key])
|
|
180
|
+
}
|
|
181
|
+
else if (this.propertyHasDecorator(definition.prototype, key)) {
|
|
182
|
+
contenedor[key] = this.decifrarTexto(value as string);
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
contenedor[key] = value;
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return contenedor;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Cifra el texto especificado
|
|
195
|
+
* @param datos - Contiene los datos que se cifraran
|
|
196
|
+
* @returns Datos cifrados
|
|
197
|
+
*/
|
|
198
|
+
private cifrarTexto(datos: string): string {
|
|
199
|
+
return this.cifradoService.cifrar(datos);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Descifra el texto proporcionado
|
|
204
|
+
* @param datos - Contiene los datos que se descifraran
|
|
205
|
+
* @returns Datos descifrados
|
|
206
|
+
*/
|
|
207
|
+
private decifrarTexto(datosCifrados: string): string {
|
|
208
|
+
return this.cifradoService.descifrar(datosCifrados);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import 'reflect-metadata'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Fabrica de decoradores para del modulo de seguridad
|
|
5
|
+
* @param cipher Indica el algoritmo de cifrado
|
|
6
|
+
*/
|
|
7
|
+
export function secure(cipher?: string) {
|
|
8
|
+
/**
|
|
9
|
+
* Función para la fabrica de decoradores de clases y propiedades
|
|
10
|
+
* @param target Target del decorador
|
|
11
|
+
* @param propertyKey Nombre de la propiedad
|
|
12
|
+
* @returns Function de devolución para la fabrica de decoradores
|
|
13
|
+
*/
|
|
14
|
+
return function (target: any, propertyKey?: string) {
|
|
15
|
+
if (propertyKey) {
|
|
16
|
+
Reflect.defineProperty(target, propertyKey, { writable: true });
|
|
17
|
+
Reflect.defineMetadata(TOKEN_SECURE, cipher, target, propertyKey);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
Reflect.defineMetadata(TOKEN_SECURE, cipher, target.prototype);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Token para decorador de seguridad
|
|
27
|
+
*/
|
|
28
|
+
export const TOKEN_SECURE = secure.name;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enumera los tipos de operación para el modulo de seguridad
|
|
3
|
+
*/
|
|
4
|
+
export enum TipoOperacion {
|
|
5
|
+
/**
|
|
6
|
+
* Indica que la operación a realizar es una codificación
|
|
7
|
+
*/
|
|
8
|
+
Codificar,
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Indica que la operación a realizar es una decodificación
|
|
12
|
+
*/
|
|
13
|
+
Decodificar,
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Indica que se deberá realizar la codificación y decodificación
|
|
17
|
+
*/
|
|
18
|
+
CodificarYDecodificar
|
|
19
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { TestBed } from '@angular/core/testing';
|
|
2
|
+
|
|
3
|
+
import { CifradoService } from './cifrado.service';
|
|
4
|
+
|
|
5
|
+
describe('CifradoService', () => {
|
|
6
|
+
let service: CifradoService;
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
TestBed.configureTestingModule({});
|
|
10
|
+
service = TestBed.inject(CifradoService);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('should be created', () => {
|
|
14
|
+
expect(service).toBeTruthy();
|
|
15
|
+
});
|
|
16
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Servicio de cifrado y descifrado de información
|
|
5
|
+
* @decorator `@Injectable()`
|
|
6
|
+
*/
|
|
7
|
+
@Injectable({
|
|
8
|
+
providedIn: 'root'
|
|
9
|
+
})
|
|
10
|
+
export class CifradoService {
|
|
11
|
+
|
|
12
|
+
constructor() {
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Método que realiza el cifrado de los datos tipo Texto
|
|
17
|
+
* @param data - Texto a cifrar
|
|
18
|
+
* @returns Datos cifrados en modo tex
|
|
19
|
+
*/
|
|
20
|
+
public cifrar(data: string): string {
|
|
21
|
+
return window.btoa(encodeURIComponent(data));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Método que descifra el texto
|
|
26
|
+
* @params data - Texto a descifrar
|
|
27
|
+
* @returns Texto descifrado
|
|
28
|
+
*/
|
|
29
|
+
public descifrar(data: string): string {
|
|
30
|
+
return window.atob(decodeURIComponent(data));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
2
|
+
|
|
3
|
+
import { NgxRediCoreComponent } from './ngx-redi-core.component';
|
|
4
|
+
|
|
5
|
+
describe('NgxRediCoreComponent', () => {
|
|
6
|
+
let component: NgxRediCoreComponent;
|
|
7
|
+
let fixture: ComponentFixture<NgxRediCoreComponent>;
|
|
8
|
+
|
|
9
|
+
beforeEach(async () => {
|
|
10
|
+
await TestBed.configureTestingModule({
|
|
11
|
+
declarations: [ NgxRediCoreComponent ]
|
|
12
|
+
})
|
|
13
|
+
.compileComponents();
|
|
14
|
+
|
|
15
|
+
fixture = TestBed.createComponent(NgxRediCoreComponent);
|
|
16
|
+
component = fixture.componentInstance;
|
|
17
|
+
fixture.detectChanges();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('should create', () => {
|
|
21
|
+
expect(component).toBeTruthy();
|
|
22
|
+
});
|
|
23
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { NgModule } from '@angular/core';
|
|
2
|
+
import { NgxRediCoreComponent } from './ngx-redi-core.component';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@NgModule({
|
|
7
|
+
declarations: [
|
|
8
|
+
NgxRediCoreComponent
|
|
9
|
+
],
|
|
10
|
+
imports: [
|
|
11
|
+
],
|
|
12
|
+
exports: [
|
|
13
|
+
NgxRediCoreComponent
|
|
14
|
+
]
|
|
15
|
+
})
|
|
16
|
+
export class NgxRediCoreModule { }
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { TestBed } from '@angular/core/testing';
|
|
2
|
+
|
|
3
|
+
import { NgxRediCoreService } from './ngx-redi-core.service';
|
|
4
|
+
|
|
5
|
+
describe('NgxRediCoreService', () => {
|
|
6
|
+
let service: NgxRediCoreService;
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
TestBed.configureTestingModule({});
|
|
10
|
+
service = TestBed.inject(NgxRediCoreService);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('should be created', () => {
|
|
14
|
+
expect(service).toBeTruthy();
|
|
15
|
+
});
|
|
16
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
|
2
|
+
{
|
|
3
|
+
"extends": "../../tsconfig.json",
|
|
4
|
+
"compilerOptions": {
|
|
5
|
+
"outDir": "../../out-tsc/lib",
|
|
6
|
+
"declaration": true,
|
|
7
|
+
"declarationMap": true,
|
|
8
|
+
"inlineSources": true,
|
|
9
|
+
"types": []
|
|
10
|
+
},
|
|
11
|
+
"exclude": [
|
|
12
|
+
"**/*.spec.ts"
|
|
13
|
+
]
|
|
14
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
|
2
|
+
{
|
|
3
|
+
"extends": "../../tsconfig.json",
|
|
4
|
+
"compilerOptions": {
|
|
5
|
+
"outDir": "../../out-tsc/spec",
|
|
6
|
+
"types": [
|
|
7
|
+
"jasmine"
|
|
8
|
+
]
|
|
9
|
+
},
|
|
10
|
+
"include": [
|
|
11
|
+
"**/*.spec.ts",
|
|
12
|
+
"**/*.d.ts"
|
|
13
|
+
]
|
|
14
|
+
}
|