chore: merge develop → main (maintenance window 2026-06-28) #7

Merged
hiveiq merged 12 commits from develop into main 2026-06-28 07:25:43 -04:00
10 changed files with 152 additions and 205 deletions
-12
View File
@@ -130,18 +130,6 @@ jobs:
docker compose pull hiveiq-aria && \
REGISTRY_URL=${{ secrets.DEV_REGISTRY_URL }} ARIA_VERSION=dev \
docker compose up -d hiveiq-aria"
- name: Notify Slack
if: always()
run: |
STATUS="${{ job.status }}"
[ "$STATUS" = "success" ] && COLOR="good" || COLOR="danger"
SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7)
RUN_URL="https://hiveiq-gitea.directlx.dev/hiveiq-src/hiveops-aria/actions/runs/${{ github.run_id }}"
curl -s -X POST "${{ secrets.SLACK_WEBHOOK_URL }}" \
-H "Content-Type: application/json" \
-d "{\"attachments\":[{\"color\":\"$COLOR\",\"text\":\"*<$RUN_URL|hiveops-aria CD Develop — $STATUS>*\n${{ github.ref_name }} · $SHORT_SHA · ${{ github.actor }}\",\"mrkdwn_in\":[\"text\"],\"footer\":\"Gitea Actions\"}]}"
- name: Cleanup
if: always()
run: rm -f ~/.ssh/deploy_key
+7 -31
View File
@@ -4,10 +4,11 @@ on:
push:
branches:
- main
workflow_dispatch:
jobs:
build-and-deploy:
runs-on: ubuntu-latest
runs-on: production
env:
GIT_SSL_NO_VERIFY: "true"
MAVEN_OPTS: "-Dmaven.wagon.http.ssl.insecure=true -Dmaven.wagon.http.ssl.allowall=true"
@@ -16,20 +17,12 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Verify toolchain
run: java -version && mvn -version && trivy --version
- name: Clean runner disk
run: docker system prune -f 2>/dev/null || true
- name: Install Java 21 and Maven
run: |
apt-get update -qq
apt-get install -y -qq wget apt-transport-https gnupg
wget -qO - https://packages.adoptium.net/artifactory/api/gpg/key/public | gpg --dearmor -o /usr/share/keyrings/adoptium.gpg
echo "deb [signed-by=/usr/share/keyrings/adoptium.gpg] https://packages.adoptium.net/artifactory/deb $(. /etc/os-release && echo $VERSION_CODENAME) main" | tee /etc/apt/sources.list.d/adoptium.list
apt-get update -qq
apt-get install -y -qq temurin-21-jdk maven
java -version
mvn -version
- name: Configure Maven settings
run: |
mkdir -p ~/.m2
@@ -73,9 +66,6 @@ jobs:
- name: Build JAR
run: mvn clean package -DskipTests -B
- name: Install Trivy
run: curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin
- name: Trivy vulnerability scan
run: |
trivy fs \
@@ -83,6 +73,7 @@ jobs:
--severity HIGH,CRITICAL \
--ignore-unfixed \
--scanners vuln \
--skip-db-update \
--format table \
target/
@@ -98,16 +89,12 @@ jobs:
-DautoUpdate=false \
-DdataDirectory=/tmp/owasp-data \
-DsuppressionFile=deployment/owasp-suppressions.xml \
-DassemblyAnalyzerEnabled=false \
-Dformats=HTML,JSON \
-B
- name: Build and push Docker image
run: |
if ! command -v docker &> /dev/null; then
apt-get update -qq && apt-get install -y -qq docker.io
fi
DOCKER_BUILDKIT=0 docker system prune -f 2>/dev/null || true
export DOCKER_BUILDKIT=0
echo "${{ secrets.REGISTRY_PASSWORD }}" | \
docker login ${{ secrets.REGISTRY_URL }} \
-u ${{ secrets.REGISTRY_USERNAME }} --password-stdin
@@ -117,14 +104,3 @@ jobs:
-t ${{ secrets.REGISTRY_URL }}/hiveiq-aria:${SHORT_SHA} .
docker push ${{ secrets.REGISTRY_URL }}/hiveiq-aria:latest
docker push ${{ secrets.REGISTRY_URL }}/hiveiq-aria:${SHORT_SHA}
- name: Notify Slack
if: always()
run: |
STATUS="${{ job.status }}"
[ "$STATUS" = "success" ] && COLOR="good" || COLOR="danger"
SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7)
RUN_URL="https://hiveiq-gitea.directlx.dev/hiveiq-src/hiveops-aria/actions/runs/${{ github.run_id }}"
curl -s -X POST "${{ secrets.SLACK_PROD_WEBHOOK_URL }}" \
-H "Content-Type: application/json" \
-d "{\"attachments\":[{\"color\":\"$COLOR\",\"text\":\"*<$RUN_URL|hiveops-aria CD Production — $STATUS>*\n${{ github.ref_name }} · $SHORT_SHA · ${{ github.actor }}\",\"mrkdwn_in\":[\"text\"],\"footer\":\"Gitea Actions\"}]}"
+8 -1
View File
@@ -12,7 +12,14 @@ while [[ "$#" -gt 0 ]]; do
shift
done
IMAGE="$REGISTRY/hiveiq-aria:latest"
# Use :dev tag for the dev registry, :latest for everything else
if [[ "$REGISTRY" == *"bcos.dev"* ]]; then
TAG="dev"
else
TAG="latest"
fi
IMAGE="$REGISTRY/hiveiq-aria:$TAG"
echo "Building JAR..."
mvn clean package -DskipTests -B
+2 -9
View File
@@ -1,19 +1,12 @@
#!/bin/sh
set -e
# Inject runtime config from environment variables into the built SPA.
# This file is written to /app/dist/config.js and loaded by index.html
# BEFORE the Vite bundle — so window.__APP_CONFIG__ is available at startup.
#
# Add new config values here and in src/lib/api.ts Window interface.
cat > /app/dist/config.js <<EOF
window.__APP_CONFIG__ = {
apiUrl: '${VITE_API_URL:-http://localhost:8080}',
authUrl: '${VITE_AUTH_URL:-http://localhost:8082}'
apiUrl: '${VITE_API_URL:-http://localhost:8017}'
};
EOF
echo "config.js: apiUrl=${VITE_API_URL:-http://localhost:8080}"
echo "config.js: apiUrl=${VITE_API_URL:-http://localhost:8017}"
exec "$@"
+1 -1
View File
@@ -38,7 +38,7 @@
onMount(() => {
document.documentElement.classList.add('dark-mode');
authApi.get('/api/auth/users/me').then((res: any) => {
authApi.get('/auth/api/users/me').then((res: any) => {
userInfo = { name: res.data.name, email: res.data.email, role: res.data.role };
}).catch(() => {});
});
+43 -38
View File
@@ -122,16 +122,17 @@
// Auto-refresh
const REFRESH_SECONDS = 60;
const CIRCUMFERENCE = 2 * Math.PI * 14;
let secondsLeft = REFRESH_SECONDS;
let refreshing = false;
let autoRefreshEnabled = true;
const _AR_KEY = 'aria_posture_autoRefresh';
let autoRefreshEnabled: boolean = typeof localStorage !== 'undefined'
? (localStorage.getItem(_AR_KEY) ?? 'true') === 'true'
: true;
let tickInterval: ReturnType<typeof setInterval>;
$: dashOffset = CIRCUMFERENCE * (1 - secondsLeft / REFRESH_SECONDS);
function toggleAutoRefresh() {
autoRefreshEnabled = !autoRefreshEnabled;
if (typeof localStorage !== 'undefined') localStorage.setItem(_AR_KEY, String(autoRefreshEnabled));
if (autoRefreshEnabled) secondsLeft = REFRESH_SECONDS;
}
@@ -166,32 +167,13 @@
<p>Per-device security compliance — disk encryption, image integrity, OS currency</p>
</div>
<div class="header-controls">
<label class="auto-refresh-toggle" title={autoRefreshEnabled ? `Auto-refresh in ${secondsLeft}s` : 'Auto-refresh disabled'}>
<input type="checkbox" checked={autoRefreshEnabled} on:change={toggleAutoRefresh} />
<span class="toggle-track"><span class="toggle-thumb"></span></span>
<span class="toggle-label">Auto-refresh{autoRefreshEnabled ? ` (${secondsLeft}s)` : ''}</span>
</label>
<button class="btn-manual-refresh" on:click={doRefresh} disabled={refreshing}
title="Refresh now" aria-label="Refresh">{refreshing ? '⟳' : '↻'}</button>
<button class="refresh-countdown" class:paused={!autoRefreshEnabled}
on:click={toggleAutoRefresh}
title={autoRefreshEnabled ? `Auto-refresh in ${secondsLeft}s — click to pause` : 'Auto-refresh paused — click to resume'}
aria-label="Toggle auto-refresh">
<svg width="72" height="72" viewBox="0 0 36 36">
<circle cx="18" cy="18" r="14" fill="none" stroke="rgba(255,255,255,0.2)" stroke-width="3"/>
{#if autoRefreshEnabled}
<circle cx="18" cy="18" r="14" fill="none"
stroke={secondsLeft <= 5 ? '#f87171' : 'rgba(255,255,255,0.85)'}
stroke-width="3" stroke-dasharray={CIRCUMFERENCE} stroke-dashoffset={dashOffset}
stroke-linecap="round" transform="rotate(-90 18 18)" class:pulsing={secondsLeft <= 5}/>
{:else}
<circle cx="18" cy="18" r="14" fill="none" stroke="rgba(255,255,255,0.3)"
stroke-width="3" stroke-dasharray="4 3" transform="rotate(-90 18 18)"/>
{/if}
{#if refreshing}
<text x="18" y="22" text-anchor="middle" font-size="9" fill="rgba(255,255,255,0.9)" font-family="sans-serif">⟳</text>
{:else if autoRefreshEnabled}
<text x="18" y="22" text-anchor="middle" font-size="9" fill="rgba(255,255,255,0.9)" font-family="sans-serif">{secondsLeft}</text>
{:else}
<text x="18" y="22" text-anchor="middle" font-size="9" fill="rgba(255,255,255,0.5)" font-family="sans-serif">⏸</text>
{/if}
</svg>
</button>
</div>
</div>
@@ -570,6 +552,39 @@
.toolbar { display: flex; align-items: center; justify-content: space-between; flex-shrink: 0; }
.toolbar-count { font-size: var(--font-size-body-sm); color: #6b7280; }
.header-controls { display: flex; align-items: center; gap: 0.5rem; flex-shrink: 0; }
.auto-refresh-toggle {
display: flex;
align-items: center;
gap: 0.5rem;
cursor: pointer;
user-select: none;
flex-shrink: 0;
}
.auto-refresh-toggle input { display: none; }
.toggle-track {
width: 36px; height: 20px;
background: rgba(255,255,255,0.25);
border-radius: 10px;
position: relative;
transition: background 0.2s;
flex-shrink: 0;
}
.auto-refresh-toggle input:checked + .toggle-track { background: #34d399; }
.toggle-thumb {
position: absolute;
top: 3px; left: 3px;
width: 14px; height: 14px;
background: white;
border-radius: 50%;
transition: transform 0.2s;
}
.auto-refresh-toggle input:checked + .toggle-track .toggle-thumb { transform: translateX(16px); }
.toggle-label {
color: rgba(255,255,255,0.9);
font-size: 0.8rem;
white-space: nowrap;
min-width: 110px;
}
.btn-manual-refresh {
background: rgba(255,255,255,0.15); border: 1px solid rgba(255,255,255,0.3);
color: white; border-radius: 50%; width: 36px; height: 36px;
@@ -578,16 +593,6 @@
}
.btn-manual-refresh:hover:not(:disabled) { background: rgba(255,255,255,0.28); }
.btn-manual-refresh:disabled { opacity: 0.5; cursor: not-allowed; }
.refresh-countdown {
flex-shrink: 0; background: none; border: none; cursor: pointer; padding: 0;
border-radius: 50%; display: flex; align-items: center; justify-content: center;
opacity: 0.9; transition: opacity 0.15s, transform 0.15s;
}
.refresh-countdown:hover { opacity: 1; transform: scale(1.08); }
.refresh-countdown.paused { opacity: 0.5; }
.refresh-countdown.paused:hover { opacity: 0.8; }
@keyframes countdown-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }
:global(.pulsing) { animation: countdown-pulse 0.8s ease-in-out infinite; }
/* Table card — canonical */
.table-card {
+43 -38
View File
@@ -110,16 +110,17 @@
// Auto-refresh
const REFRESH_SECONDS = 60;
const CIRCUMFERENCE = 2 * Math.PI * 14;
let secondsLeft = REFRESH_SECONDS;
let refreshing = false;
let autoRefreshEnabled = true;
const _AR_KEY = 'aria_alerts_autoRefresh';
let autoRefreshEnabled: boolean = typeof localStorage !== 'undefined'
? (localStorage.getItem(_AR_KEY) ?? 'true') === 'true'
: true;
let tickInterval: ReturnType<typeof setInterval>;
$: dashOffset = CIRCUMFERENCE * (1 - secondsLeft / REFRESH_SECONDS);
function toggleAutoRefresh() {
autoRefreshEnabled = !autoRefreshEnabled;
if (typeof localStorage !== 'undefined') localStorage.setItem(_AR_KEY, String(autoRefreshEnabled));
if (autoRefreshEnabled) secondsLeft = REFRESH_SECONDS;
}
@@ -162,32 +163,13 @@
<p>Multi-phase attack sequence detection — jackpotting and skimming precursors</p>
</div>
<div class="header-controls">
<label class="auto-refresh-toggle" title={autoRefreshEnabled ? `Auto-refresh in ${secondsLeft}s` : 'Auto-refresh disabled'}>
<input type="checkbox" checked={autoRefreshEnabled} on:change={toggleAutoRefresh} />
<span class="toggle-track"><span class="toggle-thumb"></span></span>
<span class="toggle-label">Auto-refresh{autoRefreshEnabled ? ` (${secondsLeft}s)` : ''}</span>
</label>
<button class="btn-manual-refresh" on:click={doRefresh} disabled={refreshing}
title="Refresh now" aria-label="Refresh">{refreshing ? '⟳' : '↻'}</button>
<button class="refresh-countdown" class:paused={!autoRefreshEnabled}
on:click={toggleAutoRefresh}
title={autoRefreshEnabled ? `Auto-refresh in ${secondsLeft}s — click to pause` : 'Auto-refresh paused — click to resume'}
aria-label="Toggle auto-refresh">
<svg width="72" height="72" viewBox="0 0 36 36">
<circle cx="18" cy="18" r="14" fill="none" stroke="rgba(255,255,255,0.2)" stroke-width="3"/>
{#if autoRefreshEnabled}
<circle cx="18" cy="18" r="14" fill="none"
stroke={secondsLeft <= 5 ? '#f87171' : 'rgba(255,255,255,0.85)'}
stroke-width="3" stroke-dasharray={CIRCUMFERENCE} stroke-dashoffset={dashOffset}
stroke-linecap="round" transform="rotate(-90 18 18)" class:pulsing={secondsLeft <= 5}/>
{:else}
<circle cx="18" cy="18" r="14" fill="none" stroke="rgba(255,255,255,0.3)"
stroke-width="3" stroke-dasharray="4 3" transform="rotate(-90 18 18)"/>
{/if}
{#if refreshing}
<text x="18" y="22" text-anchor="middle" font-size="9" fill="rgba(255,255,255,0.9)" font-family="sans-serif">⟳</text>
{:else if autoRefreshEnabled}
<text x="18" y="22" text-anchor="middle" font-size="9" fill="rgba(255,255,255,0.9)" font-family="sans-serif">{secondsLeft}</text>
{:else}
<text x="18" y="22" text-anchor="middle" font-size="9" fill="rgba(255,255,255,0.5)" font-family="sans-serif">⏸</text>
{/if}
</svg>
</button>
</div>
</div>
@@ -551,6 +533,39 @@
.toolbar-count { font-size: var(--font-size-body-sm); color: #6b7280; }
.header-controls { display: flex; align-items: center; gap: 0.5rem; flex-shrink: 0; }
.auto-refresh-toggle {
display: flex;
align-items: center;
gap: 0.5rem;
cursor: pointer;
user-select: none;
flex-shrink: 0;
}
.auto-refresh-toggle input { display: none; }
.toggle-track {
width: 36px; height: 20px;
background: rgba(255,255,255,0.25);
border-radius: 10px;
position: relative;
transition: background 0.2s;
flex-shrink: 0;
}
.auto-refresh-toggle input:checked + .toggle-track { background: #34d399; }
.toggle-thumb {
position: absolute;
top: 3px; left: 3px;
width: 14px; height: 14px;
background: white;
border-radius: 50%;
transition: transform 0.2s;
}
.auto-refresh-toggle input:checked + .toggle-track .toggle-thumb { transform: translateX(16px); }
.toggle-label {
color: rgba(255,255,255,0.9);
font-size: 0.8rem;
white-space: nowrap;
min-width: 110px;
}
.btn-manual-refresh {
background: rgba(255,255,255,0.15); border: 1px solid rgba(255,255,255,0.3);
color: white; border-radius: 50%; width: 36px; height: 36px;
@@ -559,16 +574,6 @@
}
.btn-manual-refresh:hover:not(:disabled) { background: rgba(255,255,255,0.28); }
.btn-manual-refresh:disabled { opacity: 0.5; cursor: not-allowed; }
.refresh-countdown {
flex-shrink: 0; background: none; border: none; cursor: pointer; padding: 0;
border-radius: 50%; display: flex; align-items: center; justify-content: center;
opacity: 0.9; transition: opacity 0.15s, transform 0.15s;
}
.refresh-countdown:hover { opacity: 1; transform: scale(1.08); }
.refresh-countdown.paused { opacity: 0.5; }
.refresh-countdown.paused:hover { opacity: 0.8; }
@keyframes countdown-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }
:global(.pulsing) { animation: countdown-pulse 0.8s ease-in-out infinite; }
/* Table card — canonical */
.table-card {
+43 -38
View File
@@ -85,16 +85,17 @@
// Auto-refresh
const REFRESH_SECONDS = 60;
const CIRCUMFERENCE = 2 * Math.PI * 14;
let secondsLeft = REFRESH_SECONDS;
let refreshing = false;
let autoRefreshEnabled = true;
const _AR_KEY = 'aria_threats_autoRefresh';
let autoRefreshEnabled: boolean = typeof localStorage !== 'undefined'
? (localStorage.getItem(_AR_KEY) ?? 'true') === 'true'
: true;
let tickInterval: ReturnType<typeof setInterval>;
$: dashOffset = CIRCUMFERENCE * (1 - secondsLeft / REFRESH_SECONDS);
function toggleAutoRefresh() {
autoRefreshEnabled = !autoRefreshEnabled;
if (typeof localStorage !== 'undefined') localStorage.setItem(_AR_KEY, String(autoRefreshEnabled));
if (autoRefreshEnabled) secondsLeft = REFRESH_SECONDS;
}
@@ -128,32 +129,13 @@
<p>IOC match events detected across the fleet</p>
</div>
<div class="header-controls">
<label class="auto-refresh-toggle" title={autoRefreshEnabled ? `Auto-refresh in ${secondsLeft}s` : 'Auto-refresh disabled'}>
<input type="checkbox" checked={autoRefreshEnabled} on:change={toggleAutoRefresh} />
<span class="toggle-track"><span class="toggle-thumb"></span></span>
<span class="toggle-label">Auto-refresh{autoRefreshEnabled ? ` (${secondsLeft}s)` : ''}</span>
</label>
<button class="btn-manual-refresh" on:click={doRefresh} disabled={refreshing}
title="Refresh now" aria-label="Refresh">{refreshing ? '⟳' : '↻'}</button>
<button class="refresh-countdown" class:paused={!autoRefreshEnabled}
on:click={toggleAutoRefresh}
title={autoRefreshEnabled ? `Auto-refresh in ${secondsLeft}s — click to pause` : 'Auto-refresh paused — click to resume'}
aria-label="Toggle auto-refresh">
<svg width="72" height="72" viewBox="0 0 36 36">
<circle cx="18" cy="18" r="14" fill="none" stroke="rgba(255,255,255,0.2)" stroke-width="3"/>
{#if autoRefreshEnabled}
<circle cx="18" cy="18" r="14" fill="none"
stroke={secondsLeft <= 5 ? '#f87171' : 'rgba(255,255,255,0.85)'}
stroke-width="3" stroke-dasharray={CIRCUMFERENCE} stroke-dashoffset={dashOffset}
stroke-linecap="round" transform="rotate(-90 18 18)" class:pulsing={secondsLeft <= 5}/>
{:else}
<circle cx="18" cy="18" r="14" fill="none" stroke="rgba(255,255,255,0.3)"
stroke-width="3" stroke-dasharray="4 3" transform="rotate(-90 18 18)"/>
{/if}
{#if refreshing}
<text x="18" y="22" text-anchor="middle" font-size="9" fill="rgba(255,255,255,0.9)" font-family="sans-serif">⟳</text>
{:else if autoRefreshEnabled}
<text x="18" y="22" text-anchor="middle" font-size="9" fill="rgba(255,255,255,0.9)" font-family="sans-serif">{secondsLeft}</text>
{:else}
<text x="18" y="22" text-anchor="middle" font-size="9" fill="rgba(255,255,255,0.5)" font-family="sans-serif">⏸</text>
{/if}
</svg>
</button>
</div>
</div>
@@ -290,6 +272,39 @@
}
.header-controls { display: flex; align-items: center; gap: 0.5rem; flex-shrink: 0; }
.auto-refresh-toggle {
display: flex;
align-items: center;
gap: 0.5rem;
cursor: pointer;
user-select: none;
flex-shrink: 0;
}
.auto-refresh-toggle input { display: none; }
.toggle-track {
width: 36px; height: 20px;
background: rgba(255,255,255,0.25);
border-radius: 10px;
position: relative;
transition: background 0.2s;
flex-shrink: 0;
}
.auto-refresh-toggle input:checked + .toggle-track { background: #34d399; }
.toggle-thumb {
position: absolute;
top: 3px; left: 3px;
width: 14px; height: 14px;
background: white;
border-radius: 50%;
transition: transform 0.2s;
}
.auto-refresh-toggle input:checked + .toggle-track .toggle-thumb { transform: translateX(16px); }
.toggle-label {
color: rgba(255,255,255,0.9);
font-size: 0.8rem;
white-space: nowrap;
min-width: 110px;
}
.btn-manual-refresh {
background: rgba(255,255,255,0.15); border: 1px solid rgba(255,255,255,0.3);
color: white; border-radius: 50%; width: 36px; height: 36px;
@@ -298,16 +313,6 @@
}
.btn-manual-refresh:hover:not(:disabled) { background: rgba(255,255,255,0.28); }
.btn-manual-refresh:disabled { opacity: 0.5; cursor: not-allowed; }
.refresh-countdown {
flex-shrink: 0; background: none; border: none; cursor: pointer; padding: 0;
border-radius: 50%; display: flex; align-items: center; justify-content: center;
opacity: 0.9; transition: opacity 0.15s, transform 0.15s;
}
.refresh-countdown:hover { opacity: 1; transform: scale(1.08); }
.refresh-countdown.paused { opacity: 0.5; }
.refresh-countdown.paused:hover { opacity: 0.8; }
@keyframes countdown-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }
:global(.pulsing) { animation: countdown-pulse 0.8s ease-in-out infinite; }
.page-body {
display: flex; flex: 1; overflow: hidden; min-height: 0; margin: 0 0 16px;
+4 -5
View File
@@ -4,21 +4,20 @@ declare global {
interface Window {
__APP_CONFIG__?: {
apiUrl?: string;
authUrl?: string;
};
}
}
const API_BASE = window.__APP_CONFIG__?.apiUrl || 'http://localhost:8017';
const AUTH_BASE = window.__APP_CONFIG__?.authUrl || 'http://localhost:8082';
const ariaApiUrl = window.__APP_CONFIG__?.apiUrl || 'http://localhost:8017';
const gatewayUrl = ariaApiUrl.replace(/\/aria$/, '');
const api = axios.create({
baseURL: API_BASE,
baseURL: ariaApiUrl,
headers: { 'Content-Type': 'application/json' },
});
export const authApi = axios.create({
baseURL: AUTH_BASE,
baseURL: gatewayUrl,
headers: { 'Content-Type': 'application/json' },
});
@@ -10,12 +10,6 @@ import org.springframework.security.config.annotation.web.configurers.AbstractHt
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import java.util.Arrays;
import java.util.List;
@Configuration
@EnableWebSecurity
@@ -31,7 +25,7 @@ public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.cors(cors -> cors.configurationSource(corsConfigurationSource()))
.cors(AbstractHttpConfigurer::disable)
.csrf(AbstractHttpConfigurer::disable)
.sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
@@ -46,29 +40,4 @@ public class SecurityConfig {
return http.build();
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
String originsEnv = System.getenv("CORS_ALLOWED_ORIGINS");
if (originsEnv != null && !originsEnv.isBlank()) {
config.setAllowedOrigins(Arrays.asList(originsEnv.split(",")));
} else {
config.setAllowedOrigins(List.of(
"https://aria.bcos.cloud",
"https://portal.bcos.cloud",
"http://localhost:5181"
));
}
config.setAllowedMethods(List.of("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"));
config.setAllowedHeaders(List.of("Authorization", "Content-Type", "X-Requested-With", "X-Service-Secret"));
config.setAllowCredentials(true);
config.setMaxAge(3600L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
}