@mindfulauth/core 2.0.0-beta.4 → 2.0.0-beta.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/astro/ForgotPasswordScript.astro +64 -0
- package/dist/astro/LoginScript.astro +209 -0
- package/dist/astro/MagicLoginScript.astro +62 -0
- package/dist/astro/MagicRegisterScript.astro +73 -0
- package/dist/astro/MainScript.astro +236 -0
- package/dist/astro/RegisterPasswordScript.astro +118 -0
- package/dist/astro/ResendVerificationScript.astro +51 -0
- package/dist/astro/ResetPasswordScript.astro +155 -0
- package/dist/astro/SecurityScript.astro +490 -0
- package/dist/astro/TurnstileInit.astro +112 -0
- package/dist/astro/VerifyEmailScript.astro +72 -0
- package/dist/astro/VerifyMagicLinkScript.astro +195 -0
- package/dist/astro/index.d.ts +13 -0
- package/dist/astro/index.d.ts.map +1 -0
- package/dist/astro/index.js +15 -0
- package/dist/core/auth-handler.d.ts.map +1 -0
- package/dist/core/auth.d.ts.map +1 -0
- package/dist/{config.d.ts → core/config.d.ts} +0 -1
- package/dist/core/config.d.ts.map +1 -0
- package/dist/{config.js → core/config.js} +0 -1
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/middleware.d.ts.map +1 -0
- package/dist/core/security.d.ts.map +1 -0
- package/dist/core/types.d.ts.map +1 -0
- package/package.json +20 -15
- package/dist/auth-handler.d.ts.map +0 -1
- package/dist/auth.d.ts.map +0 -1
- package/dist/config.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/middleware.d.ts.map +0 -1
- package/dist/security.d.ts.map +0 -1
- package/dist/types.d.ts.map +0 -1
- /package/dist/{auth-handler.d.ts → core/auth-handler.d.ts} +0 -0
- /package/dist/{auth-handler.js → core/auth-handler.js} +0 -0
- /package/dist/{auth.d.ts → core/auth.d.ts} +0 -0
- /package/dist/{auth.js → core/auth.js} +0 -0
- /package/dist/{index.d.ts → core/index.d.ts} +0 -0
- /package/dist/{index.js → core/index.js} +0 -0
- /package/dist/{middleware.d.ts → core/middleware.d.ts} +0 -0
- /package/dist/{middleware.js → core/middleware.js} +0 -0
- /package/dist/{security.d.ts → core/security.d.ts} +0 -0
- /package/dist/{security.js → core/security.js} +0 -0
- /package/dist/{types.d.ts → core/types.d.ts} +0 -0
- /package/dist/{types.js → core/types.js} +0 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
---
|
|
2
|
+
// Mindful Auth - Register Password Script Component
|
|
3
|
+
// Provides: Password registration form handling
|
|
4
|
+
---
|
|
5
|
+
<script is:inline>
|
|
6
|
+
// Register password script - Astro Optimized
|
|
7
|
+
async function handleRegisterSubmit(event) {
|
|
8
|
+
event.preventDefault();
|
|
9
|
+
const form = event.target;
|
|
10
|
+
const messageEl = document.querySelector('[data-mindfulauth-field="message"]');
|
|
11
|
+
const nameInput = form.querySelector('[data-mindfulauth-field="name"]');
|
|
12
|
+
const emailInput = form.querySelector('[data-mindfulauth-field="email"]');
|
|
13
|
+
const passwordInput = form.querySelector('[data-mindfulauth-field="password"]');
|
|
14
|
+
const confirmPasswordInput = form.querySelector('[data-mindfulauth-field="confirm-password"]');
|
|
15
|
+
const submitBtn = form.querySelector('button[type="submit"]');
|
|
16
|
+
|
|
17
|
+
// Skip API call on localhost to prevent production logs pollution
|
|
18
|
+
const hostname = window.location.hostname;
|
|
19
|
+
if (hostname === 'localhost' || hostname === '127.0.0.1' || hostname.endsWith('.local')) {
|
|
20
|
+
messageEl.textContent = 'Registration is disabled on localhost. Use a real domain for testing.';
|
|
21
|
+
console.log('[Register] Blocked form submission on localhost');
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Clear previous messages
|
|
26
|
+
messageEl.textContent = '';
|
|
27
|
+
|
|
28
|
+
// Client-side validation
|
|
29
|
+
if (!nameInput.value.trim()) {
|
|
30
|
+
messageEl.textContent = 'Name is required.';
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (!emailInput.value.trim()) {
|
|
35
|
+
messageEl.textContent = 'Email is required.';
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (passwordInput.value.length < 8) {
|
|
40
|
+
messageEl.textContent = 'Password must be at least 8 characters.';
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (passwordInput.value !== confirmPasswordInput.value) {
|
|
45
|
+
messageEl.textContent = 'Passwords do not match.';
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
messageEl.textContent = 'Validating password...';
|
|
50
|
+
submitBtn.disabled = true;
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
// First validate password against policy
|
|
54
|
+
const passwordValidateResponse = await window.apiFetch('/auth/validate-password', {
|
|
55
|
+
body: JSON.stringify({
|
|
56
|
+
password: passwordInput.value
|
|
57
|
+
})
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const passwordValidateResult = await passwordValidateResponse.json();
|
|
61
|
+
if (!passwordValidateResult.success) {
|
|
62
|
+
throw new Error(passwordValidateResult.message);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
messageEl.textContent = 'Creating account...';
|
|
66
|
+
|
|
67
|
+
// Get Turnstile token
|
|
68
|
+
const turnstileResponse = form.querySelector('[name="cf-turnstile-response"]')?.value;
|
|
69
|
+
if (!turnstileResponse) {
|
|
70
|
+
throw new Error('Bot protection validation required.');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Register user via Mindful Auth API (backend validates Turnstile)
|
|
74
|
+
const registerResponse = await window.apiFetch('/auth/register-password', {
|
|
75
|
+
body: JSON.stringify({
|
|
76
|
+
name: nameInput.value.trim(),
|
|
77
|
+
email: emailInput.value.trim(),
|
|
78
|
+
password: passwordInput.value,
|
|
79
|
+
'cf-turnstile-response': turnstileResponse
|
|
80
|
+
})
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const registerResult = await registerResponse.json();
|
|
84
|
+
if (!registerResult.success) {
|
|
85
|
+
throw new Error(registerResult.message || 'Registration failed. Please try again.');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Success
|
|
89
|
+
messageEl.textContent = registerResult.message || 'Account created successfully! Please check your email to verify your account.';
|
|
90
|
+
form.reset();
|
|
91
|
+
|
|
92
|
+
// Don't auto-redirect - user needs to verify email first
|
|
93
|
+
// Show link to login page (using safe DOM manipulation)
|
|
94
|
+
setTimeout(() => {
|
|
95
|
+
const loginLink = document.createElement('p');
|
|
96
|
+
const anchor = document.createElement('a');
|
|
97
|
+
anchor.href = '/login';
|
|
98
|
+
anchor.textContent = 'Return to login page';
|
|
99
|
+
loginLink.appendChild(anchor);
|
|
100
|
+
messageEl.appendChild(loginLink);
|
|
101
|
+
}, 2000);
|
|
102
|
+
|
|
103
|
+
} catch (error) {
|
|
104
|
+
messageEl.textContent = `Error: ${error.message}`;
|
|
105
|
+
} finally {
|
|
106
|
+
submitBtn.disabled = false;
|
|
107
|
+
window.turnstile?.reset();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// --- MAIN EXECUTION ---
|
|
112
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
113
|
+
const form = document.querySelector('[data-mindfulauth-form="register"]');
|
|
114
|
+
if (!form) return;
|
|
115
|
+
|
|
116
|
+
form.addEventListener('submit', handleRegisterSubmit);
|
|
117
|
+
});
|
|
118
|
+
</script>
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
// Mindful Auth - Resend Verification Script Component
|
|
3
|
+
// Provides: Resend verification email form handling
|
|
4
|
+
---
|
|
5
|
+
<script is:inline>
|
|
6
|
+
// Resend verification Script - Astro Optimized
|
|
7
|
+
async function handleResendVerificationSubmit(event) {
|
|
8
|
+
event.preventDefault();
|
|
9
|
+
const form = event.target;
|
|
10
|
+
const emailInput = form.querySelector('[data-mindfulauth-field="email"]');
|
|
11
|
+
const messageEl = document.querySelector('[data-mindfulauth-field="message"]');
|
|
12
|
+
const submitBtn = form.querySelector('button[type="submit"]');
|
|
13
|
+
|
|
14
|
+
// Skip API call on localhost to prevent production logs pollution
|
|
15
|
+
const hostname = window.location.hostname;
|
|
16
|
+
if (hostname === 'localhost' || hostname === '127.0.0.1' || hostname.endsWith('.local')) {
|
|
17
|
+
messageEl.textContent = 'Resend verification is disabled on localhost. Use a real domain for testing.';
|
|
18
|
+
console.log('[Resend Verification] Blocked form submission on localhost');
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
messageEl.textContent = 'Sending...';
|
|
23
|
+
submitBtn.disabled = true;
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
const response = await window.apiFetch('/auth/resend-verification', {
|
|
27
|
+
body: JSON.stringify({
|
|
28
|
+
'cf-turnstile-response': form.querySelector('[name="cf-turnstile-response"]')?.value,
|
|
29
|
+
email: emailInput.value
|
|
30
|
+
})
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const result = await response.json();
|
|
34
|
+
messageEl.textContent = result.message;
|
|
35
|
+
|
|
36
|
+
} catch (error) {
|
|
37
|
+
messageEl.textContent = 'An error occurred. Please try again.';
|
|
38
|
+
} finally {
|
|
39
|
+
submitBtn.disabled = false;
|
|
40
|
+
window.turnstile?.reset();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// --- MAIN EXECUTION ---
|
|
45
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
46
|
+
const form = document.querySelector('[data-mindfulauth-form="resend-verification"]');
|
|
47
|
+
if (!form) return;
|
|
48
|
+
|
|
49
|
+
form.addEventListener('submit', handleResendVerificationSubmit);
|
|
50
|
+
});
|
|
51
|
+
</script>
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
---
|
|
2
|
+
// Mindful Auth - Reset Password Script Component
|
|
3
|
+
// Provides: Reset password form handling with 2FA support
|
|
4
|
+
---
|
|
5
|
+
<script is:inline>
|
|
6
|
+
// Reset password script - Astro Optimized
|
|
7
|
+
function getPathParams() {
|
|
8
|
+
const pathParts = window.location.pathname.split('/');
|
|
9
|
+
return {
|
|
10
|
+
recordid: pathParts[2],
|
|
11
|
+
token: pathParts[3]
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async function handleResetSubmit(event) {
|
|
16
|
+
event.preventDefault();
|
|
17
|
+
const form = event.target;
|
|
18
|
+
const messageEl = document.querySelector('[data-mindfulauth-field="message"]');
|
|
19
|
+
const newPasswordEl = form.querySelector('[data-mindfulauth-field="new-password"]');
|
|
20
|
+
const confirmPasswordEl = form.querySelector('[data-mindfulauth-field="confirm-password"]');
|
|
21
|
+
const twoFACodeEl = form.querySelector('[data-mindfulauth-field="twofa-code"]');
|
|
22
|
+
const submitBtn = form.querySelector('button[type="submit"]');
|
|
23
|
+
|
|
24
|
+
// Skip API call on localhost to prevent production logs pollution
|
|
25
|
+
const hostname = window.location.hostname;
|
|
26
|
+
if (hostname === 'localhost' || hostname === '127.0.0.1' || hostname.endsWith('.local')) {
|
|
27
|
+
messageEl.textContent = 'Password reset is disabled on localhost. Use a real domain for testing.';
|
|
28
|
+
console.log('[Reset Password] Blocked form submission on localhost');
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (newPasswordEl.value !== confirmPasswordEl.value) {
|
|
33
|
+
messageEl.textContent = "Passwords do not match.";
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const { recordid, token } = getPathParams();
|
|
38
|
+
|
|
39
|
+
if (!recordid || !token) {
|
|
40
|
+
messageEl.textContent = "Invalid or expired link. Please request a new one.";
|
|
41
|
+
form.style.display = 'none';
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (newPasswordEl.value !== confirmPasswordEl.value) {
|
|
46
|
+
messageEl.textContent = "Passwords do not match.";
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
messageEl.textContent = "Validating password...";
|
|
51
|
+
submitBtn.disabled = true;
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
// First validate password against policy
|
|
55
|
+
const passwordValidateResponse = await window.apiFetch('/auth/validate-password', {
|
|
56
|
+
body: JSON.stringify({ password: newPasswordEl.value })
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const passwordValidateResult = await passwordValidateResponse.json();
|
|
60
|
+
if (!passwordValidateResult.success) {
|
|
61
|
+
throw new Error(passwordValidateResult.message);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Check if user has 2FA enabled
|
|
65
|
+
messageEl.textContent = 'Checking security settings...';
|
|
66
|
+
const statusResponse = await window.apiFetch('/auth/get-2fa-status-by-record', {
|
|
67
|
+
method: 'POST',
|
|
68
|
+
headers: { 'Content-Type': 'application/json' },
|
|
69
|
+
body: JSON.stringify({ recordid })
|
|
70
|
+
});
|
|
71
|
+
const statusResult = await statusResponse.json();
|
|
72
|
+
|
|
73
|
+
// If 2FA is enabled and code not provided yet, show the input and wait
|
|
74
|
+
let twoFACode = null;
|
|
75
|
+
if (statusResult.isEnabled) {
|
|
76
|
+
if (!twoFACodeEl || !twoFACodeEl.value) {
|
|
77
|
+
// Show the 2FA input field aggressively
|
|
78
|
+
const twoFAContainer = form.querySelector('[data-mindfulauth-field="twofa-code-container"]');
|
|
79
|
+
if (twoFAContainer) {
|
|
80
|
+
twoFAContainer.removeAttribute('hidden');
|
|
81
|
+
twoFAContainer.classList && twoFAContainer.classList.remove('hidden');
|
|
82
|
+
twoFAContainer.style.setProperty('display', 'block', 'important');
|
|
83
|
+
// Try common display values
|
|
84
|
+
if (window.getComputedStyle(twoFAContainer).display === 'none') {
|
|
85
|
+
twoFAContainer.style.setProperty('display', 'flex', 'important');
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (twoFACodeEl) {
|
|
89
|
+
twoFACodeEl.focus();
|
|
90
|
+
}
|
|
91
|
+
messageEl.textContent = '2FA code is required for password reset.';
|
|
92
|
+
submitBtn.textContent = 'Reset Password with 2FA';
|
|
93
|
+
submitBtn.disabled = false;
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
twoFACode = twoFACodeEl.value;
|
|
97
|
+
if (twoFACode.length !== 6) {
|
|
98
|
+
messageEl.textContent = 'Please enter a valid 6-digit 2FA code.';
|
|
99
|
+
submitBtn.disabled = false;
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
messageEl.textContent = 'Resetting password...';
|
|
105
|
+
|
|
106
|
+
const requestBody = {
|
|
107
|
+
'cf-turnstile-response': form.querySelector('[name="cf-turnstile-response"]')?.value,
|
|
108
|
+
recordid,
|
|
109
|
+
token,
|
|
110
|
+
newPassword: newPasswordEl.value
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
if (twoFACode) {
|
|
114
|
+
requestBody.twoFACode = twoFACode;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const response = await window.apiFetch('/auth/reset-password', {
|
|
118
|
+
body: JSON.stringify(requestBody)
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
const result = await response.json();
|
|
122
|
+
if (result.success) {
|
|
123
|
+
messageEl.textContent = result.message;
|
|
124
|
+
form.style.display = 'none';
|
|
125
|
+
// Redirect to login page after successful reset
|
|
126
|
+
if (result.redirect) {
|
|
127
|
+
setTimeout(() => {
|
|
128
|
+
window.location.href = result.redirect;
|
|
129
|
+
}, 2000);
|
|
130
|
+
}
|
|
131
|
+
} else {
|
|
132
|
+
throw new Error(result.message);
|
|
133
|
+
}
|
|
134
|
+
} catch (error) {
|
|
135
|
+
messageEl.textContent = `Error: ${error.message}`;
|
|
136
|
+
} finally {
|
|
137
|
+
submitBtn.disabled = false;
|
|
138
|
+
window.turnstile?.reset();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// --- MAIN EXECUTION ---
|
|
143
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
144
|
+
const form = document.querySelector('[data-mindfulauth-form="reset-password"]');
|
|
145
|
+
if (!form) return;
|
|
146
|
+
|
|
147
|
+
// Initially hide 2FA field - it will be shown during submit if needed
|
|
148
|
+
const twoFAContainer = form.querySelector('[data-mindfulauth-field="twofa-code-container"]');
|
|
149
|
+
if (twoFAContainer) {
|
|
150
|
+
twoFAContainer.style.display = 'none';
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
form.addEventListener('submit', handleResetSubmit);
|
|
154
|
+
});
|
|
155
|
+
</script>
|