format project
This commit is contained in:
parent
90d8e39eb3
commit
c02cf8c12e
39 changed files with 2062 additions and 909 deletions
19
.eslintrc.json
Normal file
19
.eslintrc.json
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true,
|
||||
"es6": true
|
||||
},
|
||||
"extends": ["eslint:recommended", "plugin:prettier/recommended"],
|
||||
"rules": {
|
||||
"prettier/prettier": [
|
||||
"error",
|
||||
{
|
||||
"singleQuote": true,
|
||||
"semi": false,
|
||||
"trailingComma": "es5"
|
||||
}
|
||||
],
|
||||
"no-console": "warn"
|
||||
}
|
||||
}
|
||||
8
.prettierrc
Normal file
8
.prettierrc
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"plugins": [
|
||||
"prettier-plugin-ejs"
|
||||
],
|
||||
"singleQuote": true,
|
||||
"semi": true,
|
||||
"trailingComma": "es5"
|
||||
}
|
||||
9
eslint.config.mjs
Normal file
9
eslint.config.mjs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import globals from 'globals'
|
||||
import pluginJs from '@eslint/js'
|
||||
|
||||
/** @type {import('eslint').Linter.Config[]} */
|
||||
export default [
|
||||
{ files: ['**/*.js'], languageOptions: { sourceType: 'commonjs' } },
|
||||
{ languageOptions: { globals: { ...globals.browser, ...globals.node } } },
|
||||
pluginJs.configs.recommended,
|
||||
]
|
||||
1041
package-lock.json
generated
1041
package-lock.json
generated
File diff suppressed because it is too large
Load diff
15
package.json
15
package.json
|
|
@ -20,9 +20,20 @@
|
|||
"start:containers": "docker compose up -d --build",
|
||||
"stop:containers": "docker compose down",
|
||||
"cli": "node src/cli.js",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"lint": "eslint . --fix",
|
||||
"format": "prettier --write \"src/**/*.{js,jsx,ts,tsx,json,css,scss,html,ejs}\""
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.20.0",
|
||||
"eslint": "^9.20.1",
|
||||
"eslint-config-prettier": "^10.0.1",
|
||||
"eslint-plugin-prettier": "^5.2.3",
|
||||
"globals": "^15.15.0",
|
||||
"prettier": "^3.5.1",
|
||||
"prettier-plugin-ejs": "^1.0.3"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@ const program = new Command();
|
|||
|
||||
const createAppInviteCommand = require('./commands/createAppInvite');
|
||||
|
||||
program
|
||||
.version('1.0.0')
|
||||
.description('CLI for managing web app tasks');
|
||||
program.version('1.0.0').description('CLI for managing web app tasks');
|
||||
|
||||
program
|
||||
.command('createAppInvite <inviterNpub>')
|
||||
|
|
|
|||
|
|
@ -3,5 +3,5 @@ const DEFAULT_NOSTR_CHALLENGE_DURATION_SECONDS = 60 * 60 * 24 * 30;
|
|||
|
||||
module.exports = {
|
||||
DEFAULT_SESSION_DURATION_SECONDS,
|
||||
DEFAULT_NOSTR_CHALLENGE_DURATION_SECONDS
|
||||
}
|
||||
DEFAULT_NOSTR_CHALLENGE_DURATION_SECONDS,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -14,13 +14,16 @@ const sequelize = new Sequelize({
|
|||
timestamps: false,
|
||||
freezeTableName: true,
|
||||
underscored: true,
|
||||
quoteIdentifiers: false
|
||||
quoteIdentifiers: false,
|
||||
},
|
||||
});
|
||||
|
||||
sequelize.sync().then(() => {
|
||||
sequelize
|
||||
.sync()
|
||||
.then(() => {
|
||||
console.log('Database synced');
|
||||
}).catch(err => {
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('Error syncing the database:', err);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,21 +1,21 @@
|
|||
class AlreadyUsedError extends Error {
|
||||
constructor(message) {
|
||||
super(message);
|
||||
this.name = "AlreadyUsedError"
|
||||
this.name = 'AlreadyUsedError';
|
||||
}
|
||||
}
|
||||
|
||||
class InvalidSignatureError extends Error {
|
||||
constructor(message) {
|
||||
super(message);
|
||||
this.name = "InvalidSignatureError";
|
||||
this.name = 'InvalidSignatureError';
|
||||
}
|
||||
}
|
||||
|
||||
class NotFoundError extends Error {
|
||||
constructor(message) {
|
||||
super(message);
|
||||
this.name = "AppInvitedUsedError";
|
||||
this.name = 'AppInvitedUsedError';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -30,5 +30,5 @@ module.exports = {
|
|||
AlreadyUsedError,
|
||||
InvalidSignatureError,
|
||||
NotFoundError,
|
||||
ExpiredError
|
||||
ExpiredError,
|
||||
};
|
||||
|
|
@ -1,10 +1,9 @@
|
|||
const sessionService = require('../services/sessionService');
|
||||
|
||||
async function attachPublicKeyMiddleware(req, res, next) {
|
||||
|
||||
const publicKey = await sessionService.getPublicKeyRelatedToSession(
|
||||
req.cookies.sessionUuid
|
||||
)
|
||||
);
|
||||
req.cookies.publicKey = publicKey;
|
||||
|
||||
next();
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ async function rejectIfNotAuthorizedMiddleware(req, res, next) {
|
|||
if (!(await sessionService.isSessionAuthorized(req.cookies.sessionUuid))) {
|
||||
return res.status(403).json({
|
||||
success: false,
|
||||
message: 'Your session is not authorized.'
|
||||
})
|
||||
message: 'Your session is not authorized.',
|
||||
});
|
||||
}
|
||||
next();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,22 +1,23 @@
|
|||
const uuid = require("uuid");
|
||||
const uuid = require('uuid');
|
||||
|
||||
const sessionService = require('../services/sessionService');
|
||||
const constants = require('../constants');
|
||||
|
||||
async function setAndPersistNewSession(res) {
|
||||
const sessionUuid = uuid.v7();
|
||||
res.cookie('sessionUuid', sessionUuid, { httpOnly: true, maxAge: constants.DEFAULT_SESSION_DURATION_SECONDS * 1000 });
|
||||
res.cookie('sessionUuid', sessionUuid, {
|
||||
httpOnly: true,
|
||||
maxAge: constants.DEFAULT_SESSION_DURATION_SECONDS * 1000,
|
||||
});
|
||||
return await sessionService.createSession(sessionUuid);
|
||||
}
|
||||
|
||||
async function createSessionMiddleware(req, res, next) {
|
||||
|
||||
const sessionUuid = req.cookies.sessionUuid;
|
||||
|
||||
if (!sessionUuid) {
|
||||
const newSession = await setAndPersistNewSession(res);
|
||||
req.cookies.sessionUuid = newSession.uuid;
|
||||
|
||||
}
|
||||
|
||||
if (sessionUuid) {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
const { DataTypes } = require('sequelize');
|
||||
const sequelize = require('../database');
|
||||
|
||||
const AppInviteCreated = sequelize.define('AppInviteCreated', {
|
||||
const AppInviteCreated = sequelize.define(
|
||||
'AppInviteCreated',
|
||||
{
|
||||
uuid: {
|
||||
type: DataTypes.UUID,
|
||||
allowNull: false,
|
||||
unique: true,
|
||||
primaryKey: true
|
||||
primaryKey: true,
|
||||
},
|
||||
inviter_pub_key: {
|
||||
type: DataTypes.STRING,
|
||||
|
|
@ -14,10 +16,12 @@ const AppInviteCreated = sequelize.define('AppInviteCreated', {
|
|||
},
|
||||
created_at: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: false
|
||||
allowNull: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
tableName: 'app_invite_created',
|
||||
}
|
||||
}, {
|
||||
tableName: 'app_invite_created'
|
||||
});
|
||||
);
|
||||
|
||||
module.exports = AppInviteCreated;
|
||||
|
|
@ -1,27 +1,31 @@
|
|||
const { DataTypes } = require('sequelize');
|
||||
const sequelize = require('../database');
|
||||
|
||||
const ContactDetailsSet = sequelize.define('ContactDetailsSet', {
|
||||
const ContactDetailsSet = sequelize.define(
|
||||
'ContactDetailsSet',
|
||||
{
|
||||
uuid: {
|
||||
type: DataTypes.UUID,
|
||||
allowNull: false,
|
||||
unique: true,
|
||||
primaryKey: true
|
||||
primaryKey: true,
|
||||
},
|
||||
public_key: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
allowNull: false,
|
||||
},
|
||||
encrypted_contact_details: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: false
|
||||
allowNull: false,
|
||||
},
|
||||
created_at: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: false
|
||||
allowNull: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
tableName: 'contact_details_set',
|
||||
}
|
||||
}, {
|
||||
tableName: 'contact_details_set'
|
||||
});
|
||||
);
|
||||
|
||||
module.exports = ContactDetailsSet;
|
||||
|
|
@ -1,31 +1,35 @@
|
|||
const { DataTypes } = require('sequelize');
|
||||
const sequelize = require('../database');
|
||||
|
||||
const NostrChallengeCompleted = sequelize.define('NostrChallengeCompleted', {
|
||||
const NostrChallengeCompleted = sequelize.define(
|
||||
'NostrChallengeCompleted',
|
||||
{
|
||||
uuid: {
|
||||
type: DataTypes.UUID,
|
||||
allowNull: false,
|
||||
unique: true,
|
||||
primaryKey: true
|
||||
primaryKey: true,
|
||||
},
|
||||
challenge: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
allowNull: false,
|
||||
},
|
||||
signed_event: {
|
||||
type: DataTypes.JSONB,
|
||||
allowNull: false
|
||||
allowNull: false,
|
||||
},
|
||||
public_key: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
allowNull: false,
|
||||
},
|
||||
created_at: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: false
|
||||
allowNull: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
tableName: 'nostr_challenge_completed',
|
||||
}
|
||||
}, {
|
||||
tableName: 'nostr_challenge_completed'
|
||||
});
|
||||
);
|
||||
|
||||
module.exports = NostrChallengeCompleted;
|
||||
|
|
@ -1,27 +1,31 @@
|
|||
const { DataTypes } = require('sequelize');
|
||||
const sequelize = require('../database');
|
||||
|
||||
const NostrChallengeCreated = sequelize.define('NostrChallengeCreated', {
|
||||
const NostrChallengeCreated = sequelize.define(
|
||||
'NostrChallengeCreated',
|
||||
{
|
||||
uuid: {
|
||||
type: DataTypes.UUID,
|
||||
allowNull: false,
|
||||
unique: true,
|
||||
primaryKey: true
|
||||
primaryKey: true,
|
||||
},
|
||||
challenge: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
allowNull: false,
|
||||
},
|
||||
expires_at: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: false
|
||||
allowNull: false,
|
||||
},
|
||||
created_at: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: false
|
||||
allowNull: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
tableName: 'nostr_challenge_created',
|
||||
}
|
||||
}, {
|
||||
tableName: 'nostr_challenge_created'
|
||||
});
|
||||
);
|
||||
|
||||
module.exports = NostrChallengeCreated;
|
||||
|
|
@ -1,27 +1,31 @@
|
|||
const { DataTypes } = require('sequelize');
|
||||
const sequelize = require('../database');
|
||||
|
||||
const NymSet = sequelize.define('NymSet', {
|
||||
const NymSet = sequelize.define(
|
||||
'NymSet',
|
||||
{
|
||||
uuid: {
|
||||
type: DataTypes.UUID,
|
||||
allowNull: false,
|
||||
unique: true,
|
||||
primaryKey: true
|
||||
primaryKey: true,
|
||||
},
|
||||
public_key: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
allowNull: false,
|
||||
},
|
||||
nym: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: false
|
||||
allowNull: false,
|
||||
},
|
||||
created_at: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: false
|
||||
allowNull: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
tableName: 'nym_set',
|
||||
}
|
||||
}, {
|
||||
tableName: 'nym_set'
|
||||
});
|
||||
);
|
||||
|
||||
module.exports = NymSet;
|
||||
|
|
@ -1,23 +1,27 @@
|
|||
const { DataTypes } = require('sequelize');
|
||||
const sequelize = require('../database');
|
||||
|
||||
const SessionCreated = sequelize.define('SessionCreated', {
|
||||
const SessionCreated = sequelize.define(
|
||||
'SessionCreated',
|
||||
{
|
||||
uuid: {
|
||||
type: DataTypes.UUID,
|
||||
allowNull: false,
|
||||
unique: true,
|
||||
primaryKey: true
|
||||
primaryKey: true,
|
||||
},
|
||||
created_at: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: false
|
||||
allowNull: false,
|
||||
},
|
||||
expires_at: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: false
|
||||
allowNull: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
tableName: 'session_created',
|
||||
}
|
||||
}, {
|
||||
tableName: 'session_created'
|
||||
});
|
||||
);
|
||||
|
||||
module.exports = SessionCreated;
|
||||
|
|
@ -1,12 +1,14 @@
|
|||
const { DataTypes } = require('sequelize');
|
||||
const sequelize = require('../database');
|
||||
|
||||
const SessionRelatedToPublickey = sequelize.define('SessionRelatedToPublickey', {
|
||||
const SessionRelatedToPublickey = sequelize.define(
|
||||
'SessionRelatedToPublickey',
|
||||
{
|
||||
uuid: {
|
||||
type: DataTypes.UUID,
|
||||
allowNull: false,
|
||||
unique: true,
|
||||
primaryKey: true
|
||||
primaryKey: true,
|
||||
},
|
||||
session_uuid: {
|
||||
type: DataTypes.UUID,
|
||||
|
|
@ -14,14 +16,16 @@ const SessionRelatedToPublickey = sequelize.define('SessionRelatedToPublickey',
|
|||
},
|
||||
public_key: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
allowNull: false,
|
||||
},
|
||||
created_at: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: false
|
||||
allowNull: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
tableName: 'session_related_to_public_key',
|
||||
}
|
||||
}, {
|
||||
tableName: 'session_related_to_public_key'
|
||||
});
|
||||
);
|
||||
|
||||
module.exports = SessionRelatedToPublickey;
|
||||
|
|
@ -1,12 +1,14 @@
|
|||
const { DataTypes } = require('sequelize');
|
||||
const sequelize = require('../database');
|
||||
|
||||
const SignUpChallengeCompleted = sequelize.define('SignUpChallengeCompleted', {
|
||||
const SignUpChallengeCompleted = sequelize.define(
|
||||
'SignUpChallengeCompleted',
|
||||
{
|
||||
uuid: {
|
||||
type: DataTypes.UUID,
|
||||
allowNull: false,
|
||||
unique: true,
|
||||
primaryKey: true
|
||||
primaryKey: true,
|
||||
},
|
||||
nostr_challenge_completed_uuid: {
|
||||
type: DataTypes.UUID,
|
||||
|
|
@ -14,18 +16,20 @@ const SignUpChallengeCompleted = sequelize.define('SignUpChallengeCompleted', {
|
|||
},
|
||||
app_invite_uuid: {
|
||||
type: DataTypes.UUID,
|
||||
allowNull: false
|
||||
allowNull: false,
|
||||
},
|
||||
public_key: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
allowNull: false,
|
||||
},
|
||||
created_at: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: false
|
||||
allowNull: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
tableName: 'sign_up_challenge_completed',
|
||||
}
|
||||
}, {
|
||||
tableName: 'sign_up_challenge_completed'
|
||||
});
|
||||
);
|
||||
|
||||
module.exports = SignUpChallengeCompleted;
|
||||
|
|
@ -1,27 +1,31 @@
|
|||
const { DataTypes } = require('sequelize');
|
||||
const sequelize = require('../database');
|
||||
|
||||
const SignUpChallengeCreated = sequelize.define('SignUpChallengeCreated', {
|
||||
const SignUpChallengeCreated = sequelize.define(
|
||||
'SignUpChallengeCreated',
|
||||
{
|
||||
uuid: {
|
||||
type: DataTypes.UUID,
|
||||
allowNull: false,
|
||||
unique: true,
|
||||
primaryKey: true
|
||||
primaryKey: true,
|
||||
},
|
||||
nostr_challenge_uuid: {
|
||||
type: DataTypes.UUID,
|
||||
allowNull: false
|
||||
allowNull: false,
|
||||
},
|
||||
app_invite_uuid: {
|
||||
type: DataTypes.UUID,
|
||||
allowNull: false
|
||||
allowNull: false,
|
||||
},
|
||||
created_at: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: false
|
||||
allowNull: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
tableName: 'sign_up_challenge_created',
|
||||
}
|
||||
}, {
|
||||
tableName: 'sign_up_challenge_created'
|
||||
});
|
||||
);
|
||||
|
||||
module.exports = SignUpChallengeCreated;
|
||||
|
|
@ -9,7 +9,9 @@ class ContactDetails {
|
|||
}
|
||||
|
||||
removeDetails(type, value) {
|
||||
this.details = this.details.filter(detail => detail.type !== type || detail.value !== value);
|
||||
this.details = this.details.filter(
|
||||
(detail) => detail.type !== type || detail.value !== value
|
||||
);
|
||||
}
|
||||
|
||||
syncUi() {
|
||||
|
|
@ -19,20 +21,20 @@ class ContactDetails {
|
|||
const addedDetailFragment = this.buildContactDetailBadge(detail);
|
||||
this.rootUiElement.appendChild(addedDetailFragment);
|
||||
});
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
buildContactDetailBadge(detail) {
|
||||
const fragment = document.createDocumentFragment();
|
||||
|
||||
const div = document.createElement("div");
|
||||
div.className = "added-contact-detail badge";
|
||||
const div = document.createElement('div');
|
||||
div.className = 'added-contact-detail badge';
|
||||
|
||||
const p = document.createElement("p");
|
||||
const p = document.createElement('p');
|
||||
p.textContent = `${detail.type}: ${detail.value}`;
|
||||
|
||||
const button = document.createElement("button");
|
||||
button.textContent = "Eliminar";
|
||||
const button = document.createElement('button');
|
||||
button.textContent = 'Eliminar';
|
||||
button.onclick = () => {
|
||||
this.removeDetails(detail.type, detail.value);
|
||||
this.syncUi();
|
||||
|
|
@ -48,7 +50,10 @@ class ContactDetails {
|
|||
|
||||
async getEncryptedContactDetails() {
|
||||
const jsonString = JSON.stringify(this.details);
|
||||
const encryptedContactDetails = await window.nostr.nip04.encrypt(await window.nostr.getPublicKey(), jsonString);
|
||||
const encryptedContactDetails = await window.nostr.nip04.encrypt(
|
||||
await window.nostr.getPublicKey(),
|
||||
jsonString
|
||||
);
|
||||
return encryptedContactDetails;
|
||||
}
|
||||
}
|
||||
|
|
@ -56,9 +61,11 @@ class ContactDetails {
|
|||
let contactDetails;
|
||||
|
||||
window.onload = () => {
|
||||
contactDetails = new ContactDetails(document.querySelector('#created-contact-details-list'));
|
||||
contactDetails = new ContactDetails(
|
||||
document.querySelector('#created-contact-details-list')
|
||||
);
|
||||
|
||||
document.querySelectorAll('.contact-detail-add-button').forEach(button => {
|
||||
document.querySelectorAll('.contact-detail-add-button').forEach((button) => {
|
||||
button.addEventListener('click', function () {
|
||||
const badge = this.parentElement;
|
||||
const type = badge.getAttribute('data-type');
|
||||
|
|
@ -76,29 +83,24 @@ window.onload = () => {
|
|||
|
||||
document
|
||||
.querySelector('#submit-details-button')
|
||||
.addEventListener(
|
||||
'click',
|
||||
async () => {
|
||||
const encryptedContactDetails = await contactDetails.getEncryptedContactDetails();
|
||||
await fetch('/api/set-contact-details',
|
||||
{
|
||||
.addEventListener('click', async () => {
|
||||
const encryptedContactDetails =
|
||||
await contactDetails.getEncryptedContactDetails();
|
||||
await fetch('/api/set-contact-details', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ encryptedContactDetails })
|
||||
body: JSON.stringify({ encryptedContactDetails }),
|
||||
});
|
||||
|
||||
const nym = document.querySelector('#nym-input').value;
|
||||
await fetch('/api/set-nym',
|
||||
{
|
||||
await fetch('/api/set-nym', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ nym })
|
||||
body: JSON.stringify({ nym }),
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
);
|
||||
};
|
||||
|
|
@ -1,22 +1,21 @@
|
|||
window.onload = function () {
|
||||
if (!window.nostr) {
|
||||
console.log("Nostr extension not present");
|
||||
console.log('Nostr extension not present');
|
||||
document.querySelector('#nostr-signup').disabled = true;
|
||||
document.querySelector('#no-extension-nudges').style.display = 'block';
|
||||
} else {
|
||||
console.log("Nostr extension present");
|
||||
}
|
||||
console.log('Nostr extension present');
|
||||
}
|
||||
};
|
||||
|
||||
async function acceptInvite() {
|
||||
|
||||
let challengeResponse;
|
||||
try {
|
||||
challengeResponse = await fetch('/api/signup/nostr-challenge', {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.log(`Something went wrong: ${error}`);
|
||||
|
|
@ -35,9 +34,9 @@ async function acceptInvite() {
|
|||
const event = {
|
||||
kind: 22242,
|
||||
created_at: Math.floor(Date.now() / 1000),
|
||||
tags: [["challenge", challenge]],
|
||||
content: "Sign this challenge to authenticate",
|
||||
pubkey: pubkey
|
||||
tags: [['challenge', challenge]],
|
||||
content: 'Sign this challenge to authenticate',
|
||||
pubkey: pubkey,
|
||||
};
|
||||
|
||||
let signedEvent;
|
||||
|
|
@ -50,9 +49,9 @@ async function acceptInvite() {
|
|||
|
||||
let verifyResponse;
|
||||
try {
|
||||
verifyResponse = await fetch("/api/signup/nostr-verify", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
verifyResponse = await fetch('/api/signup/nostr-verify', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(signedEvent),
|
||||
});
|
||||
} catch (error) {
|
||||
|
|
@ -63,7 +62,7 @@ async function acceptInvite() {
|
|||
if (verifyResponse.ok) {
|
||||
document.querySelector('#sign-up-success').style.display = 'block';
|
||||
setTimeout(() => {
|
||||
window.location.href = "/createProfile";
|
||||
window.location.href = '/createProfile';
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
|
@ -15,84 +15,82 @@ router.get('/signup/nostr-challenge', async (req, res) => {
|
|||
|
||||
let signUpChallenge;
|
||||
try {
|
||||
signUpChallenge = await invitesService.createSignUpChallenge(
|
||||
inviteUuid
|
||||
)
|
||||
signUpChallenge = await invitesService.createSignUpChallenge(inviteUuid);
|
||||
} catch (error) {
|
||||
if (error instanceof errors.NotFoundError) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: 'Could not find invite with that id.'
|
||||
})
|
||||
message: 'Could not find invite with that id.',
|
||||
});
|
||||
}
|
||||
|
||||
if (error instanceof errors.AlreadyUsedError) {
|
||||
return res.status(410).json({
|
||||
success: false,
|
||||
message: 'That invite has already been used.'
|
||||
})
|
||||
message: 'That invite has already been used.',
|
||||
});
|
||||
}
|
||||
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: 'Unexpected error.'
|
||||
})
|
||||
message: 'Unexpected error.',
|
||||
});
|
||||
}
|
||||
|
||||
let relatedNostrChallenge;
|
||||
try {
|
||||
relatedNostrChallenge = await nostrService.getNostrChallenge(
|
||||
signUpChallenge.nostr_challenge_uuid
|
||||
)
|
||||
);
|
||||
} catch (error) {
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: 'Unexpected error.'
|
||||
})
|
||||
message: 'Unexpected error.',
|
||||
});
|
||||
}
|
||||
|
||||
return res.status(200).json({ 'challenge': relatedNostrChallenge.challenge });
|
||||
return res.status(200).json({ challenge: relatedNostrChallenge.challenge });
|
||||
});
|
||||
|
||||
|
||||
router.post("/signup/nostr-verify", async (req, res) => {
|
||||
router.post('/signup/nostr-verify', async (req, res) => {
|
||||
const signedEvent = req.body;
|
||||
const sessionUuid = req.cookies.sessionUuid;
|
||||
|
||||
let completedSignUpChallenge;
|
||||
try {
|
||||
completedSignUpChallenge = await invitesService.verifySignUpChallenge(signedEvent);
|
||||
completedSignUpChallenge =
|
||||
await invitesService.verifySignUpChallenge(signedEvent);
|
||||
} catch (error) {
|
||||
if (error instanceof errors.ExpiredError) {
|
||||
return res.status(410).json({
|
||||
success: false,
|
||||
message: 'The challenge has expired, request a new one.'
|
||||
})
|
||||
message: 'The challenge has expired, request a new one.',
|
||||
});
|
||||
}
|
||||
if (error instanceof errors.AlreadyUsedError) {
|
||||
return res.status(410).json({
|
||||
success: false,
|
||||
message: 'The challenge has been used, request a new one.'
|
||||
})
|
||||
message: 'The challenge has been used, request a new one.',
|
||||
});
|
||||
}
|
||||
if (error instanceof errors.InvalidSignatureError) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: 'The challenge signature is not valid.'
|
||||
})
|
||||
message: 'The challenge signature is not valid.',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await sessionService.relateSessionToPublicKey(
|
||||
sessionUuid,
|
||||
completedSignUpChallenge.public_key
|
||||
)
|
||||
);
|
||||
|
||||
return res.status(200).json({ success: true });
|
||||
});
|
||||
|
||||
router.post(
|
||||
"/set-contact-details",
|
||||
'/set-contact-details',
|
||||
rejectIfNotAuthorizedMiddleware,
|
||||
attachPublicKeyMiddleware,
|
||||
async (req, res) => {
|
||||
|
|
@ -102,24 +100,21 @@ router.post(
|
|||
if (!encryptedContactDetails) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: 'Missing contact details.'
|
||||
})
|
||||
message: 'Missing contact details.',
|
||||
});
|
||||
}
|
||||
|
||||
await profileService.setContactDetails(
|
||||
publicKey,
|
||||
encryptedContactDetails
|
||||
)
|
||||
await profileService.setContactDetails(publicKey, encryptedContactDetails);
|
||||
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
message: 'Contact details set successfully.'
|
||||
})
|
||||
message: 'Contact details set successfully.',
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
router.post(
|
||||
"/set-nym",
|
||||
'/set-nym',
|
||||
rejectIfNotAuthorizedMiddleware,
|
||||
attachPublicKeyMiddleware,
|
||||
async (req, res) => {
|
||||
|
|
@ -129,19 +124,16 @@ router.post(
|
|||
if (!nym) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: 'Missing nym'
|
||||
})
|
||||
message: 'Missing nym',
|
||||
});
|
||||
}
|
||||
|
||||
await profileService.setNym(
|
||||
publicKey,
|
||||
nym
|
||||
)
|
||||
await profileService.setNym(publicKey, nym);
|
||||
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
message: 'Nym set successfully.'
|
||||
})
|
||||
message: 'Nym set successfully.',
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ const express = require('express');
|
|||
const router = express.Router();
|
||||
|
||||
const redirectIfNotAuthorizedMiddleware = require('../middlewares/redirectIfNotAuthorizedMiddleware');
|
||||
const invitesService = require('../services/invitesService')
|
||||
const invitesService = require('../services/invitesService');
|
||||
|
||||
router.get('/', (req, res) => {
|
||||
res.render('index', { uuid: req.cookies.sessionUuid });
|
||||
|
|
@ -21,9 +21,8 @@ router.get('/invite/:inviteUuid', async (req, res) => {
|
|||
}
|
||||
|
||||
if (await invitesService.isAppInviteSpent(inviteUuid)) {
|
||||
return res.status(410).render('invite_spent', { invite })
|
||||
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' });
|
||||
|
|
@ -45,9 +44,8 @@ router.get('/invite/:inviteUuid', async (req, res) => {
|
|||
}
|
||||
|
||||
if (await invitesService.isAppInviteSpent(inviteUuid)) {
|
||||
return res.status(410).render('invite_spent', { invite })
|
||||
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' });
|
||||
|
|
@ -56,9 +54,13 @@ router.get('/invite/:inviteUuid', async (req, res) => {
|
|||
return res.render('invite', { invite });
|
||||
});
|
||||
|
||||
router.get('/createProfile', redirectIfNotAuthorizedMiddleware, async (req, res) => {
|
||||
router.get(
|
||||
'/createProfile',
|
||||
redirectIfNotAuthorizedMiddleware,
|
||||
async (req, res) => {
|
||||
return res.status(200).render('createProfile');
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
router.get('/private', redirectIfNotAuthorizedMiddleware, (req, res) => {
|
||||
res.render('private', {});
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@ const SignUpChallengeCompleted = require('../models/SignUpChallengeCompleted');
|
|||
const errors = require('../errors');
|
||||
|
||||
async function appInviteExists(inviteUuid) {
|
||||
const invite = await AppInviteCreated.findOne({ where: { uuid: inviteUuid } });
|
||||
const invite = await AppInviteCreated.findOne({
|
||||
where: { uuid: inviteUuid },
|
||||
});
|
||||
if (invite) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -16,16 +18,18 @@ async function appInviteExists(inviteUuid) {
|
|||
}
|
||||
|
||||
async function getAppInvite(inviteUuid) {
|
||||
const invite = await AppInviteCreated.findOne({ where: { uuid: inviteUuid } });
|
||||
const invite = await AppInviteCreated.findOne({
|
||||
where: { uuid: inviteUuid },
|
||||
});
|
||||
return invite;
|
||||
}
|
||||
|
||||
async function isAppInviteSpent(appInviteUuid) {
|
||||
const signUpChallengeCompleted = await SignUpChallengeCompleted.findOne({
|
||||
where: {
|
||||
app_invite_uuid: appInviteUuid
|
||||
}
|
||||
})
|
||||
app_invite_uuid: appInviteUuid,
|
||||
},
|
||||
});
|
||||
|
||||
if (signUpChallengeCompleted) {
|
||||
return true;
|
||||
|
|
@ -37,82 +41,71 @@ async function createAppInvite(inviterPubKey) {
|
|||
return await AppInviteCreated.create({
|
||||
uuid: uuid.v7(),
|
||||
inviter_pub_key: inviterPubKey,
|
||||
created_at: new Date().toISOString()
|
||||
}
|
||||
);
|
||||
created_at: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
|
||||
async function createSignUpChallenge(appInviteUuid) {
|
||||
|
||||
if (!(await appInviteExists(appInviteUuid))) {
|
||||
throw new errors.NotFoundError("Invite doesn't exist.")
|
||||
throw new errors.NotFoundError("Invite doesn't exist.");
|
||||
}
|
||||
|
||||
if (await isAppInviteSpent(appInviteUuid)) {
|
||||
throw new errors.AlreadyUsedError("Invite has already been used.")
|
||||
throw new errors.AlreadyUsedError('Invite has already been used.');
|
||||
}
|
||||
|
||||
const nostrChallenge = await nostrService.createNostrChallenge()
|
||||
const nostrChallenge = await nostrService.createNostrChallenge();
|
||||
|
||||
return await SignUpChallengeCreated.create({
|
||||
'uuid': uuid.v7(),
|
||||
uuid: uuid.v7(),
|
||||
nostr_challenge_uuid: nostrChallenge.uuid,
|
||||
app_invite_uuid: appInviteUuid,
|
||||
created_at: new Date().toISOString()
|
||||
created_at: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
async function verifySignUpChallenge(signedEvent) {
|
||||
|
||||
const challengeTag = signedEvent.tags.find(tag => tag[0] === "challenge");
|
||||
const challengeTag = signedEvent.tags.find((tag) => tag[0] === 'challenge');
|
||||
const challenge = challengeTag[1];
|
||||
|
||||
const nostrChallenge = await nostrService.getNostrChallenge(
|
||||
null, challenge
|
||||
);
|
||||
const nostrChallenge = await nostrService.getNostrChallenge(null, challenge);
|
||||
|
||||
const signUpChallenge = await SignUpChallengeCreated.findOne({
|
||||
where: {
|
||||
nostr_challenge_uuid: nostrChallenge.uuid
|
||||
}
|
||||
})
|
||||
nostr_challenge_uuid: nostrChallenge.uuid,
|
||||
},
|
||||
});
|
||||
|
||||
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.');
|
||||
}
|
||||
|
||||
const completedNostrChallenge = await nostrService.verifyNostrChallenge(signedEvent);
|
||||
const completedNostrChallenge =
|
||||
await nostrService.verifyNostrChallenge(signedEvent);
|
||||
|
||||
const completedSignUpChallenge = await SignUpChallengeCompleted.create(
|
||||
{
|
||||
'uuid': uuid.v7(),
|
||||
const completedSignUpChallenge = await SignUpChallengeCompleted.create({
|
||||
uuid: uuid.v7(),
|
||||
nostr_challenge_completed_uuid: completedNostrChallenge.uuid,
|
||||
app_invite_uuid: signUpChallenge.app_invite_uuid,
|
||||
public_key: completedNostrChallenge.public_key,
|
||||
created_at: new Date().toISOString()
|
||||
}
|
||||
);
|
||||
created_at: new Date().toISOString(),
|
||||
});
|
||||
|
||||
return completedSignUpChallenge;
|
||||
}
|
||||
|
||||
async function isPublicKeySignedUp(publicKey) {
|
||||
const signUpChallengeCompleted = await SignUpChallengeCompleted.findOne(
|
||||
{
|
||||
const signUpChallengeCompleted = await SignUpChallengeCompleted.findOne({
|
||||
where: {
|
||||
public_key: publicKey
|
||||
}
|
||||
}
|
||||
)
|
||||
public_key: publicKey,
|
||||
},
|
||||
});
|
||||
|
||||
if (signUpChallengeCompleted) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
|
@ -122,5 +115,5 @@ module.exports = {
|
|||
createAppInvite,
|
||||
createSignUpChallenge,
|
||||
verifySignUpChallenge,
|
||||
isPublicKeySignedUp
|
||||
isPublicKeySignedUp,
|
||||
};
|
||||
|
|
@ -1,77 +1,78 @@
|
|||
const uuid = require("uuid");
|
||||
const crypto = require("crypto");
|
||||
const uuid = require('uuid');
|
||||
const crypto = require('crypto');
|
||||
const { Op, TimeoutError } = require('sequelize');
|
||||
const { verifyEvent } = require("nostr-tools");
|
||||
const { verifyEvent } = require('nostr-tools');
|
||||
|
||||
const NostrChallengeCreated = require('../models/NostrChallengeCreated');
|
||||
const NostrChallengeCompleted = require("../models/NostrChallengeCompleted");
|
||||
const NostrChallengeCompleted = require('../models/NostrChallengeCompleted');
|
||||
|
||||
const constants = require('../constants');
|
||||
const errors = require('../errors');
|
||||
|
||||
async function createNostrChallenge() {
|
||||
|
||||
const currentTimestamp = new Date();
|
||||
const expiryTimestamp = new Date(currentTimestamp.getTime());
|
||||
expiryTimestamp.setSeconds(expiryTimestamp.getSeconds() + constants.DEFAULT_NOSTR_CHALLENGE_DURATION_SECONDS);
|
||||
expiryTimestamp.setSeconds(
|
||||
expiryTimestamp.getSeconds() +
|
||||
constants.DEFAULT_NOSTR_CHALLENGE_DURATION_SECONDS
|
||||
);
|
||||
|
||||
const nostrChallenge = await NostrChallengeCreated.create({
|
||||
'uuid': uuid.v7(),
|
||||
challenge: crypto.randomBytes(32).toString("hex"),
|
||||
uuid: uuid.v7(),
|
||||
challenge: crypto.randomBytes(32).toString('hex'),
|
||||
expires_at: expiryTimestamp.toISOString(),
|
||||
created_at: currentTimestamp.toISOString()
|
||||
created_at: currentTimestamp.toISOString(),
|
||||
});
|
||||
|
||||
return nostrChallenge;
|
||||
}
|
||||
|
||||
async function getNostrChallenge(nostrChallengeUuid = null, challenge = null) {
|
||||
|
||||
if (nostrChallengeUuid) {
|
||||
return await NostrChallengeCreated.findOne({
|
||||
where: {
|
||||
'uuid': nostrChallengeUuid
|
||||
}
|
||||
})
|
||||
uuid: nostrChallengeUuid,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (challenge) {
|
||||
return await NostrChallengeCreated.findOne({
|
||||
where: {
|
||||
challenge
|
||||
}
|
||||
})
|
||||
challenge,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
throw Error('You need to pass a uuid or a challenge.')
|
||||
|
||||
throw Error('You need to pass a uuid or a challenge.');
|
||||
}
|
||||
|
||||
async function verifyNostrChallenge(signedEvent) {
|
||||
const challengeTag = signedEvent.tags.find(tag => tag[0] === "challenge");
|
||||
const challengeTag = signedEvent.tags.find((tag) => tag[0] === 'challenge');
|
||||
const challenge = challengeTag[1];
|
||||
|
||||
if (!(await isNostrChallengeFresh(challenge))) {
|
||||
throw TimeoutError("Challenge expired, request new one.");
|
||||
throw TimeoutError('Challenge expired, request new one.');
|
||||
}
|
||||
|
||||
if (await hasNostrChallengeBeenCompleted(challenge)) {
|
||||
throw new errors.AlreadyUsedError("Challenge already used, request new one.");
|
||||
throw new errors.AlreadyUsedError(
|
||||
'Challenge already used, request new one.'
|
||||
);
|
||||
}
|
||||
|
||||
const isSignatureValid = verifyEvent(signedEvent);
|
||||
if (!isSignatureValid) {
|
||||
throw new errors.InvalidSignatureError("Signature is not valid.");
|
||||
throw new errors.InvalidSignatureError('Signature is not valid.');
|
||||
}
|
||||
|
||||
return await NostrChallengeCompleted.create({
|
||||
'uuid': uuid.v7(),
|
||||
uuid: uuid.v7(),
|
||||
challenge: challenge,
|
||||
signed_event: signedEvent,
|
||||
public_key: signedEvent.pubkey,
|
||||
created_at: new Date().toISOString()
|
||||
}
|
||||
);
|
||||
created_at: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
|
||||
async function isNostrChallengeFresh(challengeString) {
|
||||
|
|
@ -79,9 +80,9 @@ async function isNostrChallengeFresh(challengeString) {
|
|||
where: {
|
||||
challenge: challengeString,
|
||||
expires_at: {
|
||||
[Op.gt]: new Date()
|
||||
}
|
||||
}
|
||||
[Op.gt]: new Date(),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (nostrChallenge) {
|
||||
|
|
@ -91,13 +92,11 @@ async function isNostrChallengeFresh(challengeString) {
|
|||
}
|
||||
|
||||
async function hasNostrChallengeBeenCompleted(challengeString) {
|
||||
const completedNostrChallenge = await NostrChallengeCompleted.findOne(
|
||||
{
|
||||
const completedNostrChallenge = await NostrChallengeCompleted.findOne({
|
||||
where: {
|
||||
challenge: challengeString
|
||||
}
|
||||
}
|
||||
);
|
||||
challenge: challengeString,
|
||||
},
|
||||
});
|
||||
|
||||
if (completedNostrChallenge) {
|
||||
return true;
|
||||
|
|
@ -105,11 +104,10 @@ async function hasNostrChallengeBeenCompleted(challengeString) {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
module.exports = {
|
||||
createNostrChallenge,
|
||||
getNostrChallenge,
|
||||
verifyNostrChallenge,
|
||||
isNostrChallengeFresh,
|
||||
hasNostrChallengeBeenCompleted
|
||||
hasNostrChallengeBeenCompleted,
|
||||
};
|
||||
|
|
@ -3,28 +3,24 @@ const ContactDetailsSet = require('../models/ContactDetailsSet');
|
|||
const NymSet = require('../models/NymSet');
|
||||
|
||||
async function setContactDetails(publicKey, encryptedContactDetails) {
|
||||
return await ContactDetailsSet.create(
|
||||
{
|
||||
'uuid': uuid.v7(),
|
||||
return await ContactDetailsSet.create({
|
||||
uuid: uuid.v7(),
|
||||
public_key: publicKey,
|
||||
encrypted_contact_details: encryptedContactDetails,
|
||||
created_at: new Date().toISOString()
|
||||
}
|
||||
)
|
||||
created_at: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
|
||||
async function setNym(publicKey, nym) {
|
||||
return await NymSet.create(
|
||||
{
|
||||
'uuid': uuid.v7(),
|
||||
return await NymSet.create({
|
||||
uuid: uuid.v7(),
|
||||
public_key: publicKey,
|
||||
nym: nym,
|
||||
created_at: new Date().toISOString()
|
||||
}
|
||||
)
|
||||
created_at: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
setContactDetails,
|
||||
setNym
|
||||
setNym,
|
||||
};
|
||||
|
|
@ -9,20 +9,22 @@ const constants = require('../constants');
|
|||
async function createSession(sessionUuid) {
|
||||
const currentTimestamp = new Date();
|
||||
const expiryTimestamp = new Date(currentTimestamp.getTime());
|
||||
expiryTimestamp.setSeconds(expiryTimestamp.getSeconds() + constants.DEFAULT_SESSION_DURATION_SECONDS);
|
||||
expiryTimestamp.setSeconds(
|
||||
expiryTimestamp.getSeconds() + constants.DEFAULT_SESSION_DURATION_SECONDS
|
||||
);
|
||||
|
||||
return await SessionCreated.create({
|
||||
uuid: sessionUuid,
|
||||
created_at: currentTimestamp.toISOString(),
|
||||
expires_at: expiryTimestamp.toISOString()
|
||||
expires_at: expiryTimestamp.toISOString(),
|
||||
});
|
||||
}
|
||||
|
||||
async function isSessionValid(sessionUuid) {
|
||||
const currentSession = await SessionCreated.findOne({
|
||||
where: {
|
||||
'uuid': sessionUuid
|
||||
}
|
||||
uuid: sessionUuid,
|
||||
},
|
||||
});
|
||||
|
||||
if (!currentSession) {
|
||||
|
|
@ -38,30 +40,27 @@ async function isSessionValid(sessionUuid) {
|
|||
|
||||
async function relateSessionToPublicKey(sessionUuid, publicKey) {
|
||||
if (!(await isSessionValid(sessionUuid))) {
|
||||
throw Error("Session is not valid anymore.");
|
||||
throw Error('Session is not valid anymore.');
|
||||
}
|
||||
|
||||
if (!(await invitesService.isPublicKeySignedUp(publicKey))) {
|
||||
throw Error("Public key is not signed up.");
|
||||
throw Error('Public key is not signed up.');
|
||||
}
|
||||
|
||||
return SessionRelatedToPublickey.create({
|
||||
'uuid': uuid.v7(),
|
||||
uuid: uuid.v7(),
|
||||
session_uuid: sessionUuid,
|
||||
public_key: publicKey,
|
||||
created_at: new Date().toISOString()
|
||||
|
||||
created_at: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
|
||||
async function isSessionAuthorized(sessionUuid) {
|
||||
const isSessionRelatedToPublicKey = await SessionRelatedToPublickey.findOne(
|
||||
{
|
||||
const isSessionRelatedToPublicKey = await SessionRelatedToPublickey.findOne({
|
||||
where: {
|
||||
session_uuid: sessionUuid
|
||||
}
|
||||
}
|
||||
);
|
||||
session_uuid: sessionUuid,
|
||||
},
|
||||
});
|
||||
|
||||
if (isSessionRelatedToPublicKey) {
|
||||
return true;
|
||||
|
|
@ -71,16 +70,13 @@ async function isSessionAuthorized(sessionUuid) {
|
|||
}
|
||||
|
||||
async function getPublicKeyRelatedToSession(sessionUuid) {
|
||||
const sessionRelatedToPublickey = await SessionRelatedToPublickey.findOne(
|
||||
{
|
||||
const sessionRelatedToPublickey = await SessionRelatedToPublickey.findOne({
|
||||
where: {
|
||||
session_uuid: sessionUuid
|
||||
}
|
||||
}
|
||||
);
|
||||
session_uuid: sessionUuid,
|
||||
},
|
||||
});
|
||||
|
||||
return sessionRelatedToPublickey.public_key;
|
||||
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
|
@ -88,5 +84,5 @@ module.exports = {
|
|||
isSessionValid,
|
||||
relateSessionToPublicKey,
|
||||
isSessionAuthorized,
|
||||
getPublicKeyRelatedToSession
|
||||
}
|
||||
getPublicKeyRelatedToSession,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<title>Crear perfil</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="/css/seca.css">
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="stylesheet" href="/css/seca.css" />
|
||||
<script src="/javascript/createProfile.js"></script>
|
||||
</head>
|
||||
|
||||
|
|
@ -13,41 +12,66 @@
|
|||
<h1>Crea tu perfil</h1>
|
||||
<p>Tu clave de Nostr ya es parte de la seca.</p>
|
||||
<p>Añade detalles a tu perfil para poder empezar a comerciar.</p>
|
||||
</p>
|
||||
<hr>
|
||||
<hr />
|
||||
<form onsubmit="return false">
|
||||
<label>Pseudónimo (Nym):<input type="text" name="nym" id="nym-input"></label>
|
||||
<label
|
||||
>Pseudónimo (Nym):<input type="text" name="nym" id="nym-input"
|
||||
/></label>
|
||||
<div id="contacts">
|
||||
<p>Añade métodos de contacto para poder hablar con otros miembros.</p>
|
||||
<div class="badges">
|
||||
<div class="badge" data-type="whatsapp">📱 Teléfono <input><button
|
||||
class="contact-detail-add-button">Añadir</button></div>
|
||||
<div class="badge" data-type="whatsapp">📱 WhatsApp <input><button
|
||||
class="contact-detail-add-button">Añadir</button></div>
|
||||
<div class="badge" data-type="telegram">📩 Telegram <input><button
|
||||
class="contact-detail-add-button"></button>>Añadir</button></div>
|
||||
<div class="badge" data-type="email">📧 Email <input><button
|
||||
class="contact-detail-add-button">Añadir</button></div>
|
||||
<div class="badge" data-type="nostr">📧 Nostr <input><button
|
||||
class="contact-detail-add-button">Añadir</button></div>
|
||||
<div class="badge" data-type="signal">📧 Signal <input><button
|
||||
class="contact-detail-add-button">Añadir</button></div>
|
||||
<div class="badge" data-type="matrix">📧 Matrix <input><button
|
||||
class="contact-detail-add-button">Añadir</button></div>
|
||||
<div class="badge" data-type="xmpp">📧 XMPP <input><button
|
||||
class="contact-detail-add-button">Añadir</button></div>
|
||||
<div class="badge" data-type="simplex">📧 Simplex <input><button
|
||||
class="contact-detail-add-button">Añadir</button></div>
|
||||
<div class="badge" data-type="whatsapp">
|
||||
📱 Teléfono <input /><button class="contact-detail-add-button">
|
||||
Añadir
|
||||
</button>
|
||||
</div>
|
||||
<div class="badge" data-type="whatsapp">
|
||||
📱 WhatsApp <input /><button class="contact-detail-add-button">
|
||||
Añadir
|
||||
</button>
|
||||
</div>
|
||||
<div class="badge" data-type="telegram">
|
||||
📩 Telegram <input /><button class="contact-detail-add-button">
|
||||
Añadir
|
||||
</button>
|
||||
</div>
|
||||
<div class="badge" data-type="email">
|
||||
📧 Email <input /><button class="contact-detail-add-button">
|
||||
Añadir
|
||||
</button>
|
||||
</div>
|
||||
<div class="badge" data-type="nostr">
|
||||
📧 Nostr <input /><button class="contact-detail-add-button">
|
||||
Añadir
|
||||
</button>
|
||||
</div>
|
||||
<div class="badge" data-type="signal">
|
||||
📧 Signal <input /><button class="contact-detail-add-button">
|
||||
Añadir
|
||||
</button>
|
||||
</div>
|
||||
<div class="badge" data-type="matrix">
|
||||
📧 Matrix <input /><button class="contact-detail-add-button">
|
||||
Añadir
|
||||
</button>
|
||||
</div>
|
||||
<div class="badge" data-type="xmpp">
|
||||
📧 XMPP <input /><button class="contact-detail-add-button">
|
||||
Añadir
|
||||
</button>
|
||||
</div>
|
||||
<div class="badge" data-type="simplex">
|
||||
📧 Simplex <input /><button class="contact-detail-add-button">
|
||||
Añadir
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="created-contact-details-section">
|
||||
<p>Contactos añadidos</p>
|
||||
<div id="created-contact-details-list">
|
||||
|
||||
</div>
|
||||
<div id="created-contact-details-list"></div>
|
||||
</div>
|
||||
<button id="submit-details-button" type="submit">Crear tu perfil</button>
|
||||
</form>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -1,17 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Error</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Error</h1>
|
||||
<p>
|
||||
<%= message %>
|
||||
</p>
|
||||
<p><%= message %></p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -1,10 +1,9 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<title>Hello World</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<script src="/javascript/index.js"></script>
|
||||
</head>
|
||||
|
||||
|
|
@ -15,9 +14,13 @@
|
|||
<button type="submit">Login con extensión de Nostr</button>
|
||||
</form>
|
||||
<p>
|
||||
¿No tienes cuenta de Nostr? <a href="https://start.njump.me/" target="_blank" rel="noopener noreferrer">Crea una
|
||||
gratis</a>.
|
||||
¿No tienes cuenta de Nostr?
|
||||
<a
|
||||
href="https://start.njump.me/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>Crea una gratis</a
|
||||
>.
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -1,43 +1,72 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<title>Invite Details</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<script src="/javascript/invite.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>¡Has sido invitado!</h1>
|
||||
<p>Has sido invitado a la seca.</p>
|
||||
<p>Invite UUID: <%= invite.uuid %>
|
||||
</p>
|
||||
<p>Invite UUID: <%= invite.uuid %></p>
|
||||
<p>Usa tu extensión de Nostr para darte de alta:</p>
|
||||
<form onsubmit="acceptInvite();return false">
|
||||
<button id="nostr-signup" type="submit">Alta con Nostr</button>
|
||||
</form>
|
||||
<div id="rejected-nostr-nudges" style="display: none">
|
||||
<p>Ups, parece que no has aceptado que usemos tus claves. Si te has equivocado, puedes intentarlo de nuevo.</p>
|
||||
<p>
|
||||
Ups, parece que no has aceptado que usemos tus claves. Si te has
|
||||
equivocado, puedes intentarlo de nuevo.
|
||||
</p>
|
||||
</div>
|
||||
<div id="no-extension-nudges" style="display: none">
|
||||
<p>¡Atención! No se ha encontrado una extensión de Nostr en tu navegador. Puedes usar: </p>
|
||||
<p>
|
||||
¡Atención! No se ha encontrado una extensión de Nostr en tu navegador.
|
||||
Puedes usar:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Firefox
|
||||
<li>
|
||||
Firefox
|
||||
<ul>
|
||||
<li><a href="https://addons.mozilla.org/en-US/firefox/addon/alby/" target="_blank"
|
||||
rel="noopener noreferrer">Alby</a></li>
|
||||
<li><a href="https://addons.mozilla.org/en-US/firefox/addon/nos2x-fox/" target="_blank"
|
||||
rel="noopener noreferrer">nos2x-fox</a></li>
|
||||
<li>
|
||||
<a
|
||||
href="https://addons.mozilla.org/en-US/firefox/addon/alby/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>Alby</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://addons.mozilla.org/en-US/firefox/addon/nos2x-fox/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>nos2x-fox</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
Chrome
|
||||
<ul>
|
||||
<li><a href="https://chromewebstore.google.com/detail/alby-bitcoin-wallet-for-l/iokeahhehimjnekafflcihljlcjccdbe?pli=1"
|
||||
target="_blank" rel="noopener noreferrer">Alby</a></li>
|
||||
<li><a href="https://chromewebstore.google.com/detail/nos2x/kpgefcfmnafjgpblomihpgmejjdanjjp"
|
||||
target="_blank" rel="noopener noreferrer">nos2x</a></li>
|
||||
<li>
|
||||
<a
|
||||
href="https://chromewebstore.google.com/detail/alby-bitcoin-wallet-for-l/iokeahhehimjnekafflcihljlcjccdbe?pli=1"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>Alby</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://chromewebstore.google.com/detail/nos2x/kpgefcfmnafjgpblomihpgmejjdanjjp"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>nos2x</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -46,8 +75,14 @@
|
|||
<p>¡Bien! Hemos dado de alta tu clave de Nostr.</p>
|
||||
<p>Te vamos a redirigir a la seca, espera un momento.</p>
|
||||
</div>
|
||||
<p>¿No tienes cuenta de Nostr? <a href="https://start.njump.me/" target="_blank" rel="noopener noreferrer">Crea
|
||||
una aquí.</a< /p>
|
||||
<p>
|
||||
¿No tienes cuenta de Nostr?
|
||||
<a
|
||||
href="https://start.njump.me/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>Crea una aquí.</a
|
||||
>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -1,20 +1,17 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<title>Invite Details</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Invite Details</h1>
|
||||
<p>Invite UUID: <%= invite.uuid %>
|
||||
</p>
|
||||
<p>Invite UUID: <%= invite.uuid %></p>
|
||||
<h2>Wait right there buddy... that invite has been spent already!</h2>
|
||||
<form>
|
||||
<button onclick="" disabled>Click to accept invite with Nostr</button>
|
||||
</form>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -1,15 +1,16 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<title>Private page</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Private page</h1>
|
||||
<p>If you are here, it's because your npub is white listed, and your session cookie is related to it.</p>
|
||||
<p>
|
||||
If you are here, it's because your npub is white listed, and your session
|
||||
cookie is related to it.
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue