session upgrades work
This commit is contained in:
parent
bee8218e40
commit
74019e97a6
7 changed files with 146 additions and 40 deletions
|
|
@ -1,10 +1,3 @@
|
||||||
class ChallengedUsedError extends Error {
|
|
||||||
constructor(message) {
|
|
||||||
super(message);
|
|
||||||
this.name = "ChallengeUsedError";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class AlreadyUsedError extends Error {
|
class AlreadyUsedError extends Error {
|
||||||
constructor(message) {
|
constructor(message) {
|
||||||
super(message);
|
super(message);
|
||||||
|
|
@ -19,13 +12,6 @@ class InvalidSignatureError extends Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AppInvitedUsedError extends Error {
|
|
||||||
constructor(message) {
|
|
||||||
super(message);
|
|
||||||
this.name = "AppInvitedUsedError";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class NotFoundError extends Error {
|
class NotFoundError extends Error {
|
||||||
constructor(message) {
|
constructor(message) {
|
||||||
super(message);
|
super(message);
|
||||||
|
|
@ -33,8 +19,16 @@ class NotFoundError extends Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ExpiredError extends Error {
|
||||||
|
constructor(message) {
|
||||||
|
super(message);
|
||||||
|
this.name = 'ExpiredError';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
AlreadyUsedError,
|
AlreadyUsedError,
|
||||||
InvalidSignatureError,
|
InvalidSignatureError,
|
||||||
NotFoundError
|
NotFoundError,
|
||||||
|
ExpiredError
|
||||||
};
|
};
|
||||||
|
|
@ -11,16 +11,24 @@ async function setAndPersistNewSession(res) {
|
||||||
|
|
||||||
async function createSessionMiddleware(req, res, next) {
|
async function createSessionMiddleware(req, res, next) {
|
||||||
|
|
||||||
if (!req.cookies.sessionUuid) {
|
const sessionUuid = req.cookies.sessionUuid;
|
||||||
|
|
||||||
|
console.log("Running cookie middleware")
|
||||||
|
|
||||||
|
if (!sessionUuid) {
|
||||||
|
console.log("Found no cookie")
|
||||||
await setAndPersistNewSession(res);
|
await setAndPersistNewSession(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.cookies.sessionUuid) {
|
if (sessionUuid) {
|
||||||
if (await sessionService.isSessionExpired(req.cookies.sessionUuid)) {
|
console.log(`Found a cookie ${sessionUuid}`)
|
||||||
|
if (!(await sessionService.isSessionValid(sessionUuid))) {
|
||||||
|
console.log("But it's not valid")
|
||||||
await setAndPersistNewSession(res);
|
await setAndPersistNewSession(res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log("Moving on...")
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
27
src/models/SessionRelatedToPublickey.js
Normal file
27
src/models/SessionRelatedToPublickey.js
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
const { DataTypes } = require('sequelize');
|
||||||
|
const sequelize = require('../database');
|
||||||
|
|
||||||
|
const SessionRelatedToPublickey = sequelize.define('SessionRelatedToPublickey', {
|
||||||
|
uuid: {
|
||||||
|
type: DataTypes.UUID,
|
||||||
|
allowNull: false,
|
||||||
|
unique: true,
|
||||||
|
primaryKey: true
|
||||||
|
},
|
||||||
|
session_uuid: {
|
||||||
|
type: DataTypes.UUID,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
public_key: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false
|
||||||
|
},
|
||||||
|
created_at: {
|
||||||
|
type: DataTypes.DATE,
|
||||||
|
allowNull: false
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
tableName: 'session_related_to_public_key'
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = SessionRelatedToPublickey;
|
||||||
|
|
@ -2,6 +2,7 @@ const express = require('express');
|
||||||
|
|
||||||
const invitesService = require('../services/invitesService');
|
const invitesService = require('../services/invitesService');
|
||||||
const nostrService = require('../services/nostrService');
|
const nostrService = require('../services/nostrService');
|
||||||
|
const sessionService = require('../services/sessionService');
|
||||||
const { TimeoutError } = require('sequelize');
|
const { TimeoutError } = require('sequelize');
|
||||||
const errors = require('../errors');
|
const errors = require('../errors');
|
||||||
|
|
||||||
|
|
@ -55,22 +56,37 @@ router.get('/signup/nostr-challenge', async (req, res) => {
|
||||||
|
|
||||||
router.post("/signup/nostr-verify", async (req, res) => {
|
router.post("/signup/nostr-verify", async (req, res) => {
|
||||||
const signedEvent = req.body;
|
const signedEvent = req.body;
|
||||||
|
const sessionUuid = req.cookies.sessionUuid;
|
||||||
|
|
||||||
|
let completedSignUpChallenge;
|
||||||
try {
|
try {
|
||||||
console.log(`Starting nostr-verify with event: ${signedEvent}`);
|
completedSignUpChallenge = await invitesService.verifySignUpChallenge(signedEvent);
|
||||||
const completedSignUpChallenge = await invitesService.verifySignUpChallenge(signedEvent);
|
|
||||||
console.log(`Finished nostr-verify`);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof TimeoutError) {
|
if (error instanceof errors.ExpiredError) {
|
||||||
console.error('The challenge is outdated.');
|
return res.status(410).json({
|
||||||
|
success: false,
|
||||||
|
message: 'The challenge has expired, request a new one.'
|
||||||
|
})
|
||||||
}
|
}
|
||||||
if (error instanceof errors.AlreadyUsedError) {
|
if (error instanceof errors.AlreadyUsedError) {
|
||||||
console.error('The challenge was already used, request a new one.');
|
return res.status(410).json({
|
||||||
|
success: false,
|
||||||
|
message: 'The challenge has been used, request a new one.'
|
||||||
|
})
|
||||||
}
|
}
|
||||||
if (error instanceof errors.InvalidSignatureError) {
|
if (error instanceof errors.InvalidSignatureError) {
|
||||||
console.error('Signature is not valid.')
|
return res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
message: 'The challenge signature is not valid.'
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await sessionService.relateSessionToPublicKey(
|
||||||
|
sessionUuid,
|
||||||
|
completedSignUpChallenge.public_key
|
||||||
|
)
|
||||||
|
|
||||||
return res.status(200).json({ success: true });
|
return res.status(200).json({ success: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,30 @@ router.get('/invite/:inviteUuid', async (req, res) => {
|
||||||
return res.render('invite', { invite });
|
return res.render('invite', { invite });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.get('/invite/:inviteUuid', async (req, res) => {
|
||||||
|
const { inviteUuid } = req.params;
|
||||||
|
|
||||||
|
res.cookie('inviteUuid', inviteUuid, { httpOnly: true, maxAge: 86400000 });
|
||||||
|
|
||||||
|
let invite;
|
||||||
|
try {
|
||||||
|
invite = await invitesService.getAppInvite(inviteUuid);
|
||||||
|
if (!invite) {
|
||||||
|
return res.status(404).render('error', { message: 'Invite not found.' });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (await invitesService.isAppInviteSpent(inviteUuid)) {
|
||||||
|
return res.status(410).render('invite_spent', { invite })
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching invite:', error);
|
||||||
|
return res.status(500).render('error', { message: 'An error occurred' });
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.render('invite', { invite });
|
||||||
|
});
|
||||||
|
|
||||||
router.get('/private', authMiddleware, (req, res) => {
|
router.get('/private', authMiddleware, (req, res) => {
|
||||||
res.render('private', {});
|
res.render('private', {});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -73,22 +73,17 @@ async function verifySignUpChallenge(signedEvent) {
|
||||||
null, challenge
|
null, challenge
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log(`Found this nostr challenge: ${nostrChallenge}`);
|
|
||||||
|
|
||||||
const signUpChallenge = await SignUpChallengeCreated.findOne({
|
const signUpChallenge = await SignUpChallengeCreated.findOne({
|
||||||
where: {
|
where: {
|
||||||
nostr_challenge_uuid: nostrChallenge.uuid
|
nostr_challenge_uuid: nostrChallenge.uuid
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log(`Found this signup challenge: ${signUpChallenge}`);
|
|
||||||
|
|
||||||
if (await nostrService.hasNostrChallengeBeenCompleted(challenge)) {
|
if (await nostrService.hasNostrChallengeBeenCompleted(challenge)) {
|
||||||
throw new errors.AlreadyUsedError("This challenge has already been used.");
|
throw new errors.AlreadyUsedError("This challenge has already been used.");
|
||||||
}
|
}
|
||||||
console.log(`I'm gonna verify the nostr challenge`);
|
|
||||||
const completedNostrChallenge = await nostrService.verifyNostrChallenge(signedEvent);
|
const completedNostrChallenge = await nostrService.verifyNostrChallenge(signedEvent);
|
||||||
console.log(`Verified the NostrChallenge: ${completedNostrChallenge}`);
|
|
||||||
|
|
||||||
const completedSignUpChallenge = await SignUpChallengeCompleted.create(
|
const completedSignUpChallenge = await SignUpChallengeCompleted.create(
|
||||||
{
|
{
|
||||||
|
|
@ -99,17 +94,33 @@ async function verifySignUpChallenge(signedEvent) {
|
||||||
created_at: new Date().toISOString()
|
created_at: new Date().toISOString()
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
console.log(`Verified the SignUpChallenge: ${completedSignUpChallenge}`);
|
|
||||||
|
|
||||||
|
|
||||||
return completedSignUpChallenge;
|
return completedSignUpChallenge;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function isPublicKeySignedUp(publicKey) {
|
||||||
|
const signUpChallengeCompleted = await SignUpChallengeCompleted.findOne(
|
||||||
|
{
|
||||||
|
where: {
|
||||||
|
public_key: publicKey
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if (signUpChallengeCompleted) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
appInviteExists,
|
appInviteExists,
|
||||||
getAppInvite,
|
getAppInvite,
|
||||||
isAppInviteSpent,
|
isAppInviteSpent,
|
||||||
createAppInvite,
|
createAppInvite,
|
||||||
createSignUpChallenge,
|
createSignUpChallenge,
|
||||||
verifySignUpChallenge
|
verifySignUpChallenge,
|
||||||
|
isPublicKeySignedUp
|
||||||
};
|
};
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
|
const uuid = require('uuid');
|
||||||
|
|
||||||
const SessionCreated = require('../models/SessionCreated');
|
const SessionCreated = require('../models/SessionCreated');
|
||||||
|
const SessionRelatedToPublickey = require('../models/SessionRelatedToPublickey');
|
||||||
|
|
||||||
|
const invitesService = require('./invitesService');
|
||||||
|
|
||||||
const constants = require('../constants');
|
const constants = require('../constants');
|
||||||
|
|
||||||
|
|
@ -14,7 +19,7 @@ async function createSession(sessionUuid) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function isSessionExpired(sessionUuid) {
|
async function isSessionValid(sessionUuid) {
|
||||||
const currentSession = await SessionCreated.findOne({
|
const currentSession = await SessionCreated.findOne({
|
||||||
where: {
|
where: {
|
||||||
'uuid': sessionUuid
|
'uuid': sessionUuid
|
||||||
|
|
@ -22,15 +27,36 @@ async function isSessionExpired(sessionUuid) {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!currentSession) {
|
if (!currentSession) {
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentSession.expires_at <= new Date()) {
|
if (currentSession.expires_at <= new Date()) {
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.createSession = createSession;
|
async function relateSessionToPublicKey(sessionUuid, publicKey) {
|
||||||
exports.isSessionExpired = isSessionExpired;
|
if (!(await isSessionValid(sessionUuid))) {
|
||||||
|
throw Error("Session is not valid anymore.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(await invitesService.isPublicKeySignedUp(publicKey))) {
|
||||||
|
throw Error("Public key is not signed up.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return SessionRelatedToPublickey.create({
|
||||||
|
'uuid': uuid.v7(),
|
||||||
|
session_uuid: sessionUuid,
|
||||||
|
public_key: publicKey,
|
||||||
|
created_at: new Date().toISOString()
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
createSession,
|
||||||
|
isSessionValid,
|
||||||
|
relateSessionToPublicKey
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue