mirror of
https://github.com/sourcebot-dev/sourcebot.git
synced 2025-12-15 05:45:20 +00:00
* sign up copy nits * first pass at new onboarding page * wip join onboard logic * refactor auth provider fetch logic * add member approval and invite link flag logic * update join request flow and remove jit logic * onboard guard * nits, onboard role check, invite link enabled check * fix bg color issue in onboarding page * refactor onboard UI * ui nits and more onboarding resource cards * revamp auth docs * change member approval default behavior and updated docs * merge prisma migrations * add id to resource card * feedback * feedback * feedback and fixed build * settings drop down UI nit * ui nits * handle join when max capacity case * add news data for member toggle * refactor for public access case * add iap bridge to onboard logic * fetch member approval req and invite link enabled flag on server * ui nits * fix invite link enable toggle snapping issue * ui nits * styling and ui nits, pass in invite id from server * add mcp resource in onboard step * get invite link in server * fix build issue * refactor docs on config * minor doc nit
98 lines
No EOL
4 KiB
TypeScript
98 lines
No EOL
4 KiB
TypeScript
'use client';
|
|
|
|
import React, { useState, useEffect } from "react";
|
|
import { env } from "@/env.mjs";
|
|
|
|
interface AuthSecurityNoticeProps {
|
|
closable?: boolean;
|
|
}
|
|
|
|
const AUTH_SECURITY_NOTICE_COOKIE = "auth-security-notice-dismissed";
|
|
|
|
const getSecurityNoticeDismissed = (): boolean => {
|
|
if (typeof document === "undefined") return false;
|
|
const cookies = document.cookie.split(';').map(cookie => cookie.trim());
|
|
const targetCookie = cookies.find(cookie => cookie.startsWith(`${AUTH_SECURITY_NOTICE_COOKIE}=`));
|
|
|
|
if (!targetCookie) return false;
|
|
|
|
try {
|
|
const cookieValue = targetCookie.substring(`${AUTH_SECURITY_NOTICE_COOKIE}=`.length);
|
|
return JSON.parse(decodeURIComponent(cookieValue));
|
|
} catch (error) {
|
|
console.warn('Failed to parse security notice cookie:', error);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
const setSecurityNoticeDismissed = (dismissed: boolean) => {
|
|
if (typeof document === "undefined") return;
|
|
try {
|
|
const expires = new Date();
|
|
expires.setFullYear(expires.getFullYear() + 1);
|
|
const cookieValue = encodeURIComponent(JSON.stringify(dismissed));
|
|
document.cookie = `${AUTH_SECURITY_NOTICE_COOKIE}=${cookieValue}; expires=${expires.toUTCString()}; path=/; SameSite=Lax`;
|
|
} catch (error) {
|
|
console.warn('Failed to set security notice cookie:', error);
|
|
}
|
|
};
|
|
|
|
export const AuthSecurityNotice = ({ closable = false }: AuthSecurityNoticeProps) => {
|
|
const [isDismissed, setIsDismissed] = useState(false);
|
|
const [hasMounted, setHasMounted] = useState(false);
|
|
|
|
// Only check cookie after component mounts to avoid hydration error
|
|
useEffect(() => {
|
|
setHasMounted(true);
|
|
if (closable) {
|
|
setIsDismissed(getSecurityNoticeDismissed());
|
|
}
|
|
}, [closable]);
|
|
|
|
const handleDismiss = () => {
|
|
setIsDismissed(true);
|
|
setSecurityNoticeDismissed(true);
|
|
};
|
|
|
|
// Don't render if dismissed when closable, or if closable but not yet mounted
|
|
if (closable && (!hasMounted || isDismissed)) {
|
|
return null;
|
|
}
|
|
|
|
// Only render for self-hosted deployments
|
|
if (env.NEXT_PUBLIC_SOURCEBOT_CLOUD_ENVIRONMENT !== undefined) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<div className={`p-4 rounded-lg bg-[var(--highlight)]/10 border border-[var(--highlight)]/20 relative ${closable ? 'pr-10' : ''}`}>
|
|
{closable && (
|
|
<button
|
|
onClick={handleDismiss}
|
|
className="absolute top-3 right-3 p-1 text-[var(--highlight)] hover:text-[var(--highlight)]/80 transition-colors"
|
|
aria-label="Dismiss security notice"
|
|
>
|
|
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
|
|
</svg>
|
|
</button>
|
|
)}
|
|
<p className="text-sm text-[var(--highlight)] leading-6 flex items-start gap-2">
|
|
<svg className="w-4 h-4 mt-0.5 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
|
|
</svg>
|
|
<span>
|
|
<strong>Security Notice:</strong> Authentication data is managed by your deployment and is encrypted at rest. Zero data leaves your deployment.{' '}
|
|
<a
|
|
href="https://docs.sourcebot.dev/docs/configuration/auth/faq"
|
|
target="_blank"
|
|
rel="noopener"
|
|
className="underline text-[var(--highlight)] hover:text-[var(--highlight)]/80 font-medium"
|
|
>
|
|
Learn more
|
|
</a>
|
|
</span>
|
|
</p>
|
|
</div>
|
|
);
|
|
};
|