diff --git a/docs/sim-objenious/Alarms/Alarm by id.bru b/docs/sim-objenious/Alarms/Alarm by id.bru new file mode 100644 index 0000000..8c07ffc --- /dev/null +++ b/docs/sim-objenious/Alarms/Alarm by id.bru @@ -0,0 +1,24 @@ +meta { + name: Alarm by id + type: http + seq: 2 +} + +get { + url: {{baseUrl}}alarms/{{alarmId}} + body: none + auth: bearer +} + +auth:bearer { + token: {{ws-access-token-partenaire}} +} + +vars:pre-request { + alarmId: 2439 +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/docs/sim-objenious/Alarms/Alerts.bru b/docs/sim-objenious/Alarms/Alerts.bru new file mode 100644 index 0000000..17d4873 --- /dev/null +++ b/docs/sim-objenious/Alarms/Alerts.bru @@ -0,0 +1,28 @@ +meta { + name: Alerts + type: http + seq: 3 +} + +get { + url: {{baseUrl}}alarms/alerts?pageNumber=100 + body: none + auth: bearer +} + +params:query { + pageNumber: 100 +} + +auth:bearer { + token: {{ws-access-token-partenaire}} +} + +vars:pre-request { + alarmId: 2439 +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/docs/sim-objenious/Alarms/All Alarms.bru b/docs/sim-objenious/Alarms/All Alarms.bru new file mode 100644 index 0000000..d16789b --- /dev/null +++ b/docs/sim-objenious/Alarms/All Alarms.bru @@ -0,0 +1,20 @@ +meta { + name: All Alarms + type: http + seq: 1 +} + +get { + url: {{baseUrl}}alarms + body: none + auth: bearer +} + +auth:bearer { + token: {{ws-access-token-partenaire}} +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/docs/sim-objenious/Alarms/folder.bru b/docs/sim-objenious/Alarms/folder.bru new file mode 100644 index 0000000..3acaf58 --- /dev/null +++ b/docs/sim-objenious/Alarms/folder.bru @@ -0,0 +1,8 @@ +meta { + name: Alarms + seq: 21 +} + +auth { + mode: inherit +} diff --git a/packages/sim-consumidor-alai/.env b/packages/sim-consumidor-alai/.env index b79014f..c8d94e3 100644 --- a/packages/sim-consumidor-alai/.env +++ b/packages/sim-consumidor-alai/.env @@ -7,6 +7,7 @@ ALAI_API_URL=https://wsaccess.alaisecure.com/bssrest ALAI_CERTIFICATES_DIR=./certificates/ ALAI_CERTIFICATE_NAME=wsaccess_alaisecure_com_cert_client_new.p12 +ALAI_CERTIFICATE_PASSWORD=iHaaek+zyzWz6cH6rg== ALAI_USERNAME=palomaibanez ALAI_PASSWORD=palomaibanez1234 ALAI_BRANDID=savefamily diff --git a/packages/sim-consumidor-alai/aplication/AlaiTokenManager.ts b/packages/sim-consumidor-alai/aplication/AlaiTokenManager.ts index 4653c92..d622e98 100644 --- a/packages/sim-consumidor-alai/aplication/AlaiTokenManager.ts +++ b/packages/sim-consumidor-alai/aplication/AlaiTokenManager.ts @@ -15,6 +15,8 @@ export class AlaiTokenManager implements JWTProvider<{}> { if (res.error != undefined) { console.error("Error obteniendo el token de ALAI", res.error) + } else { + this.authToken = new JWTToken(res.data.accessToken) } } diff --git a/packages/sim-consumidor-alai/aplication/DebugTokenManager.ts b/packages/sim-consumidor-alai/aplication/DebugTokenManager.ts new file mode 100644 index 0000000..4d94ff1 --- /dev/null +++ b/packages/sim-consumidor-alai/aplication/DebugTokenManager.ts @@ -0,0 +1,50 @@ +import { JWTToken } from "sim-shared/domain/JWT.js"; +import { JWTProvider } from "sim-shared/infrastructure/HTTPClient.js"; +import { LegacyJWTTokenRepository } from "#infrastructure/LegacyJWTTokensRepository.js"; +import { env } from "#config/env/env.js"; + +const tokenDir = String(env.ALAI_CERTIFICATES_DIR) +const tokenFile = ".debugToken" + +/** + * Usa un token guardado a mano en archivo para no gastar tokens de Alai + */ +export class DebugTokenManager implements JWTProvider<{}> { + + isRefreshing: boolean = false; + authToken: JWTToken<{}> | undefined; + + private async getNewAuthToken() { + // TODO: Si no funcionase hay que reprogramar los mensajes para ser + // consumidos mas tarde. + const res = LegacyJWTTokenRepository.getTokenFromFile(tokenDir, tokenFile) + + + if (res.error != undefined) { + console.error("Error obteniendo el token de ALAI", res.error) + } else { + this.authToken = new JWTToken(res.data) + console.log("[d] Token DEBUG: ", this.authToken) + } + } + + public tryRefreshToken(): Promise> { + // En Alai no existe el concepto de refresh, se solicita otro token nuevo + return this.getAccessToken() + }; + + public async getAccessToken(): Promise> { + // Caso 1: El token actual es valido + if (this.authToken != undefined && !this.authToken.isExpired()) { + return this.authToken + } else { + // Caso 2: El token actual no existe o ha expirado + await this.getNewAuthToken() + } + + // Si después de todo no se ha generado el token es un error catastrofico + if (this.authToken == undefined) throw new Error("Error obteniendo tokens de auth") + + return this.authToken + }; +} diff --git a/packages/sim-consumidor-alai/aplication/SimAlai.controller.ts b/packages/sim-consumidor-alai/aplication/SimAlai.controller.ts index ed89565..c325a46 100644 --- a/packages/sim-consumidor-alai/aplication/SimAlai.controller.ts +++ b/packages/sim-consumidor-alai/aplication/SimAlai.controller.ts @@ -74,7 +74,6 @@ export class SimAlaiController { iccid: iccid, correlation_id: correlation_id })) - return res; } } @@ -99,6 +98,7 @@ export class SimAlaiController { } } + /* public reActivate() { return async (msg: ConsumeMessage) => { console.log("Evento reActivate ", msg.fields) @@ -113,6 +113,7 @@ export class SimAlaiController { return res; } } + */ /** * Select especificamente por REST para evitar pasar por las colas. @@ -136,7 +137,7 @@ export class SimAlaiController { // TODO: Automatizar la paginacion //const usecaseRes = this.uscases.selectMany({ iccid }) } else { - const usecaseRes = await this.uscases.selectOne({ iccid }) + const usecaseRes = await this.uscases.selectOne(iccid) if (usecaseRes.error != undefined) { res.status(500).json(usecaseRes) return; @@ -150,28 +151,29 @@ export class SimAlaiController { } } - - public selectPageREST() { - return async (req: Request, res: Response) => { - const { offset, limit, filter, orderBy } = req.query - const params = { - offset: (offset != undefined) ? Number(offset) : undefined, - limit: (limit != undefined) ? Number(limit) : undefined, - filter: (filter != undefined) ? String(filter) : undefined, - orderBy: (orderBy != undefined) ? String(orderBy) : undefined - } - - const usecaseRes = await this.uscases.selectPage(params) - - if (usecaseRes.error != undefined) { - res.status(500).json(usecaseRes) - return; - } else { - res.status(200).send(usecaseRes.data) - return; + /** + public selectPageREST() { + return async (req: Request, res: Response) => { + const { offset, limit, filter, orderBy } = req.query + const params = { + offset: (offset != undefined) ? Number(offset) : undefined, + limit: (limit != undefined) ? Number(limit) : undefined, + filter: (filter != undefined) ? String(filter) : undefined, + orderBy: (orderBy != undefined) ? String(orderBy) : undefined + } + + const usecaseRes = await this.uscases.selectPage(params) + + if (usecaseRes.error != undefined) { + res.status(500).json(usecaseRes) + return; + } else { + res.status(200).send(usecaseRes.data) + return; + } } } - } + **/ } diff --git a/packages/sim-consumidor-alai/aplication/SimAlai.router.ts b/packages/sim-consumidor-alai/aplication/SimAlai.router.ts index 71ca693..4d83559 100644 --- a/packages/sim-consumidor-alai/aplication/SimAlai.router.ts +++ b/packages/sim-consumidor-alai/aplication/SimAlai.router.ts @@ -14,15 +14,15 @@ type FuncType = ((m: ConsumeMessage) => Promise>) export class SimAlaiRouter { private readonly routes: Map; + // WIP constructor( private readonly simController: SimAlaiController, private readonly eventBus: EventBus ) { this.routes = new Map([ - //["select", undefined], ["activate", this.simController.activate()], ["pause", this.simController.suspend()], - ["reactivate", this.simController.reActivate()], + //["reactivate", this.simController.reActivate()], //["cancel", this.simController.terminate()], //["preActivate", this.simController.preActivate()] ]); diff --git a/packages/sim-consumidor-alai/aplication/SimAlai.usecases.ts b/packages/sim-consumidor-alai/aplication/SimAlai.usecases.ts index 66b47ac..1dee242 100644 --- a/packages/sim-consumidor-alai/aplication/SimAlai.usecases.ts +++ b/packages/sim-consumidor-alai/aplication/SimAlai.usecases.ts @@ -59,6 +59,10 @@ export class SimAlaiUsecases { return order } + /** + * Gestiona el ciclo de vida de una petición. No aplica + * a peticiones de lectura (no pasan por la cola y no generan un order) + */ public usecaseTemplate( func: (_: T) => Promise>, args: T, @@ -70,6 +74,8 @@ export class SimAlaiUsecases { this.setRunning(correlation_id) .then() .catch(e => console.error("Error actualizando el order", e)) + else + console.warn("[!] Se ha lanzado una caso de uso sin correlation_id") try { const res = await func(args) @@ -129,4 +135,9 @@ export class SimAlaiUsecases { return reserved }, args.iccid, args.correlation_id) } + + public async selectOne(iccid: string) { + const sim = await this.alaiRepository.getSimByICCID(iccid) + return sim + } } diff --git a/packages/sim-consumidor-alai/aplication/SslService.ts b/packages/sim-consumidor-alai/aplication/SslService.ts index 7846367..0cda0b5 100644 --- a/packages/sim-consumidor-alai/aplication/SslService.ts +++ b/packages/sim-consumidor-alai/aplication/SslService.ts @@ -13,6 +13,10 @@ export type SSLCert = { keypem: string } +/** + * TODO: + * - Se ha usado https.Agent en su lugar, eliminar si no se usa + */ export class SSLCertificateLoader { constructor( diff --git a/packages/sim-consumidor-alai/certificates/.debugToken b/packages/sim-consumidor-alai/certificates/.debugToken new file mode 100644 index 0000000..06ce4eb --- /dev/null +++ b/packages/sim-consumidor-alai/certificates/.debugToken @@ -0,0 +1 @@ +eyJhbGciOiJIUzM4NCJ9.eyJiciI6InNhdmVmYW1pbHkiLCJpcCI6IjUyLjIxNC4xMTIuMTgxIiwic3ViIjoiaW5mb3NhdmVmYW1pbHkiLCJzIjoiRVdTMTY0NjI4YjE0MmRlZWI3IiwicG9zIjoic2F2ZWZhbWlseUNhYyIsImlkV3NVc2VyIjoiODkiLCJpc012bmEiOmZhbHNlLCJkb21haW4iOiJBbGFpfHNhdmVmYW1pbHkiLCJpYXQiOjE3Nzc4OTA0ODEsImV4cCI6MTc3NzkwMTI4MX0.SNO14ONoayy7MEnauSsT7H4To7bbW_GYTq1ZvC2IdcdHZq8oOLlVPAJyu3uMXHRk diff --git a/packages/sim-consumidor-alai/config/env/env.ts b/packages/sim-consumidor-alai/config/env/env.ts index bf6019f..45a155f 100644 --- a/packages/sim-consumidor-alai/config/env/env.ts +++ b/packages/sim-consumidor-alai/config/env/env.ts @@ -38,6 +38,8 @@ export const env = { // ESPECIFICO ALAI ALAI_API_URL: process.env.ALAI_API_URL, ALAI_CERTIFICATES_DIR: process.env.ALAI_CERTIFICATES_DIR, + ALAI_CERTIFICATE_NAME: process.env.ALAI_CERTIFICATE_NAME, + ALAI_CERTIFICATE_PASSWORD: process.env.ALAI_CERTIFICATE_PASSWORD, ALAI_USERNAME: process.env.ALAI_USERNAME, ALAI_PASSWORD: process.env.ALAI_PASSWORD, ALAI_BRANDID: process.env.ALAI_BRANDID, @@ -52,3 +54,7 @@ assert.ok(env.ALAI_USERNAME != undefined, "ALAI_USERNAME no definido") assert.ok(env.ALAI_PASSWORD != undefined, "ALAI_PASSWORD no definido") assert.ok(env.ALAI_BRANDID != undefined, "ALAI_BRANDID no definido") assert.ok(env.ALAI_API_URL != undefined, "ALAI_API_URL no definido") + +assert.ok(env.ALAI_CERTIFICATE_NAME != undefined, "ALAI_CERTIFICATE_NAME no definido") +assert.ok(env.ALAI_CERTIFICATES_DIR != undefined, "ALAI_CERTIFICATES_DIR no definido") +assert.ok(env.ALAI_CERTIFICATE_PASSWORD != undefined, "ALAI_CERTIFICATE_PASSWORD no definido") diff --git a/packages/sim-consumidor-alai/config/httpClient.config.ts b/packages/sim-consumidor-alai/config/httpClient.config.ts index 02b28d3..d0402a1 100644 --- a/packages/sim-consumidor-alai/config/httpClient.config.ts +++ b/packages/sim-consumidor-alai/config/httpClient.config.ts @@ -1,11 +1,17 @@ import { HttpClient } from "sim-shared/infrastructure/HTTPClient.js" import { AlaiTokenManager } from "#aplication/AlaiTokenManager.js" import { env } from "#config/env/env.js"; +import { httpsAgent } from "./httpsAgent.js" +import { DebugTokenManager } from "#aplication/DebugTokenManager.js"; const tokenManager = new AlaiTokenManager() +const debugTokenManagr = new DebugTokenManager() +console.error("USANDO DebugTokenManager! Eliminar en prod") + export const alaiHttp = new HttpClient({ baseURL: env.ALAI_API_URL as string, headers: {}, - jwtManager: tokenManager + jwtManager: debugTokenManagr, + httpsAgent: httpsAgent }) diff --git a/packages/sim-consumidor-alai/config/httpsAgent.ts b/packages/sim-consumidor-alai/config/httpsAgent.ts index 20db79e..be41583 100644 --- a/packages/sim-consumidor-alai/config/httpsAgent.ts +++ b/packages/sim-consumidor-alai/config/httpsAgent.ts @@ -1,19 +1,14 @@ import fs from 'fs'; import https from 'https'; -import axios from 'axios'; import { env } from './env/env.js'; import path from 'path'; -const certificatesDir = env.ALAI_CERTIFICATES_DIR -const certificateName = env.ALAI_CERTIFICATE_NAME -// ... -const httpsAgent = new https.Agent({ - pfx: fs.readFileSync(path.join(certificatesDir, 'keystore.p12')), - passphrase: '' +const certificatesDir = String(env.ALAI_CERTIFICATES_DIR) +const certificateName = String(env.ALAI_CERTIFICATE_NAME) +const certificatePassword = String(env.ALAI_CERTIFICATE_PASSWORD) + +export const httpsAgent = new https.Agent({ + pfx: fs.readFileSync(path.join(certificatesDir, certificateName)), + passphrase: certificatePassword }); -// TODO: EJEMPLO, METER EN EL HTTP CLIENT -const result = await axios.get('https://myserver.internal.net:9443', { httpsAgent }); -// do something with the result - -// ... diff --git a/packages/sim-consumidor-alai/index.ts b/packages/sim-consumidor-alai/index.ts index 4344262..898a3f2 100644 --- a/packages/sim-consumidor-alai/index.ts +++ b/packages/sim-consumidor-alai/index.ts @@ -52,11 +52,11 @@ async function startWorker() { // WIP app.get("/select", alaiController.selectREST()) - app.get("/selectPage", alaiController.selectPageREST()) + //app.get("/selectPage", alaiController.selectPageREST()) app.listen(PORT, HOSTNAME, (e) => { if (e == undefined) { - console.log("[o] Servidor iniciado en el puerto %d", PORT) + console.log("[o] Servidor (Alai) iniciado en el puerto %d", PORT) } else { console.error("Error express ", e) } @@ -66,10 +66,10 @@ async function startWorker() { startWorker() .then(e => { - console.log("[o] Worker de SIM de NOS iniciado") + console.log("[o] Worker de SIM de Alai iniciado") }) .catch(e => { - console.log("[x] Error iniciando worker de SIM de NOS") + console.log("[x] Error iniciando worker de SIM de Alai") }) export default {} diff --git a/packages/sim-consumidor-alai/infrastructure/AlaiRepository.ts b/packages/sim-consumidor-alai/infrastructure/AlaiRepository.ts index 911ce23..671f9f0 100644 --- a/packages/sim-consumidor-alai/infrastructure/AlaiRepository.ts +++ b/packages/sim-consumidor-alai/infrastructure/AlaiRepository.ts @@ -108,7 +108,7 @@ export class AlaiRepository { public async getSimByICCID(iccid: string) { const endpoint = `/v1/sim/${iccid}` - const promReq = this.httpClient.post(endpoint, undefined) + const promReq = this.httpClient.post(endpoint, undefined) const res = await this.manageRequest(promReq) return res } diff --git a/packages/sim-consumidor-alai/infrastructure/LegacyJWTTokensRepository.ts b/packages/sim-consumidor-alai/infrastructure/LegacyJWTTokensRepository.ts new file mode 100644 index 0000000..41bb140 --- /dev/null +++ b/packages/sim-consumidor-alai/infrastructure/LegacyJWTTokensRepository.ts @@ -0,0 +1,65 @@ +import path from "path"; +import fs from 'fs'; +import { Result } from "sim-shared/domain/Result.js"; +import { PgClient } from "sim-shared/infrastructure/PgClient.js"; + +type TokenLine = { + id: number, + url: string, + user_name: string, + pass: string, + brand_id: string, + cert_file: string, + key_file: string, + ca_file: string, + p12_file: string, + cert_password: string, + token: string +} + +/** + * Repositorio para usar los tokens guardados en la bdd de intranet o en un archivo + */ +export class LegacyJWTTokenRepository { + constructor( + // En prod (no deberia usarse) tiene que apuntar a intranet + private pgClient: PgClient + ) { + } + + public async getTokenFromDB(): Promise> { + const query = "SELECT * FROM alai_api_credentials;" + + try { + const res = await this.pgClient.query(query) + if (res.rowCount == 0) { + return { + error: "Error recuperando el token actual" + } + } else { + return { + data: res.rows[0].token + } + } + } catch (e) { + return { + error: String(e) + } + } + } + + public static getTokenFromFile(dir: string, file: string): Result { + try { + const tokenPath = path.join(dir, file) + const fileContent = fs.readFileSync(tokenPath).toString() + return { + data: fileContent + } + } catch (e) { + return { + error: "[d!] No se ha podido leer el archivo del token de debug" + String(e) + } + } + } + +} diff --git a/packages/sim-shared/infrastructure/HTTPClient.ts b/packages/sim-shared/infrastructure/HTTPClient.ts index 6ed8490..b8b5da8 100644 --- a/packages/sim-shared/infrastructure/HTTPClient.ts +++ b/packages/sim-shared/infrastructure/HTTPClient.ts @@ -1,5 +1,6 @@ import axios, { AxiosInstance } from "axios" import { IJWTService, JWTToken } from "../domain/JWT.js" +import https from "https" // Cambiar por IJWRGeneralService @@ -20,11 +21,14 @@ export class HttpClient { constructor(args: { baseURL: string, headers: Record, - jwtManager: JWTProvider<{}> // todo: asociar el tipo de token, - jwtService?: IJWTService + jwtManager: JWTProvider<{}>, // todo: asociar el tipo de token + jwtService?: IJWTService, + httpsAgent: https.Agent }) { this.client = axios.create({ - ...args + baseURL: args.baseURL, + headers: args.headers, + httpsAgent: args.httpsAgent }) this.jwtManager = args.jwtManager