Compare commits

...
8 Commits
Author SHA1 Message Date
boxi 4269f980db cleanUp Intellij warnings
Build Remsly / Compute-Version (push) Successful in 5s
Build Remsly / Build-Remsly-Backend (push) Successful in 2m21s
Build Remsly / Build-Remsly-Frontend (push) Successful in 1m28s
Build Remsly / Package-Prod-Config (push) Successful in 5s
2026-07-12 20:39:55 +02:00
boxi c23836e5fe init deploy.sh 2026-07-12 20:32:47 +02:00
boxi 7ccf9e1bc3 init versioning JJJJ.MM-<MAYOR>-<BuildNR> & config upload 2026-07-12 16:56:44 +02:00
boxi 8c6e31166a fixed ES migrationFile loading 2026-07-12 14:49:40 +02:00
boxi 0e2120e414 copied config from prod 2026-07-12 13:35:10 +02:00
boxi d09fb5d9b7 fixed some FR warnings & bugs 2026-07-12 13:11:49 +02:00
boxi 99d683796a remove unused truststore 2026-07-12 12:44:06 +02:00
boxi a6fb0e41fe fixinf deeplinks 2026-07-09 23:22:03 +02:00
24 changed files with 293 additions and 110 deletions

No files matched your search

+60 -9
View File
@@ -5,11 +5,30 @@ on:
branches: [ main ]
jobs:
Build-Remsly-Backend:
Compute-Version:
runs-on: ubuntu-latest
container:
image: gitea.tail276105.ts.net/remsly/ci-image:5
outputs:
version: ${{ steps.v.outputs.version }}
steps:
- name: Check out repository code
uses: actions/checkout@v4
- name: Compute version
id: v
run: |
MAJOR=$(tr -d '[:space:]' < deploy/prod/VERSION)
VERSION="$(date -u +%Y.%m)-${MAJOR}-${GITHUB_RUN_NUMBER}"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "Computed version: $VERSION"
Build-Remsly-Backend:
runs-on: ubuntu-latest
needs: Compute-Version
container:
image: gitea.tail276105.ts.net/remsly/ci-image:5
env:
VERSION: ${{ needs.Compute-Version.outputs.version }}
DB_HOST_PORT: buildPostgres:5432
DB_USER: develop
DB_PASSWD: develop
@@ -42,20 +61,20 @@ jobs:
REPOSITORY_LC=$(echo "${{ gitea.repository }}" | tr '[:upper:]' '[:lower:]')
(
cd backend;
docker build -t gitea.tail276105.ts.net/${REPOSITORY_LC}-backend:${GITHUB_RUN_NUMBER} .;
docker tag gitea.tail276105.ts.net/${REPOSITORY_LC}-backend:${GITHUB_RUN_NUMBER} gitea.tail276105.ts.net/${REPOSITORY_LC}-backend:latest
docker build -t gitea.tail276105.ts.net/${REPOSITORY_LC}-backend:${VERSION} .;
docker tag gitea.tail276105.ts.net/${REPOSITORY_LC}-backend:${VERSION} gitea.tail276105.ts.net/${REPOSITORY_LC}-backend:latest
)
- name: Push Docker Images
run: |
REPOSITORY_LC=$(echo "${{ gitea.repository }}" | tr '[:upper:]' '[:lower:]')
docker push gitea.tail276105.ts.net/${REPOSITORY_LC}-backend:${GITHUB_RUN_NUMBER}
docker push gitea.tail276105.ts.net/${REPOSITORY_LC}-backend:${VERSION}
docker push gitea.tail276105.ts.net/${REPOSITORY_LC}-backend:latest
- name: Docker imageTags
run: |
REPOSITORY_LC=$(echo "${{ gitea.repository }}" | tr '[:upper:]' '[:lower:]')
echo "versioned: gitea.tail276105.ts.net/${REPOSITORY_LC}-backend:${GITHUB_RUN_NUMBER}"
echo "versioned: gitea.tail276105.ts.net/${REPOSITORY_LC}-backend:${VERSION}"
echo "latest: gitea.tail276105.ts.net/${REPOSITORY_LC}-backend:latest"
- name: Log out from Docker registry
@@ -64,8 +83,11 @@ jobs:
Build-Remsly-Frontend:
runs-on: ubuntu-latest
needs: Compute-Version
container:
image: gitea.tail276105.ts.net/remsly/ci-image:5
env:
VERSION: ${{ needs.Compute-Version.outputs.version }}
steps:
- name: Check out repository code
uses: actions/checkout@v4
@@ -85,22 +107,51 @@ jobs:
REPOSITORY_LC=$(echo "${{ gitea.repository }}" | tr '[:upper:]' '[:lower:]')
(
cd frontend;
docker build -t gitea.tail276105.ts.net/${REPOSITORY_LC}-frontend:${GITHUB_RUN_NUMBER} .;
docker tag gitea.tail276105.ts.net/${REPOSITORY_LC}-frontend:${GITHUB_RUN_NUMBER} gitea.tail276105.ts.net/${REPOSITORY_LC}-frontend:latest
docker build -t gitea.tail276105.ts.net/${REPOSITORY_LC}-frontend:${VERSION} .;
docker tag gitea.tail276105.ts.net/${REPOSITORY_LC}-frontend:${VERSION} gitea.tail276105.ts.net/${REPOSITORY_LC}-frontend:latest
)
- name: Push Docker Images
run: |
REPOSITORY_LC=$(echo "${{ gitea.repository }}" | tr '[:upper:]' '[:lower:]')
docker push gitea.tail276105.ts.net/${REPOSITORY_LC}-frontend:${GITHUB_RUN_NUMBER}
docker push gitea.tail276105.ts.net/${REPOSITORY_LC}-frontend:${VERSION}
docker push gitea.tail276105.ts.net/${REPOSITORY_LC}-frontend:latest
- name: Docker imageTags
run: |
REPOSITORY_LC=$(echo "${{ gitea.repository }}" | tr '[:upper:]' '[:lower:]')
echo "versioned: gitea.tail276105.ts.net/${REPOSITORY_LC}-frontend:${GITHUB_RUN_NUMBER}"
echo "versioned: gitea.tail276105.ts.net/${REPOSITORY_LC}-frontend:${VERSION}"
echo "latest: gitea.tail276105.ts.net/${REPOSITORY_LC}-frontend:latest"
- name: Log out from Docker registry
if: always()
run: docker logout gitea.tail276105.ts.net
Package-Prod-Config:
runs-on: ubuntu-latest
needs: [ Compute-Version, Build-Remsly-Backend, Build-Remsly-Frontend ]
container:
image: gitea.tail276105.ts.net/remsly/ci-image:5
env:
VERSION: ${{ needs.Compute-Version.outputs.version }}
steps:
- name: Check out repository code
uses: actions/checkout@v4
- name: Bake image versions into docker-compose.yml
run: |
# The compose file pins backend/frontend to the <<VERSION>> placeholder;
# replace it with this build's version. The manually maintained services
# (elasticsearch, keycloak, postgres, tailscale) keep their own tags.
sed -i "s|<<VERSION>>|${VERSION}|g" deploy/prod/docker-compose.yml
echo "Pinned backend/frontend images to ${VERSION}:"
grep -nE "remsly-(backend|frontend)" deploy/prod/docker-compose.yml
- name: Build config.tar.gz
run: tar -czf config.tar.gz -C deploy/prod .
- name: Upload config to Gitea generic package registry
run: |
REPOSITORY_LC=$(echo "${{ gitea.repository }}" | tr '[:upper:]' '[:lower:]')
OWNER=${REPOSITORY_LC%%/*}
curl -fsSL --user "${{ secrets.REGISTRY_USER }}:${{ secrets.REGISTRY_PASSWORD }}" \
--upload-file config.tar.gz \
"https://gitea.tail276105.ts.net/api/packages/${OWNER}/generic/prod-config/${VERSION}/config.tar.gz"
echo "Uploaded prod-config/${VERSION}/config.tar.gz"
+1 -1
View File
@@ -62,7 +62,7 @@ The DB schema is the source of truth. Migrations live in `backend/src/main/resou
- `db/` — jOOQ-based repositories built on `SimpleCrudRepository` / `AbstractSimpleCrudRepositoryImpl` plus composable `JooqFilter` classes (`CombinedAndFilter`, `CombinedOrFilter`, ...).
- `searchindex/` — Elasticsearch index per feature (folder, note, task) with its own migration support; `db/elasticsearchSync` + `domain/elasticSearchSync` implement DB→ES synchronization.
- `clientapi/` — outbound HTTP clients (e.g. OpenStreetMap geocoding).
- `security/` — Keycloak/OIDC config and SSL client config (truststore at `backend/src/main/resources/truststore.jks`; Elasticsearch CA certs must be imported there — see readme.md).
- `security/` — Keycloak/OIDC config and SSL client config (`SSLClientConfig` pins outbound HTTPS to TLS 1.2; trust uses the JVM default cacerts — no custom truststore).
### Frontend layers (`frontend/src/app`)
@@ -7,14 +7,11 @@ import ch.boxi.boxit.searchindex.migration.data.MigrationOperation
import ch.boxi.boxit.searchindex.migration.data.MigrationScript
import ch.boxi.boxit.searchindex.migration.data.Version
import com.google.common.base.Strings
import com.google.common.io.PatternFilenameFilter
import org.springframework.core.io.ClassPathResource
import org.springframework.core.io.Resource
import org.springframework.core.io.support.PathMatchingResourcePatternResolver
import org.springframework.http.HttpMethod
import java.io.BufferedReader
import java.io.File
import java.io.FileInputStream
import java.io.InputStreamReader
import java.nio.file.Path
import java.util.Arrays
import java.util.SortedSet
import java.util.regex.Pattern
@@ -29,35 +26,35 @@ class MigrationLoader {
}
fun loadMigrations(): SortedSet<MigrationScript> {
val filenameFilter = PatternFilenameFilter(FILENAME_PATTERN)
val folderResource = ClassPathResource("elasticsearch")
return Arrays.stream(folderResource.file.listFiles(filenameFilter))
.map(File::toPath)
val resources = PathMatchingResourcePatternResolver().getResources("classpath*:elasticsearch/*.edql")
return Arrays.stream(resources)
.filter { resource -> resource.filename?.let { FILENAME_PATTERN.matcher(it).matches() } ?: false }
.map(this::loadMigration)
.toSortedSet()
}
private fun loadMigration(path: Path): MigrationScript {
LOG.debug("found migration file $path")
val matcher = FILENAME_PATTERN.matcher(path.fileName.toString())
private fun loadMigration(resource: Resource): MigrationScript {
val filename = resource.filename!!
LOG.debug("found migration file $filename")
val matcher = FILENAME_PATTERN.matcher(filename)
matcher.matches()
val script = matcher.group(0)
val version = Version.parse(matcher.group(1))
val description = matcher.group(2)
val operations = readOperations(path)
val operations = readOperations(resource)
return MigrationScript(version, description, script, operations.second.value, operations.first)
}
private fun readOperations(path: Path): Pair<List<MigrationOperation>, Checksum> {
private fun readOperations(resource: Resource): Pair<List<MigrationOperation>, Checksum> {
val operations = mutableListOf<MigrationOperation>()
var httpMethod: HttpMethod? = null
var operationPath: String? = null
val checkSum: Checksum
var body = StringBuilder()
CheckedInputStream(FileInputStream(path.toFile()), CRC32()).use { checkedReader ->
CheckedInputStream(resource.inputStream, CRC32()).use { checkedReader ->
BufferedReader(InputStreamReader(checkedReader)).use { reader ->
reader.lines().forEach { line ->
val subLine = line.trim()
@@ -1,21 +1,16 @@
package ch.boxi.boxit.security
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Configuration
import org.springframework.core.env.Environment
import javax.annotation.PostConstruct
@Configuration
class SSLClientConfig {
@Autowired
private val env: Environment? = null
@PostConstruct
private fun configureSSL() {
// Pin outbound HttpsURLConnection to TLS 1.2. Trust uses the JVM's default cacerts (no custom
// trust store): all internal services run over plain HTTP, and the only outbound HTTPS targets
// are public hosts (Gravatar, OSM) that the built-in CA bundle already trusts.
System.setProperty("https.protocols", "TLSv1.2")
val trustStore = env!!.getProperty("boxit.server.ssl.trust-store")
System.setProperty("javax.net.ssl.trustStore", trustStore)
System.setProperty("javax.net.ssl.trustStorePassword", env.getProperty("boxit.server.ssl.trust-store-password")!!)
}
}
@@ -13,9 +13,6 @@ boxit.elasticsearch.pass=elasticPassword
spring.jackson.date-format="yyyy-MM-dd HH:mm:ss"
boxit.server.ssl.trust-store=src/main/resources/truststore.jks
boxit.server.ssl.trust-store-password=Tester11
management.endpoint.metrics.enabled=true
management.endpoints.web.exposure.include=*
management.endpoint.prometheus.enabled=true
Binary file not shown.
@@ -12,10 +12,6 @@ boxit.elasticsearch.pass=elasticPassword
spring.jackson.date-format="yyyy.MM.dd HH:mm:ss"
#boxit.server.ssl.trust-store=truststore
boxit.server.ssl.trust-store=src/main/resources/truststore.jks
boxit.server.ssl.trust-store-password=Tester11
management.endpoint.metrics.enabled=true
management.endpoints.web.exposure.include=*
management.endpoint.prometheus.enabled=true
@@ -251,7 +251,7 @@ Listen 80
form-action 'self'; \
frame-ancestors 'none'; \
img-src 'self' api.mapbox.com data:; \
#upgrade-insecure-requests" "expr=%{CONTENT_TYPE} =~ m#text\/(html|javascript)|application\/pdf|xml#i"
upgrade-insecure-requests" "expr=%{CONTENT_TYPE} =~ m#text\/(html|javascript)|application\/pdf|xml#i"
Header always append X-Frame-Options SAMEORIGIN
Header always set X-Content-Type-Options nosniff
Header always set Referrer-Policy "same-origin"
+6
View File
@@ -11,6 +11,7 @@ KC_ADMIN_PASSWORD=
# --- Tailscale ---
# Reusable, tag:server pre-authorized auth key from the Tailscale admin console.
TS_AUTHKEY=
TS_DNS_NAME=
# --- Apache OIDC (mod_auth_openidc) ---
OIDC_CRYPTO_PASSPHRASE=
@@ -22,3 +23,8 @@ ELASTIC_PASSWORD=
# --- Backend ---
# Keycloak client id (resource) the bearer-only backend expects.
KEYCLOAK_RESOURCE=
# --- Gitea registry (used by deploy.sh to download config.tar.gz) ---
# User + access token with package read scope for gitea.tail276105.ts.net.
GITEA_USER=
GITEA_TOKEN=
+1
View File
@@ -0,0 +1 @@
A0
+6 -6
View File
@@ -18,12 +18,6 @@ boxit.elasticsearch.pass=${ELASTIC_PASSWORD}
spring.jackson.date-format="yyyy-MM-dd HH:mm:ss"
# SSLClientConfig overrides the JVM trust store unconditionally, so point it at the JDK
# default CA bundle. That keeps outbound HTTPS (e.g. fetching Keycloak's JWKS over the
# Let's Encrypt / tailscale cert) working without shipping a custom truststore.
boxit.server.ssl.trust-store=/opt/java/openjdk/lib/security/cacerts
boxit.server.ssl.trust-store-password=changeit
management.endpoint.metrics.enabled=true
management.endpoints.web.exposure.include=*
management.endpoint.prometheus.enabled=true
@@ -31,6 +25,11 @@ management.metrics.export.prometheus.enabled=true
logging.level.root=INFO
keycloak.realm=Remsly
keycloak.bearer-only=true
keycloak.auth-server-url=https://remsly-id.tail276105.ts.net
keycloak.resource=${KEYCLOAK_RESOURCE}
# Bearer-only JWT validation via Spring Security OAuth2 resource server.
# issuer-uri : compared against the token's "iss" claim (the public https hostname, set by
# KC_HOSTNAME) - a pure string check, no network call.
@@ -40,3 +39,4 @@ logging.level.root=INFO
# regardless of the hostname in the request.
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://remsly-id.tail276105.ts.net/realms/Remsly
spring.security.oauth2.resourceserver.jwt.jwk-set-uri=http://remsly-id.tail276105.ts.net:8080/realms/Remsly/protocol/openid-connect/certs
+179
View File
@@ -0,0 +1,179 @@
#!/usr/bin/env bash
#
# Boxit/Remsly prod deployment helper.
#
# One script, two modes:
# * Bootstrap (`deploy <version>`): downloads config-<version>.tar.gz from the
# Gitea generic package registry into ./config, extracts it to a staging dir
# and re-executes the deploy.sh *from the tarball* in install mode. The install
# logic therefore always comes from the deployed version (self-updating), which
# is what lets a release carry its own migration/special steps.
# * Install (`__install`, internal): syncs the staged config into the deploy
# directory (never touching .env or ./config) and runs docker compose.
#
# The deploy directory is the folder this script lives in; it also holds .env
# (secrets, host-only) and docker-compose.yml. Ship this script once to the host,
# afterwards every deploy refreshes it from the tarball.
#
# Usage:
# ./deploy.sh <version> deploy a specific version (e.g. 2026.07-A0-6)
# ./deploy.sh deploy <version> same, explicit
# ./deploy.sh list-remote [n] list the last n versions in the registry (default 10)
# ./deploy.sh list-local list downloaded config archives
# ./deploy.sh help
#
set -euo pipefail
# --- Constants ---------------------------------------------------------------
GITEA_HOST="gitea.tail276105.ts.net"
OWNER="remsly"
PKG="prod-config"
DEPLOY_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONFIG_DIR="${DEPLOY_DIR}/config"
INSTALLED_FILE="${DEPLOY_DIR}/.installed-version"
# --- Helpers -----------------------------------------------------------------
die() { echo "ERROR: $*" >&2; exit 1; }
# Read a single key from .env without sourcing it (values are unquoted KEY=value).
read_env() {
local key="$1" val
[ -f "${DEPLOY_DIR}/.env" ] || return 1
val="$(grep -E "^${key}=" "${DEPLOY_DIR}/.env" | head -n1 | cut -d= -f2-)" || return 1
# strip trailing CR (CRLF files) and surrounding quotes
val="${val%$'\r'}"; val="${val%\"}"; val="${val#\"}"; val="${val%\'}"; val="${val#\'}"
printf '%s' "$val"
}
# Basic-auth curl against Gitea, using GITEA_USER/GITEA_TOKEN from .env.
gitea_curl() {
local user token
user="$(read_env GITEA_USER || true)"
token="$(read_env GITEA_TOKEN || true)"
[ -n "$user" ] && [ -n "$token" ] || die "GITEA_USER/GITEA_TOKEN missing in ${DEPLOY_DIR}/.env"
curl -fsSL --user "${user}:${token}" "$@"
}
# Resolve the docker compose command (v2 plugin preferred, v1 fallback).
compose() {
if docker compose version >/dev/null 2>&1; then
docker compose "$@"
elif command -v docker-compose >/dev/null 2>&1; then
docker-compose "$@"
else
die "neither 'docker compose' nor 'docker-compose' found"
fi
}
tarball_url() { printf 'https://%s/api/packages/%s/generic/%s/%s/config.tar.gz' "$GITEA_HOST" "$OWNER" "$PKG" "$1"; }
# --- Commands ----------------------------------------------------------------
cmd_list_remote() {
local n="${1:-10}"
echo "Last ${n} remote version(s) of ${PKG}:"
gitea_curl "https://${GITEA_HOST}/api/v1/packages/${OWNER}?type=generic&q=${PKG}" \
| grep -o '"version":"[^"]*"' | cut -d'"' -f4 \
| sort -Vr | head -n "$n" \
| sed 's/^/ /'
}
cmd_list_local() {
local current="" f v
[ -f "$INSTALLED_FILE" ] && current="$(cat "$INSTALLED_FILE")"
echo "Local config archives in ${CONFIG_DIR}:"
if ! ls "${CONFIG_DIR}"/config-*.tar.gz >/dev/null 2>&1; then
echo " (none)"
return 0
fi
for f in "${CONFIG_DIR}"/config-*.tar.gz; do
v="$(basename "$f")"; v="${v#config-}"; v="${v%.tar.gz}"
if [ "$v" = "$current" ]; then
echo " ${v} <- installed"
else
echo " ${v}"
fi
done | sort -Vr
}
cmd_deploy() {
local version="${1:-}"
[ -n "$version" ] || die "version required (e.g. ${0##*/} 2026.07-A0-6)"
mkdir -p "$CONFIG_DIR"
local archive="${CONFIG_DIR}/config-${version}.tar.gz"
if [ -f "$archive" ]; then
echo "Using cached ${archive}"
else
echo "Downloading ${version} ..."
gitea_curl -o "$archive" "$(tarball_url "$version")" \
|| { rm -f "$archive"; die "download of ${version} failed"; }
fi
local stage
stage="$(mktemp -d)"
tar -xzf "$archive" -C "$stage"
[ -f "${stage}/deploy.sh" ] || die "tarball has no deploy.sh"
# Hand off to the deploy.sh shipped in this version (self-updating install logic).
# The running host copy is not overwritten because we exec the staged copy.
exec bash "${stage}/deploy.sh" __install "$version" "$DEPLOY_DIR" "$stage"
}
cmd_install() {
local version="$1" deploydir="$2" stage="$3"
echo "Installing ${version} into ${deploydir} ..."
# Sync staged config into the deploy dir; never clobber secrets or downloads.
if command -v rsync >/dev/null 2>&1; then
rsync -a --exclude='.env' --exclude='config/' "${stage}/" "${deploydir}/"
else
# cp fallback: copy everything except .env / config (tarball has neither, but be safe)
( cd "$stage" && find . -mindepth 1 -maxdepth 1 \
! -name '.env' ! -name 'config' \
-exec cp -a {} "${deploydir}/" \; )
fi
( cd "$deploydir" && compose pull && compose up -d )
# Optional per-version migration/special-task hook shipped inside the tarball.
if [ -f "${deploydir}/post-deploy.sh" ]; then
echo "Running post-deploy.sh hook ..."
bash "${deploydir}/post-deploy.sh" "$version"
fi
printf '%s\n' "$version" > "${deploydir}/.installed-version"
rm -rf "$stage"
echo "Deployed ${version}."
}
usage() {
local me="${0##*/}"
cat <<EOF
${me} - Boxit/Remsly prod deployment helper
Usage:
${me} <version> deploy a specific version (e.g. 2026.07-A0-6)
${me} deploy <version> same, explicit
${me} list-remote [n] list the last n versions in the registry (default 10)
${me} list-local list downloaded config archives under ./config
${me} help
Requires GITEA_USER/GITEA_TOKEN in ./.env for registry access.
EOF
}
# --- Dispatch ----------------------------------------------------------------
main() {
local cmd="${1:-help}"
case "$cmd" in
list-remote) shift; cmd_list_remote "$@" ;;
list-local) cmd_list_local ;;
deploy) shift; cmd_deploy "$@" ;;
__install) shift; cmd_install "$@" ;;
help|-h|--help) usage ;;
*) cmd_deploy "$cmd" ;; # bare version shorthand
esac
}
main "$@"
+4 -2
View File
@@ -60,7 +60,8 @@ services:
- tailscale-id
apache-oidc:
image: gitea.tail276105.ts.net/remsly/remsly-frontend:4
# <<VERSION>> is replaced with the build version by the Package-Prod-Config CI job.
image: gitea.tail276105.ts.net/remsly/remsly-frontend:<<VERSION>>
restart: always
environment:
OIDC_CRYPTO_PASSPHRASE: ${OIDC_CRYPTO_PASSPHRASE}
@@ -87,7 +88,8 @@ services:
- tailscale-apache
backend:
image: gitea.tail276105.ts.net/remsly/remsly-backend:3
# <<VERSION>> is replaced with the build version by the Package-Prod-Config CI job.
image: gitea.tail276105.ts.net/remsly/remsly-backend:<<VERSION>>
restart: always
environment:
# The CI-built image ships no application.properties, so mount one and activate it.
-3
View File
@@ -3,9 +3,6 @@ IncludeOptional mods-enabled/*.conf
Listen 80
# Run as the distro's apache user and use the standard runtime dir, otherwise the
# child processes run as uid -1 and mod_auth_openidc cannot write its OIDCCacheDir
# (state/cache) -> HTTP 500 on the first authenticated request.
User ${APACHE_RUN_USER}
Group ${APACHE_RUN_GROUP}
DefaultRuntimeDir ${APACHE_RUN_DIR}
+7
View File
@@ -40,6 +40,10 @@
AllowOverride None
Options -Indexes -Includes
Require all granted
# SPA deep-link support: serve index.html (HTTP 200) for any path that does not map to a
# real file, so the Angular router can resolve it client-side. Existing assets are still
# served directly; /api/ (proxied) and /openidc (mod_auth_openidc) are unaffected.
FallbackResource /index.html
</Directory>
RequestHeader set X-Forwarded-User expr=%{REMOTE_USER}
@@ -55,6 +59,9 @@
OIDCRefreshAccessTokenBeforeExpiry 10
OIDCRedirectURI ${OIDC_REDIRECT_URI}
OIDCCryptoPassphrase ${OIDC_CRYPTO_PASSPHRASE}
# Where to land after a successful login when no original target URL is known (e.g. SSO entry
# via the redirect URI). Without this, mod_auth_openidc aborts with "Invalid Request".
OIDCDefaultURL https://remsly.tail276105.ts.net/
OIDCDefaultLoggedOutURL ${KC_ADDR}/realms/${KC_REALM}/protocol/openid-connect/logout?redirect_uri=https%3A%2F%2Fremsly.tail276105.ts.net
OIDCRemoteUserClaim preferred_username
OIDCStateMaxNumberOfCookies 3 true
+1 -1
View File
@@ -70,13 +70,13 @@
"node_modules/prismjs/components/prism-nginx.min.js",
"node_modules/prismjs/components/prism-php.min.js",
"node_modules/prismjs/components/prism-perl.min.js",
"node_modules/prismjs/components/prism-sql.min.js",
"node_modules/prismjs/components/prism-plsql.min.js",
"node_modules/prismjs/components/prism-python.min.js",
"node_modules/prismjs/components/prism-ruby.min.js",
"node_modules/prismjs/components/prism-properties.min.js",
"node_modules/prismjs/components/prism-typescript.min.js",
"node_modules/prismjs/components/prism-yaml.min.js",
"node_modules/prismjs/components/prism-sql.min.js",
"node_modules/prismjs/components/prism-css.min.js"
],
"vendorChunk": true,
-8
View File
@@ -1,8 +0,0 @@
export class ErrorDto {
constructor(private readonly _code: string) {
}
get code() {
return this._code;
}
}
@@ -1,6 +1,6 @@
import {AfterViewInit, Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild} from '@angular/core';
import {disableBodyScroll, enableBodyScroll} from 'body-scroll-lock';
import {Accent} from "../../../business/item/folder/Accent.model";
import {Accent} from '../../../business/item/folder/Accent.model';
@Component({
selector: 'app-modal',
@@ -18,7 +18,7 @@ export class ModalComponent implements OnInit, AfterViewInit {
@Output()
closed = new EventEmitter<void>();
@ViewChild('modalComponentDialog', { read: false })
@ViewChild('modalComponentDialog')
dialog: ElementRef;
isShown = false;
@@ -10,7 +10,6 @@ import {Background} from '../../../../business/item/folder/Background.model';
import {ViewMode} from '../../../../business/item/folder/viewMode.model';
import {ImageCroppedEvent} from 'ngx-image-cropper';
import {OffsetDateTime} from '@js-joda/core';
import {Attachment} from '../../../../business/attachment/Attachment.model';
@Component({
selector: 'app-folder-edit',
@@ -19,7 +18,7 @@ import {Attachment} from '../../../../business/attachment/Attachment.model';
})
export class FolderEditComponent implements OnInit {
@ViewChild(ModalComponent, {read: false})
@ViewChild(ModalComponent)
private dialog: ModalComponent;
public background: Folder;
@@ -19,7 +19,7 @@ export class StateColumnComponent implements OnInit {
@Output() dragStart = new EventEmitter<TaskOverview>();
@Output() dropFailed = new EventEmitter<null>();
@ViewChild('stateElement', { read: false })
@ViewChild('stateElement')
stateElement: ElementRef;
dragOver = false;
@@ -18,10 +18,10 @@ export class NoteHeaderComponent implements OnInit {
@Input() public note: Note;
@Input() public folder: Folder;
@ViewChild('infoDialog', {read: false})
@ViewChild('infoDialog')
private infoDialog: ModalComponent;
@ViewChild('deleteDialog', {read: false})
@ViewChild('deleteDialog')
private deleteDialog: ModalComponent;
hamburgerEntries: DropdownItem[] = [
@@ -38,7 +38,6 @@ export class NoteHeaderComponent implements OnInit {
];
constructor(private router: Router,
private route: ActivatedRoute,
private noteService: NoteService) {
}
@@ -54,7 +53,7 @@ export class NoteHeaderComponent implements OnInit {
}
public onDelete() {
this.noteService.delete(this.note).then((ok: any) => {
this.noteService.delete(this.note).then(() => {
this.router.navigate(['/folder/' + this.note.folderId]);
});
}
@@ -18,10 +18,10 @@ export class TaskHeaderComponent implements OnInit {
@Input() public task: Task;
@Input() public folder: Folder;
@ViewChild('infoDialog', {read: false})
@ViewChild('infoDialog')
private infoDialog: ModalComponent;
@ViewChild('deleteDialog', {read: false})
@ViewChild('deleteDialog')
private deleteDialog: ModalComponent;
hamburgerEntries: DropdownItem[] = [
@@ -38,7 +38,6 @@ export class TaskHeaderComponent implements OnInit {
];
constructor(private router: Router,
private route: ActivatedRoute,
private taskService: TaskService) {
}
@@ -54,7 +53,7 @@ export class TaskHeaderComponent implements OnInit {
}
public onDelete() {
this.taskService.delete(this.task).then((ok: any) => {
this.taskService.delete(this.task).then(() => {
this.router.navigate(['/folder/' + this.task.folderId]);
});
}
+2 -1
View File
@@ -8,6 +8,7 @@
},
"exclude": [
"test.ts",
"**/*.spec.ts"
"**/*.spec.ts",
"environments/environment.prod.ts"
]
}
-35
View File
@@ -29,41 +29,6 @@ Until Keycloak is updated you have to:
3. Disable "SameSite by default cookies" and "Cookies without SameSite must be secure" flags.
4. Relaunch.
OSM Request Trust Certificate
=============================
**Valid until:** 15. Sep 2025 18:00:00 CEST
Handle truststore.jks
---------------------
### List truststore Certs:
```
cd backend/src/main/resources
keytool -list -keystore truststore.jks
keytool -list -v -keystore truststore.jks
```
### Renew Root Cert in TrustStore
1. Download new Cert \\\
**From:** [Let's Encrypt](https://letsencrypt.org/certificates/) (Take Active -> Let’s Encrypt R3 Cert in the "der" format)
2. installing the Cert \\\
```
cd backend/src/main/resources
rm truststore.jks
keytool -import -keystore truststore.jks -storepass Tester11 -noprompt -trustcacerts -alias LetsEncryptR3CrossSigned -file ~/Downloads/lets-encrypt-r3-cross-signed.der
keytool -import -keystore truststore.jks -storepass Tester11 -noprompt -trustcacerts -alias LetsEncryptR3 -file ~/Downloads/lets-encrypt-r3.der
```
Elasticsrach connection
=======================
Add the Certs generated by Elasticsearch to the KeyStore:
```
keytool -import -v -trustcacerts -file ./deploy/localDev/boxit/elasticsearch/certs/ca/ca.crt -alias elasticsearch_ca_cert -keystore ./backend/src/main/resources/truststore.jks
keytool -import -v -trustcacerts -file ./deploy/localDev/boxit/elasticsearch/certs/elasticsearch/elasticsearch.crt -alias elasticsearch_cert -keystore ./backend/src/main/resources/truststore.jks
```
Artifacts
=========
- **LogoFont** \
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.