Add source:sociowire for user posts, fix time filter, cross-origin SSO
This commit is contained in:
parent
d4829ae628
commit
d5aa930d34
|
|
@ -0,0 +1,33 @@
|
||||||
|
FROM node:22-alpine AS build
|
||||||
|
WORKDIR /app
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm ci
|
||||||
|
COPY . .
|
||||||
|
ARG VITE_API_BASE_URL=
|
||||||
|
ARG VITE_KC_URL=/auth
|
||||||
|
ENV VITE_API_BASE_URL=${VITE_API_BASE_URL}
|
||||||
|
ENV VITE_KC_URL=${VITE_KC_URL}
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
FROM nginx:alpine
|
||||||
|
RUN rm /etc/nginx/conf.d/default.conf
|
||||||
|
COPY --from=build /app/dist /usr/share/nginx/html
|
||||||
|
COPY <<EOF /etc/nginx/conf.d/default.conf
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name _;
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
try_files \$uri \$uri/ /index.html;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||||
|
expires 1y;
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
EXPOSE 80
|
||||||
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
|
|
@ -17,6 +17,16 @@ const KC_REALM = import.meta?.env?.VITE_KC_REALM || "sociowire";
|
||||||
const KC_CLIENT_ID = import.meta?.env?.VITE_KC_CLIENT_ID || "sociowire-frontend";
|
const KC_CLIENT_ID = import.meta?.env?.VITE_KC_CLIENT_ID || "sociowire-frontend";
|
||||||
const KC_SSO_ENABLED = (import.meta?.env?.VITE_KC_SSO || "true") !== "false";
|
const KC_SSO_ENABLED = (import.meta?.env?.VITE_KC_SSO || "true") !== "false";
|
||||||
|
|
||||||
|
// Check if Keycloak is on a different origin (cross-domain SSO)
|
||||||
|
function isCrossOriginSSO() {
|
||||||
|
try {
|
||||||
|
const kcOrigin = new URL(KC_URL).origin;
|
||||||
|
return kcOrigin !== window.location.origin;
|
||||||
|
} catch {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let kcInstance = null;
|
let kcInstance = null;
|
||||||
function getKeycloak() {
|
function getKeycloak() {
|
||||||
if (!kcInstance) {
|
if (!kcInstance) {
|
||||||
|
|
@ -473,6 +483,7 @@ export function AuthProvider({ children }) {
|
||||||
try {
|
try {
|
||||||
kc = getKeycloak();
|
kc = getKeycloak();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
console.error("[Auth] Keycloak init error:", err);
|
||||||
setAnon("SSO failed to initialize. Please try again.");
|
setAnon("SSO failed to initialize. Please try again.");
|
||||||
return { ok: false, reason: "init_failed", detail: err?.message || "" };
|
return { ok: false, reason: "init_failed", detail: err?.message || "" };
|
||||||
}
|
}
|
||||||
|
|
@ -482,6 +493,7 @@ export function AuthProvider({ children }) {
|
||||||
const errDesc = params.get("error_description") || params.get("kc_error_description") || "";
|
const errDesc = params.get("error_description") || params.get("kc_error_description") || "";
|
||||||
|
|
||||||
if (errCode) {
|
if (errCode) {
|
||||||
|
console.error("[Auth] SSO error from Keycloak:", errCode, errDesc);
|
||||||
setAnon(`SSO failed: ${errCode}${errDesc ? " - " + errDesc : ""}`);
|
setAnon(`SSO failed: ${errCode}${errDesc ? " - " + errDesc : ""}`);
|
||||||
cleanupAuthUrl();
|
cleanupAuthUrl();
|
||||||
return { ok: false, reason: "kc_error", detail: errDesc || errCode };
|
return { ok: false, reason: "kc_error", detail: errDesc || errCode };
|
||||||
|
|
@ -489,18 +501,23 @@ export function AuthProvider({ children }) {
|
||||||
|
|
||||||
let ok = false;
|
let ok = false;
|
||||||
try {
|
try {
|
||||||
|
console.log("[Auth] Initializing Keycloak for SSO callback...");
|
||||||
ok = await kc.init({
|
ok = await kc.init({
|
||||||
onLoad: "check-sso",
|
onLoad: "check-sso",
|
||||||
pkceMethod: "S256",
|
pkceMethod: "S256",
|
||||||
checkLoginIframe: false,
|
checkLoginIframe: false,
|
||||||
|
enableLogging: true,
|
||||||
});
|
});
|
||||||
|
console.log("[Auth] Keycloak init result:", ok, "authenticated:", kc.authenticated);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
console.error("[Auth] Keycloak init failed:", err);
|
||||||
setAnon("SSO failed to finish. Please try again.");
|
setAnon("SSO failed to finish. Please try again.");
|
||||||
cleanupAuthUrl();
|
cleanupAuthUrl();
|
||||||
return { ok: false, reason: "kc_init_failed", detail: err?.message || "" };
|
return { ok: false, reason: "kc_init_failed", detail: err?.message || "" };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ok || !kc.authenticated || !kc.token) {
|
if (!ok || !kc.authenticated || !kc.token) {
|
||||||
|
console.warn("[Auth] Keycloak not authenticated after init");
|
||||||
setAnon("SSO login failed. Please try again.");
|
setAnon("SSO login failed. Please try again.");
|
||||||
cleanupAuthUrl();
|
cleanupAuthUrl();
|
||||||
return { ok: false, reason: "not_authenticated" };
|
return { ok: false, reason: "not_authenticated" };
|
||||||
|
|
@ -540,6 +557,12 @@ export function AuthProvider({ children }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function trySilentKeycloakSession() {
|
async function trySilentKeycloakSession() {
|
||||||
|
// Skip silent SSO check for cross-origin (third-party cookies blocked)
|
||||||
|
if (isCrossOriginSSO()) {
|
||||||
|
console.log("[Auth] Skipping silent SSO check (cross-origin)");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
let kc = null;
|
let kc = null;
|
||||||
try {
|
try {
|
||||||
if (sessionStorage.getItem("sociowire:logout")) {
|
if (sessionStorage.getItem("sociowire:logout")) {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import React from "react";
|
||||||
|
|
||||||
export default function TimeFilterButtons({ activeHours, onSelect }) {
|
export default function TimeFilterButtons({ activeHours, onSelect }) {
|
||||||
const buttons = [
|
const buttons = [
|
||||||
{ hours: 5, label: "Now", icon: "fa-solid fa-bolt" },
|
{ hours: 3, label: "Now", icon: "fa-solid fa-bolt" },
|
||||||
{ hours: 24, label: "Today", icon: "fa-solid fa-sun" },
|
{ hours: 24, label: "Today", icon: "fa-solid fa-sun" },
|
||||||
{ hours: 96, label: "4Days", icon: "fa-solid fa-calendar-days" },
|
{ hours: 96, label: "4Days", icon: "fa-solid fa-calendar-days" },
|
||||||
{ hours: 336, label: "Old", icon: "fa-solid fa-hourglass-half" },
|
{ hours: 336, label: "Old", icon: "fa-solid fa-hourglass-half" },
|
||||||
|
|
|
||||||
|
|
@ -1376,6 +1376,8 @@ export default function MapView({
|
||||||
.split(",")
|
.split(",")
|
||||||
.map((u) => u.trim())
|
.map((u) => u.trim())
|
||||||
.filter(Boolean),
|
.filter(Boolean),
|
||||||
|
// Mark as user-created post so enrichment preserves the position
|
||||||
|
source: "sociowire",
|
||||||
};
|
};
|
||||||
|
|
||||||
if (draftUrl.trim()) {
|
if (draftUrl.trim()) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue