Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 2 additions & 12 deletions apps/sim/app/(auth)/components/oauth-provider-checker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,9 @@ import { env } from '@/lib/env'
import { isProd } from '@/lib/environment'

export async function getOAuthProviderStatus() {
const githubAvailable = !!(
env.GITHUB_CLIENT_ID &&
env.GITHUB_CLIENT_SECRET &&
env.GITHUB_CLIENT_ID !== 'placeholder' &&
env.GITHUB_CLIENT_SECRET !== 'placeholder'
)
const githubAvailable = !!(env.GITHUB_CLIENT_ID && env.GITHUB_CLIENT_SECRET)

const googleAvailable = !!(
env.GOOGLE_CLIENT_ID &&
env.GOOGLE_CLIENT_SECRET &&
env.GOOGLE_CLIENT_ID !== 'placeholder' &&
env.GOOGLE_CLIENT_SECRET !== 'placeholder'
)
const googleAvailable = !!(env.GOOGLE_CLIENT_ID && env.GOOGLE_CLIENT_SECRET)

return { githubAvailable, googleAvailable, isProduction: isProd }
}
13 changes: 0 additions & 13 deletions apps/sim/app/(auth)/components/social-login-buttons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,6 @@ export function SocialLoginButtons({
setIsGithubLoading(true)
try {
await client.signIn.social({ provider: 'github', callbackURL })

// Mark that the user has previously logged in
if (typeof window !== 'undefined') {
localStorage.setItem('has_logged_in_before', 'true')
document.cookie = 'has_logged_in_before=true; path=/; max-age=31536000; SameSite=Lax' // 1 year expiry
}
} catch (err: any) {
let errorMessage = 'Failed to sign in with GitHub'

Expand All @@ -66,13 +60,6 @@ export function SocialLoginButtons({
setIsGoogleLoading(true)
try {
await client.signIn.social({ provider: 'google', callbackURL })

// Mark that the user has previously logged in
if (typeof window !== 'undefined') {
localStorage.setItem('has_logged_in_before', 'true')
// Also set a cookie to enable middleware to check login status
document.cookie = 'has_logged_in_before=true; path=/; max-age=31536000; SameSite=Lax' // 1 year expiry
}
} catch (err: any) {
let errorMessage = 'Failed to sign in with Google'

Expand Down
51 changes: 8 additions & 43 deletions apps/sim/app/(auth)/login/login-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,12 @@ const validatePassword = (passwordValue: string): string[] => {

if (!PASSWORD_VALIDATIONS.required.test(passwordValue)) {
errors.push(PASSWORD_VALIDATIONS.required.message)
return errors // Return early for required field
return errors
}

if (!PASSWORD_VALIDATIONS.notEmpty.test(passwordValue)) {
errors.push(PASSWORD_VALIDATIONS.notEmpty.message)
return errors // Return early for empty field
return errors
}

return errors
Expand All @@ -104,11 +104,9 @@ export default function LoginPage({
const [showValidationError, setShowValidationError] = useState(false)
const [buttonClass, setButtonClass] = useState('auth-button-gradient')

// Initialize state for URL parameters
const [callbackUrl, setCallbackUrl] = useState('/workspace')
const [isInviteFlow, setIsInviteFlow] = useState(false)

// Forgot password states
const [forgotPasswordOpen, setForgotPasswordOpen] = useState(false)
const [forgotPasswordEmail, setForgotPasswordEmail] = useState('')
const [isSubmittingReset, setIsSubmittingReset] = useState(false)
Expand All @@ -117,38 +115,31 @@ export default function LoginPage({
message: string
}>({ type: null, message: '' })

// Email validation state
const [email, setEmail] = useState('')
const [emailErrors, setEmailErrors] = useState<string[]>([])
const [showEmailValidationError, setShowEmailValidationError] = useState(false)

// Extract URL parameters after component mounts to avoid SSR issues
useEffect(() => {
setMounted(true)

// Only access search params on the client side
if (searchParams) {
const callback = searchParams.get('callbackUrl')
if (callback) {
// Validate the callbackUrl before setting it
if (validateCallbackUrl(callback)) {
setCallbackUrl(callback)
} else {
logger.warn('Invalid callback URL detected and blocked:', { url: callback })
// Keep the default safe value ('/workspace')
}
}

const inviteFlow = searchParams.get('invite_flow') === 'true'
setIsInviteFlow(inviteFlow)
}

// Check if CSS variable has been customized
const checkCustomBrand = () => {
const computedStyle = getComputedStyle(document.documentElement)
const brandAccent = computedStyle.getPropertyValue('--brand-accent-hex').trim()

// Check if the CSS variable exists and is different from the default
if (brandAccent && brandAccent !== '#6f3dfa') {
setButtonClass('auth-button-custom')
} else {
Expand All @@ -158,7 +149,6 @@ export default function LoginPage({

checkCustomBrand()

// Also check on window resize or theme changes
window.addEventListener('resize', checkCustomBrand)
const observer = new MutationObserver(checkCustomBrand)
observer.observe(document.documentElement, {
Expand Down Expand Up @@ -189,7 +179,6 @@ export default function LoginPage({
const newEmail = e.target.value
setEmail(newEmail)

// Silently validate but don't show errors until submit
const errors = validateEmailField(newEmail)
setEmailErrors(errors)
setShowEmailValidationError(false)
Expand All @@ -199,7 +188,6 @@ export default function LoginPage({
const newPassword = e.target.value
setPassword(newPassword)

// Silently validate but don't show errors until submit
const errors = validatePassword(newPassword)
setPasswordErrors(errors)
setShowValidationError(false)
Expand All @@ -210,26 +198,23 @@ export default function LoginPage({
setIsLoading(true)

const formData = new FormData(e.currentTarget)
const email = formData.get('email') as string
const emailRaw = formData.get('email') as string
const email = emailRaw.trim().toLowerCase()

// Validate email on submit
const emailValidationErrors = validateEmailField(email)
setEmailErrors(emailValidationErrors)
setShowEmailValidationError(emailValidationErrors.length > 0)

// Validate password on submit
const passwordValidationErrors = validatePassword(password)
setPasswordErrors(passwordValidationErrors)
setShowValidationError(passwordValidationErrors.length > 0)

// If there are validation errors, stop submission
if (emailValidationErrors.length > 0 || passwordValidationErrors.length > 0) {
setIsLoading(false)
return
}

try {
// Final validation before submission
const safeCallbackUrl = validateCallbackUrl(callbackUrl) ? callbackUrl : '/workspace'

const result = await client.signIn.email(
Expand Down Expand Up @@ -291,33 +276,13 @@ export default function LoginPage({
setIsLoading(false)
return
}

// Mark that the user has previously logged in
if (typeof window !== 'undefined') {
localStorage.setItem('has_logged_in_before', 'true')
document.cookie = 'has_logged_in_before=true; path=/; max-age=31536000; SameSite=Lax' // 1 year expiry
}
} catch (err: any) {
// Handle only the special verification case that requires a redirect
if (err.message?.includes('not verified') || err.code?.includes('EMAIL_NOT_VERIFIED')) {
try {
await client.emailOtp.sendVerificationOtp({
email,
type: 'email-verification',
})

if (typeof window !== 'undefined') {
sessionStorage.setItem('verificationEmail', email)
}

router.push('/verify')
return
} catch (_verifyErr) {
setPasswordErrors(['Failed to send verification code. Please try again later.'])
setShowValidationError(true)
setIsLoading(false)
return
if (typeof window !== 'undefined') {
sessionStorage.setItem('verificationEmail', email)
}
router.push('/verify')
return
}

console.error('Uncaught login error:', err)
Expand Down
2 changes: 0 additions & 2 deletions apps/sim/app/(auth)/reset-password/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ function ResetPasswordContent() {
text: '',
})

// Validate token presence
useEffect(() => {
if (!token) {
setStatusMessage({
Expand Down Expand Up @@ -60,7 +59,6 @@ function ResetPasswordContent() {
text: 'Password reset successful! Redirecting to login...',
})

// Redirect to login page after 1.5 seconds
setTimeout(() => {
router.push('/login?resetSuccess=true')
}, 1500)
Expand Down
7 changes: 0 additions & 7 deletions apps/sim/app/(auth)/reset-password/reset-password-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,10 @@ export function RequestResetForm({
const [buttonClass, setButtonClass] = useState('auth-button-gradient')

useEffect(() => {
// Check if CSS variable has been customized
const checkCustomBrand = () => {
const computedStyle = getComputedStyle(document.documentElement)
const brandAccent = computedStyle.getPropertyValue('--brand-accent-hex').trim()

// Check if the CSS variable exists and is different from the default
if (brandAccent && brandAccent !== '#6f3dfa') {
setButtonClass('auth-button-custom')
} else {
Expand All @@ -45,7 +43,6 @@ export function RequestResetForm({

checkCustomBrand()

// Also check on window resize or theme changes
window.addEventListener('resize', checkCustomBrand)
const observer = new MutationObserver(checkCustomBrand)
observer.observe(document.documentElement, {
Expand Down Expand Up @@ -132,12 +129,10 @@ export function SetNewPasswordForm({
const [buttonClass, setButtonClass] = useState('auth-button-gradient')

useEffect(() => {
// Check if CSS variable has been customized
const checkCustomBrand = () => {
const computedStyle = getComputedStyle(document.documentElement)
const brandAccent = computedStyle.getPropertyValue('--brand-accent-hex').trim()

// Check if the CSS variable exists and is different from the default
if (brandAccent && brandAccent !== '#6f3dfa') {
setButtonClass('auth-button-custom')
} else {
Expand All @@ -147,7 +142,6 @@ export function SetNewPasswordForm({

checkCustomBrand()

// Also check on window resize or theme changes
window.addEventListener('resize', checkCustomBrand)
const observer = new MutationObserver(checkCustomBrand)
observer.observe(document.documentElement, {
Expand All @@ -164,7 +158,6 @@ export function SetNewPasswordForm({
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()

// Simple validation
if (password.length < 8) {
setValidationMessage('Password must be at least 8 characters long')
return
Expand Down
1 change: 0 additions & 1 deletion apps/sim/app/(auth)/signup/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { env, isTruthy } from '@/lib/env'
import { getOAuthProviderStatus } from '@/app/(auth)/components/oauth-provider-checker'
import SignupForm from '@/app/(auth)/signup/signup-form'

// Force dynamic rendering to avoid prerender errors with search params
export const dynamic = 'force-dynamic'

export default async function SignupPage() {
Expand Down
Loading