diff --git a/astro.config.mjs b/astro.config.mjs index b08b435..1cda960 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -25,20 +25,18 @@ export default defineConfig({ // Define environment variables that should be available to client components vite: { define: { - "import.meta.env.PUBLIC_LOGTO_APP_ID": JSON.stringify( - process.env.PUBLIC_LOGTO_APP_ID, + "import.meta.env.LOGTO_APP_ID": JSON.stringify(process.env.LOGTO_APP_ID), + "import.meta.env.LOGTO_APP_SECRET": JSON.stringify( + process.env.LOGTO_APP_SECRET, ), - "import.meta.env.PUBLIC_LOGTO_APP_SECRET": JSON.stringify( - process.env.PUBLIC_LOGTO_APP_SECRET, + "import.meta.env.LOGTO_ENDPOINT": JSON.stringify( + process.env.LOGTO_ENDPOINT, ), - "import.meta.env.PUBLIC_LOGTO_ENDPOINT": JSON.stringify( - process.env.PUBLIC_LOGTO_ENDPOINT, + "import.meta.env.LOGTO_TOKEN_ENDPOINT": JSON.stringify( + process.env.LOGTO_TOKEN_ENDPOINT, ), - "import.meta.env.PUBLIC_LOGTO_TOKEN_ENDPOINT": JSON.stringify( - process.env.PUBLIC_LOGTO_TOKEN_ENDPOINT, - ), - "import.meta.env.PUBLIC_LOGTO_API_ENDPOINT": JSON.stringify( - process.env.PUBLIC_LOGTO_API_ENDPOINT, + "import.meta.env.LOGTO_API_ENDPOINT": JSON.stringify( + process.env.LOGTO_API_ENDPOINT, ), }, }, diff --git a/src/components/dashboard/SettingsSection/PasswordChangeSettings.tsx b/src/components/dashboard/SettingsSection/PasswordChangeSettings.tsx index 04c40c5..d8857ec 100644 --- a/src/components/dashboard/SettingsSection/PasswordChangeSettings.tsx +++ b/src/components/dashboard/SettingsSection/PasswordChangeSettings.tsx @@ -32,11 +32,11 @@ export default function PasswordChangeSettings({ const [debugInfo, setDebugInfo] = useState(null); // Access environment variables directly - const envLogtoAppId = import.meta.env.PUBLIC_LOGTO_APP_ID; - const envLogtoAppSecret = import.meta.env.PUBLIC_LOGTO_APP_SECRET; - const envLogtoEndpoint = import.meta.env.PUBLIC_LOGTO_ENDPOINT; - const envLogtoTokenEndpoint = import.meta.env.PUBLIC_LOGTO_TOKEN_ENDPOINT; - const envLogtoApiEndpoint = import.meta.env.PUBLIC_LOGTO_API_ENDPOINT; + const envLogtoAppId = import.meta.env.LOGTO_APP_ID; + const envLogtoAppSecret = import.meta.env.LOGTO_APP_SECRET; + const envLogtoEndpoint = import.meta.env.LOGTO_ENDPOINT; + const envLogtoTokenEndpoint = import.meta.env.LOGTO_TOKEN_ENDPOINT; + const envLogtoApiEndpoint = import.meta.env.LOGTO_API_ENDPOINT; // Use environment variables or props (fallback) const logtoAppId = envLogtoAppId || propLogtoAppId; @@ -53,11 +53,11 @@ export default function PasswordChangeSettings({ console.log("Props - logtoEndpoint:", propLogtoEndpoint); console.log("Props - logtoTokenEndpoint:", propLogtoTokenEndpoint); console.log("Props - logtoApiEndpoint:", propLogtoApiEndpoint); - console.log("Env - PUBLIC_LOGTO_APP_ID:", envLogtoAppId); - console.log("Env - PUBLIC_LOGTO_APP_SECRET:", envLogtoAppSecret); - console.log("Env - PUBLIC_LOGTO_ENDPOINT:", envLogtoEndpoint); - console.log("Env - PUBLIC_LOGTO_TOKEN_ENDPOINT:", envLogtoTokenEndpoint); - console.log("Env - PUBLIC_LOGTO_API_ENDPOINT:", envLogtoApiEndpoint); + console.log("Env - LOGTO_APP_ID:", envLogtoAppId); + console.log("Env - LOGTO_APP_SECRET:", envLogtoAppSecret); + console.log("Env - LOGTO_ENDPOINT:", envLogtoEndpoint); + console.log("Env - LOGTO_TOKEN_ENDPOINT:", envLogtoTokenEndpoint); + console.log("Env - LOGTO_API_ENDPOINT:", envLogtoApiEndpoint); console.log("Using - logtoAppId:", logtoAppId); console.log("Using - logtoAppSecret:", logtoAppSecret); console.log("Using - logtoEndpoint:", logtoEndpoint); @@ -328,6 +328,7 @@ export default function PasswordChangeSettings({ // Prepare request data with explicit values (not relying on variable references that might be undefined) const requestData = { userId: logtoUserId, + currentPassword: formData.currentPassword, newPassword: formData.newPassword, logtoAppId: logtoAppId || "", logtoAppSecret: logtoAppSecret || "", @@ -337,6 +338,7 @@ export default function PasswordChangeSettings({ console.log("Request data:", { ...requestData, + currentPassword: "[REDACTED]", newPassword: "[REDACTED]", logtoAppSecret: "[REDACTED]" }); @@ -471,10 +473,10 @@ export default function PasswordChangeSettings({ console.log("Debug Info:"); console.log("- logtoUserId:", logtoUserId); console.log("- Environment Variables:"); - console.log(" - PUBLIC_LOGTO_APP_ID:", import.meta.env.PUBLIC_LOGTO_APP_ID); - console.log(" - PUBLIC_LOGTO_ENDPOINT:", import.meta.env.PUBLIC_LOGTO_ENDPOINT); - console.log(" - PUBLIC_LOGTO_TOKEN_ENDPOINT:", import.meta.env.PUBLIC_LOGTO_TOKEN_ENDPOINT); - console.log(" - PUBLIC_LOGTO_API_ENDPOINT:", import.meta.env.PUBLIC_LOGTO_API_ENDPOINT); + console.log(" - LOGTO_APP_ID:", import.meta.env.LOGTO_APP_ID); + console.log(" - LOGTO_ENDPOINT:", import.meta.env.LOGTO_ENDPOINT); + console.log(" - LOGTO_TOKEN_ENDPOINT:", import.meta.env.LOGTO_TOKEN_ENDPOINT); + console.log(" - LOGTO_API_ENDPOINT:", import.meta.env.LOGTO_API_ENDPOINT); toast.success("Debug info logged to console"); }} diff --git a/src/lib/pocketbase.ts b/src/lib/pocketbase.ts index d37318e..43e3123 100644 --- a/src/lib/pocketbase.ts +++ b/src/lib/pocketbase.ts @@ -1,5 +1,5 @@ -import PocketBase from 'pocketbase'; +import PocketBase from "pocketbase"; -const pb = new PocketBase(import.meta.env.PUBLIC_POCKETBASE_URL); +const pb = new PocketBase(import.meta.env.POCKETBASE_URL); -export default pb; \ No newline at end of file +export default pb; diff --git a/src/pages/api/change-password.ts b/src/pages/api/change-password.ts index efce815..9de557b 100644 --- a/src/pages/api/change-password.ts +++ b/src/pages/api/change-password.ts @@ -51,6 +51,54 @@ async function getLogtoAccessToken( } } +// Helper function to verify user's current password +async function verifyUserPassword( + logtoApiEndpoint: string, + userId: string, + currentPassword: string, + accessToken: string, +): Promise { + try { + console.log("Verifying current password"); + + const response = await fetch( + `${logtoApiEndpoint}/api/users/${userId}/password/verify`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${accessToken}`, + }, + body: JSON.stringify({ password: currentPassword }), + }, + ); + + // 204 means password matches, 422 means it doesn't match + if (response.status === 204) { + console.log("Current password verified successfully"); + return true; + } + + if (response.status === 422) { + console.error( + "Current password verification failed: Password does not match", + ); + return false; + } + + const errorText = await response.text(); + console.error("Password verification error:", { + status: response.status, + statusText: response.statusText, + body: errorText, + }); + return false; + } catch (error) { + console.error("Error verifying password:", error); + return false; + } +} + export const POST: APIRoute = async ({ request }) => { try { console.log("Received change password request"); @@ -81,6 +129,7 @@ export const POST: APIRoute = async ({ request }) => { // Extract required parameters const { userId, + currentPassword, newPassword, logtoAppId, logtoAppSecret, @@ -91,6 +140,7 @@ export const POST: APIRoute = async ({ request }) => { // Validate required parameters const missingParams = []; if (!userId) missingParams.push("userId"); + if (!currentPassword) missingParams.push("currentPassword"); if (!newPassword) missingParams.push("newPassword"); if (!logtoAppId) missingParams.push("logtoAppId"); if (!logtoAppSecret) missingParams.push("logtoAppSecret"); @@ -130,6 +180,27 @@ export const POST: APIRoute = async ({ request }) => { ); } + // Verify current password before proceeding + const isPasswordValid = await verifyUserPassword( + logtoApiEndpoint, + userId, + currentPassword, + accessToken, + ); + + if (!isPasswordValid) { + return new Response( + JSON.stringify({ + success: false, + message: "Current password is incorrect", + }), + { + status: 400, + headers: { "Content-Type": "application/json" }, + }, + ); + } + // Change password using Logto Management API const changePasswordResponse = await fetch( `${logtoApiEndpoint}/api/users/${userId}/password`,