diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml new file mode 100644 index 0000000..2144787 --- /dev/null +++ b/.github/workflows/integration.yaml @@ -0,0 +1,62 @@ +name: Integration + +on: + pull_request: + branches: ["dev"] + +jobs: + check-format: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-python@v4 + with: + python-version: '3.11' + cache: 'pip' + + - name: Install dependencies + run: pip install -r requirements.txt + + - name: Check format + run: black --check . + + check-linter: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-python@v4 + with: + python-version: '3.11' + cache: 'pip' + + - name: Install dependencies + run: pip install -r requirements.txt + + - name: Check linter + run: ruff check . + + test: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + + - name: Set up docker environment + run: docker-compose up -d + + - uses: actions/setup-python@v4 + with: + python-version: '3.11' + cache: 'pip' + + - name: Install dependencies + run: pip install -r requirements.txt + + - name: Run tests + run: pytest + env: + PYTHONPATH: "." + + - name: Clean docker environment + run: docker compose down --rmi all -v --remove-orphans \ No newline at end of file diff --git a/.github/workflows/testing.yaml b/.github/workflows/testing.yaml deleted file mode 100644 index c627fe7..0000000 --- a/.github/workflows/testing.yaml +++ /dev/null @@ -1,30 +0,0 @@ -name: Test - -on: - pull_request: - branches: ["dev"] - -jobs: - test: - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v3 - - - name: Set up docker environment - run: docker-compose up -d - - - uses: actions/setup-python@v4 - with: - python-version: '3.11' - cache: 'pip' - - - name: Install dependencies - run: pip install -r requirements.txt - - - name: Run tests - run: pytest - env: - PYTHONPATH: "." - - - name: Clean docker environment - run: docker compose down --rmi all -v --remove-orphans \ No newline at end of file diff --git a/.gitignore b/.gitignore index 6127ff0..a9b9dfc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,12 @@ +# Python files venv __pycache__ + +# Vscode files +.vscode/* +!.vscode/extensions.json + +# Pipelines files .coverage node_modules coverage.xml \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..be3e2f8 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,8 @@ +{ + "recommendations": [ + "ms-python.python", + "ms-python.black-formatter", + "charliermarsh.ruff", + "usernamehw.errorlens" + ] +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 0637aa1..85afce8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,22 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### 0.0.6 (2023-10-08) + + +### Features + +* endpoint challenge ([#33](https://github.com/hawks-atlanta/proxy-python/issues/33)) ([ee78fb6](https://github.com/hawks-atlanta/proxy-python/commit/ee78fb6864d0f6616464439c5c177884e514cf29)) + +### 0.0.5 (2023-10-04) + + +### Features + +* endpoint login ([#15](https://github.com/hawks-atlanta/proxy-python/issues/15)) ([4921ca1](https://github.com/hawks-atlanta/proxy-python/commit/4921ca11b886d950d7811f67ac573b7a9adc6831)) + +### 0.0.4 (2023-08-24) + ### 0.0.3 (2023-08-24) diff --git a/README.md b/README.md index f850d17..aa2ec4f 100644 --- a/README.md +++ b/README.md @@ -60,8 +60,34 @@ docker compose up -d coverage run -m pytest ``` +### Formatting and linting + +If you installed the recommended extensions for VSCode, you may have the formatting and linting configured out of the box. + +Additionally, you may need to configure `black` to format `python` files with the following steps: + +- Open the command palette (Ctrl + Shift + P) +- Search Format Document With... +- Search Configure Default Formatter... +- Select "Black Formatter" + +You can also run the following commands to format and lint the code from the console: + +```bash +# Check format +black --check . + +# Format all python files +black . + +# Check lint +ruff check . + +# Fix lint (if possible) +ruff check --fix . +``` + ## Coverage | [![circle](https://codecov.io/gh/hawks-atlanta/proxy-python/graphs/sunburst.svg?token=JODBEVCYCF)](https://app.codecov.io/gh/hawks-atlanta/proxy-python) | [![square](https://codecov.io/gh/hawks-atlanta/proxy-python/graphs/tree.svg?token=JODBEVCYCF)](https://app.codecov.io/gh/hawks-atlanta/proxy-python) | -| ------------------------------------------------------------ | ------------------------------------------------------------ | - +| -------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | diff --git a/docker-compose.yaml b/docker-compose.yaml index 99b65e8..d48e5d2 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,4 +1,4 @@ -version: '3.1' +version: "3.1" services: # Gateway @@ -11,9 +11,24 @@ services: environment: METADATA_BASEURL: http://metadata:8080 AUTHENTICATION_BASEURL: http://authentication:8080 - # TODO: Worker + WORKER_HOST: worker + WORKER_PORT: 1099 + depends_on: + - worker + - metadata + - authentication # Microservices - # TODO: Add worker service + worker: + image: ghcr.io/hawks-atlanta/worker-java:latest + container_name: worker + restart: on-failure + ports: + - "127.0.0.1:1099:1099" + environment: + METADATA_BASEURL: http://metadata:8080/api/v1 + # Use the default directory that is created in the worker container + # VOLUME_BASE_PATH: /tmp + # VOLUME_COUNT: 3 metadata: image: ghcr.io/hawks-atlanta/metadata-scala:latest container_name: metadata @@ -21,11 +36,13 @@ services: ports: - "127.0.0.1:8082:8080" environment: - DATABASE_HOST: "postgres-db" + DATABASE_HOST: "metadata-db" DATABASE_PORT: "5432" DATABASE_NAME: "database" DATABASE_USER: "username" DATABASE_PASSWORD: "password" + depends_on: + - metadata-db authentication: image: ghcr.io/hawks-atlanta/authentication-go:latest container_name: authentication @@ -34,11 +51,13 @@ services: - "127.0.0.1:8083:8080" environment: DATABASE_ENGINE: postgres - DATABASE_DSN: "host=postgres-db user=username password=password dbname=database port=5432 sslmode=disable" - # Database - postgres-db: - image: postgres:latest - container_name: postgres-db + DATABASE_DSN: "host=authentication-db user=username password=password dbname=database port=5432 sslmode=disable" + depends_on: + - authentication-db + # Databases + authentication-db: + image: postgres:alpine3.18 + container_name: authentication-db restart: on-failure ports: - "127.0.0.1:5432:5432" @@ -46,7 +65,16 @@ services: - POSTGRES_USER=username - POSTGRES_PASSWORD=password - POSTGRES_DB=database - + metadata-db: + image: postgres:alpine3.18 + container_name: metadata-db + restart: on-failure + ports: + - "127.0.0.1:5434:5432" + environment: + - POSTGRES_USER=username + - POSTGRES_PASSWORD=password + - POSTGRES_DB=database postgres-admin: image: dpage/pgadmin4 container_name: postgres-admin @@ -56,4 +84,5 @@ services: - PGADMIN_DEFAULT_EMAIL=postgres@postgres.com - PGADMIN_DEFAULT_PASSWORD=postgres depends_on: - - postgres-db \ No newline at end of file + - authentication-db + - metadata-db diff --git a/docs/spec.openapi.yaml b/docs/spec.openapi.yaml new file mode 100644 index 0000000..830f42a --- /dev/null +++ b/docs/spec.openapi.yaml @@ -0,0 +1,597 @@ +openapi: 3.0.3 + +info: + title: Proxy Python + license: + name: MIT + url: https://github.com/hawks-atlanta/proxy-python/blob/main/LICENSE + version: 1.0.0 + +tags: + - name: Authentication + - name: Account + - name: Authorization + - name: Files + +paths: + /login: + post: + tags: + - Authentication + description: Authenticates to the server + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/credentials" + responses: + "200": + description: Login succeed + content: + application/json: + schema: + $ref: "#/components/schemas/authorization" + "401": + description: Invalid credentials + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + "500": + description: Internal error + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + /register: + post: + tags: + - Authentication + description: Register the new user in the service + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/credentials" + responses: + "201": + description: Registration succeed + content: + application/json: + schema: + $ref: "#/components/schemas/authorization" + "409": + description: Username already registered + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + "500": + description: Internal error + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + /challenge: + post: + tags: + - Authorization + description: Verifies the received token is still valid + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/authorization" + responses: + "200": + description: Account token is still valid + content: + application/json: + schema: + $ref: "#/components/schemas/account" + "401": + description: Unauthorized + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + "500": + description: Internal error + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + /account/password: + patch: + tags: + - Account + description: Updates the username password + requestBody: + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/authorization" + - type: object + properties: + currentPassword: + type: string + newPassword: + type: string + responses: + "200": + description: Password updated successfully + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + "401": + description: Unauthorized + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + "500": + description: Internal error + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + + /files: + post: + tags: + - Files + description: Create a new file + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + fileName: + type: string + location: + type: string + file: + type: string + responses: + "201": + description: File created successfully + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + "401": + description: Not authorized + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + "500": + description: Internal error + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + + /folders: + post: + tags: + - Files + description: Create a new folder + requestBody: + content: + application/json: + schema: + type: object + properties: + folderName: + type: string + location: + type: string #UUID + responses: + "201": + description: Folder created successfully + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + "401": + description: Not authorized + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + "500": + description: Internal error + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + + /files/shared: + get: + tags: + - Files + description: Gets the list of shared files + responses: + "200": + description: List of shared files obtained + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/fileDetailsShared" + "401": + description: Not authorized + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + "500": + description: Internal error + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + /files/{fileId}/edit: + put: + tags: + - Files + description: Edit an existing file + parameters: + - in: path + name: fileId + required: true + schema: + type: string + - in: query + name: newContent + required: true + schema: + type: string + responses: + "200": + description: File successfully edited + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + "401": + description: Not authorized + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + "500": + description: Internal error + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + /files/{fileId}: + delete: + tags: + - Files + description: Deletes an existing file + parameters: + - in: path + name: fileId + required: true + schema: + type: string + responses: + "200": + description: File successfully deleted + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + "401": + description: Not authorized + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + "500": + description: Internal error + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + /files/{fileId}/move: + patch: + tags: + - Files + description: Move an existing file to a different location + parameters: + - in: path + name: fileId + required: true + schema: + type: string + - in: query + name: newLocation + required: true + schema: + type: string + responses: + "200": + description: File moved successfully + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + "401": + description: Not authorized + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + "500": + description: Internal error + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + + /files/list: + get: + tags: + - Files + description: List files in a given location + parameters: + - in: query + name: location + required: false + schema: + type: string + description: The location (UUID) to list files from + responses: + "200": + description: List of files in the location + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/fileDetails" + "401": + description: Not authorized + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + "500": + description: Internal error + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + + /files/download/{fileUUID}: + get: + tags: + - Files + description: Download a file by UUID + parameters: + - in: path + name: fileUUID + required: true + schema: + type: string + description: The UUID of the file to download + responses: + "200": + description: File downloaded successfully + content: + application/octet-stream: + schema: + type: string + format: binary + "401": + description: Not authorized + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + "404": + description: File not found + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + "500": + description: Internal error + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + + /files/share: + post: + tags: + - Files + description: Share a file with a user + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/shareWithReq" + responses: + "200": + description: File shared successfully + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + "400": + description: Bad request + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + "401": + description: Not authorized + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + "404": + description: File not found + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + "500": + description: Internal error + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + + /files/unshare: + post: + tags: + - Files + description: Unshare a file with a user + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/shareWithReq" + responses: + "200": + description: File unshared successfully + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + "400": + description: Bad request + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + "401": + description: Not authorized + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + "404": + description: File not found + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + "500": + description: Internal error + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + + /files/sharedwithwho: + get: + tags: + - Files + description: Get the list of users the file is shared with + parameters: + - in: query + name: fileUUID + required: true + schema: + type: string + responses: + "200": + description: List of users the file is shared with + content: + application/json: + schema: + type: object + properties: + users: + type: array + items: + type: string + example: sulcud + + "401": + description: Not authorized + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + "404": + description: File not found + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + "500": + description: Internal error + content: + application/json: + schema: + $ref: "#/components/schemas/statusResponse" + +components: + schemas: + account: + type: object + properties: + uuid: + type: string + statusResponse: + type: object + properties: + msg: + type: string + credentials: + type: object + properties: + username: + type: string + example: sulcud + password: + type: string + example: password + authorization: + type: object + properties: + jwt: + type: string + fileDetails: + type: object + properties: + fileName: + type: string + fileSize: + type: integer + isFile: + type: boolean + fileUUID: + type: string + fileDetailsShared: + type: object + properties: + fileName: + type: string + fileSize: + type: integer + isFile: + type: boolean + fileUUID: + type: string + ownerusername: + type: string + shareWithReq: + type: object + properties: + fileUUID: + type: string + otherUsername: + type: string diff --git a/main.py b/main.py index 33b5539..c8edc98 100644 --- a/main.py +++ b/main.py @@ -1,6 +1,8 @@ import flask -import pages.home +from src.views import views -app = flask.Flask(__name__, template_folder="templates") +app = flask.Flask(__name__) +app.register_blueprint(views) -app.register_blueprint(pages.home.home) +if __name__ == "__main__": + app.run(debug=True) diff --git a/package-lock.json b/package-lock.json index 6bd4c6a..dfe5b9f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { "name": "frontend-python", - "version": "0.0.3", + "version": "0.0.6", "lockfileVersion": 3, "requires": true, "packages": { "": { - "version": "0.0.3", + "version": "0.0.6", "devDependencies": { "git-semver-tags": "^4.1.1", "standard-version": "^9.5.0" diff --git a/package.json b/package.json index e6d1774..6697cfe 100644 --- a/package.json +++ b/package.json @@ -3,5 +3,5 @@ "git-semver-tags": "^4.1.1", "standard-version": "^9.5.0" }, - "version": "0.0.3" + "version": "0.0.6" } diff --git a/pages/home/__init__.py b/pages/home/__init__.py deleted file mode 100644 index c02413e..0000000 --- a/pages/home/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -import flask -from ._view import * - -home = flask.Blueprint("home", __name__) -home.register_blueprint(view) \ No newline at end of file diff --git a/pages/home/_view.py b/pages/home/_view.py deleted file mode 100644 index 9e3e92a..0000000 --- a/pages/home/_view.py +++ /dev/null @@ -1,7 +0,0 @@ -import flask - -view = flask.Blueprint("home", __name__) - -@view.route("/", methods=["GET"]) -def index(): - return flask.render_template("index.html") \ No newline at end of file diff --git a/pages/home/_view_test.py b/pages/home/_view_test.py deleted file mode 100644 index 59d3e45..0000000 --- a/pages/home/_view_test.py +++ /dev/null @@ -1,5 +0,0 @@ -from main import app - -def test_view() -> None: - response = app.test_client().get("/") - assert response.status_code == 200 \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index c119a06..7e74095 100644 Binary files a/requirements.txt and b/requirements.txt differ diff --git a/src/config/environment.py b/src/config/environment.py new file mode 100644 index 0000000..5f7962d --- /dev/null +++ b/src/config/environment.py @@ -0,0 +1,5 @@ +import os + +variables = { + "GATEWAY_BASEURL": os.getenv("GATEWAY_BASEURL", "http://localhost:8080"), +} diff --git a/src/config/soap_client.py b/src/config/soap_client.py new file mode 100644 index 0000000..8235b0d --- /dev/null +++ b/src/config/soap_client.py @@ -0,0 +1,5 @@ +from zeep import Client +from .environment import variables + +soap_wsdl = f"{variables['GATEWAY_BASEURL']}/gw/service?wsdl" +soap_client = Client(soap_wsdl) diff --git a/src/controllers/_authentication_controllers.py b/src/controllers/_authentication_controllers.py new file mode 100644 index 0000000..1807967 --- /dev/null +++ b/src/controllers/_authentication_controllers.py @@ -0,0 +1,61 @@ +from flask import request +from src.config.soap_client import soap_client + + +def login_handler(): + try: + # Get JSON data from the request + data = request.json + + if not data: + return {"msg": "No JSON data provided in the request"}, 400 + + username = data.get("username") + password = data.get("password") + + if not username or not password: + return {"msg": "Required fields are missing in JSON data"}, 400 + + result = soap_client.service.auth_login( + {"username": username, "password": password} + ) + + if result.auth is not None: + jwt = result.auth.token + return {"msg": "Login successful", "jwt": jwt}, 200 + + return {"msg": "Invalid credentials"}, 401 + + except Exception as e: + print("SOAP Error:", str(e)) + return {"msg": "Internal error", "error": str(e)}, 500 + + +def challenge(): + try: + data = request.json + + if not data: + return {"msg": "No JSON data provided in the request"}, 400 + + token = data.get("jwt") + + if not token: + return {"msg": "Token is missing in JSON data"}, 400 + + response = soap_client.service.auth_refresh({"token": token}) + + print(response) + + if hasattr(response, "auth") and hasattr(response.auth, "token"): + jwt = response.auth.token + return { + "msg": "JWT refreshed successfully", + "jwt": jwt, + }, 200 + else: + return {"msg": response.msg}, response.code + + except Exception as e: + print("Error:", str(e)) + return {"msg": "Internal error: " + str(e)}, 500 diff --git a/src/views/__init__.py b/src/views/__init__.py new file mode 100644 index 0000000..127bccd --- /dev/null +++ b/src/views/__init__.py @@ -0,0 +1,9 @@ +import flask +from ._authentication_views import views as authentication_views + + +# NOTE: Register all views / routes using the following blueprint +views = flask.Blueprint("views", __name__) + + +views.register_blueprint(authentication_views) diff --git a/src/views/_authentication_views.py b/src/views/_authentication_views.py new file mode 100644 index 0000000..618e056 --- /dev/null +++ b/src/views/_authentication_views.py @@ -0,0 +1,14 @@ +import flask +from src.controllers import _authentication_controllers + +views = flask.Blueprint("authentication", __name__) + + +@views.route("/auth_login", methods=["POST"]) +def auth_login(): + return _authentication_controllers.login_handler() + + +@views.route("/auth_refresh", methods=["POST"]) +def auth_refresh(): + return _authentication_controllers.challenge() diff --git a/src/views/_authentication_views_test.py b/src/views/_authentication_views_test.py new file mode 100644 index 0000000..e12914a --- /dev/null +++ b/src/views/_authentication_views_test.py @@ -0,0 +1,95 @@ +import json +from main import app +from config.soap_client import soap_client + + +def test_auth_login_successful() -> None: + registration_data = {"username": "miguel12", "password": "miguel12"} + + registration_result = soap_client.service.account_register(registration_data) + + assert registration_result.error is False + + login_data = {"username": "miguel12", "password": "miguel12"} + + response = app.test_client().post("/auth_login", json=login_data) + + assert response.status_code == 200 + + assert json.loads(response.data)["msg"] == "Login successful" + + assert "jwt" in json.loads(response.data) + + +def test_auth_login_invalid_credentials() -> None: + data = {"username": "miguel", "password": "miguel"} + + response = app.test_client().post("/auth_login", json=data) + + assert response.status_code == 401 + + assert json.loads(response.data)["msg"] == "Invalid credentials" + + +def test_auth_login_missing_fields() -> None: + data = {"username": "miguel"} + + response = app.test_client().post("/auth_login", json=data) + + assert response.status_code == 400 + + assert ( + json.loads(response.data)["msg"] == "Required fields are missing in JSON data" + ) + + +def test_auth_refresh_missing_token() -> None: + # Simulate a request without a token + data = {"jwt": ""} + + response = app.test_client().post("/auth_refresh", json=data) + + assert response.status_code == 400 + + assert json.loads(response.data)["msg"] == "Token is missing in JSON data" + + +def test_no_valid() -> None: + registration_data = {"username": "pedro19", "password": "pedro19"} + registration_result = soap_client.service.account_register(registration_data) + assert registration_result.error is False + + login_data = {"username": "pedro19", "password": "pedro19"} + login_response = app.test_client().post("/auth_login", json=login_data) + assert login_response.status_code == 200 + jwt = json.loads(login_response.data)["jwt"] + + data = {"jwt": jwt + "a"} + response = app.test_client().post("/auth_refresh", json=data) + + assert response.status_code == 401 + + response_data = json.loads(response.data) + assert "msg" in response_data + assert response_data["msg"] != "" + + +def test_challenge_valid_token() -> None: + registration_data = {"username": "gloria1", "password": "gloria1"} + registration_result = soap_client.service.account_register(registration_data) + assert registration_result.error is False + + login_data = {"username": "gloria1", "password": "gloria1"} + login_response = app.test_client().post("/auth_login", json=login_data) + assert login_response.status_code == 200 + jwt = json.loads(login_response.data)["jwt"] + + data = {"jwt": jwt} + response = app.test_client().post("/auth_refresh", json=data) + + assert response.status_code == 200 + + # Verificar si la respuesta contiene un token JWT vĂ¡lido + response_data = json.loads(response.data) + assert "jwt" in response_data + assert response_data["jwt"] != "" diff --git a/templates/index.html b/templates/index.html deleted file mode 100644 index 6116828..0000000 --- a/templates/index.html +++ /dev/null @@ -1 +0,0 @@ -