Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM maven:3.9-eclipse-temurin-17 as compilador
FROM maven:3.9-eclipse-temurin-25 as compilador

RUN echo "Se crea carpeta de servidor" && \
mkdir app
Expand All @@ -10,7 +10,7 @@ RUN echo "Se compila la aplicación" && \
mvn clean package -DskipTests && \
cp -f server.app/target/*.jar ./servidor.jar

FROM eclipse-temurin:17-jre
FROM eclipse-temurin:25-jre

LABEL version=1.0.0
LABEL description="Jonnattan Griffiths"
Expand Down
193 changes: 176 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,183 @@
# Emulador de algunas cosas interesantes

Emula el comportamiento de algunas aplicaciones que me siven para el desarrollo mobile
Ideal para hacer pruebas en desarrollo, se utilizara este servidor con mi pagina de prueba

##
Utiliza Spring boot durante el desarrollo

##
Está programado en JAVA con Spring boot y una conexión a base de datos MySQL

# Emulator Server API

[![SonarCloud](https://sonarcloud.io/images/project_badges/sonarcloud-black.svg)](https://sonarcloud.io/summary/new_code?id=jonnattangc_java.server)

[![Duplicated Lines (%)](https://sonarcloud.io/api/project_badges/measure?project=jonnattangc_java.server&metric=duplicated_lines_density)](https://sonarcloud.io/summary/new_code?id=jonnattangc_java.server)
[![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=jonnattangc_java.server&metric=reliability_rating)](https://sonarcloud.io/summary/new_code?id=jonnattangc_java.server)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=jonnattangc_java.server&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=jonnattangc_java.server)
[![Technical Debt](https://sonarcloud.io/api/project_badges/measure?project=jonnattangc_java.server&metric=sqale_index)](https://sonarcloud.io/summary/new_code?id=jonnattangc_java.server)
[![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=jonnattangc_java.server&metric=ncloc)](https://sonarcloud.io/summary/new_code?id=jonnattangc_java.server)
[![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=jonnattangc_java.server&metric=code_smells)](https://sonarcloud.io/summary/new_code?id=jonnattangc_java.server)
[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=jonnattangc_java.server&metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=jonnattangc_java.server)
[![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=jonnattangc_java.server&metric=reliability_rating)](https://sonarcloud.io/summary/new_code?id=jonnattangc_java.server)
[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=jonnattangc_java.server&metric=security_rating)](https://sonarcloud.io/summary/new_code?id=jonnattangc_java.server)
[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=jonnattangc_java.server&metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=jonnattangc_java.server)
[![Technical Debt](https://sonarcloud.io/api/project_badges/measure?project=jonnattangc_java.server&metric=sqale_index)](https://sonarcloud.io/summary/new_code?id=jonnattangc_java.server)
[![Bugs](https://sonarcloud.io/api/project_badges/measure?project=jonnattangc_java.server&metric=bugs)](https://sonarcloud.io/summary/new_code?id=jonnattangc_java.server)
[![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=jonnattangc_java.server&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=jonnattangc_java.server)
[![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=jonnattangc_java.server&metric=code_smells)](https://sonarcloud.io/summary/new_code?id=jonnattangc_java.server)
[![Duplicated Lines (%)](https://sonarcloud.io/api/project_badges/measure?project=jonnattangc_java.server&metric=duplicated_lines_density)](https://sonarcloud.io/summary/new_code?id=jonnattangc_java.server)
[![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=jonnattangc_java.server&metric=ncloc)](https://sonarcloud.io/summary/new_code?id=jonnattangc_java.server)

---

## Resumen

Emulador de APIs de terceros construido para apoyar el desarrollo mobile y pruebas de integración. Expone endpoints REST que replican el comportamiento de servicios de pago, tokenización, autenticación y gestión de tarjetas, y persiste transacciones, tarjetas, usuarios y configuraciones en MySQL.

## Tecnologías

| Componente | Versión |
|---------------------|----------|
| Java | 21 |
| Spring Boot | 4.0.5 |
| MySQL Connector | 8.0.33 |
| Lombok | 1.18.38 |
| BouncyCastle | 1.70 |
| Apache HttpClient | 4.5.14 |
| Log4j2 | 2.21.0 |
| JUnit | 4.13.1 |
| Maven | 3.9 |

## Arquitectura

Proyecto Maven multi-módulo:

| Módulo | Responsabilidad |
|-------------------|----------------------------------------------------------------------------------|
| `server.app` | Aplicación Spring Boot. Controllers REST y punto de entrada (`Application.java`). |
| `server.services` | Lógica de negocio, configuración, seguridad, criptografía y utilidades. |
| `server.dao` | Repositorios Spring Data JPA. |
| `server.domain` | Entidades JPA (`Card`, `Transaction`, `User`, `Device`, `Configuration`) y enums. |
| `server.json` | DTOs de request/response y serialización Jackson. |

```
java.server/
├── server.app/ # Controllers y bootstrap Spring Boot
├── server.services/ # Servicios, configuración y utilidades
├── server.dao/ # Repositorios JPA
├── server.domain/ # Entidades y enums
├── server.json/ # DTOs
├── Dockerfile
├── docker-compose.yml
└── pom.xml # POM raíz
```

## Endpoints

> Base path: `${CONTEXT}` (por defecto `/emulator`). Todos los ejemplos omiten el context path.

### Configuración dinámica — `/config`

| Método | Path | Request | Response | Descripción |
|--------|-------------------|----------------------------------|-----------------------------------|-----------------------------------------------|
| POST | `/config/create` | `AppConfigurationRequestDTO` | `String` | Crea configuración para un endpoint. |
| POST | `/config/update` | `AppConfigurationRequestDTO` | `String` | Actualiza configuración existente. |
| POST | `/config/save` | `AppConfigurationRequestDTO` | `String` | Persiste la configuración. |
| GET | `/config/list` | — | `AppListConfigurationDTOResponse` | Lista todas las configuraciones. |

### Pagos y Tokens (TecApi) — `CetipaController`

| Método | Path | Request | Response | Descripción |
|--------|---------------------------------------------------|--------------------------------------------|----------------|-----------------------------------------------------------|
| POST | `/pay/ptm/v1/authorizations` | `EdrPayAuthorizeRequestDTO` | `IEmulator` | Autoriza una transacción de pago. |
| POST | `/pay/ptm/v1/voids` | `EdrPaymentReverseRequestDTO` | `IEmulator` | Reversa o anula una transacción autorizada. |
| POST | `/tsp/ttm/v1/enrollments` | `EdrTokenEnrollmentRequestDTO` | `IEmulator` | Enrola un dispositivo o tarjeta. |
| POST | `/tsp/ttm/v1/par/search` | `EdrTokenGetDigitalPanRequestDTO` | `IEmulator` | Búsqueda de tarjeta digital (PAR). |
| GET | `/tsp/ttm/v1/tokens/{token}` | — | `IEmulator` | Obtiene el detalle del token. |
| POST | `/tsp/ttm/v1/tokens/{token}/acquired` | — | `String` | Notifica que el token fue adquirido. |
| POST | `/tsp/ttm/v1/tokens/{token}/cryptograms` | `EdrPaymentCreateCryptogramRequestDTO` | `IEmulator` | Genera criptograma para el token. |
| POST | `/pay/prm/v1/requestors/{requestor}/logon` | `EdrPaymentLogonRequestDTO` | `IEmulator` | Logon PRM (Payment Requestor). Retorna `access_token` en header. |
| POST | `/tsp/trm/v1/requestors/{requestor}/logon` | `EdrTokenLogonRequestDTO` | `IEmulator` | Logon TRM (Token Requestor). Retorna `access_token` en header. |

### Commerce — `/commerceapps`

| Método | Path | Request | Response | Descripción |
|--------|---------------------------|---------------------------|----------------------------|------------------------------------------|
| POST | `/commerceapps/sendMail` | Body crudo | `CommerceMailResponseDTO` | Simula envío de email desde Commerce. |
| POST | `/commerceapps/getToken` | `MultiValueMap` (headers) | `CommerceTokenResponseDTO` | Emite token de acceso emulado. |

### CXP (proxy ChileExpress) — `/cxp`

| Método | Path | Request | Response | Descripción |
|--------|-------------|-------------------------|---------------------|----------------------------------------------------------|
| POST | `/cxp/**` | `HttpServletRequest` | `ICxpResponse` | Reenvía POST al backend CXP configurado dinámicamente. |
| GET | `/cxp/**` | `HttpServletRequest` | `String` | Reenvía GET al backend CXP configurado dinámicamente. |

### Logon externos — `/edr`

| Método | Path | Request | Response | Descripción |
|--------|---------------------------|---------------------------|------------|---------------------------------|
| POST | `/edr/login/tickettest` | `MultiValueMap` (headers) | `String` | Logon de prueba (EDR). |
| POST | `/edr/login/ticket` | `MultiValueMap` (headers) | `String` | Logon EDR. |
| POST | `/edr/login/beanuj` | `MultiValueMap` (headers) | `String` | Logon JUNAEB. |

### EDR-EGD Foods

| Método | Path | Request | Response | Descripción |
|--------|-----------------------------|-----------------------|---------------|------------------------------------------|
| ANY | `/api/v1/foods/cards/**` | `HttpServletRequest` | `IEmulator` | Búsqueda y procesamiento de tarjetas. |

### Página personal — `/page`

| Método | Path | Request | Response | Descripción |
|--------|----------------------|--------------------------------------|---------------|--------------------------------------|
| POST | `/page/users/save` | `MultiValueMap` (form-urlencoded) | `IEmulator` | Registra un usuario nuevo (CORS). |
| GET | `/page/users` | — | `IEmulator` | Lista los usuarios (CORS). |

## Configuración

La aplicación selecciona su perfil activo mediante la variable `ENV` (`local`, `dev`, `prod`).

### Variables de entorno

| Variable | Descripción | Default |
|--------------|-------------------------------------------------|---------------|
| `ENV` | Perfil Spring activo. | `dev` |
| `PORT` | Puerto HTTP del servidor. | `8089` |
| `CONTEXT` | Context path de la aplicación. | `/emulator` |
| `BD_ADDR` | Host MySQL. | — |
| `BD_PORT` | Puerto MySQL. | `3306` |
| `BD_NAME` | Nombre del esquema. | — |
| `BD_USER` | Usuario MySQL. | — |
| `BD_PASS` | Password MySQL. | — |
| `LOG_LEVEL` | Nivel de logging (`DEBUG`, `INFO`, ...). | `INFO` |
| `AES_KEY` | Clave AES para cifrado (32+ caracteres). | — |

### Persistencia

- JDBC URL: `jdbc:mysql://${BD_ADDR}:${BD_PORT}/${BD_NAME}?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true&autoReconnect=true`
- Pool: HikariCP (`max-pool-size=10`, `connection-timeout=30s`).
- DDL: `hibernate.ddl-auto=update` en ambientes de desarrollo.
- Perfil `local` usa H2 en memoria.

## Ejecución

### Maven

```bash
export ENV=local
export PORT=8089
export CONTEXT=/emulator
export LOG_LEVEL=DEBUG
export AES_KEY=''
export BD_ADDR=localhost
export BD_PORT=3306
export BD_NAME=emulator
export BD_USER=emulator
export BD_PASS=''

mvn clean package
java -Xmx1024m -Xms512m -jar server.app/target/server.app-1.2.0-SNAPSHOT.jar
```

### Docker

```bash
docker build -t java-server:v1 .
docker-compose up -d
```

`docker-compose.yml` publica el puerto `8089` y lee las variables desde `../envs/java_server.env`. El `Dockerfile` usa build multi-stage con Maven 3.9 y Eclipse Temurin 25 como runtime.

## Seguridad

Consulta [SECURITY.md](./SECURITY.md) para la política de reporte de vulnerabilidades.

## Licencia

Ver [LICENSE](./LICENSE).
6 changes: 3 additions & 3 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ services:
restart: always
deploy:
replicas: 1
env_file:
- ../envs/java_server.env
env_file:
- ../envs/java_server.env
networks:
- db-net
- db-net
ports:
- 8089:8089
networks:
Expand Down
28 changes: 21 additions & 7 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@
<java.version>21</java.version>
<test.version>1.2.0-SNAPSHOT</test.version>
<spring.boot.version>4.0.5</spring.boot.version>
<junit.version>4.13.1</junit.version>
<javax.json-api.version>1.1.4</javax.json-api.version>
<hibernate-types-52.version>2.6.1</hibernate-types-52.version>
<javax.json.version>1.1.4</javax.json.version>
<org.osgi.core.version>1.0.0</org.osgi.core.version>
<lombok.version>1.18.38</lombok.version>
<maven-bundle-plugin.version>4.2.1</maven-bundle-plugin.version>
<jacoco.version>0.8.12</jacoco.version>
</properties>

<dependencyManagement>
Expand All @@ -43,12 +43,6 @@
<version>${spring.boot.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
Expand Down Expand Up @@ -154,6 +148,26 @@
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
<executions>
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>verify</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
4 changes: 2 additions & 2 deletions server.app/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@

/**
* Controlles respuesta a la APPs Cmc
*
*
* @author Jonnattan Griffiths
* @since Programa EMULADOR
* @version 1.0 del 30-09-2020
*
*
*/
@RestController
@RequestMapping("/commerceapps")
Expand All @@ -43,8 +43,9 @@ public ResponseEntity<CommerceMailResponseDTO> sendMail(HttpServletRequest reque
int dato = -1;
ServletInputStream sis = request.getInputStream();
ByteBuffer bb = ByteBuffer.allocate(1024);
while ((dato = sis.read()) != -1)
while ((dato = sis.read()) != -1) {
bb.put((byte) dato);
}
bb.flip();
int len = bb.remaining();
String body = "";
Expand All @@ -69,6 +70,6 @@ public ResponseEntity<CommerceTokenResponseDTO> getToken(@RequestHeader MultiVal
token.setAccess_token("1111111222222333334444455555666677788899");
token.setExpires_in(10);
token.setToken_type("Emnulado");
return new ResponseEntity<CommerceTokenResponseDTO>(token, HttpStatus.OK);
return new ResponseEntity<>(token, HttpStatus.OK);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@


import cl.jonnattan.emulator.dto.AppListConfigurationDTOResponse;
import cl.jonnattan.emulator.dto.ints.IEmulator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
Expand All @@ -25,20 +23,23 @@
* Controller de configuraci'on de emulador
* Sirve para configurar como queremos que respondan los servicios
* ac'a definidos
*
*
* @author Jonnattan Griffiths
* @since Programa EMULADOR
* @version 1.0 del 22-06-2020
*
*
*/
@RestController
@RequestMapping("/config")
public class AppController {

private static final Logger logger = LoggerFactory.getLogger(AppController.class);

@Autowired
private IConfigurations configService;

private final IConfigurations configService;

public AppController(IConfigurations configService) {
this.configService = configService;
}

@PostMapping(value = "/update")
public ResponseEntity<String> update(@Valid @RequestBody AppConfigurationRequestDTO request) {
Expand Down Expand Up @@ -82,16 +83,16 @@ public ResponseEntity<String> save(@Valid @RequestBody AppConfigurationRequestDT
return new ResponseEntity<>(success, status);
}

@GetMapping(value = "/list")
public ResponseEntity<AppListConfigurationDTOResponse> list(){
logger.info(UtilConst.LINE);
HttpStatus status = HttpStatus.OK;
AppListConfigurationDTOResponse response = null;
try {
response = configService.getConfigurations();
} catch (ConfException e) {
status = e.getStatus();
}
return new ResponseEntity<AppListConfigurationDTOResponse>(response, status);
}
@GetMapping(value = "/list")
public ResponseEntity<AppListConfigurationDTOResponse> list(){
logger.info(UtilConst.LINE);
HttpStatus status = HttpStatus.OK;
AppListConfigurationDTOResponse response = null;
try {
response = configService.getConfigurations();
} catch (ConfException e) {
status = e.getStatus();
}
return new ResponseEntity<>(response, status);
}
}
Loading
Loading