Ensuring exclusive access to a website poses a significant challenge, especially when dealing with non-technical guests. How do we grant access to those who need it without compromising security?
My initial consideration was simplifying the access process for guests who may not be tech-savvy. With only physical invitations as a means of communication, I needed a solution that didn't involve complex sign-up procedures.
After careful thought, I devised a system utilizing randomized codes unique to each guest. By combining this code with known information about the guest, such as their name, they could generate a unique hash granting them access. This approach struck a balance between ease of use and safeguarding the site, especially considering its temporary nature.
Once I knew my approach, I could look to making the initial page component and what I would ask them to provide:
After gathering the necessary guest details, including their names and unique access codes, the next step was to verify the information against a suitable database. I was looking for a lightweight and efficient storage solution, I opted for SQLite due to its speed and compact size. Storing the database alongside the code made it convenient and easier for a small-scale project like mine.
With the database decision made, I explored communication options and discovered Sequelize, an ORM framework that offers support for TypeScript. This choice allowed for a seamless integration with my Next.js project and simplified the database operations.
To kickstart the process, I created a Sequelize model specifically for attendees. This model serves as the blueprint for my CRUD operations on the database, providing a structured approach to managing guest data.
const users = sequelize.define("attendees", {
entry1: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
entry2: {
type: DataTypes.STRING,
allowNull: true,
},
entry3: {
type: DataTypes.STRING,
allowNull: true,
},
entry4: {
type: DataTypes.INTEGER,
allowNull: true,
},
entry5: {
type: DataTypes.BOOLEAN,
allowNull: true,
},
...
});
Next using the model, I could start accessing the database and checking for users that already existed in the database:
const user = await attendees.findAll({
where: {
[Op.or]: [
{
entry2: entry2_value,
entry1: entry1_value,
},
{
[Op.and]: [
{
[Op.or]: [
{
alias_name: {
[Op.like]: `${entry2_value},%`,
},
},
{
alias_name: {
[Op.like]: `%, ${entry2_value}`,
},
},
{
alias_name: {
[Op.like]: `${entry2_value}`,
},
},
],
},
{ entry1: entry1_value },
],
},
],
},
});
Remember all these entries are incorrect and have been changed for security but they are used to help show the code.
In the code snippet above, we're using the Sequelize model to query the database for all attendees. We're looking for records where either 'entry1' or 'entry2' matches certain values, while also considering the 'alias_name' field. This field allows users to input alternative names they might be known by, such as nicknames or middle names.
Once we've retrieved the relevant data, we need to verify the user's access using a pre-made hash stored in the database. To do this, we generate a SHA-256 hash based on the user's input values and compare it with the hash stored in the database 'entry3'. If the hashes match, it confirms the user's access, and they're granted entry to the website.
for (const attendee of user) {
//Logging information to keep logs on the server
logger.info(`Validate: Working with: ${attendee}`);
const dataValues = attendees.dataValues;
// Generate the hash
const hash = crypto
.createHash("sha256")
.update(dataValues.entry2 + entry1)
.digest("hex");
// Compare generated hash with the stored fc_hash
console.log(hash, "===", dataValues.entry3)
if (hash === dataValues.entry3) {
logger.info(`Validate: Hash correct`);
return true;
}
...
}
If the return is true we found our match and the user is one of our guests!
With the use of Sequelize and SQLite, I was able to efficiently store and retrieve guest information, ensuring a smooth and secure experience for all visitors to the wedding website. This approach not only simplified the access process but also provided robust protection for the site's exclusive content. I hope you found this explanation both informative and engaging!