Compare commits

...

9 commits

Author SHA1 Message Date
Dmitry Miasnenko
466dd6b3f0
Fix 1 commit behind (#27)
* readme-fix: remove warning about cli tool. Update version in docker-compose.yml to match.

* Updated readme.md. Fully remove openapi.json. Remove version cmp beteen Cargo.toml and openapi.json. Added openapi.josn to gitignore.

* Removed openapi.json

* Update readme.md

* Update readme.md
2024-10-04 16:24:02 +03:00
Dmitry Miasnenko
782d8e4b05
Update readme. Remove openapi.json and adjust workflows. (#26)
* readme-fix: remove warning about cli tool. Update version in docker-compose.yml to match.

* Updated readme.md. Fully remove openapi.json. Remove version cmp beteen Cargo.toml and openapi.json. Added openapi.josn to gitignore.
2024-10-04 15:59:59 +03:00
Dmitry Miasnenko
7214330e53
readme-fix: remove warning about cli tool. Update version in docker-compose.yml to match. (#25) 2024-08-06 04:02:44 +03:00
Dmitry Miasnenko
a86f6ba0e7
Release 0.2.6 (#24)
* Added docker-compose for dev. Added dev build build and push job for dockerhub

* Moved cors layer to check if /api now is not guarded

* Added logging for error in response

* Removed too strict validation rules for credentials

* fix: x-subdmain was overwritten on correct request. Updated nginx-template and nginx now waits for server

* proxy-fix: New nginx config as the previous one failed with subdomain

* archive-fix: Remove skipping first component in path of entry. Zip archive should not containt root folder.

* assets-fix: Remove root folder inside zips to pass tests. The root dir is not skipped now due to previous commit

* tests-fix: enable logging to see error message in gh actions. Lokal tests work fine

* fmt: for tests

* tests-fix: disable logging to see error message in gh actions. That was gh issue

* fmt: remove unused import

* openapi-client: add build and publih with gh actions

* fix-deploy: nginx now waits for server in dev also

* fix-deploy: publsh to pypi
2024-08-06 00:12:03 +03:00
clowzed
b22e8817e1 fix: fmt 2024-06-28 14:08:57 +03:00
clowzed
ac8bcf4e2a fix: donotstart profile removed from docker-compose.yml. Obsolete files will be removed from database too. Try cors check return allowed if x-subdomain missing. This should not be desired behaviour and needs to be resolved using placement of layers in router. 2024-06-28 14:03:14 +03:00
clowzed
6eb836ee19 version-update for: toolchane update in fmt test. Add optimized build in profile. 2024-06-24 13:08:25 +03:00
clowzed
aa27492f6f actions-fix: update toolchain to nightly for cargo fmt to use crate imports granularity part 2. remove +nightly 2024-06-24 13:03:05 +03:00
clowzed
017ab86591 actions-fix: update toolchain to nightly for cargo fmt to use crate imports granularity 2024-06-24 12:58:04 +03:00
39 changed files with 251 additions and 1416 deletions

27
.github/workflows/dev.yml vendored Normal file
View file

@ -0,0 +1,27 @@
name: "Test"
on:
push:
branches:
- "dev"
jobs:
push-to-registry:
name: "Build and push Docker image to Docker Hub"
runs-on: "ubuntu-latest"
steps:
- name: "Check out the repo"
uses: actions/checkout@v3
- name: "Log in to Docker Hub"
uses: "docker/login-action@v2"
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: "Build and push Docker image"
uses: "docker/build-push-action@v3"
with:
context: .
push: true
tags: clowzed/sero:dev-unstable

View file

@ -104,3 +104,53 @@ jobs:
push: true
tags: clowzed/sero:v${{ needs.get-tag.outputs.pkg-version }}
labels: ${{ steps.meta.outputs.labels }}
upload-openapi-client:
needs:
- "push-to-registry"
name: "Build and upload openapi python client"
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: "16"
- name: Install OpenAPI Generator CLI
run: |
npm install @openapitools/openapi-generator-cli -g
- name: Extract version from OpenAPI spec
id: extract_version
run: |
VERSION=$(jq -r '.info.version' openapi.json)
echo "VERSION=$VERSION" >> $GITHUB_ENV
- name: Generate Python client from OpenAPI spec
run: |
openapi-generator-cli generate -i openapi.json -g python -o seroapi --additional-properties=packageName=seroapi,packageVersion=${{ env.VERSION }}
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: "3.x"
- name: Install Poetry
run: |
curl -sSL https://install.python-poetry.org | python3 -
- name: Configure Poetry
run: |
poetry config virtualenvs.in-project true
- name: Install dependencies
run: |
cd seroapi
poetry install
- name: Publish to Test PyPI
run: |
cd seroapi
poetry publish -u __token__ -p ${{ secrets.PYPI_PASSWORD }} --build

View file

@ -46,24 +46,6 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: "Get version from Cargo.toml"
id: "get-cargo-version"
shell: "bash"
run: |
echo PKG_VERSION=$(awk -F ' = ' '$1 ~ /version/ { gsub(/["]/, "", $2); printf("%s",$2) }' Cargo.toml) >> $GITHUB_OUTPUT
- name: Get version from openapi.json
id: get-openapi-version
run: |
echo OAPI_VERSION=$(jq -r '.info.version' openapi.json) >> $GITHUB_OUTPUT
- name: Compare versions
run: |
if [ "${{ steps.get-cargo-version.outputs.PKG_VERSION }}" != "${{ steps.get-openapi-version.outputs.OAPI_VERSION }}" ]; then
echo "Version mismatch between cargo.toml and generated OpenAPI JSON."
exit 1
else
echo "Version matches between cargo.toml and generated OpenAPI JSON."
fi
- name: Run tests (with database service)
run: cargo test --verbose -- --test-threads=1
@ -77,14 +59,14 @@ jobs:
- uses: "actions-rs/toolchain@v1"
with:
profile: "minimal"
toolchain: "stable"
toolchain: "nightly"
override: true
- run: "rustup component add rustfmt"
- uses: "actions-rs/cargo@v1"
with:
command: "+nightly fmt"
command: "fmt"
args: "--all -- --check"
clippy:

1
.gitignore vendored
View file

@ -4,3 +4,4 @@ sites-uploads
logs
test_upload_files
.env
openapi.json

View file

@ -1,6 +1,6 @@
[package]
name = "sero"
version = "0.2.1"
version = "0.2.8"
edition = "2021"
authors = ["clowzed <clowzed.work@gmail.com>"]
description = "Muiltidomain static site hosting"
@ -11,19 +11,19 @@ license = "MIT"
[dependencies]
envy = "0.4.2"
sea-orm = { version = "0.12.3", features = [
"sqlx-postgres",
"runtime-tokio-rustls",
"macros",
"sqlx-postgres",
"runtime-tokio-rustls",
"macros",
] }
tokio = { version = "1.32.0", features = ["full"] }
tokio-postgres = "0.7.10"
tracing = { version = "0.1.37", features = ["async-await"] }
tracing-subscriber = { version = "0.3.17", features = [
"env-filter",
"fmt",
"ansi",
"std",
"json",
"env-filter",
"fmt",
"ansi",
"std",
"json",
] }
entity = { path = "entity" }
migration = { path = "migration" }
@ -41,9 +41,9 @@ mime = "0.3.17"
mime_guess = "2.0.4"
argon2 = { version = "0.5.3", features = ["std"] }
utoipa = { version = "4.2.0", features = [
"axum_extras",
"chrono",
"preserve_order",
"axum_extras",
"chrono",
"preserve_order",
] }
dotenvy = "0.15.7"
toml = "0.8.8"
@ -52,16 +52,16 @@ utoipa-rapidoc = { version = "4.0.0", features = ["axum"] }
utoipa-redoc = { version = "4.0.0", features = ["axum"] }
utoipa-swagger-ui = { version = "7.1.0", features = ["axum"] }
axum = { version = "0.7.4", features = [
"macros",
"tracing",
"json",
"multipart",
"macros",
"tracing",
"json",
"multipart",
] }
axum_typed_multipart = "0.11.0"
tower-http = { git = "https://github.com/tower-rs/tower-http.git", features = [
"cors",
"trace",
"timeout",
"cors",
"trace",
"timeout",
] }
tower = { version = "0.4.13", features = ["util"] }
hyper = "0.14.28"
@ -77,5 +77,11 @@ members = [".", "entity", "migration"]
[dev-dependencies]
axum-test = "15.2.0"
[profile.release]
lto = true
strip = true
opt-level = 3
codegen-units = 1

Binary file not shown.

Binary file not shown.

Binary file not shown.

69
docker-compose.dev.yml Normal file
View file

@ -0,0 +1,69 @@
version: "3"
services:
database:
image: postgres:16
user: postgres
environment:
- POSTGRES_USER=postgres
- POSTGRES_DB=sero
- POSTGRES_PASSWORD=1234
healthcheck:
test: ["CMD-SHELL", "pg_isready"]
interval: 5s
timeout: 5s
retries: 5
volumes:
- pgdata:/var/lib/postgresql/data
proxy:
image: nginx:alpine3.18-slim
environment:
- DOLLAR=$
- SERVER_PORT=8080
- SERVER=server
# Edit this
- DOMAIN=
- ZONE=
# End of edit
volumes:
- ./nginx-templates:/etc/nginx/templates
ports:
- 443:443
- 80:80
links:
- server
depends_on:
- server
server:
image: clowzed/sero:dev-unstable
build: .
depends_on:
database:
condition: service_healthy
volumes:
- server-files:/app/sites-uploads
ports:
- 8080:8080
environment:
- DATABASE_URL=postgresql://postgres:1234@database/sero
- PORT=8080
# You can edit this section
# Empty means no limits
- MAX_USERS=1
- MAX_SITES_PER_USER=100
- MAX_BODY_LIMIT_SIZE=10000000 # 10mb
- RUST_LOG=none,sero=trace
- JWT_SECRET=mysuperstrongjwtscret
# end of section
- JWT_TTL_SECONDS=120
- SQLX_LOGGING=true
- UPLOAD_FOLDER=./sites-uploads
volumes:
server-files:
pgdata:

View file

@ -4,7 +4,6 @@ services:
database:
image: postgres:16
user: postgres
restart: always
environment:
- POSTGRES_USER=postgres
- POSTGRES_DB=sero
@ -21,7 +20,6 @@ services:
proxy:
image: nginx:alpine3.18-slim
restart: always
environment:
- DOLLAR=$
- SERVER_PORT=8080
@ -37,20 +35,17 @@ services:
- 80:80
links:
- server
profiles:
- donotstart
depends_on:
- server
server:
image: clowzed/sero
restart: always
image: clowzed/sero:v0.2.7
build: .
depends_on:
database:
condition: service_healthy
volumes:
- server-files:/app/sites-uploads
ports:
- 8080:8080
environment:
- DATABASE_URL=postgresql://postgres:1234@database/sero
- PORT=8080
@ -60,8 +55,8 @@ services:
- MAX_SITES_PER_USER=100
- MAX_BODY_LIMIT_SIZE=10000000 # 10mb
- RUST_LOG=none,sero=trace
# end of section
- JWT_SECRET=mysuperstrongjwtscret
# end of section
- JWT_TTL_SECONDS=120
- SQLX_LOGGING=true
- UPLOAD_FOLDER=./sites-uploads

View file

@ -1,18 +1,22 @@
map $http_host $subdomain {
~^(?<subdomain>[a-zA-Z0-9-]+)\.${DOMAIN}\.${ZONE}${DOLLAR} $subdomain;
}
server {
# We check if $subdomain is not empty and if the X-subdomain header is not present in the request
# ($http_x_subdomain = "").
# If both conditions are met, we set the X-subdomain header using proxy_set_header.
# Otherwise, we do nothing, and the existing X-subdomain header (if any) will be preserved.
listen 80;
server_name ~^(?<subdomain>\w*)\.${DOMAIN}.${ZONE}${DOLLAR};
server_name ~^(?<subdomain>[a-zA-Z0-9-]+)\.${DOMAIN}\.${ZONE}${DOLLAR};
location / {
if ($subdomain != "" && $http_x_subdomain = "") {
proxy_set_header x-subdomain $subdomain;
}
proxy_pass http://${SERVER}:${SERVER_PORT}/;
proxy_set_header X-Subdomain $subdomain;
proxy_pass http://${SERVER}:${SERVER_PORT};
}
}
server {
listen 80;
server_name ${DOMAIN}.${ZONE};
location / {
proxy_pass http://${SERVER}:${SERVER_PORT};
}
}

File diff suppressed because it is too large Load diff

View file

@ -21,31 +21,23 @@
</p>
</p>
# Warning
> [!CAUTION]
>
> **_This project was in a huge rewrite and upload tool and docs are not updated!
> THis will be fixed very soon._**
## 📖 Table Of Contents
- [Warning!](#warning)
- [📖 Table Of Contents](#-table-of-contents)
- [Docs](#docs)
- [🔧 Tools](#-tools)
- [❓ About The Project](#-about-the-project)
- [🚀 Features](#-features)
- [🔌 Built With](#-built-with)
- [📍 Roadmap](#-roadmap)
- [🧑‍🤝‍🧑 Contributing](#-contributing)
- [Creating A Pull Request](#creating-a-pull-request)
- [License](#license)
- [Authors](#authors)
- [📖 Table Of Contents](#-table-of-contents)
- [Docs](#docs)
- [🔧 Tools](#-tools)
- [❓ About The Project](#-about-the-project)
- [🚀 Features](#-features)
- [🔌 Built With](#-built-with)
- [📍 Roadmap](#-roadmap)
- [🧑‍🤝‍🧑 Contributing](#-contributing)
- [Creating A Pull Request](#creating-a-pull-request)
- [License](#license)
- [Authors](#authors)
## Docs
Read [docs here]("http://sero-docs.clowzed.ru") for fast installation.
Read [docs here]("clowzed.github.io/sero-docs/") for fast installation.
## 🔧 Tools
@ -70,7 +62,7 @@ One key feature that it is self-hosted. This gives users more flexibility and co
- Custom 503.html `new` `(on disabled site)`
- Clean urls
- Dynamic CORS Management
- `[WIP]` Server events with websocket
- `[WIP]` SSE
## 🔌 Built With

View file

@ -27,7 +27,7 @@ impl IntoResponse for LoginError {
fn into_response(self) -> Response {
let reason = self.to_string();
let status_code: StatusCode = self.into();
tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!");
(status_code, Json(Details { reason })).into_response()
}
}

View file

@ -1,25 +1,15 @@
use std::fmt::{self, Debug};
use serde::{Deserialize, Serialize};
use std::fmt::{self, Debug};
use utoipa::{schema, ToSchema};
use validator::{Validate, ValidationError};
use validator::Validate;
#[derive(Deserialize, Serialize, Validate, ToSchema)]
pub struct LoginRequest {
/// The username used for authentication.
/// It must adhere to the following criteria:
/// - It can contain letters (a-z), numbers (0-9), and periods (.).
/// - It cannot contain any of the following characters: & = ' - + , < >
/// - It cannot have multiple periods (.) consecutively.
/// - Minimum length of 5 characters.
/// - Maximum length of 40 characters.
#[validate(
length(min = 5, max = 40),
custom(
function = validate_login,
message = "Login can contain letters (a-z), numbers (0-9), and periods (.),
and cannot contain any of the following characters: & = ' + , < > or multiple periods (.)"
))]
#[validate(length(min = 5, max = 40))]
#[schema(min_length = 5, max_length = 40)]
pub login: String,
@ -27,53 +17,11 @@ pub struct LoginRequest {
/// It must meet the following requirements:
/// - Minimum length of 12 characters.
/// - Maximum length of 40 characters.
/// - A combination of letters, numbers, and symbols.
#[validate(
length(min = 12, max = 40),
custom(function = validate_password,
message = "Minimum length of 12 characters and maximum length of 40 characters and a combination of
letters, numbers, and symbols.")
)]
#[validate(length(min = 12, max = 40))]
#[schema(min_length = 12, max_length = 40)]
pub password: String,
}
fn validate_login(login: &str) -> Result<(), ValidationError> {
let invalid_chars = "&='+,<>";
let invalid_double_period = "..";
if login.chars().any(|c| invalid_chars.contains(c)) || login.contains(invalid_double_period) {
return Err(ValidationError::new(
"Rules for login: Login can contain letters (a-z), numbers (0-9), and periods (.),
and cannot contain any of the following characters: & = ' + , < > or multiple periods (.)",
));
}
Ok(())
}
fn validate_password(password: &str) -> Result<(), ValidationError> {
let mut has_digit = false;
let mut has_special_char = false;
for c in password.chars() {
if !has_digit && c.is_ascii_digit() {
has_digit = true;
} else if c.is_ascii_punctuation() || c.is_ascii_whitespace() {
has_special_char = true;
}
if has_digit && has_special_char {
return Ok(());
}
}
Err(ValidationError::new(
"Rules for password: Minimum length of 12 characters and maximum length of 40 characters and a combination of
letters, numbers, and symbols.",
))
}
impl Debug for LoginRequest {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("LoginRequest")

View file

@ -32,6 +32,7 @@ impl IntoResponse for RegistrationError {
let reason = self.to_string();
let status_code: StatusCode = self.into();
tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!");
(status_code, Json(Details { reason })).into_response()
}
}

View file

@ -1,25 +1,15 @@
use std::fmt::{self, Debug};
use serde::{Deserialize, Serialize};
use std::fmt::{self, Debug};
use utoipa::{schema, ToSchema};
use validator::{Validate, ValidationError};
use validator::Validate;
#[derive(Deserialize, Serialize, Validate, ToSchema)]
pub struct RegistrationRequest {
/// The username used for authentication.
/// It must adhere to the following criteria:
/// - It can contain letters (a-z), numbers (0-9), and periods (.).
/// - It cannot contain any of the following characters: & = ' - + , < >
/// - It cannot have multiple periods (.) consecutively.
/// - Minimum length of 5 characters.
/// - Maximum length of 40 characters.
#[validate(
length(min = 5, max = 40),
custom(
function = validate_login,
message = "Login can contain letters (a-z), numbers (0-9), and periods (.),
and cannot contain any of the following characters: & = ' + , < > or multiple periods (.)"
))]
#[validate(length(min = 5, max = 40))]
#[schema(min_length = 5, max_length = 40)]
pub login: String,
@ -27,53 +17,11 @@ pub struct RegistrationRequest {
/// It must meet the following requirements:
/// - Minimum length of 12 characters.
/// - Maximum length of 40 characters.
/// - A combination of letters, numbers, and symbols.
#[validate(
length(min = 12, max = 40),
custom(function = validate_password,
message = "Minimum length of 12 characters and maximum length of 40 characters and a combination of
letters, numbers, and symbols.")
)]
#[validate(length(min = 12, max = 40))]
#[schema(min_length = 12, max_length = 40)]
pub password: String,
}
fn validate_login(login: &str) -> Result<(), ValidationError> {
let invalid_chars = "&='+,<>";
let invalid_double_period = "..";
if login.chars().any(|c| invalid_chars.contains(c)) || login.contains(invalid_double_period) {
return Err(ValidationError::new(
"Rules for login: Login can contain letters (a-z), numbers (0-9), and periods (.),
and cannot contain any of the following characters: & = ' + , < > or multiple periods (.)",
));
}
Ok(())
}
fn validate_password(password: &str) -> Result<(), ValidationError> {
let mut has_digit = false;
let mut has_special_char = false;
for c in password.chars() {
if !has_digit && c.is_ascii_digit() {
has_digit = true;
} else if c.is_ascii_punctuation() || c.is_ascii_whitespace() {
has_special_char = true;
}
if has_digit && has_special_char {
return Ok(());
}
}
Err(ValidationError::new(
"Rules for password: Minimum length of 12 characters and maximum length of 40 characters and a combination of
letters, numbers, and symbols.",
))
}
impl Debug for RegistrationRequest {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("RegistrationRequest")

View file

@ -24,6 +24,7 @@ impl IntoResponse for AddOriginError {
let reason = self.to_string();
let status_code: StatusCode = self.into();
tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!");
(status_code, Json(Details { reason })).into_response()
}
}

View file

@ -28,6 +28,7 @@ impl IntoResponse for DeleteOriginError {
let reason = self.to_string();
let status_code: StatusCode = self.into();
tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!");
(status_code, Json(Details { reason })).into_response()
}
}

View file

@ -24,6 +24,7 @@ impl IntoResponse for ListOriginsError {
let reason = self.to_string();
let status_code: StatusCode = self.into();
tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!");
(status_code, Json(Details { reason })).into_response()
}
}

View file

@ -24,6 +24,7 @@ impl IntoResponse for DeleteOriginsError {
let reason = self.to_string();
let status_code: StatusCode = self.into();
tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!");
(status_code, Json(Details { reason })).into_response()
}
}

View file

@ -24,6 +24,7 @@ impl IntoResponse for GetOriginError {
let reason = self.to_string();
let status_code: StatusCode = self.into();
tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!");
(status_code, Json(Details { reason })).into_response()
}
}

View file

@ -27,6 +27,7 @@ impl IntoResponse for DisableError {
let reason = self.to_string();
let status_code: StatusCode = self.into();
tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!");
(status_code, Json(Details { reason })).into_response()
}
}

View file

@ -32,6 +32,7 @@ impl IntoResponse for DownloadError {
let reason = self.to_string();
let status_code: StatusCode = self.into();
tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!");
(status_code, Json(Details { reason })).into_response()
}
}

View file

@ -28,6 +28,7 @@ impl IntoResponse for EnableError {
let reason = self.to_string();
let status_code: StatusCode = self.into();
tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!");
(status_code, Json(Details { reason })).into_response()
}
}

View file

@ -28,6 +28,7 @@ impl IntoResponse for PageError {
let reason = self.to_string();
let status_code: StatusCode = self.into();
tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!");
(status_code, Json(Details { reason })).into_response()
}
}

View file

@ -28,6 +28,7 @@ impl IntoResponse for TeardownError {
let reason = self.to_string();
let status_code: StatusCode = self.into();
tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!");
(status_code, Json(Details { reason })).into_response()
}
}

View file

@ -34,6 +34,7 @@ impl IntoResponse for UploadError {
let reason = self.to_string();
let status_code: StatusCode = self.into();
tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!");
(status_code, Json(Details { reason })).into_response()
}
}

View file

@ -61,6 +61,7 @@ impl IntoResponse for AuthError {
let reason = self.to_string();
let status_code: StatusCode = self.into();
tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!");
(status_code, Json(Details { reason })).into_response()
}
}

View file

@ -49,6 +49,7 @@ impl IntoResponse for GuardError {
let reason = self.to_string();
let status_code: StatusCode = self.into();
tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!");
(status_code, Json(Details { reason })).into_response()
}
}

View file

@ -41,6 +41,7 @@ impl IntoResponse for SubdomainError {
let reason = self.to_string();
let status_code: StatusCode = self.into();
tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!");
(status_code, Json(Details { reason })).into_response()
}
}

View file

@ -32,6 +32,7 @@ impl IntoResponse for SubdomainNameError {
let reason = self.to_string();
let status_code: StatusCode = self.into();
tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!");
(status_code, Json(Details { reason })).into_response()
}
}

View file

@ -41,6 +41,7 @@ impl IntoResponse for SubdomainOwnedError {
let reason = self.to_string();
let status_code: StatusCode = self.into();
tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!");
(status_code, Json(Details { reason })).into_response()
}
}

View file

@ -11,7 +11,7 @@ use configuration::{reader::ConfigurationReader, *};
use futures::StreamExt;
use migration::{Migrator, MigratorTrait};
use origin::service::Service as CorsService;
use sea_orm::{ConnectOptions, Database, DbErr};
use sea_orm::{ActiveModelTrait, ConnectOptions, Database, DbErr, IntoActiveModel};
use serde::{Deserialize, Serialize};
use services::*;
use site::service::Service as SiteService;
@ -165,6 +165,15 @@ pub async fn app() -> Result<(Router, Arc<State>), AppCreationError> {
|cause| tracing::warn!(%cause, "Failed to remove file with path : {}", file.real_path),
)
.ok();
let file_id = file.id;
file.into_active_model()
.delete(state_for_file_deletion_task.connection())
.await
.inspect_err(
|cause| tracing::warn!(%cause, %file_id, "Failed to remove file from database"),
)
.ok();
}
}
}
@ -197,6 +206,12 @@ pub async fn app() -> Result<(Router, Arc<State>), AppCreationError> {
};
async move {
//? If header was not provided
//? Allow as it probably management tool
if task.subdomain.is_empty() {
return true;
}
if cors_task_sender
.send(task)
.await
@ -232,10 +247,10 @@ pub async fn app() -> Result<(Router, Arc<State>), AppCreationError> {
let mut app = Router::new()
.merge(openapi)
.nest("/api", api::router())
.route("/*path", get(api::site::page::handler::implementation))
.route("/", get(api::site::page::handler::redirect::implementation))
.layer(cors_layer)
.nest("/api", api::router())
.layer(tracing_layer)
.layer(TimeoutLayer::new(Duration::from_secs(10)))
.with_state(state.clone());

View file

@ -44,11 +44,11 @@ impl Service {
.filename()
.as_str()
.inspect_err(|cause| tracing::warn!(%cause, "Failed to convert entry filepath to str"))?;
PathBuf::from(entry_filename).components().skip(1).collect::<PathBuf>()
PathBuf::from(entry_filename)
};
tracing::trace!(?path, "Entry filepath was successfully retrieved");
//? Generating filename for entry
//? Generating filename for enty
// Just random to prevent collisions
let u1 = Uuid::new_v4();
let u2 = Uuid::new_v4();