Add in registration token requirement to prevent unauthorised registrations.
This commit is contained in:
parent
5268d6aecd
commit
0d277e3035
4 changed files with 50 additions and 8 deletions
|
@ -9,6 +9,7 @@ import {
|
||||||
import { isoBase64URL } from '@simplewebauthn/server/helpers'; // Ensure this is imported if not already
|
import { isoBase64URL } from '@simplewebauthn/server/helpers'; // Ensure this is imported if not already
|
||||||
import prisma from '../database.js';
|
import prisma from '../database.js';
|
||||||
import { rpID, rpName, origin, challengeStore } from '../server.js'; // Import RP details and challenge store
|
import { rpID, rpName, origin, challengeStore } from '../server.js'; // Import RP details and challenge store
|
||||||
|
import { getSetting } from '../utils/settings.js';
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
|
@ -49,13 +50,21 @@ async function getAuthenticatorByCredentialID(credentialID)
|
||||||
router.post('/generate-registration-options', async(req, res) =>
|
router.post('/generate-registration-options', async(req, res) =>
|
||||||
{
|
{
|
||||||
// Destructure username, email, and fullName from the request body
|
// Destructure username, email, and fullName from the request body
|
||||||
const { username, email, fullName } = req.body;
|
const { username, email, fullName, registrationToken } = req.body;
|
||||||
|
|
||||||
if (!username)
|
if (!username)
|
||||||
{
|
{
|
||||||
return res.status(400).json({ error: 'Username is required' });
|
return res.status(400).json({ error: 'Username is required' });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Check if the registrationToken matches the setting
|
||||||
|
const registrationTokenSetting = await getSetting('REGISTRATION_TOKEN');
|
||||||
|
|
||||||
|
if (registrationTokenSetting !== registrationToken)
|
||||||
|
{
|
||||||
|
return res.status(403).json({ error: 'Invalid registration token' });
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
let user = await getUserByUsername(username);
|
let user = await getUserByUsername(username);
|
||||||
|
@ -71,7 +80,6 @@ router.post('/generate-registration-options', async(req, res) =>
|
||||||
data: userData,
|
data: userData,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// ... rest of the existing logic ...
|
|
||||||
|
|
||||||
const userAuthenticators = await getUserAuthenticators(user.id);
|
const userAuthenticators = await getUserAuthenticators(user.id);
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,15 @@
|
||||||
:rules="[val => !!val || 'Full Name is required']"
|
:rules="[val => !!val || 'Full Name is required']"
|
||||||
@keyup.enter="handleRegister"
|
@keyup.enter="handleRegister"
|
||||||
/>
|
/>
|
||||||
|
<q-input
|
||||||
|
v-model="registrationToken"
|
||||||
|
label="Registration Token"
|
||||||
|
outlined
|
||||||
|
class="q-mb-md"
|
||||||
|
:rules="[val => !!val || 'Registration Token is required']"
|
||||||
|
:readonly="!showTokenInput"
|
||||||
|
@keyup.enter="handleRegister"
|
||||||
|
/>
|
||||||
<q-btn
|
<q-btn
|
||||||
label="Register Passkey"
|
label="Register Passkey"
|
||||||
color="primary"
|
color="primary"
|
||||||
|
@ -70,8 +79,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue'; // Remove computed and onMounted
|
import { ref, onMounted } from 'vue'; // Add onMounted
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter, useRoute } from 'vue-router'; // Add useRoute
|
||||||
import { startRegistration } from '@simplewebauthn/browser';
|
import { startRegistration } from '@simplewebauthn/browser';
|
||||||
import axios from 'boot/axios';
|
import axios from 'boot/axios';
|
||||||
// Remove auth store import
|
// Remove auth store import
|
||||||
|
@ -80,6 +89,7 @@ const loading = ref(false);
|
||||||
const errorMessage = ref('');
|
const errorMessage = ref('');
|
||||||
const successMessage = ref('');
|
const successMessage = ref('');
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const route = useRoute(); // Get route object
|
||||||
// Remove auth store usage
|
// Remove auth store usage
|
||||||
|
|
||||||
// Remove isLoggedIn computed property
|
// Remove isLoggedIn computed property
|
||||||
|
@ -87,13 +97,30 @@ const router = useRouter();
|
||||||
const username = ref('');
|
const username = ref('');
|
||||||
const email = ref('');
|
const email = ref('');
|
||||||
const fullName = ref('');
|
const fullName = ref('');
|
||||||
|
const registrationToken = ref(''); // Add registrationToken ref
|
||||||
|
const showTokenInput = ref(false); // Control visibility of token input
|
||||||
|
|
||||||
|
// Check for token in route params when component mounts
|
||||||
|
onMounted(() =>
|
||||||
|
{
|
||||||
|
const tokenFromRoute = route.params.token;
|
||||||
|
if (tokenFromRoute && typeof tokenFromRoute === 'string')
|
||||||
|
{
|
||||||
|
registrationToken.value = tokenFromRoute;
|
||||||
|
showTokenInput.value = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
showTokenInput.value = true; // Show input if no token in route
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Remove onMounted hook
|
// Remove onMounted hook
|
||||||
|
|
||||||
async function handleRegister()
|
async function handleRegister()
|
||||||
{
|
{
|
||||||
// Validate all fields
|
// Validate all fields including registration token if input is shown
|
||||||
if (!username.value || !email.value || !fullName.value)
|
if (!username.value || !email.value || !fullName.value || (showTokenInput.value && !registrationToken.value))
|
||||||
{
|
{
|
||||||
errorMessage.value = 'Please fill in all required fields.';
|
errorMessage.value = 'Please fill in all required fields.';
|
||||||
return;
|
return;
|
||||||
|
@ -111,11 +138,12 @@ async function handleRegister()
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Prepare payload - always include all fields
|
// Prepare payload - always include all fields + registrationToken
|
||||||
const payload = {
|
const payload = {
|
||||||
username: username.value,
|
username: username.value,
|
||||||
email: email.value,
|
email: email.value,
|
||||||
fullName: fullName.value,
|
fullName: fullName.value,
|
||||||
|
registrationToken: registrationToken.value, // Add registrationToken to payload
|
||||||
};
|
};
|
||||||
|
|
||||||
// 1. Get options from server
|
// 1. Get options from server
|
||||||
|
|
|
@ -87,6 +87,12 @@ const $q = useQuasar();
|
||||||
|
|
||||||
// Define the structure of settings
|
// Define the structure of settings
|
||||||
const settings = ref({
|
const settings = ref({
|
||||||
|
General: [
|
||||||
|
{
|
||||||
|
name: 'Registration Token',
|
||||||
|
key: 'REGISTRATION_TOKEN',
|
||||||
|
}
|
||||||
|
],
|
||||||
Mantis: [
|
Mantis: [
|
||||||
{
|
{
|
||||||
name: 'Mantis API Key',
|
name: 'Mantis API Key',
|
||||||
|
|
|
@ -22,7 +22,7 @@ const routes = [
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/register',
|
path: '/register/:token?',
|
||||||
name: 'register',
|
name: 'register',
|
||||||
component: () => import('pages/RegisterPage.vue'),
|
component: () => import('pages/RegisterPage.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue