')
- .description('Create an invite')
- .action(createAppInviteCommand);
-
- return wipCli;
-}
-
-const cliDependencies = buildCLIDependencies();
-
-const cli = buildCLI(cliDependencies);
-
-cli.parse(process.argv);
+program.parse(process.argv);
diff --git a/src/commands/createAppInvite.js b/src/commands/createAppInvite.js
index 610c098..0767123 100644
--- a/src/commands/createAppInvite.js
+++ b/src/commands/createAppInvite.js
@@ -1,17 +1,7 @@
-class CreateAppInviteProvider {
- constructor({ invitesService }) {
- this.invitesService = invitesService;
- }
+const invitesService = require('../services/invitesService');
- provide() {
- const createAppInvite = async (inviterNpub) => {
- const appInvite = await this.invitesService.createAppInvite(inviterNpub);
- console.log('Invite created');
- console.log(`Check at http://localhost/invite/${appInvite.uuid}`);
- };
-
- return createAppInvite;
- }
-}
-
-module.exports = CreateAppInviteProvider;
+module.exports = async function createAppInvite(inviterNpub) {
+ const appInvite = await invitesService.createAppInvite(inviterNpub);
+ console.log('Invite created');
+ console.log(`Check at http://localhost/invite/${appInvite.uuid}`);
+};
diff --git a/src/constants.js b/src/constants.js
index 7af448b..8bec536 100644
--- a/src/constants.js
+++ b/src/constants.js
@@ -1,15 +1,7 @@
const DEFAULT_SESSION_DURATION_SECONDS = 60 * 60 * 24 * 30;
const DEFAULT_NOSTR_CHALLENGE_DURATION_SECONDS = 60 * 60 * 24 * 30;
-const DEFAULT_REDIRECT_DELAY = 3 * 1000; // 3seconds times milliseconds;
-
-const API_PATHS = {
- createProfile: '/createProfile',
- home: '/home',
-};
module.exports = {
DEFAULT_SESSION_DURATION_SECONDS,
DEFAULT_NOSTR_CHALLENGE_DURATION_SECONDS,
- API_PATHS,
- DEFAULT_REDIRECT_DELAY,
};
diff --git a/src/database/database.js b/src/database.js
similarity index 74%
rename from src/database/database.js
rename to src/database.js
index ed4ef6c..b90f77f 100644
--- a/src/database/database.js
+++ b/src/database.js
@@ -10,11 +10,6 @@ const sequelize = new Sequelize({
database: process.env.POSTGRES_DB,
username: process.env.POSTGRES_USER,
password: process.env.POSTGRES_PASSWORD,
- /* logging: (msg) => {
- if (msg && (msg.includes('ERROR') || msg.includes('error'))) {
- console.error(msg);
- }
- }, */
define: {
timestamps: false,
freezeTableName: true,
@@ -23,4 +18,13 @@ const sequelize = new Sequelize({
},
});
+sequelize
+ .sync()
+ .then(() => {
+ console.log('Database synced');
+ })
+ .catch((err) => {
+ console.error('Error syncing the database:', err);
+ });
+
module.exports = sequelize;
diff --git a/src/database/associations.js b/src/database/associations.js
deleted file mode 100644
index 45747be..0000000
--- a/src/database/associations.js
+++ /dev/null
@@ -1,36 +0,0 @@
-class AssociationsDefiner {
- constructor({ models, DataTypes }) {
- this.models = models;
- this.DataTypes = DataTypes;
- }
-
- define() {
- this.models.NostrChallengeCreated.hasOne(
- this.models.NostrChallengeCompleted,
- {
- foreignKey: 'challenge',
- }
- );
- this.models.NostrChallengeCompleted.belongsTo(
- this.models.NostrChallengeCreated,
- {
- foreignKey: {
- name: 'challenge',
- },
- }
- );
-
- this.models.OfferCreated.hasOne(this.models.OfferDeleted, {
- foreignKey: 'offer_uuid',
- });
- this.models.OfferDeleted.belongsTo(this.models.OfferCreated, {
- foreignKey: {
- name: 'offer_uuid',
- type: this.DataTypes.UUID,
- allowNull: false,
- },
- });
- }
-}
-
-module.exports = AssociationsDefiner;
diff --git a/src/database/config.js b/src/database/config.js
deleted file mode 100644
index 2800b22..0000000
--- a/src/database/config.js
+++ /dev/null
@@ -1,21 +0,0 @@
-const dotenv = require('dotenv');
-
-dotenv.config();
-
-module.exports = {
- development: {
- dialect: 'postgres',
- host: process.env.POSTGRES_HOST,
- port: 5432,
- database: process.env.POSTGRES_DB,
- username: process.env.POSTGRES_USER,
- password: process.env.POSTGRES_PASSWORD,
- logging: console.log,
- define: {
- timestamps: false,
- freezeTableName: true,
- underscored: true,
- quoteIdentifiers: false,
- },
- },
-};
diff --git a/src/database/migrations/20250308000000-first-schema-tables.js b/src/database/migrations/20250308000000-first-schema-tables.js
deleted file mode 100644
index 3fb5cb9..0000000
--- a/src/database/migrations/20250308000000-first-schema-tables.js
+++ /dev/null
@@ -1,379 +0,0 @@
-'use strict';
-
-module.exports = {
- up: (queryInterface, Sequelize) => {
- return queryInterface.sequelize.transaction((t) => {
- return Promise.all([
- queryInterface.createTable(
- 'app_invite_created',
- {
- uuid: {
- type: Sequelize.UUID,
- allowNull: false,
- unique: true,
- primaryKey: true,
- },
- inviter_pub_key: {
- type: Sequelize.STRING,
- allowNull: false,
- },
- created_at: {
- type: Sequelize.DATE,
- allowNull: false,
- },
- },
- { transaction: t }
- ),
- queryInterface.createTable(
- 'contact_details_set',
- {
- uuid: {
- type: Sequelize.UUID,
- allowNull: false,
- unique: true,
- primaryKey: true,
- },
- public_key: {
- type: Sequelize.STRING,
- allowNull: false,
- },
- encrypted_contact_details: {
- type: Sequelize.TEXT,
- allowNull: false,
- },
- created_at: {
- type: Sequelize.DATE,
- allowNull: false,
- },
- },
- { transaction: t }
- ),
- queryInterface.createTable(
- 'nostr_challenge_created',
- {
- uuid: {
- type: Sequelize.UUID,
- allowNull: false,
- unique: true,
- primaryKey: true,
- },
- challenge: {
- type: Sequelize.STRING,
- allowNull: false,
- unique: true,
- },
- expires_at: {
- type: Sequelize.DATE,
- allowNull: false,
- },
- created_at: {
- type: Sequelize.DATE,
- allowNull: false,
- },
- },
- { transaction: t }
- ),
- queryInterface.createTable(
- 'login_challenge_created',
- {
- uuid: {
- type: Sequelize.UUID,
- allowNull: false,
- unique: true,
- primaryKey: true,
- },
- nostr_challenge_uuid: {
- type: Sequelize.UUID,
- allowNull: false,
- },
- created_at: {
- type: Sequelize.DATE,
- allowNull: false,
- },
- },
- { transaction: t }
- ),
- queryInterface.createTable(
- 'nostr_challenge_completed',
- {
- uuid: {
- type: Sequelize.UUID,
- allowNull: false,
- unique: true,
- primaryKey: true,
- },
- challenge: {
- type: Sequelize.STRING,
- allowNull: false,
- unique: true,
- },
- signed_event: {
- type: Sequelize.JSONB,
- allowNull: false,
- },
- public_key: {
- type: Sequelize.STRING,
- allowNull: false,
- },
- created_at: {
- type: Sequelize.DATE,
- allowNull: false,
- },
- },
- { transaction: t }
- ),
- queryInterface.createTable(
- 'login_challenge_completed',
- {
- uuid: {
- type: Sequelize.UUID,
- allowNull: false,
- unique: true,
- primaryKey: true,
- },
- nostr_challenge_completed_uuid: {
- type: Sequelize.UUID,
- allowNull: false,
- },
- public_key: {
- type: Sequelize.STRING,
- allowNull: false,
- },
- created_at: {
- type: Sequelize.DATE,
- allowNull: false,
- },
- },
- { transaction: t }
- ),
- queryInterface.createTable(
- 'nym_set',
- {
- uuid: {
- type: Sequelize.UUID,
- allowNull: false,
- unique: true,
- primaryKey: true,
- },
- public_key: {
- type: Sequelize.STRING,
- allowNull: false,
- },
- nym: {
- type: Sequelize.TEXT,
- allowNull: false,
- },
- created_at: {
- type: Sequelize.DATE,
- allowNull: false,
- },
- },
- { transaction: t }
- ),
- queryInterface.createTable(
- 'offer_created',
- {
- uuid: {
- type: Sequelize.UUID,
- allowNull: false,
- unique: true,
- primaryKey: true,
- },
- public_key: {
- type: Sequelize.STRING,
- allowNull: false,
- },
- created_at: {
- type: Sequelize.DATE,
- allowNull: false,
- },
- },
- { transaction: t }
- ),
- queryInterface.createTable(
- 'offer_deleted',
- {
- uuid: {
- type: Sequelize.UUID,
- allowNull: false,
- unique: true,
- primaryKey: true,
- },
- offer_uuid: {
- type: Sequelize.UUID,
- allowNull: false,
- },
- created_at: {
- type: Sequelize.DATE,
- allowNull: false,
- },
- },
- { transaction: t }
- ),
- queryInterface.createTable(
- 'offer_details_set',
- {
- uuid: {
- type: Sequelize.UUID,
- allowNull: false,
- unique: true,
- primaryKey: true,
- },
- offer_uuid: {
- type: Sequelize.UUID,
- allowNull: false,
- },
- wants: {
- type: Sequelize.STRING,
- allowNull: false,
- },
- premium: {
- type: Sequelize.DECIMAL(5, 2),
- allowNull: false,
- },
- trade_amount_eur: {
- type: Sequelize.INTEGER,
- allowNull: false,
- },
- location_details: {
- type: Sequelize.TEXT,
- allowNull: false,
- },
- time_availability_details: {
- type: Sequelize.TEXT,
- allowNull: false,
- },
- show_offer_to_trusted: {
- type: Sequelize.BOOLEAN,
- allowNull: false,
- },
- show_offer_to_trusted_trusted: {
- type: Sequelize.BOOLEAN,
- allowNull: false,
- },
- show_offer_to_all_members: {
- type: Sequelize.BOOLEAN,
- allowNull: false,
- },
- is_onchain_accepted: {
- type: Sequelize.BOOLEAN,
- allowNull: false,
- },
- is_lightning_accepted: {
- type: Sequelize.BOOLEAN,
- allowNull: false,
- },
- are_big_notes_accepted: {
- type: Sequelize.BOOLEAN,
- allowNull: false,
- },
- created_at: {
- type: Sequelize.DATE,
- allowNull: false,
- },
- },
- { transaction: t }
- ),
- queryInterface.createTable(
- 'session_created',
- {
- uuid: {
- type: Sequelize.UUID,
- allowNull: false,
- unique: true,
- primaryKey: true,
- },
- created_at: {
- type: Sequelize.DATE,
- allowNull: false,
- },
- expires_at: {
- type: Sequelize.DATE,
- allowNull: false,
- },
- },
- { transaction: t }
- ),
- queryInterface.createTable(
- 'session_related_to_public_key',
- {
- uuid: {
- type: Sequelize.UUID,
- allowNull: false,
- unique: true,
- primaryKey: true,
- },
- session_uuid: {
- type: Sequelize.UUID,
- allowNull: false,
- },
- public_key: {
- type: Sequelize.STRING,
- allowNull: false,
- },
- created_at: {
- type: Sequelize.DATE,
- allowNull: false,
- },
- },
- { transaction: t }
- ),
- queryInterface.createTable(
- 'sign_up_challenge_created',
- {
- uuid: {
- type: Sequelize.UUID,
- allowNull: false,
- unique: true,
- primaryKey: true,
- },
- nostr_challenge_uuid: {
- type: Sequelize.UUID,
- allowNull: false,
- },
- app_invite_uuid: {
- type: Sequelize.UUID,
- allowNull: false,
- },
- created_at: {
- type: Sequelize.DATE,
- allowNull: false,
- },
- },
- { transaction: t }
- ),
- queryInterface.createTable(
- 'sign_up_challenge_completed',
- {
- uuid: {
- type: Sequelize.UUID,
- allowNull: false,
- unique: true,
- primaryKey: true,
- },
- nostr_challenge_completed_uuid: {
- type: Sequelize.UUID,
- allowNull: false,
- },
- app_invite_uuid: {
- type: Sequelize.UUID,
- allowNull: false,
- },
- public_key: {
- type: Sequelize.STRING,
- allowNull: false,
- },
- created_at: {
- type: Sequelize.DATE,
- allowNull: false,
- },
- },
- { transaction: t }
- ),
- ]);
- });
- },
- down: (queryInterface, Sequelize) => {
- return queryInterface.dropTable('Users');
- },
-};
diff --git a/src/database/migrations/20250308000001-first-schema-fks.js b/src/database/migrations/20250308000001-first-schema-fks.js
deleted file mode 100644
index 2052b0a..0000000
--- a/src/database/migrations/20250308000001-first-schema-fks.js
+++ /dev/null
@@ -1,152 +0,0 @@
-'use strict';
-module.exports = {
- up: (queryInterface, Sequelize) => {
- return queryInterface.sequelize.transaction((t) => {
- return Promise.all([
- queryInterface.addConstraint(
- 'login_challenge_created',
- {
- fields: ['nostr_challenge_uuid'],
- type: 'foreign key',
- references: {
- table: 'nostr_challenge_created',
- field: 'uuid',
- },
- onDelete: 'cascade',
- onUpdate: 'cascade',
- },
- { transaction: t }
- ),
- queryInterface.addConstraint(
- 'nostr_challenge_completed',
- {
- fields: ['challenge'],
- type: 'foreign key',
- references: {
- table: 'nostr_challenge_created',
- field: 'challenge',
- },
- onDelete: 'cascade',
- onUpdate: 'cascade',
- },
- { transaction: t }
- ),
- queryInterface.addConstraint(
- 'login_challenge_completed',
- {
- fields: ['nostr_challenge_completed_uuid'],
- type: 'foreign key',
- references: {
- table: 'nostr_challenge_completed',
- field: 'uuid',
- },
- onDelete: 'cascade',
- onUpdate: 'cascade',
- },
- { transaction: t }
- ),
- queryInterface.addConstraint(
- 'offer_deleted',
- {
- fields: ['offer_uuid'],
- type: 'foreign key',
- references: {
- table: 'offer_created',
- field: 'uuid',
- },
- onDelete: 'cascade',
- onUpdate: 'cascade',
- },
- { transaction: t }
- ),
- queryInterface.addConstraint(
- 'offer_details_set',
- {
- fields: ['offer_uuid'],
- type: 'foreign key',
- references: {
- table: 'offer_created',
- field: 'uuid',
- },
- onDelete: 'cascade',
- onUpdate: 'cascade',
- },
- { transaction: t }
- ),
- queryInterface.addConstraint(
- 'session_related_to_public_key',
- {
- fields: ['session_uuid'],
- type: 'foreign key',
- references: {
- table: 'session_created',
- field: 'uuid',
- },
- onDelete: 'cascade',
- onUpdate: 'cascade',
- },
- { transaction: t }
- ),
- queryInterface.addConstraint(
- 'sign_up_challenge_created',
- {
- fields: ['nostr_challenge_uuid'],
- type: 'foreign key',
- references: {
- table: 'nostr_challenge_created',
- field: 'uuid',
- },
- onDelete: 'cascade',
- onUpdate: 'cascade',
- },
- { transaction: t }
- ),
- queryInterface.addConstraint(
- 'sign_up_challenge_created',
- {
- fields: ['app_invite_uuid'],
- type: 'foreign key',
- references: {
- table: 'app_invite_created',
- field: 'uuid',
- },
- onDelete: 'cascade',
- onUpdate: 'cascade',
- },
- { transaction: t }
- ),
- queryInterface.addConstraint(
- 'sign_up_challenge_completed',
- {
- fields: ['nostr_challenge_completed_uuid'],
- type: 'foreign key',
- references: {
- table: 'nostr_challenge_completed',
- field: 'uuid',
- },
- onDelete: 'cascade',
- onUpdate: 'cascade',
- },
- { transaction: t }
- ),
- queryInterface.addConstraint(
- 'sign_up_challenge_completed',
- {
- fields: ['app_invite_uuid'],
- type: 'foreign key',
- references: {
- table: 'app_invite_created',
- field: 'uuid',
- },
- onDelete: 'cascade',
- onUpdate: 'cascade',
- },
- { transaction: t }
- ),
- ]);
- });
- },
- down: (queryInterface, Sequelize) => {
- return queryInterface.dropTable('Users');
- },
-};
diff --git a/src/dependencies.js b/src/dependencies.js
deleted file mode 100644
index af0495b..0000000
--- a/src/dependencies.js
+++ /dev/null
@@ -1,52 +0,0 @@
-const express = require('express');
-
-function buildDependencies() {
- const dependencies = {};
- const errors = require('./errors');
- const constants = require('./constants');
-
- const sequelize = require('./database/database');
- const { DataTypes } = require('sequelize');
- const ModelsProvider = require('./models');
- const models = new ModelsProvider({ sequelize, DataTypes }).provide();
-
- const AssociationsDefiner = require('./database/associations');
- new AssociationsDefiner({ models, DataTypes }).define();
-
- const ServicesProvider = require('./services');
- const services = new ServicesProvider({
- models,
- constants,
- errors,
- sequelize,
- }).provide();
- dependencies.services = services;
-
- const MiddlewaresProvider = require('./middlewares');
- const middlewares = new MiddlewaresProvider({
- constants,
- sessionService: services.sessionService,
- profileService: services.profileService,
- }).provide();
- dependencies.middlewares = middlewares;
-
- const WebRoutesProvider = require('./routes/webRoutes');
- const webRoutesProvider = new WebRoutesProvider({
- express,
- middlewares,
- invitesService: services.invitesService,
- });
- dependencies.webRoutes = webRoutesProvider.provide();
-
- const ApiRoutesProvider = require('./routes/apiRoutes');
- const apiRoutesProvider = new ApiRoutesProvider({
- express,
- middlewares,
- services,
- errors,
- });
- dependencies.apiRoutes = apiRoutesProvider.provide();
- return dependencies;
-}
-
-module.exports = { buildDependencies };
diff --git a/src/front/components/BuyOrSellButtonGroup.js b/src/front/components/BuyOrSellButtonGroup.js
deleted file mode 100644
index d563e54..0000000
--- a/src/front/components/BuyOrSellButtonGroup.js
+++ /dev/null
@@ -1,58 +0,0 @@
-class BuyOrSellButtonGroup {
- constructor({ parentElement, id }) {
- this.element = null;
- this.parentElement = parentElement;
- this.id = id;
-
- this.buyButton = null;
- this.sellButton = null;
- }
-
- render() {
- const groupDiv = document.createElement('div');
- groupDiv.className = 'button-group';
- groupDiv.id = this.id;
-
- const buyButton = document.createElement('button');
- buyButton.dataset.value = 'buy-bitcoin';
- buyButton.id = 'button-buy-bitcoin';
- buyButton.className = 'selected';
- buyButton.textContent = 'Quiero comprar Bitcoin';
- this.buyButton = buyButton;
-
- const sellButton = document.createElement('button');
- sellButton.dataset.value = 'sell-bitcoin';
- sellButton.id = 'button-sell-bitcoin';
- sellButton.textContent = 'Quiero vender Bitcoin';
- this.sellButton = sellButton;
-
- groupDiv.appendChild(this.buyButton);
- groupDiv.appendChild(this.sellButton);
-
- for (const button of [this.buyButton, this.sellButton]) {
- button.addEventListener('click', () => {
- [this.buyButton, this.sellButton].forEach((aButton) => {
- if (aButton.classList.contains('selected')) {
- aButton.classList.remove('selected');
- } else {
- aButton.classList.add('selected');
- }
- });
- });
- }
-
- this.element = groupDiv;
- this.parentElement.appendChild(this.element);
- }
-
- wants() {
- if (this.buyButton.classList.contains('selected')) {
- return 'BTC';
- }
- if (this.sellButton.classList.contains('selected')) {
- return 'EUR';
- }
- }
-}
-
-module.exports = BuyOrSellButtonGroup;
diff --git a/src/front/components/PopupNotification.js b/src/front/components/PopupNotification.js
deleted file mode 100644
index e2a0588..0000000
--- a/src/front/components/PopupNotification.js
+++ /dev/null
@@ -1,25 +0,0 @@
-class PopupNotification {
- constructor({ parentElement, id, text }) {
- this.element = null;
- this.parentElement = parentElement;
- this.id = id;
- this.text = text;
- }
-
- render() {
- const div = document.createElement('div');
- div.id = this.id;
- div.className = 'top-notification-good';
-
- div.innerHTML = `
- ${this.text}
`;
-
- this.element = div;
- this.parentElement.appendChild(div);
- }
-
- display() {
- this.element.classList.add('revealed');
- }
-}
-module.exports = PopupNotification;
diff --git a/src/front/components/PremiumSelector.js b/src/front/components/PremiumSelector.js
deleted file mode 100644
index d2defdd..0000000
--- a/src/front/components/PremiumSelector.js
+++ /dev/null
@@ -1,68 +0,0 @@
-class PremiumSelector {
- constructor({ parentElement, id, eventSink }) {
- this.element = null;
- this.parentElement = parentElement;
- this.id = id;
- this.eventSink = eventSink;
-
- this.premiumValue = null;
- }
-
- render() {
- const premiumSelectorArea = document.createElement('div');
- premiumSelectorArea.id = this.id;
-
- const premiumValue = document.createElement('div');
- premiumValue.id = 'premium-value';
- premiumValue.textContent = '0%';
- this.premiumValue = premiumValue;
-
- const premiumButtonsContainer = document.createElement('div');
- premiumButtonsContainer.id = 'premium-buttons-container';
-
- const increaseButton = document.createElement('button');
- increaseButton.classList.add('premium-button');
- increaseButton.id = 'button-increase-premium';
- increaseButton.textContent = '+';
-
- const decreaseButton = document.createElement('button');
- decreaseButton.classList.add('premium-button');
- decreaseButton.id = 'button-decrease-premium';
- decreaseButton.textContent = '-';
-
- premiumButtonsContainer.appendChild(increaseButton);
- premiumButtonsContainer.appendChild(decreaseButton);
-
- premiumSelectorArea.appendChild(premiumValue);
- premiumSelectorArea.appendChild(premiumButtonsContainer);
-
- increaseButton.addEventListener('click', () => {
- this.modifyPremiumValue(1);
- });
-
- decreaseButton.addEventListener('click', () => {
- this.modifyPremiumValue(-1);
- });
-
- this.element = premiumSelectorArea;
- this.parentElement.appendChild(this.element);
- }
-
- modifyPremiumValue(delta) {
- const regexExpression = /-*\d+/;
- const numValue = parseInt(
- this.premiumValue.innerText.match(regexExpression)[0]
- );
-
- const newValue = `${numValue + delta}%`;
-
- this.premiumValue.innerText = newValue;
- this.eventSink.dispatchEvent(new Event('premium-changed'));
- }
-
- getPremium() {
- return parseInt(this.premiumValue.textContent.match(/-?\d+/)[0]) / 100;
- }
-}
-
-module.exports = PremiumSelector;
diff --git a/src/front/components/PriceDisplay.js b/src/front/components/PriceDisplay.js
deleted file mode 100644
index 39eb16d..0000000
--- a/src/front/components/PriceDisplay.js
+++ /dev/null
@@ -1,64 +0,0 @@
-const formatNumberWithSpaces = require('../utils/formatNumbersWithSpaces');
-
-class PriceDisplay {
- constructor({
- parentElement,
- id,
- premiumProvidingCallback,
- priceProvidingCallback,
- }) {
- this.element = null;
- this.parentElement = parentElement;
- this.id = id;
- this.premiumProvidingCallback = premiumProvidingCallback;
- this.priceProvidingCallback = priceProvidingCallback;
- }
-
- render() {
- const container = document.createElement('div');
- container.id = 'premium-price-display-area';
-
- const offerParagraph = document.createElement('p');
- offerParagraph.id = 'offer-price-paragraph';
- offerParagraph.textContent = 'Tu precio: ';
-
- const offerSpan = document.createElement('span');
- offerSpan.id = 'offer-price';
- this.offerPriceSpan = offerSpan;
-
- offerParagraph.appendChild(offerSpan);
- offerParagraph.append('€/BTC');
-
- const marketParagraph = document.createElement('p');
- marketParagraph.id = 'market-price-paragraph';
- marketParagraph.textContent = '(Precio mercado: ';
-
- const marketSpan = document.createElement('span');
- marketSpan.id = 'market-price';
- this.marketPriceSpan = marketSpan;
-
- marketParagraph.appendChild(marketSpan);
- marketParagraph.append('€/BTC)');
-
- container.appendChild(offerParagraph);
- container.appendChild(marketParagraph);
-
- this.updatePrices();
-
- this.element = container;
- this.parentElement.appendChild(this.element);
- }
-
- updatePrices() {
- const marketPrice = this.priceProvidingCallback();
- const marketPriceString = formatNumberWithSpaces(marketPrice);
- const offerPriceString = formatNumberWithSpaces(
- Math.round(marketPrice * (1 + this.premiumProvidingCallback()))
- );
-
- this.marketPriceSpan.innerText = marketPriceString;
- this.offerPriceSpan.innerText = offerPriceString;
- }
-}
-
-module.exports = PriceDisplay;
diff --git a/src/front/components/PublishOfferButton.js b/src/front/components/PublishOfferButton.js
deleted file mode 100644
index d43f8c1..0000000
--- a/src/front/components/PublishOfferButton.js
+++ /dev/null
@@ -1,21 +0,0 @@
-class PublishOfferButton {
- constructor({ parentElement, id, onClickCallback }) {
- this.element = null;
- this.parentElement = parentElement;
- this.id = id;
- this.onClickCallback = onClickCallback;
- }
-
- render() {
- const button = document.createElement('button');
- button.id = this.id;
- button.className = 'button-primary button-large';
- button.innerText = 'Publicar oferta';
- button.addEventListener('click', this.onClickCallback);
-
- this.element = button;
- this.parentElement.appendChild(this.element);
- }
-}
-
-module.exports = PublishOfferButton;
diff --git a/src/front/components/WarningDiv.js b/src/front/components/WarningDiv.js
deleted file mode 100644
index ab4fa93..0000000
--- a/src/front/components/WarningDiv.js
+++ /dev/null
@@ -1,25 +0,0 @@
-class WarningDiv {
- constructor({ parentElement, id, innerHTML }) {
- this.element = null;
- this.parentElement = parentElement;
- this.id = id;
- this.innerHTML = innerHTML;
- }
-
- render() {
- const div = document.createElement('div');
- div.id = this.id;
- div.className = 'card-secondary';
- div.style.display = 'none';
-
- div.innerHTML = this.innerHTML;
-
- this.element = div;
- this.parentElement.appendChild(div);
- }
-
- display() {
- this.element.style.display = 'block';
- }
-}
-module.exports = WarningDiv;
diff --git a/src/front/components/nostrButtons.js b/src/front/components/nostrButtons.js
deleted file mode 100644
index 31513f5..0000000
--- a/src/front/components/nostrButtons.js
+++ /dev/null
@@ -1,63 +0,0 @@
-class NostrButton {
- constructor({ parentElement, id, onClickCallback, buttonText }) {
- this.element = null;
- this.parentElement = parentElement;
- this.id = id;
- this.onClickCallback = onClickCallback;
- this.buttonText = buttonText;
- }
-
- render() {
- const thisButton = document.createElement('button');
- thisButton.id = this.id;
- thisButton.type = 'submit';
- thisButton.className = 'button-large button-nostr';
-
- const figure = document.createElement('figure');
-
- const img = document.createElement('img');
- img.src = '/img/white_ostrich.svg';
- img.style.width = '40%';
- img.style.margin = '-5% -5%';
-
- figure.appendChild(img);
-
- const paragraph = document.createElement('p');
- paragraph.textContent = this.buttonText;
-
- thisButton.appendChild(figure);
- thisButton.appendChild(paragraph);
-
- thisButton.addEventListener('click', () => {
- this.onClickCallback();
- });
-
- this.element = thisButton;
- this.parentElement.appendChild(this.element);
- }
-
- disable() {
- if (this.element) {
- this.element.disabled = true;
- }
- }
-}
-
-class NostrSignupButton extends NostrButton {
- constructor({ parentElement, id, onClickCallback }) {
- super({ parentElement, id, onClickCallback, buttonText: 'Alta con Nostr' });
- }
-}
-
-class NostrLoginButton extends NostrButton {
- constructor({ parentElement, id, onClickCallback }) {
- super({
- parentElement,
- id,
- onClickCallback,
- buttonText: 'Login con Nostr',
- });
- }
-}
-
-module.exports = { NostrSignupButton, NostrLoginButton };
diff --git a/src/front/pages/createProfile.js b/src/front/pages/createProfile.js
deleted file mode 100644
index 51e61dd..0000000
--- a/src/front/pages/createProfile.js
+++ /dev/null
@@ -1,125 +0,0 @@
-const createProfilesFunction = () => {
- const createProfileConfirmation = document.querySelector(
- '#create-profile-success'
- );
-
- function debounce(func, wait) {
- let timeout;
- return function (...args) {
- clearTimeout(timeout);
- timeout = setTimeout(() => func.apply(this, args), wait);
- };
- }
-
- const validateNymInput = debounce(() => {
- const nymValue = nymInput.value.trim();
- const isValid = nymValue.length >= 3 && nymValue.length <= 128;
- if (isValid) {
- nymInputValidationWarning.style.display = 'none';
- } else {
- nymInputValidationWarning.style.display = 'block';
- }
- }, 500);
-
- const checkIfSubmittable = debounce((allInputs) => {
- const nymIsFilled = allInputs.nymInput.value !== '';
- let atLeastOneContactIsFilled = false;
-
- for (const contactInput of allInputs.contactInputs) {
- if (contactInput.value !== '') {
- atLeastOneContactIsFilled = true;
- }
- }
-
- const buttonShouldBeDisabled = !(nymIsFilled && atLeastOneContactIsFilled);
- submitProfileButton.disabled = buttonShouldBeDisabled;
- }, 500);
-
- async function createProfile(allInputs) {
- const contactDetails = [];
- for (const someInput of allInputs.contactInputs) {
- contactDetails.push({
- type: someInput.getAttribute('data-type'),
- value: someInput.value,
- });
- }
- const encryptedContactDetails = await window.nostr.nip04.encrypt(
- await window.nostr.getPublicKey(),
- JSON.stringify(contactDetails)
- );
- await fetch('/api/set-contact-details', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({ encryptedContactDetails }),
- });
-
- const nym = allInputs.nymInput.value;
- await fetch('/api/set-nym', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({ nym }),
- });
-
- createProfileConfirmation.classList.add('revealed');
- setTimeout(() => {
- window.location.href = '/home';
- }, 5000);
- }
-
- function onLoadErrands(allInputs, submitProfileButton) {
- allInputs.nymInput.addEventListener('input', validateNymInput);
-
- for (const someInput of allInputs.allInputs) {
- someInput.addEventListener('input', () => {
- checkIfSubmittable(allInputs);
- });
- }
-
- checkIfSubmittable(allInputs);
-
- submitProfileButton.addEventListener('click', () => {
- createProfile(allInputs);
- });
- }
-
- const nymInput = document.getElementById('nym-input');
- const nymInputValidationWarning = document.getElementById(
- 'nym-input-validation-warning'
- );
- const phoneInput = document.getElementById('phone-input');
- const whatsappInput = document.getElementById('whatsapp-input');
- const telegramInput = document.getElementById('telegram-input');
- const emailInput = document.getElementById('email-input');
- const nostrInput = document.getElementById('nostr-input');
- const signalInput = document.getElementById('signal-input');
- const submitProfileButton = document.getElementById('submit-profile-button');
-
- const allInputs = {
- nymInput: nymInput,
- contactInputs: [
- phoneInput,
- whatsappInput,
- telegramInput,
- emailInput,
- nostrInput,
- signalInput,
- ],
- allInputs: [
- nymInput,
- phoneInput,
- whatsappInput,
- telegramInput,
- emailInput,
- nostrInput,
- signalInput,
- ],
- };
-
- onLoadErrands(allInputs, submitProfileButton);
-};
-
-createProfilesFunction();
diff --git a/src/front/pages/home.js b/src/front/pages/home.js
deleted file mode 100644
index 92bd6bb..0000000
--- a/src/front/pages/home.js
+++ /dev/null
@@ -1,14 +0,0 @@
-const homeFunction = () => {
- const navbuttonHome = document.getElementById('navbutton-home');
- const navbuttonOffers = document.getElementById('navbutton-offers');
-
- navbuttonHome.addEventListener('click', () => {
- window.location.href = '/home';
- });
-
- navbuttonOffers.addEventListener('click', () => {
- window.location.href = '/offers';
- });
-};
-
-homeFunction();
diff --git a/src/front/pages/invite.js b/src/front/pages/invite.js
deleted file mode 100644
index 24bc3b5..0000000
--- a/src/front/pages/invite.js
+++ /dev/null
@@ -1,110 +0,0 @@
-const checkNostrExtension = require('../utils/checkNostrExtension');
-const inviteService = require('../services/inviteService');
-const constants = require('../../constants');
-const { NostrSignupButton } = require('../components/nostrButtons');
-const WarningDiv = require('../components/WarningDiv');
-const PopupNotification = require('../components/PopupNotification');
-
-const invitesFunction = () => {
- const body = document.querySelector('body');
- const warningsContainer = document.getElementById('warnings-container');
- const nostrSignupArea = document.getElementById('nostr-signup-area');
-
- const signupButton = new NostrSignupButton({
- parentElement: nostrSignupArea,
- id: 'nostr-signup-button',
- onClickCallback: async () => {
- const verifyResponse =
- await inviteService.requestAndRespondSignUpChallenge({
- onNostrErrorCallback: () => {
- rejectedNostrWarning.display();
- },
- });
-
- if (verifyResponse.ok) {
- signUpSuccessPopup.display();
- setTimeout(() => {
- window.location.href = constants.API_PATHS.createProfile;
- }, constants.DEFAULT_REDIRECT_DELAY);
- }
- },
- });
- signupButton.render();
-
- const noExtensionWarning = new WarningDiv({
- parentElement: warningsContainer,
- id: 'no-extension-nudges',
- innerHTML: `
- ¡Atención! No se ha encontrado una extensión de Nostr en tu
- navegador. Puedes usar:
-
- Firefox
-
- Alby
-
-
- nos2x-fox
-
- Chrome
-
- Alby
-
-
- nos2x
-
`,
- });
- noExtensionWarning.render();
-
- const rejectedNostrWarning = new WarningDiv({
- parentElement: warningsContainer,
- id: 'rejected-nostr-nudges',
- innerHTML: `
- Ups, parece que no has aceptado que usemos tus claves. Si te has
- equivocado, puedes intentarlo de nuevo.
-
`,
- });
- rejectedNostrWarning.render();
-
- const signUpSuccessPopup = new PopupNotification({
- parentElement: body,
- id: 'sign-up-success',
- text: '¡Bien! Hemos dado de alta tu clave de Nostr. Te vamos a redirigir a la seca, espera un momento.',
- });
- signUpSuccessPopup.render();
-
- window.onload = () => {
- checkNostrExtension({
- window,
- successCallback: () => {
- console.log('Nostr extension present');
- },
- failureCallback: () => {
- console.log('Nostr extension not present');
- signupButton.disable();
- noExtensionWarning.display();
- },
- });
- };
-};
-
-invitesFunction();
diff --git a/src/front/pages/login.js b/src/front/pages/login.js
deleted file mode 100644
index 5620a99..0000000
--- a/src/front/pages/login.js
+++ /dev/null
@@ -1,127 +0,0 @@
-const checkNostrExtension = require('../utils/checkNostrExtension');
-const loginService = require('../services/loginService');
-const WarningDiv = require('../components/WarningDiv');
-const { NostrLoginButton } = require('../components/nostrButtons');
-const PopupNotification = require('../components/PopupNotification');
-const constants = require('../../constants');
-
-const loginFunction = () => {
- const loginButtonArea = document.getElementById('login-button-area');
- const warningsArea = document.getElementById('warnings-area');
-
- const successPopup = new PopupNotification({
- parentElement: document.querySelector('body'),
- id: 'login-success-popup',
- text: '¡Éxito! Te estamos llevando a la app...',
- });
- successPopup.render();
- const nostrLoginButton = new NostrLoginButton({
- parentElement: loginButtonArea,
- id: 'login-button',
- onClickCallback: async () => {
- const verifyResponse = await loginService.requestAndRespondLoginChallenge(
- {
- onRejectedPubKeyCallback: () => {
- nostrRejectedWarning.display();
- },
- onRejectedSignatureCallback: () => {
- nostrRejectedWarning.display();
- },
- }
- );
-
- if (verifyResponse.status === 403) {
- notRegisteredPubkeyWarning.display();
- }
-
- if (verifyResponse.ok) {
- nostrLoginButton.disable();
- successPopup.display();
- setTimeout(() => {
- window.location.href = constants.API_PATHS.home;
- }, constants.DEFAULT_REDIRECT_DELAY);
- }
- },
- });
- nostrLoginButton.render();
-
- const notRegisteredPubkeyWarning = new WarningDiv({
- parentElement: warningsArea,
- id: 'rejected-public-key',
- innerHTML: `
- Ups, esa clave no está registrada en la seca. ¿Quizás estás usando un
- perfil equivocado?
-
`,
- });
- notRegisteredPubkeyWarning.render();
-
- const noExtensionWarning = new WarningDiv({
- parentElement: warningsArea,
- id: 'no-extension-nudges',
- innerHTML: `
- ¡Atención! No se ha encontrado una extensión de Nostr en tu navegador.
- Puedes usar:
-
- Firefox
-
- Alby
-
-
- nos2x-fox
-
- Chrome
-
- Alby
-
-
- nos2x
-
`,
- });
- noExtensionWarning.render();
-
- const nostrRejectedWarning = new WarningDiv({
- parentElement: warningsArea,
- id: 'rejected-nostr-nudges',
- innerHTML: `
- Ups, parece que no has aceptado que usemos tus claves. Si te has
- equivocado, puedes intentarlo de nuevo.
-
`,
- });
- nostrRejectedWarning.render();
-
- window.onload = () => {
- checkNostrExtension({
- window,
- successCallback: () => {
- console.log('Nostr extension present');
- },
- failureCallback: () => {
- console.log('Nostr extension not present');
- nostrLoginButton.disable();
- noExtensionWarning.display();
- },
- });
- };
-};
-
-loginFunction();
diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js
deleted file mode 100644
index 1913e7a..0000000
--- a/src/front/pages/offers.js
+++ /dev/null
@@ -1,694 +0,0 @@
-const formatNumberWithSpaces = require('../utils/formatNumbersWithSpaces');
-const PublishOfferButton = require('../components/PublishOfferButton');
-const BuyOrSellButtonGroup = require('../components/BuyOrSellButtonGroup');
-const PremiumSelector = require('../components/PremiumSelector');
-const PriceDisplay = require('../components/PriceDisplay');
-
-function offersPage() {
- const createOfferEventBus = new EventTarget();
-
- const publishOfferButton = new PublishOfferButton({
- parentElement: document.getElementById('submit-button-area'),
- id: 'button-submit-offer',
- onClickCallback: async () => {
- await publishOffer();
- await myOffers.getOffersFromApi();
- await myOffers.render();
- },
- });
- publishOfferButton.render();
-
- const buyOrSellButtonGroup = new BuyOrSellButtonGroup({
- parentElement: document.getElementById('buy-or-sell-area'),
- id: 'button-group-buy-or-sell',
- });
- buyOrSellButtonGroup.render();
-
- const premiumSelector = new PremiumSelector({
- parentElement: document.getElementById('premium-content-area'),
- id: 'premium-selector-area',
- eventSink: createOfferEventBus,
- });
- premiumSelector.render();
-
- const priceDisplay = new PriceDisplay({
- parentElement: document.getElementById('premium-content-area'),
- id: 'premium-price-display-area',
- premiumProvidingCallback: () => {
- return premiumSelector.getPremium();
- },
- priceProvidingCallback: () => {
- return Math.floor(Math.random() * (95000 - 70000 + 1) + 70000);
- },
- });
- priceDisplay.render();
- createOfferEventBus.addEventListener('premium-changed', () => {
- priceDisplay.updatePrices();
- });
-
- // -----------
- const navbuttonHome = document.getElementById('navbutton-home');
- const navbuttonOffers = document.getElementById('navbutton-offers');
-
- navbuttonHome.addEventListener('click', () => {
- window.location.href = '/home';
- });
-
- navbuttonOffers.addEventListener('click', () => {
- window.location.href = '/offers';
- });
-
- const buttonStartCreateOffer = document.getElementById(
- 'button-start-create-offer'
- );
- const buttonViewMyOffers = document.getElementById('button-view-my-offers');
- const closeOffer = document.getElementById('close-offer');
- const createOfferModalRoot = document.getElementById(
- 'create-offer-modal-root'
- );
- const viewMyOffersRoot = document.getElementById('view-my-offers-root');
-
- const eurAmountInput = document.getElementById('input-eur-amount');
- const btcAmountInput = document.getElementById('input-btc-amount');
-
- const placeInput = document.getElementById('place-input');
- const timeInput = document.getElementById('time-input');
-
- const onchainCheckbox = document.getElementById('onchain-checkbox');
- const lightningCheckbox = document.getElementById('lightning-checkbox');
-
- const btcMethodCheckboxes = [onchainCheckbox, lightningCheckbox];
-
- const myTrustedCheckbox = document.getElementById('my-trusted-checkbox');
- const myTrustedTrustedCheckbox = document.getElementById(
- 'my-trusted-trusted-checkbox'
- );
- const allMembersCheckbox = document.getElementById('all-members-checkbox');
-
- const bigNotesAcceptedCheckbox = document.getElementById(
- 'large-bills-checkbox'
- );
-
- const offerCreatedPopup = document.getElementById(
- 'offer-created-confirmation'
- );
- const offerDeletedPopup = document.getElementById(
- 'offer-deleted-confirmation'
- );
-
- const ownOffersContainer = document.getElementById('own-offers-container');
-
- function toggleCreateOfferModal() {
- createOfferModalRoot.classList.toggle('shown');
- }
-
- function toggleViewMyOffersPanel() {
- viewMyOffersRoot.style.display =
- viewMyOffersRoot.style.display === 'block' ? 'none' : 'block';
- }
-
- function readIntFromEurAmountInput() {
- const eurAmountFieldValue = eurAmountInput.value;
- const regularExpression = /([\d\s]+)/;
- const matchResult = eurAmountFieldValue.match(regularExpression);
-
- if (!matchResult) {
- return null;
- }
-
- const numberString = matchResult[1];
- const cleanInputNumber = parseInt(numberString.replace(/\s/gi, ''));
-
- return cleanInputNumber;
- }
-
- function validateAndFormatEurAmountInput() {
- const cleanInputNumber = readIntFromEurAmountInput();
- eurAmountInput.classList.remove('input-is-valid', 'input-is-invalid');
- if (cleanInputNumber) {
- eurAmountInput.value = formatNumberWithSpaces(cleanInputNumber);
- eurAmountInput.classList.add('input-is-valid');
- return;
- }
-
- eurAmountInput.classList.add('input-is-invalid');
- }
-
- function updateBtcInput() {
- const eurToSatRate = 1021;
- const cleanEurAmount = readIntFromEurAmountInput();
-
- const satsAmount = cleanEurAmount * eurToSatRate;
- const formattedSatsAmount = formatNumberWithSpaces(satsAmount);
- btcAmountInput.value = formattedSatsAmount;
- }
-
- function validateBitcoinMethodCheckboxes(clickedCheckbox) {
- let checkedCount = btcMethodCheckboxes.filter((cb) => cb.checked).length;
- if (checkedCount === 0) {
- clickedCheckbox.checked = true;
- }
- }
-
- function applyTrustCheckboxConstraints(pressedCheckbox) {
- if (pressedCheckbox === myTrustedTrustedCheckbox) {
- console.log('first case!');
- if (!myTrustedTrustedCheckbox.checked && allMembersCheckbox.checked) {
- allMembersCheckbox.checked = false;
- }
- }
-
- if (pressedCheckbox === allMembersCheckbox) {
- console.log('second case!');
- if (!myTrustedTrustedCheckbox.checked && allMembersCheckbox.checked) {
- myTrustedTrustedCheckbox.checked = true;
- }
- }
- }
-
- async function publishOffer() {
- const wants = buyOrSellButtonGroup.wants();
-
- const premium = premiumSelector.getPremium();
- const trade_amount_eur = eurAmountInput.value;
- const location_details = placeInput.value;
- const time_availability_details = timeInput.value;
- const is_onchain_accepted = onchainCheckbox.checked;
- const is_lightning_accepted = lightningCheckbox.checked;
- const show_offer_to_trusted = myTrustedCheckbox.checked;
- const show_offer_to_trusted_trusted = myTrustedTrustedCheckbox.checked;
- const show_offer_to_all_members = allMembersCheckbox.checked;
- const are_big_notes_accepted = bigNotesAcceptedCheckbox.checked;
-
- const offerDetails = {
- wants,
- premium,
- trade_amount_eur,
- location_details,
- time_availability_details,
- is_onchain_accepted,
- is_lightning_accepted,
- show_offer_to_trusted,
- show_offer_to_trusted_trusted,
- show_offer_to_all_members,
- are_big_notes_accepted,
- };
-
- await fetch('/api/offer', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({ offerDetails }),
- });
-
- toggleOfferCreatedAlert();
-
- toggleCreateOfferModal();
- }
-
- function toggleOfferCreatedAlert() {
- offerCreatedPopup.classList.remove('max-size-zero');
- offerCreatedPopup.classList.add('revealed');
- setTimeout(() => {
- offerCreatedPopup.classList.remove('revealed');
- }, 3000);
- setTimeout(() => {
- offerCreatedPopup.classList.add('max-size-zero');
- }, 4000);
- }
-
- function toggleOfferDeletedAlert() {
- offerDeletedPopup.classList.remove('max-size-zero');
- offerDeletedPopup.classList.add('revealed');
- setTimeout(() => {
- offerDeletedPopup.classList.remove('revealed');
- }, 3000);
- setTimeout(() => {
- offerDeletedPopup.classList.add('max-size-zero');
- }, 4000);
- }
-
- class Offer {
- constructor(offerData) {
- this.uuid = offerData.uuid;
- this.public_key = offerData.public_key;
- this.wants = offerData.wants;
- this.premium = offerData.premium;
- this.trade_amount_eur = offerData.trade_amount_eur;
- this.location_details = offerData.location_details;
- this.time_availability_details = offerData.time_availability_details;
- this.show_offer_to_trusted = offerData.show_offer_to_trusted;
- this.show_offer_to_trusted_trusted =
- offerData.show_offer_to_trusted_trusted;
- this.show_offer_to_all_members = offerData.show_offer_to_all_members;
- this.is_onchain_accepted = offerData.is_onchain_accepted;
- this.is_lightning_accepted = offerData.is_lightning_accepted;
- this.are_big_notes_accepted = offerData.are_big_notes_accepted;
- this.created_at = offerData.created_at;
- this.last_updated_at = offerData.last_updated_at;
- }
-
- buildHTML() {
- const offerCard = document.createElement('div');
- offerCard.classList.add('myoffer-card');
- offerCard.classList.add('shadowed-round-area');
-
- const tradeDescDiv = document.createElement('div');
- tradeDescDiv.classList.add('trade-desc');
-
- const youBuyText = document.createElement('p');
- youBuyText.classList.add('offer-card-content-title');
- youBuyText.innerText = 'Compras';
- tradeDescDiv.append(youBuyText);
-
- const youBuyData = document.createElement('p');
- youBuyData.classList.add('offer-card-content-data');
- if (this.wants === 'BTC') {
- youBuyData.innerText = `${this.trade_amount_eur * 1021} sats`;
- }
- if (this.wants === 'EUR') {
- youBuyData.innerText = `${this.trade_amount_eur} €`;
- }
- tradeDescDiv.append(youBuyData);
-
- const youSellText = document.createElement('p');
- youSellText.id = 'you-sell-title';
- youSellText.classList.add('offer-card-content-title');
- youSellText.innerText = 'Vendes';
- tradeDescDiv.append(youSellText);
-
- const youSellData = document.createElement('p');
- youSellData.classList.add('offer-card-content-data');
- if (this.wants === 'BTC') {
- youSellData.innerText = `${this.trade_amount_eur} €`;
- }
- if (this.wants === 'EUR') {
- youSellData.innerText = `${this.trade_amount_eur * 1021} sats`;
- }
- tradeDescDiv.append(youSellData);
-
- const premiumDescDiv = document.createElement('div');
- premiumDescDiv.classList.add('premium-desc');
-
- const premiumTitle = document.createElement('p');
- premiumTitle.classList.add('offer-card-content-title');
- premiumTitle.innerText = 'Premium';
- premiumDescDiv.append(premiumTitle);
-
- const premiumData = document.createElement('p');
- premiumData.classList.add('offer-card-content-data');
- premiumData.innerText = `${this.premium * 100} %`;
- premiumDescDiv.append(premiumData);
-
- const offerPriceTitle = document.createElement('p');
- offerPriceTitle.classList.add('offer-card-content-title');
- offerPriceTitle.innerText = 'Precio oferta';
- premiumDescDiv.append(offerPriceTitle);
-
- const offerPriceData = document.createElement('p');
- offerPriceData.classList.add('offer-card-content-data');
- offerPriceData.innerText = `90000 €/BTC`;
- premiumDescDiv.append(offerPriceData);
-
- const marketPriceTitle = document.createElement('p');
- marketPriceTitle.classList.add('offer-card-content-title');
- marketPriceTitle.innerText = 'Precio mercado';
- premiumDescDiv.append(marketPriceTitle);
-
- const marketPriceData = document.createElement('p');
- marketPriceData.innerText = `88000 €/BTC`;
- premiumDescDiv.append(marketPriceData);
-
- const whereDescDiv = document.createElement('div');
- whereDescDiv.classList.add('where-desc');
-
- const whereDescTitle = document.createElement('p');
- whereDescTitle.classList.add('offer-card-content-title');
- whereDescTitle.innerText = 'Dónde';
- whereDescDiv.append(whereDescTitle);
-
- const whereDescData = document.createElement('p');
- whereDescData.classList.add('offer-long-text');
- whereDescData.innerText = `${this.location_details}`;
- whereDescDiv.append(whereDescData);
-
- const whenDescDiv = document.createElement('div');
- whenDescDiv.classList.add('when-desc');
-
- const whenDescTitle = document.createElement('p');
- whenDescTitle.classList.add('offer-card-content-title');
- whenDescTitle.innerText = 'Cúando';
- whenDescDiv.append(whenDescTitle);
-
- const whenDescData = document.createElement('p');
- whenDescData.classList.add('offer-long-text');
- whenDescData.innerText = `${this.time_availability_details}`;
- whenDescDiv.append(whenDescData);
-
- const bitcoinMethodsDiv = document.createElement('div');
- bitcoinMethodsDiv.classList.add('bitcoin-methods-desc');
-
- const bitcoinMethodsTitle = document.createElement('p');
- bitcoinMethodsTitle.classList.add('offer-card-content-title');
- bitcoinMethodsTitle.innerText = 'Protocolos Bitcoin aceptados';
- bitcoinMethodsDiv.append(bitcoinMethodsTitle);
-
- const onchainAcceptedContainer = document.createElement('div');
- onchainAcceptedContainer.classList.add('left-icon-checkboxed-field');
- if (this.is_onchain_accepted) {
- const onchainIcon = document.createElement('img');
- onchainIcon.src = '/img/chains-lasecagold.svg';
- const onchainText = document.createElement('p');
- onchainText.innerText = 'Onchain';
- const checkIcon = document.createElement('img');
- checkIcon.src = '/img/circle-check-green.svg';
-
- onchainAcceptedContainer.append(onchainIcon, onchainText, checkIcon);
- } else {
- const onchainIcon = document.createElement('img');
- onchainIcon.src = '/img/chains-gray.svg';
- const onchainText = document.createElement('p');
- onchainText.innerText = 'Onchain';
- const checkIcon = document.createElement('img');
- checkIcon.src = '/img/circle-xmark-gray.svg';
-
- onchainAcceptedContainer.append(onchainIcon, onchainText, checkIcon);
- }
- const lightningAcceptedContainer = document.createElement('div');
-
- lightningAcceptedContainer.classList.add('left-icon-checkboxed-field');
- if (this.is_lightning_accepted) {
- const lightningIcon = document.createElement('img');
- lightningIcon.src = '/img/bolt-lightning-lasecagold.svg';
- const lightningText = document.createElement('p');
- lightningText.innerText = 'Lightning';
- const checkIcon = document.createElement('img');
- checkIcon.src = '/img/circle-check-green.svg';
-
- lightningAcceptedContainer.append(
- lightningIcon,
- lightningText,
- checkIcon
- );
- } else {
- const lightningIcon = document.createElement('img');
- lightningIcon.src = '/img/bolt-lightning-gray.svg';
- const lightningText = document.createElement('p');
- lightningText.innerText = 'Lightning';
- const checkIcon = document.createElement('img');
- checkIcon.src = '/img/circle-xmark-gray.svg';
-
- lightningAcceptedContainer.append(
- lightningIcon,
- lightningText,
- checkIcon
- );
- }
-
- bitcoinMethodsDiv.append(
- onchainAcceptedContainer,
- lightningAcceptedContainer
- );
-
- const visibilityDiv = document.createElement('div');
- visibilityDiv.classList.add('visibility-desc');
-
- const visibilityTitle = document.createElement('p');
- visibilityTitle.classList.add('offer-card-content-title');
- visibilityTitle.innerText = 'Visibilidad';
- visibilityDiv.append(visibilityTitle);
-
- const showOfferToTrustedContainer = document.createElement('div');
- showOfferToTrustedContainer.classList.add('right-icon-checkboxed-field');
-
- if (this.show_offer_to_trusted) {
- const showOfferToTrustedIcon = document.createElement('img');
- showOfferToTrustedIcon.src = '/img/user-lasecagold.svg';
- const showOfferToTrustedText = document.createElement('p');
- showOfferToTrustedText.innerText = 'Confiados';
- const checkIcon = document.createElement('img');
- checkIcon.src = '/img/circle-check-green.svg';
-
- showOfferToTrustedContainer.append(
- showOfferToTrustedIcon,
- showOfferToTrustedText,
- checkIcon
- );
- } else {
- const showOfferToTrustedIcon = document.createElement('img');
- showOfferToTrustedIcon.src = '/img/user-gray.svg';
- const showOfferToTrustedText = document.createElement('p');
- showOfferToTrustedText.innerText = 'Confiados';
- const checkIcon = document.createElement('img');
- checkIcon.src = '/img/circle-xmark-gray.svg';
-
- showOfferToTrustedContainer.append(
- showOfferToTrustedIcon,
- showOfferToTrustedText,
- checkIcon
- );
- }
-
- const showOfferToTrustedTrustedContainer = document.createElement('div');
- showOfferToTrustedTrustedContainer.classList.add(
- 'right-icon-checkboxed-field'
- );
-
- if (this.show_offer_to_trusted_trusted) {
- const showOfferToTrustedTrustedIcon = document.createElement('img');
- showOfferToTrustedTrustedIcon.src = '/img/user-group-lasecagold.svg';
- const showOfferToTrustedTrustedText = document.createElement('p');
- showOfferToTrustedTrustedText.innerText = 'Sus confiados';
- const checkIcon = document.createElement('img');
- checkIcon.src = '/img/circle-check-green.svg';
-
- showOfferToTrustedTrustedContainer.append(
- showOfferToTrustedTrustedIcon,
- showOfferToTrustedTrustedText,
- checkIcon
- );
- } else {
- const showOfferToTrustedTrustedIcon = document.createElement('img');
- showOfferToTrustedTrustedIcon.src = '/img/user-group-gray.svg';
- const showOfferToTrustedTrustedText = document.createElement('p');
- showOfferToTrustedTrustedText.innerText = 'Sus confiados';
- const checkIcon = document.createElement('img');
- checkIcon.src = '/img/circle-xmark-gray.svg';
-
- showOfferToTrustedTrustedContainer.append(
- showOfferToTrustedTrustedIcon,
- showOfferToTrustedTrustedText,
- checkIcon
- );
- }
-
- const showOfferToAllMembersContainer = document.createElement('div');
- showOfferToAllMembersContainer.classList.add(
- 'right-icon-checkboxed-field'
- );
-
- if (this.show_offer_to_all_members) {
- const showOfferToAllMembersIcon = document.createElement('img');
- showOfferToAllMembersIcon.src = '/img/many-users-lasecagold.svg';
- const showOfferToAllMembersText = document.createElement('p');
- showOfferToAllMembersText.innerText = 'Todos';
- const checkIcon = document.createElement('img');
- checkIcon.src = '/img/circle-check-green.svg';
-
- showOfferToAllMembersContainer.append(
- showOfferToAllMembersIcon,
- showOfferToAllMembersText,
- checkIcon
- );
- } else {
- const showOfferToAllMembersIcon = document.createElement('img');
- showOfferToAllMembersIcon.src = '/img/many-users-gray.svg';
- const showOfferToAllMembersText = document.createElement('p');
- showOfferToAllMembersText.innerText = 'Todos';
- const checkIcon = document.createElement('img');
- checkIcon.src = '/img/circle-xmark-gray.svg';
-
- showOfferToAllMembersContainer.append(
- showOfferToAllMembersIcon,
- showOfferToAllMembersText,
- checkIcon
- );
- }
- visibilityDiv.append(
- showOfferToTrustedContainer,
- showOfferToTrustedTrustedContainer,
- showOfferToAllMembersContainer
- );
-
- const otherOfferFeaturesDiv = document.createElement('div');
- otherOfferFeaturesDiv.classList.add('other-desc');
-
- const otherOfferFeaturesTitle = document.createElement('p');
- otherOfferFeaturesTitle.classList.add('offer-card-content-title');
- otherOfferFeaturesTitle.innerText = 'Otros';
- otherOfferFeaturesDiv.append(otherOfferFeaturesTitle);
-
- const areBigNotesAcceptedContainer = document.createElement('div');
- areBigNotesAcceptedContainer.classList.add('left-icon-checkboxed-field');
-
- if (this.are_big_notes_accepted) {
- const areBigNotesAcceptedIcon = document.createElement('img');
- areBigNotesAcceptedIcon.src = '/img/eur-bill-lasecagold.svg';
- const areBigNotesAcceptedText = document.createElement('p');
- areBigNotesAcceptedText.innerText = 'Billetes grandes';
- const checkIcon = document.createElement('img');
- checkIcon.src = '/img/circle-check-green.svg';
-
- areBigNotesAcceptedContainer.append(
- areBigNotesAcceptedIcon,
- areBigNotesAcceptedText,
- checkIcon
- );
- } else {
- const areBigNotesAcceptedIcon = document.createElement('img');
- areBigNotesAcceptedIcon.src = '/img/eur-bill-gray.svg';
- const areBigNotesAcceptedText = document.createElement('p');
- areBigNotesAcceptedText.innerText = 'Billetes grandes';
- const checkIcon = document.createElement('img');
- checkIcon.src = '/img/circle-xmark-gray.svg';
-
- areBigNotesAcceptedContainer.append(
- areBigNotesAcceptedIcon,
- areBigNotesAcceptedText,
- checkIcon
- );
- }
-
- otherOfferFeaturesDiv.append(areBigNotesAcceptedContainer);
-
- const actionButtonsArea = document.createElement('p');
- actionButtonsArea.classList.add('offer-action-buttons-area');
-
- const editActionArea = document.createElement('div');
- editActionArea.classList.add('offer-action-area');
- editActionArea.classList.add('subtle-box');
- const editActionIcon = document.createElement('img');
- editActionIcon.src = '/img/edit.svg';
- const editActionText = document.createElement('p');
- editActionText.innerText = 'Editar';
- editActionArea.append(editActionIcon, editActionText);
-
- const deleteActionArea = document.createElement('div');
- deleteActionArea.classList.add('offer-action-area');
- deleteActionArea.classList.add('subtle-box');
- const deleteActionIcon = document.createElement('img');
- deleteActionIcon.src = '/img/trash-can-darkred.svg';
- const deleteActionText = document.createElement('p');
- deleteActionText.innerText = 'Eliminar';
- deleteActionArea.append(deleteActionIcon, deleteActionText);
- deleteActionArea.addEventListener('click', async () => {
- await deleteOfferByUuid(this.uuid);
- await myOffers.getOffersFromApi();
- await myOffers.render();
- toggleOfferDeletedAlert();
- });
-
- actionButtonsArea.append(editActionArea, deleteActionArea);
-
- offerCard.append(
- tradeDescDiv,
- premiumDescDiv,
- whereDescDiv,
- whenDescDiv,
- bitcoinMethodsDiv,
- visibilityDiv,
- otherOfferFeaturesDiv,
- actionButtonsArea
- );
-
- return offerCard;
- }
- }
-
- class MyOffers {
- constructor(ownOffersContainerElement) {
- this.ownOffersContainerElement = ownOffersContainerElement;
- this.offers = [];
- }
-
- async getOffersFromApi() {
- const offersResponse = await fetch('/api/publickey-offers');
-
- this.offers = [];
-
- const offersData = (await offersResponse.json()).data;
- if (offersResponse.ok) {
- for (const record of offersData) {
- this.offers.push(new Offer(record));
- }
- }
- }
-
- async render() {
- if (this.offers.length === 0) {
- this.ownOffersContainerElement.innerHTML =
- 'Vaya, no hay nada por aquí...
';
- return;
- }
- this.ownOffersContainerElement.innerHTML = '';
-
- for (const someOffer of this.offers) {
- this.ownOffersContainerElement.append(someOffer.buildHTML());
- }
- }
- }
-
- async function deleteOfferByUuid(offerUuid) {
- await fetch(`/api/offer/${offerUuid}`, {
- method: 'DELETE',
- headers: {
- 'Content-Type': 'application/json',
- },
- });
- }
-
- buttonStartCreateOffer.addEventListener('click', () => {
- toggleCreateOfferModal();
- });
-
- buttonViewMyOffers.addEventListener('click', async () => {
- await myOffers.getOffersFromApi();
- await myOffers.render();
- toggleViewMyOffersPanel();
- });
-
- closeOffer.addEventListener('click', () => {
- toggleCreateOfferModal();
- });
-
- eurAmountInput.addEventListener('blur', () => {
- validateAndFormatEurAmountInput();
- updateBtcInput();
- });
-
- eurAmountInput.addEventListener('input', () => {
- eurAmountInput.value = eurAmountInput.value.replace(/[^0-9]/g, '');
- updateBtcInput();
- });
-
- for (const btcMethodCheckbox of btcMethodCheckboxes) {
- btcMethodCheckbox.addEventListener('click', () => {
- validateBitcoinMethodCheckboxes(btcMethodCheckbox);
- });
- }
-
- myTrustedTrustedCheckbox.addEventListener('click', () => {
- applyTrustCheckboxConstraints(myTrustedTrustedCheckbox);
- });
-
- allMembersCheckbox.addEventListener('click', () => {
- applyTrustCheckboxConstraints(allMembersCheckbox);
- });
-
- updateBtcInput();
-
- const myOffers = new MyOffers(ownOffersContainer);
-}
-
-offersPage();
diff --git a/src/front/utils/checkNostrExtension.js b/src/front/utils/checkNostrExtension.js
deleted file mode 100644
index b16d293..0000000
--- a/src/front/utils/checkNostrExtension.js
+++ /dev/null
@@ -1,9 +0,0 @@
-function checkNostrExtension({ window, successCallback, failureCallback }) {
- if (!window.nostr) {
- failureCallback();
- } else {
- successCallback();
- }
-}
-
-module.exports = checkNostrExtension;
diff --git a/src/middlewares/attachPublicKeyMiddleware.js b/src/middlewares/attachPublicKeyMiddleware.js
index 05c7758..c6ad835 100644
--- a/src/middlewares/attachPublicKeyMiddleware.js
+++ b/src/middlewares/attachPublicKeyMiddleware.js
@@ -1,20 +1,14 @@
-class AttachPublicKeyMiddlewareProvider {
- constructor({ sessionService }) {
- this.sessionService = sessionService;
- }
+const sessionService = require('../services/sessionService');
- provide() {
- return async (req, res, next) => {
- const publicKey = await this.sessionService.getPublicKeyRelatedToSession(
- req.cookies.sessionUuid
- );
+async function attachPublicKeyMiddleware(req, res, next) {
+ const publicKey = await sessionService.getPublicKeyRelatedToSession(
+ req.cookies.sessionUuid
+ );
- if (publicKey) {
- req.cookies.publicKey = publicKey;
- }
- next();
- };
+ if (publicKey) {
+ req.cookies.publicKey = publicKey;
}
+ next();
}
-module.exports = AttachPublicKeyMiddlewareProvider;
+module.exports = attachPublicKeyMiddleware;
diff --git a/src/middlewares/createSessionMiddleware.js b/src/middlewares/createSessionMiddleware.js
deleted file mode 100644
index 53e15dd..0000000
--- a/src/middlewares/createSessionMiddleware.js
+++ /dev/null
@@ -1,39 +0,0 @@
-const uuid = require('uuid');
-
-class CreateSessionMiddlewareProvider {
- constructor({ constants, sessionService }) {
- this.constants = constants;
- this.sessionService = sessionService;
- }
-
- provide() {
- return async (req, res, next) => {
- const sessionUuid = req.cookies.sessionUuid;
-
- if (!sessionUuid) {
- const newSession = await this.setAndPersistNewSession(res);
- req.cookies.sessionUuid = newSession.uuid;
- }
-
- if (sessionUuid) {
- if (!(await this.sessionService.isSessionValid(sessionUuid))) {
- const newSession = await this.setAndPersistNewSession(res);
- req.cookies.sessionUuid = newSession.uuid;
- }
- }
-
- next();
- };
- }
-
- async setAndPersistNewSession(res) {
- const sessionUuid = uuid.v7();
- res.cookie('sessionUuid', sessionUuid, {
- httpOnly: true,
- maxAge: this.constants.DEFAULT_SESSION_DURATION_SECONDS * 1000,
- });
- return await this.sessionService.createSession(sessionUuid);
- }
-}
-
-module.exports = CreateSessionMiddlewareProvider;
diff --git a/src/middlewares/index.js b/src/middlewares/index.js
deleted file mode 100644
index 1a316a1..0000000
--- a/src/middlewares/index.js
+++ /dev/null
@@ -1,55 +0,0 @@
-class MiddlewaresProvider {
- constructor({ constants, sessionService, profileService }) {
- this.constants = constants;
- this.sessionService = sessionService;
- this.profileService = profileService;
- }
-
- provide() {
- const AttachPublicKeyMiddlewareProvider = require('./attachPublicKeyMiddleware');
- const attachPublicKeyMiddleware = new AttachPublicKeyMiddlewareProvider({
- sessionService: this.sessionService,
- }).provide();
-
- const CreateSessionMiddlewareProvider = require('./createSessionMiddleware');
- const createSessionMiddleware = new CreateSessionMiddlewareProvider({
- constants: this.constants,
- sessionService: this.sessionService,
- }).provide();
-
- const RejectIfNotAuthorizedMiddleware = require('./rejectIfNotAuthorizedMiddleware');
- const rejectIfNotAuthorizedMiddleware = new RejectIfNotAuthorizedMiddleware(
- {
- sessionService: this.sessionService,
- }
- ).provide();
-
- const RedirectHomeIfAuthorized = require('./redirectHomeIfAuthorized');
- const redirectHomeIfAuthorized = new RedirectHomeIfAuthorized({
- sessionService: this.sessionService,
- }).provide();
-
- const RedirectIfNotAuthorizedMiddleware = require('./redirectIfNotAuthorizedMiddleware');
- const redirectIfNotAuthorizedMiddleware =
- new RedirectIfNotAuthorizedMiddleware({
- sessionService: this.sessionService,
- }).provide();
-
- const RedirectIfMissingProfileDetailsMiddleware = require('./redirectIfMissingProfileDetailsMiddleware');
- const redirectIfMissingProfileDetailsMiddleware =
- new RedirectIfMissingProfileDetailsMiddleware({
- profileService: this.profileService,
- }).provide();
-
- return {
- redirectIfNotAuthorizedMiddleware,
- attachPublicKeyMiddleware,
- redirectIfMissingProfileDetailsMiddleware,
- redirectHomeIfAuthorized,
- rejectIfNotAuthorizedMiddleware,
- createSessionMiddleware,
- };
- }
-}
-
-module.exports = MiddlewaresProvider;
diff --git a/src/middlewares/redirectHomeIfAuthorized.js b/src/middlewares/redirectHomeIfAuthorized.js
index f3aedf2..9619c68 100644
--- a/src/middlewares/redirectHomeIfAuthorized.js
+++ b/src/middlewares/redirectHomeIfAuthorized.js
@@ -1,18 +1,10 @@
-class RedirectHomeIfAuthorized {
- constructor({ sessionService }) {
- this.sessionService = sessionService;
- }
+const sessionService = require('../services/sessionService');
- provide() {
- return async (req, res, next) => {
- if (
- await this.sessionService.isSessionAuthorized(req.cookies.sessionUuid)
- ) {
- return res.redirect('/home');
- }
- next();
- };
+async function redirectHomeIfAuthorized(req, res, next) {
+ if (await sessionService.isSessionAuthorized(req.cookies.sessionUuid)) {
+ return res.redirect('/home');
}
+ next();
}
-module.exports = RedirectHomeIfAuthorized;
+module.exports = redirectHomeIfAuthorized;
diff --git a/src/middlewares/redirectIfMissingProfileDetailsMiddleware.js b/src/middlewares/redirectIfMissingProfileDetailsMiddleware.js
index d7e758f..934048d 100644
--- a/src/middlewares/redirectIfMissingProfileDetailsMiddleware.js
+++ b/src/middlewares/redirectIfMissingProfileDetailsMiddleware.js
@@ -1,17 +1,12 @@
-class RedirectIfMissingProfileDetailsMiddleware {
- constructor({ profileService }) {
- this.profileService = profileService;
+const profileService = require('../services/profileService');
+
+async function redirectIfMissingProfileDetailsMiddleware(req, res, next) {
+ const publicKey = req.cookies.publicKey;
+ if (!(await profileService.areProfileDetailsComplete(publicKey))) {
+ res.redirect('/createProfile');
}
- provide() {
- return async (req, res, next) => {
- const publicKey = req.cookies.publicKey;
- if (!(await this.profileService.areProfileDetailsComplete(publicKey))) {
- res.redirect('/createProfile');
- }
-
- next();
- };
- }
+ next();
}
-module.exports = RedirectIfMissingProfileDetailsMiddleware;
+
+module.exports = redirectIfMissingProfileDetailsMiddleware;
diff --git a/src/middlewares/redirectIfNotAuthorizedMiddleware.js b/src/middlewares/redirectIfNotAuthorizedMiddleware.js
index 353f21c..f4b9e47 100644
--- a/src/middlewares/redirectIfNotAuthorizedMiddleware.js
+++ b/src/middlewares/redirectIfNotAuthorizedMiddleware.js
@@ -1,20 +1,10 @@
-class RedirectIfNotAuthorizedMiddleware {
- constructor({ sessionService }) {
- this.sessionService = sessionService;
- }
+const sessionService = require('../services/sessionService');
- provide() {
- return async (req, res, next) => {
- if (
- !(await this.sessionService.isSessionAuthorized(
- req.cookies.sessionUuid
- ))
- ) {
- return res.redirect('/login');
- }
- next();
- };
+async function redirectIfNotAuthorizedMiddleware(req, res, next) {
+ if (!(await sessionService.isSessionAuthorized(req.cookies.sessionUuid))) {
+ return res.redirect('/login');
}
+ next();
}
-module.exports = RedirectIfNotAuthorizedMiddleware;
+module.exports = redirectIfNotAuthorizedMiddleware;
diff --git a/src/middlewares/rejectIfNotAuthorizedMiddleware.js b/src/middlewares/rejectIfNotAuthorizedMiddleware.js
index 548830e..85e67ad 100644
--- a/src/middlewares/rejectIfNotAuthorizedMiddleware.js
+++ b/src/middlewares/rejectIfNotAuthorizedMiddleware.js
@@ -1,23 +1,13 @@
-class RejectIfNotAuthorizedMiddleware {
- constructor({ sessionService }) {
- this.sessionService = sessionService;
- }
+const sessionService = require('../services/sessionService');
- provide() {
- return async (req, res, next) => {
- if (
- !(await this.sessionService.isSessionAuthorized(
- req.cookies.sessionUuid
- ))
- ) {
- return res.status(403).json({
- success: false,
- message: 'Your session is not authorized.',
- });
- }
- next();
- };
+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.',
+ });
}
+ next();
}
-module.exports = RejectIfNotAuthorizedMiddleware;
+module.exports = rejectIfNotAuthorizedMiddleware;
diff --git a/src/middlewares/sessionMiddleware.js b/src/middlewares/sessionMiddleware.js
new file mode 100644
index 0000000..8d181d6
--- /dev/null
+++ b/src/middlewares/sessionMiddleware.js
@@ -0,0 +1,33 @@
+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,
+ });
+ 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) {
+ if (!(await sessionService.isSessionValid(sessionUuid))) {
+ const newSession = await setAndPersistNewSession(res);
+ req.cookies.sessionUuid = newSession.uuid;
+ }
+ }
+
+ next();
+}
+
+module.exports = createSessionMiddleware;
diff --git a/src/models/AppInviteCreated.js b/src/models/AppInviteCreated.js
index 4062fb5..49967b3 100644
--- a/src/models/AppInviteCreated.js
+++ b/src/models/AppInviteCreated.js
@@ -1,34 +1,27 @@
-class AppInviteCreatedProvider {
- constructor({ sequelize, DataTypes }) {
- this.sequelize = sequelize;
- this.DataTypes = DataTypes;
- }
+const { DataTypes } = require('sequelize');
+const sequelize = require('../database');
- provide() {
- const AppInviteCreated = this.sequelize.define(
- 'AppInviteCreated',
- {
- uuid: {
- type: this.DataTypes.UUID,
- allowNull: false,
- unique: true,
- primaryKey: true,
- },
- inviter_pub_key: {
- type: this.DataTypes.STRING,
- allowNull: false,
- },
- created_at: {
- type: this.DataTypes.DATE,
- allowNull: false,
- },
- },
- {
- tableName: 'app_invite_created',
- }
- );
- return AppInviteCreated;
+const AppInviteCreated = sequelize.define(
+ 'AppInviteCreated',
+ {
+ uuid: {
+ type: DataTypes.UUID,
+ allowNull: false,
+ unique: true,
+ primaryKey: true,
+ },
+ inviter_pub_key: {
+ type: DataTypes.STRING,
+ allowNull: false,
+ },
+ created_at: {
+ type: DataTypes.DATE,
+ allowNull: false,
+ },
+ },
+ {
+ tableName: 'app_invite_created',
}
-}
+);
-module.exports = AppInviteCreatedProvider;
+module.exports = AppInviteCreated;
diff --git a/src/models/ContactDetailsSet.js b/src/models/ContactDetailsSet.js
index 4a1a6a1..8722e89 100644
--- a/src/models/ContactDetailsSet.js
+++ b/src/models/ContactDetailsSet.js
@@ -1,38 +1,31 @@
-class ContactDetailsSetProvider {
- constructor({ sequelize, DataTypes }) {
- this.sequelize = sequelize;
- this.DataTypes = DataTypes;
- }
+const { DataTypes } = require('sequelize');
+const sequelize = require('../database');
- provide() {
- const ContactDetailsSet = this.sequelize.define(
- 'ContactDetailsSet',
- {
- uuid: {
- type: this.DataTypes.UUID,
- allowNull: false,
- unique: true,
- primaryKey: true,
- },
- public_key: {
- type: this.DataTypes.STRING,
- allowNull: false,
- },
- encrypted_contact_details: {
- type: this.DataTypes.TEXT,
- allowNull: false,
- },
- created_at: {
- type: this.DataTypes.DATE,
- allowNull: false,
- },
- },
- {
- tableName: 'contact_details_set',
- }
- );
- return ContactDetailsSet;
+const ContactDetailsSet = sequelize.define(
+ 'ContactDetailsSet',
+ {
+ uuid: {
+ type: DataTypes.UUID,
+ allowNull: false,
+ unique: true,
+ primaryKey: true,
+ },
+ public_key: {
+ type: DataTypes.STRING,
+ allowNull: false,
+ },
+ encrypted_contact_details: {
+ type: DataTypes.TEXT,
+ allowNull: false,
+ },
+ created_at: {
+ type: DataTypes.DATE,
+ allowNull: false,
+ },
+ },
+ {
+ tableName: 'contact_details_set',
}
-}
+);
-module.exports = ContactDetailsSetProvider;
+module.exports = ContactDetailsSet;
diff --git a/src/models/LoginChallengeCompleted.js b/src/models/LoginChallengeCompleted.js
index bce56e8..b4774bb 100644
--- a/src/models/LoginChallengeCompleted.js
+++ b/src/models/LoginChallengeCompleted.js
@@ -1,38 +1,31 @@
-class LoginChallengeCompletedProvider {
- constructor({ sequelize, DataTypes }) {
- this.sequelize = sequelize;
- this.DataTypes = DataTypes;
- }
+const { DataTypes } = require('sequelize');
+const sequelize = require('../database');
- provide() {
- const LoginChallengeCompleted = this.sequelize.define(
- 'LoginChallengeCompleted',
- {
- uuid: {
- type: this.DataTypes.UUID,
- allowNull: false,
- unique: true,
- primaryKey: true,
- },
- nostr_challenge_completed_uuid: {
- type: this.DataTypes.UUID,
- allowNull: false,
- },
- public_key: {
- type: this.DataTypes.STRING,
- allowNull: false,
- },
- created_at: {
- type: this.DataTypes.DATE,
- allowNull: false,
- },
- },
- {
- tableName: 'login_challenge_completed',
- }
- );
- return LoginChallengeCompleted;
+const LoginChallengeCompleted = sequelize.define(
+ 'LoginChallengeCompleted',
+ {
+ uuid: {
+ type: DataTypes.UUID,
+ allowNull: false,
+ unique: true,
+ primaryKey: true,
+ },
+ nostr_challenge_completed_uuid: {
+ type: DataTypes.UUID,
+ allowNull: false,
+ },
+ public_key: {
+ type: DataTypes.STRING,
+ allowNull: false,
+ },
+ created_at: {
+ type: DataTypes.DATE,
+ allowNull: false,
+ },
+ },
+ {
+ tableName: 'login_challenge_completed',
}
-}
+);
-module.exports = LoginChallengeCompletedProvider;
+module.exports = LoginChallengeCompleted;
diff --git a/src/models/LoginChallengeCreated.js b/src/models/LoginChallengeCreated.js
index 3d29c16..c1c1792 100644
--- a/src/models/LoginChallengeCreated.js
+++ b/src/models/LoginChallengeCreated.js
@@ -1,34 +1,27 @@
-class LoginChallengeCreatedProvider {
- constructor({ sequelize, DataTypes }) {
- this.sequelize = sequelize;
- this.DataTypes = DataTypes;
- }
+const { DataTypes } = require('sequelize');
+const sequelize = require('../database');
- provide() {
- const LoginChallengeCreated = this.sequelize.define(
- 'LoginChallengeCreated',
- {
- uuid: {
- type: this.DataTypes.UUID,
- allowNull: false,
- unique: true,
- primaryKey: true,
- },
- nostr_challenge_uuid: {
- type: this.DataTypes.UUID,
- allowNull: false,
- },
- created_at: {
- type: this.DataTypes.DATE,
- allowNull: false,
- },
- },
- {
- tableName: 'login_challenge_created',
- }
- );
- return LoginChallengeCreated;
+const LoginChallengeCreated = sequelize.define(
+ 'LoginChallengeCreated',
+ {
+ uuid: {
+ type: DataTypes.UUID,
+ allowNull: false,
+ unique: true,
+ primaryKey: true,
+ },
+ nostr_challenge_uuid: {
+ type: DataTypes.UUID,
+ allowNull: false,
+ },
+ created_at: {
+ type: DataTypes.DATE,
+ allowNull: false,
+ },
+ },
+ {
+ tableName: 'login_challenge_created',
}
-}
+);
-module.exports = LoginChallengeCreatedProvider;
+module.exports = LoginChallengeCreated;
diff --git a/src/models/NostrChallengeCompleted.js b/src/models/NostrChallengeCompleted.js
index e569097..a656edd 100644
--- a/src/models/NostrChallengeCompleted.js
+++ b/src/models/NostrChallengeCompleted.js
@@ -1,43 +1,35 @@
-class NostrChallengeCompletedProvider {
- constructor({ sequelize, DataTypes }) {
- this.sequelize = sequelize;
- this.DataTypes = DataTypes;
- }
+const { DataTypes } = require('sequelize');
+const sequelize = require('../database');
- provide() {
- const NostrChallengeCompleted = this.sequelize.define(
- 'NostrChallengeCompleted',
- {
- uuid: {
- type: this.DataTypes.UUID,
- allowNull: false,
- unique: true,
- primaryKey: true,
- },
- challenge: {
- type: this.DataTypes.STRING,
- allowNull: false,
- unique: true,
- },
- signed_event: {
- type: this.DataTypes.JSONB,
- allowNull: false,
- },
- public_key: {
- type: this.DataTypes.STRING,
- allowNull: false,
- },
- created_at: {
- type: this.DataTypes.DATE,
- allowNull: false,
- },
- },
- {
- tableName: 'nostr_challenge_completed',
- }
- );
- return NostrChallengeCompleted;
+const NostrChallengeCompleted = sequelize.define(
+ 'NostrChallengeCompleted',
+ {
+ uuid: {
+ type: DataTypes.UUID,
+ allowNull: false,
+ unique: true,
+ primaryKey: true,
+ },
+ challenge: {
+ type: DataTypes.STRING,
+ allowNull: false,
+ },
+ signed_event: {
+ type: DataTypes.JSONB,
+ allowNull: false,
+ },
+ public_key: {
+ type: DataTypes.STRING,
+ allowNull: false,
+ },
+ created_at: {
+ type: DataTypes.DATE,
+ allowNull: false,
+ },
+ },
+ {
+ tableName: 'nostr_challenge_completed',
}
-}
+);
-module.exports = NostrChallengeCompletedProvider;
+module.exports = NostrChallengeCompleted;
diff --git a/src/models/NostrChallengeCreated.js b/src/models/NostrChallengeCreated.js
index f35ddc7..97a4c64 100644
--- a/src/models/NostrChallengeCreated.js
+++ b/src/models/NostrChallengeCreated.js
@@ -1,39 +1,31 @@
-class NostrChallengeCreatedProvider {
- constructor({ sequelize, DataTypes }) {
- this.sequelize = sequelize;
- this.DataTypes = DataTypes;
- }
+const { DataTypes } = require('sequelize');
+const sequelize = require('../database');
- provide() {
- const NostrChallengeCreated = this.sequelize.define(
- 'NostrChallengeCreated',
- {
- uuid: {
- type: this.DataTypes.UUID,
- allowNull: false,
- unique: true,
- primaryKey: true,
- },
- challenge: {
- type: this.DataTypes.STRING,
- allowNull: false,
- unique: true,
- },
- expires_at: {
- type: this.DataTypes.DATE,
- allowNull: false,
- },
- created_at: {
- type: this.DataTypes.DATE,
- allowNull: false,
- },
- },
- {
- tableName: 'nostr_challenge_created',
- }
- );
- return NostrChallengeCreated;
+const NostrChallengeCreated = sequelize.define(
+ 'NostrChallengeCreated',
+ {
+ uuid: {
+ type: DataTypes.UUID,
+ allowNull: false,
+ unique: true,
+ primaryKey: true,
+ },
+ challenge: {
+ type: DataTypes.STRING,
+ allowNull: false,
+ },
+ expires_at: {
+ type: DataTypes.DATE,
+ allowNull: false,
+ },
+ created_at: {
+ type: DataTypes.DATE,
+ allowNull: false,
+ },
+ },
+ {
+ tableName: 'nostr_challenge_created',
}
-}
+);
-module.exports = NostrChallengeCreatedProvider;
+module.exports = NostrChallengeCreated;
diff --git a/src/models/NymSet.js b/src/models/NymSet.js
index 4a9f26e..d59a310 100644
--- a/src/models/NymSet.js
+++ b/src/models/NymSet.js
@@ -1,38 +1,31 @@
-class NymSetProvider {
- constructor({ sequelize, DataTypes }) {
- this.sequelize = sequelize;
- this.DataTypes = DataTypes;
- }
+const { DataTypes } = require('sequelize');
+const sequelize = require('../database');
- provide() {
- const NymSet = this.sequelize.define(
- 'NymSet',
- {
- uuid: {
- type: this.DataTypes.UUID,
- allowNull: false,
- unique: true,
- primaryKey: true,
- },
- public_key: {
- type: this.DataTypes.STRING,
- allowNull: false,
- },
- nym: {
- type: this.DataTypes.TEXT,
- allowNull: false,
- },
- created_at: {
- type: this.DataTypes.DATE,
- allowNull: false,
- },
- },
- {
- tableName: 'nym_set',
- }
- );
- return NymSet;
+const NymSet = sequelize.define(
+ 'NymSet',
+ {
+ uuid: {
+ type: DataTypes.UUID,
+ allowNull: false,
+ unique: true,
+ primaryKey: true,
+ },
+ public_key: {
+ type: DataTypes.STRING,
+ allowNull: false,
+ },
+ nym: {
+ type: DataTypes.TEXT,
+ allowNull: false,
+ },
+ created_at: {
+ type: DataTypes.DATE,
+ allowNull: false,
+ },
+ },
+ {
+ tableName: 'nym_set',
}
-}
+);
-module.exports = NymSetProvider;
+module.exports = NymSet;
diff --git a/src/models/OfferCreated.js b/src/models/OfferCreated.js
index 13eeb54..fd67249 100644
--- a/src/models/OfferCreated.js
+++ b/src/models/OfferCreated.js
@@ -1,34 +1,27 @@
-class OfferCreatedProvider {
- constructor({ sequelize, DataTypes }) {
- this.sequelize = sequelize;
- this.DataTypes = DataTypes;
- }
+const { DataTypes } = require('sequelize');
+const sequelize = require('../database');
- provide() {
- const OfferCreated = this.sequelize.define(
- 'OfferCreated',
- {
- uuid: {
- type: this.DataTypes.UUID,
- allowNull: false,
- unique: true,
- primaryKey: true,
- },
- public_key: {
- type: this.DataTypes.STRING,
- allowNull: false,
- },
- created_at: {
- type: this.DataTypes.DATE,
- allowNull: false,
- },
- },
- {
- tableName: 'offer_created',
- }
- );
- return OfferCreated;
+const OfferCreated = sequelize.define(
+ 'OfferCreated',
+ {
+ uuid: {
+ type: DataTypes.UUID,
+ allowNull: false,
+ unique: true,
+ primaryKey: true,
+ },
+ public_key: {
+ type: DataTypes.STRING,
+ allowNull: false,
+ },
+ created_at: {
+ type: DataTypes.DATE,
+ allowNull: false,
+ },
+ },
+ {
+ tableName: 'offer_created',
}
-}
+);
-module.exports = OfferCreatedProvider;
+module.exports = OfferCreated;
diff --git a/src/models/OfferDeleted.js b/src/models/OfferDeleted.js
deleted file mode 100644
index 019c61f..0000000
--- a/src/models/OfferDeleted.js
+++ /dev/null
@@ -1,34 +0,0 @@
-class OfferDeletedProvider {
- constructor({ sequelize, DataTypes }) {
- this.sequelize = sequelize;
- this.DataTypes = DataTypes;
- }
-
- provide() {
- const OfferDeleted = this.sequelize.define(
- 'OfferDeleted',
- {
- uuid: {
- type: this.DataTypes.UUID,
- allowNull: false,
- unique: true,
- primaryKey: true,
- },
- offer_uuid: {
- type: this.DataTypes.UUID,
- allowNull: false,
- },
- created_at: {
- type: this.DataTypes.DATE,
- allowNull: false,
- },
- },
- {
- tableName: 'offer_deleted',
- }
- );
- return OfferDeleted;
- }
-}
-
-module.exports = OfferDeletedProvider;
diff --git a/src/models/OfferDetailsSet.js b/src/models/OfferDetailsSet.js
index d2023d7..20ac456 100644
--- a/src/models/OfferDetailsSet.js
+++ b/src/models/OfferDetailsSet.js
@@ -1,78 +1,71 @@
-class OfferDetailsSetProvider {
- constructor({ sequelize, DataTypes }) {
- this.sequelize = sequelize;
- this.DataTypes = DataTypes;
- }
+const { DataTypes } = require('sequelize');
+const sequelize = require('../database');
- provide() {
- const OfferDetailsSet = this.sequelize.define(
- 'OfferDetailsSet',
- {
- uuid: {
- type: this.DataTypes.UUID,
- allowNull: false,
- unique: true,
- primaryKey: true,
- },
- offer_uuid: {
- type: this.DataTypes.UUID,
- allowNull: false,
- },
- wants: {
- type: this.DataTypes.STRING,
- allowNull: false,
- },
- premium: {
- type: this.DataTypes.DECIMAL(5, 2),
- allowNull: false,
- },
- trade_amount_eur: {
- type: this.DataTypes.INTEGER,
- allowNull: false,
- },
- location_details: {
- type: this.DataTypes.TEXT,
- allowNull: false,
- },
- time_availability_details: {
- type: this.DataTypes.TEXT,
- allowNull: false,
- },
- show_offer_to_trusted: {
- type: this.DataTypes.BOOLEAN,
- allowNull: false,
- },
- show_offer_to_trusted_trusted: {
- type: this.DataTypes.BOOLEAN,
- allowNull: false,
- },
- show_offer_to_all_members: {
- type: this.DataTypes.BOOLEAN,
- allowNull: false,
- },
- is_onchain_accepted: {
- type: this.DataTypes.BOOLEAN,
- allowNull: false,
- },
- is_lightning_accepted: {
- type: this.DataTypes.BOOLEAN,
- allowNull: false,
- },
- are_big_notes_accepted: {
- type: this.DataTypes.BOOLEAN,
- allowNull: false,
- },
- created_at: {
- type: this.DataTypes.DATE,
- allowNull: false,
- },
- },
- {
- tableName: 'offer_details_set',
- }
- );
- return OfferDetailsSet;
+const OfferDetailsSet = sequelize.define(
+ 'OfferDetailsSet',
+ {
+ uuid: {
+ type: DataTypes.UUID,
+ allowNull: false,
+ unique: true,
+ primaryKey: true,
+ },
+ offer_uuid: {
+ type: DataTypes.STRING,
+ allowNull: false,
+ },
+ wants: {
+ type: DataTypes.STRING,
+ allowNull: false,
+ },
+ premium: {
+ type: DataTypes.DECIMAL(5, 2),
+ allowNull: false,
+ },
+ trade_amount_eur: {
+ type: DataTypes.INTEGER,
+ allowNull: false,
+ },
+ location_details: {
+ type: DataTypes.TEXT,
+ allowNull: false,
+ },
+ time_availability_details: {
+ type: DataTypes.TEXT,
+ allowNull: false,
+ },
+ show_offer_to_trusted: {
+ type: DataTypes.BOOLEAN,
+ allowNull: false,
+ },
+ show_offer_to_trusted_trusted: {
+ type: DataTypes.BOOLEAN,
+ allowNull: false,
+ },
+ show_offer_to_all_members: {
+ type: DataTypes.BOOLEAN,
+ allowNull: false,
+ },
+ is_onchain_accepted: {
+ type: DataTypes.BOOLEAN,
+ allowNull: false,
+ },
+ is_lightning_accepted: {
+ type: DataTypes.BOOLEAN,
+ allowNull: false,
+ },
+ are_big_notes_accepted: {
+ type: DataTypes.BOOLEAN,
+ allowNull: false,
+ },
+ created_at: {
+ type: DataTypes.DATE,
+ allowNull: false,
+ },
+ },
+ {
+ tableName: 'offer_details_set',
}
-}
+);
-module.exports = OfferDetailsSetProvider;
+module.exports = OfferDetailsSet;
diff --git a/src/models/SessionCreated.js b/src/models/SessionCreated.js
index a97c1fb..8d0de50 100644
--- a/src/models/SessionCreated.js
+++ b/src/models/SessionCreated.js
@@ -1,34 +1,27 @@
-class SessionCreatedProvider {
- constructor({ sequelize, DataTypes }) {
- this.sequelize = sequelize;
- this.DataTypes = DataTypes;
- }
+const { DataTypes } = require('sequelize');
+const sequelize = require('../database');
- provide() {
- const SessionCreated = this.sequelize.define(
- 'SessionCreated',
- {
- uuid: {
- type: this.DataTypes.UUID,
- allowNull: false,
- unique: true,
- primaryKey: true,
- },
- created_at: {
- type: this.DataTypes.DATE,
- allowNull: false,
- },
- expires_at: {
- type: this.DataTypes.DATE,
- allowNull: false,
- },
- },
- {
- tableName: 'session_created',
- }
- );
- return SessionCreated;
+const SessionCreated = sequelize.define(
+ 'SessionCreated',
+ {
+ uuid: {
+ type: DataTypes.UUID,
+ allowNull: false,
+ unique: true,
+ primaryKey: true,
+ },
+ created_at: {
+ type: DataTypes.DATE,
+ allowNull: false,
+ },
+ expires_at: {
+ type: DataTypes.DATE,
+ allowNull: false,
+ },
+ },
+ {
+ tableName: 'session_created',
}
-}
+);
-module.exports = SessionCreatedProvider;
+module.exports = SessionCreated;
diff --git a/src/models/SessionRelatedToPublickey.js b/src/models/SessionRelatedToPublickey.js
index 321da32..4802267 100644
--- a/src/models/SessionRelatedToPublickey.js
+++ b/src/models/SessionRelatedToPublickey.js
@@ -1,37 +1,31 @@
-class SessionRelatedToPublickeyProvider {
- constructor({ sequelize, DataTypes }) {
- this.sequelize = sequelize;
- this.DataTypes = DataTypes;
- }
+const { DataTypes } = require('sequelize');
+const sequelize = require('../database');
- provide() {
- const SessionRelatedToPublickey = this.sequelize.define(
- 'SessionRelatedToPublickey',
- {
- uuid: {
- type: this.DataTypes.UUID,
- allowNull: false,
- unique: true,
- primaryKey: true,
- },
- session_uuid: {
- type: this.DataTypes.UUID,
- allowNull: false,
- },
- public_key: {
- type: this.DataTypes.STRING,
- allowNull: false,
- },
- created_at: {
- type: this.DataTypes.DATE,
- allowNull: false,
- },
- },
- {
- tableName: 'session_related_to_public_key',
- }
- );
- return SessionRelatedToPublickey;
+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 = SessionRelatedToPublickeyProvider;
+);
+
+module.exports = SessionRelatedToPublickey;
diff --git a/src/models/SignUpChallengeCompleted.js b/src/models/SignUpChallengeCompleted.js
index afd65f2..2960421 100644
--- a/src/models/SignUpChallengeCompleted.js
+++ b/src/models/SignUpChallengeCompleted.js
@@ -1,42 +1,35 @@
-class SignUpChallengeCompletedProvider {
- constructor({ sequelize, DataTypes }) {
- this.sequelize = sequelize;
- this.DataTypes = DataTypes;
- }
+const { DataTypes } = require('sequelize');
+const sequelize = require('../database');
- provide() {
- const SignUpChallengeCompleted = this.sequelize.define(
- 'SignUpChallengeCompleted',
- {
- uuid: {
- type: this.DataTypes.UUID,
- allowNull: false,
- unique: true,
- primaryKey: true,
- },
- nostr_challenge_completed_uuid: {
- type: this.DataTypes.UUID,
- allowNull: false,
- },
- app_invite_uuid: {
- type: this.DataTypes.UUID,
- allowNull: false,
- },
- public_key: {
- type: this.DataTypes.STRING,
- allowNull: false,
- },
- created_at: {
- type: this.DataTypes.DATE,
- allowNull: false,
- },
- },
- {
- tableName: 'sign_up_challenge_completed',
- }
- );
- return SignUpChallengeCompleted;
+const SignUpChallengeCompleted = sequelize.define(
+ 'SignUpChallengeCompleted',
+ {
+ uuid: {
+ type: DataTypes.UUID,
+ allowNull: false,
+ unique: true,
+ primaryKey: true,
+ },
+ nostr_challenge_completed_uuid: {
+ type: DataTypes.UUID,
+ allowNull: false,
+ },
+ app_invite_uuid: {
+ type: DataTypes.UUID,
+ allowNull: false,
+ },
+ public_key: {
+ type: DataTypes.STRING,
+ allowNull: false,
+ },
+ created_at: {
+ type: DataTypes.DATE,
+ allowNull: false,
+ },
+ },
+ {
+ tableName: 'sign_up_challenge_completed',
}
-}
+);
-module.exports = SignUpChallengeCompletedProvider;
+module.exports = SignUpChallengeCompleted;
diff --git a/src/models/SignUpChallengeCreated.js b/src/models/SignUpChallengeCreated.js
index 3da9ec4..1d3e22e 100644
--- a/src/models/SignUpChallengeCreated.js
+++ b/src/models/SignUpChallengeCreated.js
@@ -1,39 +1,31 @@
-class SignUpChallengeCreatedProvider {
- constructor({ sequelize, DataTypes }) {
- this.sequelize = sequelize;
- this.DataTypes = DataTypes;
+const { DataTypes } = require('sequelize');
+const sequelize = require('../database');
+
+const SignUpChallengeCreated = sequelize.define(
+ 'SignUpChallengeCreated',
+ {
+ uuid: {
+ type: DataTypes.UUID,
+ allowNull: false,
+ unique: true,
+ primaryKey: true,
+ },
+ nostr_challenge_uuid: {
+ type: DataTypes.UUID,
+ allowNull: false,
+ },
+ app_invite_uuid: {
+ type: DataTypes.UUID,
+ allowNull: false,
+ },
+ created_at: {
+ type: DataTypes.DATE,
+ allowNull: false,
+ },
+ },
+ {
+ tableName: 'sign_up_challenge_created',
}
+);
- provide() {
- const SignUpChallengeCreated = this.sequelize.define(
- 'SignUpChallengeCreated',
- {
- uuid: {
- type: this.DataTypes.UUID,
- allowNull: false,
- unique: true,
- primaryKey: true,
- },
- nostr_challenge_uuid: {
- type: this.DataTypes.UUID,
- allowNull: false,
- },
- app_invite_uuid: {
- type: this.DataTypes.UUID,
- allowNull: false,
- },
- created_at: {
- type: this.DataTypes.DATE,
- allowNull: false,
- },
- },
- {
- tableName: 'sign_up_challenge_created',
- }
- );
-
- return SignUpChallengeCreated;
- }
-}
-
-module.exports = SignUpChallengeCreatedProvider;
+module.exports = SignUpChallengeCreated;
diff --git a/src/models/index.js b/src/models/index.js
deleted file mode 100644
index 02b4028..0000000
--- a/src/models/index.js
+++ /dev/null
@@ -1,97 +0,0 @@
-class ModelsProvider {
- constructor({ sequelize, DataTypes }) {
- this.sequelize = sequelize;
- this.DataTypes = DataTypes;
- }
- provide() {
- const AppInviteCreatedProvider = require('./AppInviteCreated');
- const AppInviteCreated = new AppInviteCreatedProvider({
- sequelize: this.sequelize,
- DataTypes: this.DataTypes,
- }).provide();
- const ContactDetailsSetProvider = require('./ContactDetailsSet');
- const ContactDetailsSet = new ContactDetailsSetProvider({
- sequelize: this.sequelize,
- DataTypes: this.DataTypes,
- }).provide();
- const LoginChallengeCompletedProvider = require('./LoginChallengeCompleted');
- const LoginChallengeCompleted = new LoginChallengeCompletedProvider({
- sequelize: this.sequelize,
- DataTypes: this.DataTypes,
- }).provide();
- const LoginChallengeCreatedProvider = require('./LoginChallengeCreated');
- const LoginChallengeCreated = new LoginChallengeCreatedProvider({
- sequelize: this.sequelize,
- DataTypes: this.DataTypes,
- }).provide();
- const NostrChallengeCompletedProvider = require('./NostrChallengeCompleted');
- const NostrChallengeCompleted = new NostrChallengeCompletedProvider({
- sequelize: this.sequelize,
- DataTypes: this.DataTypes,
- }).provide();
- const NostrChallengeCreatedProvider = require('./NostrChallengeCreated');
- const NostrChallengeCreated = new NostrChallengeCreatedProvider({
- sequelize: this.sequelize,
- DataTypes: this.DataTypes,
- }).provide();
- const NymSetProvider = require('./NymSet');
- const NymSet = new NymSetProvider({
- sequelize: this.sequelize,
- DataTypes: this.DataTypes,
- }).provide();
- const OfferCreatedProvider = require('./OfferCreated');
- const OfferCreated = new OfferCreatedProvider({
- sequelize: this.sequelize,
- DataTypes: this.DataTypes,
- }).provide();
- const OfferDeletedProvider = require('./OfferDeleted');
- const OfferDeleted = new OfferDeletedProvider({
- sequelize: this.sequelize,
- DataTypes: this.DataTypes,
- }).provide();
- const OfferDetailsSetProvider = require('./OfferDetailsSet');
- const OfferDetailsSet = new OfferDetailsSetProvider({
- sequelize: this.sequelize,
- DataTypes: this.DataTypes,
- }).provide();
- const SessionCreatedProvider = require('./SessionCreated');
- const SessionCreated = new SessionCreatedProvider({
- sequelize: this.sequelize,
- DataTypes: this.DataTypes,
- }).provide();
- const SessionRelatedToPublickeyProvider = require('./SessionRelatedToPublickey');
- const SessionRelatedToPublickey = new SessionRelatedToPublickeyProvider({
- sequelize: this.sequelize,
- DataTypes: this.DataTypes,
- }).provide();
- const SignUpChallengeCompletedProvider = require('./SignUpChallengeCompleted');
- const SignUpChallengeCompleted = new SignUpChallengeCompletedProvider({
- sequelize: this.sequelize,
- DataTypes: this.DataTypes,
- }).provide();
- const SignUpChallengeCreatedProvider = require('./SignUpChallengeCreated');
- const SignUpChallengeCreated = new SignUpChallengeCreatedProvider({
- sequelize: this.sequelize,
- DataTypes: this.DataTypes,
- }).provide();
-
- return {
- SignUpChallengeCreated,
- SignUpChallengeCompleted,
- SessionRelatedToPublickey,
- SessionCreated,
- OfferDeleted,
- OfferDetailsSet,
- OfferCreated,
- NymSet,
- NostrChallengeCreated,
- NostrChallengeCompleted,
- LoginChallengeCompleted,
- LoginChallengeCreated,
- ContactDetailsSet,
- AppInviteCreated,
- };
- }
-}
-
-module.exports = ModelsProvider;
diff --git a/public/css/offers.css b/src/public/css/offers.css
similarity index 52%
rename from public/css/offers.css
rename to src/public/css/offers.css
index 17ac4b5..16fad27 100644
--- a/public/css/offers.css
+++ b/src/public/css/offers.css
@@ -19,8 +19,8 @@
width: 50%;
}
- .create-offer-step {
- width: 95%;
+ #create-offer-controls > * {
+ width: 100%;
}
.checkbox-row {
@@ -31,13 +31,6 @@
flex-shrink: 0;
margin-left: 5%;
}
-
- .myoffer-card {
- width: 100%;
- height: 500px;
- margin: 5px 5px;
- padding: 10px;
- }
}
@media (min-width: 769px) {
@@ -58,12 +51,10 @@
width: 33%;
}
- .create-offer-step {
+ #create-offer-controls > * {
margin-left: auto;
margin-right: auto;
width: 70%;
- min-width: 500px;
- max-width: 95%;
}
.checkbox-row {
@@ -74,175 +65,12 @@
flex-shrink: 0;
margin-left: 20%;
}
-
- .myoffer-card {
- width: 23%;
- min-width: 339px;
- height: 500px;
- margin: 10px 10px;
- padding: 10px;
- }
}
-#view-my-offers-root {
- display: none;
+#create-offer-controls > * {
text-align: center;
}
-#view-my-offers-root > * {
- margin-left: auto;
- margin-right: auto;
-}
-
-#own-offers-container {
- display: flex;
- flex-wrap: wrap;
- justify-content: space-evenly;
-}
-
-.myoffer-card {
- display: grid;
- grid-template-columns: 48% 4% 48%;
- grid-template-rows: 25% 1% 30% 1% 18% 1% 14% 1% 10%;
-}
-
-.myoffer-card > div {
- padding: 5px;
-}
-
-.myoffer-card p {
- margin: 0;
-}
-
-.trade-desc {
- grid-column: 1;
- grid-row: 1;
- text-align: left;
-}
-
-.left-icon-checkboxed-field {
- display: flex;
- align-items: center;
- margin-bottom: 2px;
- font-size: 0.9em;
-}
-
-.left-icon-checkboxed-field > * {
- margin-right: 2px;
- margin-left: 2px;
-}
-.left-icon-checkboxed-field img {
- height: 1.1em;
-}
-
-.right-icon-checkboxed-field {
- display: flex;
- align-items: center;
- justify-content: end;
- margin-bottom: 2px;
- font-size: 0.9em;
-}
-
-.right-icon-checkboxed-field > * {
- margin-right: 2px;
- margin-left: 2px;
-}
-.right-icon-checkboxed-field img {
- height: 1.2em;
-}
-
-.offer-card-content-title {
- color: gray;
- font-size: 0.8em;
- font-weight: 100;
-}
-
-.offer-card-content-data {
- font-size: 1.1em;
- font-weight: bold;
-}
-
-.premium-desc {
- grid-column: 3;
- grid-row: 1;
- text-align: right;
-}
-
-.where-desc {
- grid-column: 1;
- grid-row: 3;
- text-align: left;
- overflow-y: auto;
- overflow-x: hidden;
-}
-
-.when-desc {
- grid-column: 3;
- grid-row: 3;
- text-align: right;
- overflow-y: auto;
- overflow-x: hidden;
-}
-
-.bitcoin-methods-desc {
- grid-column: 1;
- grid-row: 5;
- text-align: left;
-}
-
-.visibility-desc {
- grid-column: 3;
- grid-row: 5;
- text-align: right;
-}
-
-.other-desc {
- grid-column: 1;
- grid-row: 7;
- text-align: left;
-}
-
-.offer-action-buttons-area {
- grid-column-start: 1;
- grid-column-end: 4;
- grid-row: 9;
- display: flex;
- align-items: center;
- justify-content: flex-end;
-}
-
-.offer-action-area {
- cursor: pointer;
- margin-right: 20px;
- padding: 3px;
-}
-
-.offer-long-text {
- font-size: 0.9em;
-}
-
-#create-offer-controls {
- text-align: center;
- overflow-y: auto;
- max-height: 800px;
- padding: 20px;
-}
-
-.create-offer-step {
- text-align: center;
- border-radius: 20px;
- box-shadow: 0 0 13px #ccc;
- padding: 20px 0;
- margin-top: 10px;
- margin-bottom: 10px;
- margin-left: auto;
- margin-right: auto;
-}
-
-.create-offer-step h3 {
- margin-top: 0;
-}
-
#close-offer-controls-area {
display: flex;
justify-content: end;
@@ -280,9 +108,6 @@
.premium-button {
background: white;
border: 2px solid #e1c300;
- width: 100%;
- height: 50%;
- font-size: 1em;
}
.premium-button:hover {
@@ -297,6 +122,12 @@
border-bottom-right-radius: 10px;
}
+.premium-button {
+ width: 100%;
+ height: 50%;
+ font-size: 1em;
+}
+
#premium-price-display-area {
margin-left: 0;
margin-right: auto;
@@ -385,8 +216,3 @@
#button-submit-offer {
width: 33%;
}
-
-#close-offer {
- margin-left: auto;
- margin-right: auto;
-}
diff --git a/public/css/seca.css b/src/public/css/seca.css
similarity index 55%
rename from public/css/seca.css
rename to src/public/css/seca.css
index 1cc3034..629ba1a 100644
--- a/public/css/seca.css
+++ b/src/public/css/seca.css
@@ -13,17 +13,10 @@
}
.button-medium {
- padding: 0.5em 1em;
+ height: 3em;
+ padding: 1em;
border-radius: 10px;
}
-
- .top-notification-good {
- top: 25px;
- }
-
- #app-nav-bar > #laseca-logo {
- height: 30px;
- }
}
@media (min-width: 769px) {
@@ -36,22 +29,23 @@
}
.button-medium {
+ height: 3em;
padding: 1em;
border-radius: 10px;
}
-
- .top-notification-good {
- top: 50px;
- }
-
- #app-nav-bar > #laseca-logo {
- height: 30px;
- }
}
-#app-nav-bar > #laseca-logo {
- margin-top: 0;
- transform: translateY(20%);
+.badges {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ grid-template-rows: repeat(3, 1fr);
+}
+
+.badge {
+ border: 2px solid #e1c300;
+ border-radius: 10px;
+ padding: 2%;
+ margin: 2%;
}
body {
@@ -78,72 +72,6 @@ h1 {
border: 2px solid red;
}
-.max-size-zero {
- max-width: 0;
- max-height: 0;
-}
-
-.top-notification-good {
- border-radius: 10px;
- background-color: rgb(9, 165, 9);
- color: white;
- font-weight: 800;
- opacity: 0.8;
- position: fixed;
- padding: 20px;
- display: flex;
- justify-content: space-evenly;
- align-items: center;
- left: 50%;
- transform: translate(-50%, -500px);
- transition: transform 1s ease-in-out;
-}
-
-.top-notification-good.revealed {
- transform: translate(-50%, 0%);
-}
-.top-notification-good > * {
- margin: 0 20px;
-}
-.top-notification-good > *:first-child {
- margin-left: 0;
-}
-.top-notification-good > *:last-child {
- margin-right: 0;
-}
-
-.top-notification-good img {
- height: 50px;
-}
-
-.full-screen-modal-background {
- position: fixed;
- width: 100%;
- height: 100%;
- top: 0;
- left: 0;
- background-color: rgba(0, 0, 0, 0.75);
- transition: all 0.5s ease-in-out;
- opacity: 0;
- visibility: hidden;
- pointer-events: none;
-}
-
-.full-screen-modal-background.shown {
- opacity: 1;
- visibility: visible;
- pointer-events: all;
-}
-
-.full-screen-modal {
- background-color: white;
- border-radius: 20px;
- padding: 10px;
- width: fit-content;
- max-width: 95%;
- margin: 20px auto;
-}
-
.button-group button {
border: 0;
padding: 1em;
@@ -179,21 +107,10 @@ h1 {
.over-background {
background-color: white;
border-radius: 1vw;
- padding: 10px;
+ padding: 2vw;
margin: 1%;
}
-.shadowed-round-area {
- border-radius: 20px;
- box-shadow: 0 0 13px #ccc;
- padding: 20px;
-}
-
-.subtle-box {
- border-radius: 10px;
- border: 1px solid rgb(202, 202, 202);
-}
-
#login-card > * {
text-align: center;
margin-right: auto;
@@ -202,6 +119,18 @@ h1 {
margin-bottom: 1vh;
}
+.create-profile-card-section > * {
+ text-align: center;
+ margin-right: auto;
+ margin-left: auto;
+ display: block;
+ max-width: 1000px;
+}
+
+.create-profile-card-section .badge img {
+ width: 10%;
+}
+
.text-warning {
color: red;
font-weight: 800;
@@ -223,25 +152,27 @@ h1 {
cursor: default;
}
-.button-secondary {
- background: white;
- border: 0;
- color: #e1c300;
- cursor: pointer;
- border: 3px solid #e1c300;
- transition: all 0.5 ease-in-out;
-}
-
-.button-secondary:hover {
- font-weight: bold;
-}
-
.button-large {
font-weight: bold;
font-size: 1.5em;
padding: 0.5em;
}
+.invite-card {
+ margin: 5vh 20vw;
+ height: 100%;
+}
+
+.invite-card-content {
+ margin: 3% 5%;
+ padding: 0 10%;
+}
+
+.invite-card-content * {
+ margin: 1vh auto;
+ text-align: center;
+}
+
.card-secondary {
background-color: #369;
border-radius: 1vw;
@@ -263,7 +194,6 @@ h1 {
color: white;
padding: 1%;
cursor: pointer;
- border: 0;
}
.button-nostr:hover {
@@ -275,3 +205,12 @@ h1 {
cursor: default;
border: 0;
}
+
+#nostr-signup-button {
+ width: 20vw;
+ border: 0;
+}
+
+#nostr-signup-button p {
+ font-size: 1.5rem;
+}
diff --git a/public/img/circle-xmark.svg b/src/public/img/circle-xmark.svg
similarity index 100%
rename from public/img/circle-xmark.svg
rename to src/public/img/circle-xmark.svg
diff --git a/public/img/envelope.svg b/src/public/img/envelope.svg
similarity index 100%
rename from public/img/envelope.svg
rename to src/public/img/envelope.svg
diff --git a/public/img/laseca_logo_white.png b/src/public/img/laseca_logo_white.png
similarity index 100%
rename from public/img/laseca_logo_white.png
rename to src/public/img/laseca_logo_white.png
diff --git a/public/img/lasecagold_ostrich.svg b/src/public/img/lasecagold_ostrich.svg
similarity index 100%
rename from public/img/lasecagold_ostrich.svg
rename to src/public/img/lasecagold_ostrich.svg
diff --git a/public/img/message-exclamation.svg b/src/public/img/message-exclamation.svg
similarity index 100%
rename from public/img/message-exclamation.svg
rename to src/public/img/message-exclamation.svg
diff --git a/public/img/phone.svg b/src/public/img/phone.svg
similarity index 100%
rename from public/img/phone.svg
rename to src/public/img/phone.svg
diff --git a/public/img/signal-messenger.svg b/src/public/img/signal-messenger.svg
similarity index 100%
rename from public/img/signal-messenger.svg
rename to src/public/img/signal-messenger.svg
diff --git a/public/img/square-whatsapp.svg b/src/public/img/square-whatsapp.svg
similarity index 100%
rename from public/img/square-whatsapp.svg
rename to src/public/img/square-whatsapp.svg
diff --git a/public/img/telegram.svg b/src/public/img/telegram.svg
similarity index 100%
rename from public/img/telegram.svg
rename to src/public/img/telegram.svg
diff --git a/public/img/white_ostrich.svg b/src/public/img/white_ostrich.svg
similarity index 100%
rename from public/img/white_ostrich.svg
rename to src/public/img/white_ostrich.svg
diff --git a/src/public/javascript/app.js b/src/public/javascript/app.js
new file mode 100644
index 0000000..aa28857
--- /dev/null
+++ b/src/public/javascript/app.js
@@ -0,0 +1,10 @@
+const navbuttonHome = document.getElementById('navbutton-home');
+const navbuttonOffers = document.getElementById('navbutton-offers');
+
+navbuttonHome.addEventListener('click', () => {
+ window.location.href = '/home';
+});
+
+navbuttonOffers.addEventListener('click', () => {
+ window.location.href = '/offers';
+});
diff --git a/src/public/javascript/createProfile.js b/src/public/javascript/createProfile.js
new file mode 100644
index 0000000..f7af1f1
--- /dev/null
+++ b/src/public/javascript/createProfile.js
@@ -0,0 +1,116 @@
+function debounce(func, wait) {
+ let timeout;
+ return function (...args) {
+ clearTimeout(timeout);
+ timeout = setTimeout(() => func.apply(this, args), wait);
+ };
+}
+
+const validateNymInput = debounce(() => {
+ const nymValue = nymInput.value.trim();
+ const isValid = nymValue.length >= 3 && nymValue.length <= 128;
+ if (isValid) {
+ nymInputValidationWarning.style.display = 'none';
+ } else {
+ nymInputValidationWarning.style.display = 'block';
+ }
+}, 500);
+
+const checkIfSubmittable = debounce((allInputs) => {
+ const nymIsFilled = allInputs.nymInput.value !== '';
+ let atLeastOneContactIsFilled = false;
+
+ for (const contactInput of allInputs.contactInputs) {
+ if (contactInput.value !== '') {
+ atLeastOneContactIsFilled = true;
+ }
+ }
+
+ const buttonShouldBeDisabled = !(nymIsFilled && atLeastOneContactIsFilled);
+ submitProfileButton.disabled = buttonShouldBeDisabled;
+}, 500);
+
+async function createProfile(allInputs) {
+ const contactDetails = [];
+ for (const someInput of allInputs.contactInputs) {
+ contactDetails.push({
+ type: someInput.getAttribute('data-type'),
+ value: someInput.value,
+ });
+ }
+ const encryptedContactDetails = await window.nostr.nip04.encrypt(
+ await window.nostr.getPublicKey(),
+ JSON.stringify(contactDetails)
+ );
+ await fetch('/api/set-contact-details', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({ encryptedContactDetails }),
+ });
+
+ const nym = allInputs.nymInput.value;
+ await fetch('/api/set-nym', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({ nym }),
+ });
+
+ setTimeout(() => {
+ window.location.href = '/home';
+ }, 1000);
+}
+
+function onLoadErrands(allInputs, submitProfileButton) {
+ allInputs.nymInput.addEventListener('input', validateNymInput);
+
+ for (const someInput of allInputs.allInputs) {
+ someInput.addEventListener('input', () => {
+ checkIfSubmittable(allInputs);
+ });
+ }
+
+ checkIfSubmittable(allInputs);
+
+ submitProfileButton.addEventListener('click', () => {
+ createProfile(allInputs);
+ });
+}
+
+const nymInput = document.getElementById('nym-input');
+const nymInputValidationWarning = document.getElementById(
+ 'nym-input-validation-warning'
+);
+const phoneInput = document.getElementById('phone-input');
+const whatsappInput = document.getElementById('whatsapp-input');
+const telegramInput = document.getElementById('telegram-input');
+const emailInput = document.getElementById('email-input');
+const nostrInput = document.getElementById('nostr-input');
+const signalInput = document.getElementById('signal-input');
+const submitProfileButton = document.getElementById('submit-profile-button');
+
+const allInputs = {
+ nymInput: nymInput,
+ contactInputs: [
+ phoneInput,
+ whatsappInput,
+ telegramInput,
+ emailInput,
+ nostrInput,
+ signalInput,
+ ],
+ allInputs: [
+ nymInput,
+ phoneInput,
+ whatsappInput,
+ telegramInput,
+ emailInput,
+ nostrInput,
+ signalInput,
+ ],
+};
+
+onLoadErrands(allInputs, submitProfileButton);
diff --git a/src/public/javascript/home.js b/src/public/javascript/home.js
new file mode 100644
index 0000000..e69de29
diff --git a/src/front/services/inviteService.js b/src/public/javascript/invite.js
similarity index 61%
rename from src/front/services/inviteService.js
rename to src/public/javascript/invite.js
index d494c6c..04ef5c8 100644
--- a/src/front/services/inviteService.js
+++ b/src/public/javascript/invite.js
@@ -1,4 +1,14 @@
-const requestAndRespondSignUpChallenge = async ({ onNostrErrorCallback }) => {
+window.onload = function () {
+ if (!window.nostr) {
+ console.log('Nostr extension not present');
+ document.querySelector('#nostr-signup-button').disabled = true;
+ document.querySelector('#no-extension-nudges').style.display = 'block';
+ } else {
+ console.log('Nostr extension present');
+ }
+};
+
+async function acceptInvite() {
let challengeResponse;
try {
challengeResponse = await fetch('/api/signup/nostr-challenge', {
@@ -18,7 +28,7 @@ const requestAndRespondSignUpChallenge = async ({ onNostrErrorCallback }) => {
try {
pubkey = await window.nostr.getPublicKey();
} catch (error) {
- onNostrErrorCallback();
+ document.querySelector('#rejected-nostr-nudges').style.display = 'block';
return;
}
const event = {
@@ -33,7 +43,7 @@ const requestAndRespondSignUpChallenge = async ({ onNostrErrorCallback }) => {
try {
signedEvent = await window.nostr.signEvent(event);
} catch (error) {
- onNostrErrorCallback();
+ document.querySelector('#rejected-nostr-nudges').style.display = 'block';
return;
}
@@ -49,9 +59,10 @@ const requestAndRespondSignUpChallenge = async ({ onNostrErrorCallback }) => {
return;
}
- return verifyResponse;
-};
-
-module.exports = {
- requestAndRespondSignUpChallenge,
-};
+ if (verifyResponse.ok) {
+ document.querySelector('#sign-up-success').style.display = 'block';
+ setTimeout(() => {
+ window.location.href = '/createProfile';
+ }, 1000);
+ }
+}
diff --git a/src/front/services/loginService.js b/src/public/javascript/login.js
similarity index 62%
rename from src/front/services/loginService.js
rename to src/public/javascript/login.js
index d1f5815..36175b4 100644
--- a/src/front/services/loginService.js
+++ b/src/public/javascript/login.js
@@ -1,12 +1,14 @@
-const requestAndRespondLoginChallenge = async ({
- onRejectedPubKeyCallback,
- onRejectedSignatureCallback,
-}) => {
- onRejectedPubKeyCallback = () => {
- document.querySelector('#rejected-nostr-nudges').style.display = 'block';
- };
- onRejectedSignatureCallback = onRejectedPubKeyCallback;
+window.onload = function () {
+ if (!window.nostr) {
+ console.log('Nostr extension not present');
+ document.querySelector('#login-button').disabled = true;
+ document.querySelector('#no-extension-nudges').style.display = 'block';
+ } else {
+ console.log('Nostr extension present');
+ }
+};
+async function login() {
let challengeResponse;
try {
challengeResponse = await fetch('/api/login/nostr-challenge', {
@@ -26,7 +28,7 @@ const requestAndRespondLoginChallenge = async ({
try {
pubkey = await window.nostr.getPublicKey();
} catch (error) {
- onRejectedPubKeyCallback();
+ document.querySelector('#rejected-nostr-nudges').style.display = 'block';
return;
}
const event = {
@@ -41,7 +43,7 @@ const requestAndRespondLoginChallenge = async ({
try {
signedEvent = await window.nostr.signEvent(event);
} catch (error) {
- onRejectedSignatureCallback();
+ document.querySelector('#rejected-nostr-nudges').style.display = 'block';
return;
}
@@ -57,9 +59,14 @@ const requestAndRespondLoginChallenge = async ({
return;
}
- return verifyResponse;
-};
+ if (verifyResponse.status === 403) {
+ document.querySelector('#rejected-public-key').style.display = 'block';
+ }
-module.exports = {
- requestAndRespondLoginChallenge,
-};
+ if (verifyResponse.ok) {
+ document.querySelector('#sign-up-success').style.display = 'block';
+ setTimeout(() => {
+ window.location.href = '/home';
+ }, 1000);
+ }
+}
diff --git a/src/public/javascript/offers.js b/src/public/javascript/offers.js
new file mode 100644
index 0000000..3a73d12
--- /dev/null
+++ b/src/public/javascript/offers.js
@@ -0,0 +1,201 @@
+const buttonStartCreateOffer = document.getElementById(
+ 'button-start-create-offer'
+);
+const closeOfferControls = document.getElementById('close-offer-controls-x');
+const createOfferControls = document.getElementById('create-offer-controls');
+
+const buyOrSellButtonGroup = document.getElementById(
+ 'button-group-buy-or-sell'
+);
+const buyOrSellButtons = buyOrSellButtonGroup.querySelectorAll('button');
+const buyButton = document.getElementById('button-buy-bitcoin');
+const sellButton = document.getElementById('button-sell-bitcoin');
+
+const premiumValue = document.getElementById('premium-value');
+const buttonIncreasePremium = document.getElementById(
+ 'button-increase-premium'
+);
+
+const buttonDecreasePremium = document.getElementById(
+ 'button-decrease-premium'
+);
+
+const eurAmountInput = document.getElementById('input-eur-amount');
+const btcAmountInput = document.getElementById('input-btc-amount');
+
+const placeInput = document.getElementById('place-input');
+const timeInput = document.getElementById('time-input');
+
+const onchainCheckbox = document.getElementById('onchain-checkbox');
+const lightningCheckbox = document.getElementById('lightning-checkbox');
+
+const btcMethodCheckboxes = [onchainCheckbox, lightningCheckbox];
+
+const myTrustedCheckbox = document.getElementById('my-trusted-checkbox');
+const myTrustedTrustedCheckbox = document.getElementById(
+ 'my-trusted-trusted-checkbox'
+);
+const allMembersCheckbox = document.getElementById('all-members-checkbox');
+
+const bigNotesAcceptedCheckbox = document.getElementById(
+ 'large-bills-checkbox'
+);
+
+const publishOfferButton = document.getElementById('button-submit-offer');
+
+function toggleCreateOfferControls() {
+ createOfferControls.style.display =
+ createOfferControls.style.display === 'block' ? 'none' : 'block';
+
+ buttonStartCreateOffer.style.display =
+ buttonStartCreateOffer.style.display === 'block' ? 'none' : 'block';
+}
+
+function modifyPremiumValue(delta) {
+ const regexExpression = /-*\d+/;
+ const numValue = parseInt(premiumValue.innerText.match(regexExpression)[0]);
+
+ const newValue = `${numValue + delta}%`;
+
+ premiumValue.innerText = newValue;
+}
+
+function toggleBuyOrSellButtonGroup() {
+ buyOrSellButtons.forEach((button) => {
+ if (button.classList.contains('selected')) {
+ button.classList.remove('selected');
+ } else {
+ button.classList.add('selected');
+ }
+ });
+}
+
+function readIntFromEurAmountInput() {
+ const eurAmountFieldValue = eurAmountInput.value;
+ const regularExpression = /([\d\s]+)/;
+ const matchResult = eurAmountFieldValue.match(regularExpression);
+
+ if (!matchResult) {
+ return null;
+ }
+
+ const numberString = matchResult[1];
+ const cleanInputNumber = parseInt(numberString.replace(/\s/gi, ''));
+
+ return cleanInputNumber;
+}
+
+function validateAndFormatEurAmountInput() {
+ const cleanInputNumber = readIntFromEurAmountInput();
+ eurAmountInput.classList.remove('input-is-valid', 'input-is-invalid');
+ if (cleanInputNumber) {
+ eurAmountInput.value = formatNumberWithSpaces(cleanInputNumber);
+ eurAmountInput.classList.add('input-is-valid');
+ return;
+ }
+
+ eurAmountInput.classList.add('input-is-invalid');
+}
+
+function updateBtcInput() {
+ const eurToSatRate = 1021;
+ const cleanEurAmount = readIntFromEurAmountInput();
+
+ const satsAmount = cleanEurAmount * eurToSatRate;
+ const formattedSatsAmount = formatNumberWithSpaces(satsAmount);
+ btcAmountInput.value = formattedSatsAmount;
+}
+
+function validateBitcoinMethodCheckboxes(clickedCheckbox) {
+ let checkedCount = btcMethodCheckboxes.filter((cb) => cb.checked).length;
+ if (checkedCount === 0) {
+ clickedCheckbox.checked = true;
+ }
+}
+
+async function publishOffer() {
+ let wants;
+ if (buyButton.classList.contains('selected')) {
+ wants = 'BTC';
+ }
+ if (sellButton.classList.contains('selected')) {
+ wants = 'EUR';
+ }
+
+ const premium = parseInt(premiumValue.innerText.match(/\d+/)[0]) / 100;
+ const trade_amount_eur = eurAmountInput.value;
+ const location_details = placeInput.value;
+ const time_availability_details = timeInput.value;
+ const is_onchain_accepted = onchainCheckbox.checked;
+ const is_lightning_accepted = lightningCheckbox.checked;
+ const show_offer_to_trusted = myTrustedCheckbox.checked;
+ const show_offer_to_trusted_trusted = myTrustedTrustedCheckbox.checked;
+ const show_offer_to_all_members = allMembersCheckbox.checked;
+ const are_big_notes_accepted = bigNotesAcceptedCheckbox.checked;
+
+ const offerDetails = {
+ wants,
+ premium,
+ trade_amount_eur,
+ location_details,
+ time_availability_details,
+ is_onchain_accepted,
+ is_lightning_accepted,
+ show_offer_to_trusted,
+ show_offer_to_trusted_trusted,
+ show_offer_to_all_members,
+ are_big_notes_accepted,
+ };
+
+ await fetch('/api/offer', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({ offerDetails }),
+ });
+}
+
+buttonStartCreateOffer.addEventListener('click', () => {
+ toggleCreateOfferControls();
+});
+
+closeOfferControls.addEventListener('click', () => {
+ toggleCreateOfferControls();
+});
+
+buyOrSellButtons.forEach((button) => {
+ button.addEventListener('click', () => {
+ toggleBuyOrSellButtonGroup();
+ });
+});
+
+buttonIncreasePremium.addEventListener('click', () => {
+ modifyPremiumValue(1);
+});
+
+buttonDecreasePremium.addEventListener('click', () => {
+ modifyPremiumValue(-1);
+});
+
+eurAmountInput.addEventListener('blur', () => {
+ validateAndFormatEurAmountInput();
+ updateBtcInput();
+});
+
+eurAmountInput.addEventListener('input', () => {
+ eurAmountInput.value = eurAmountInput.value.replace(/[^0-9]/g, '');
+ updateBtcInput();
+});
+
+for (const btcMethodCheckbox of btcMethodCheckboxes) {
+ btcMethodCheckbox.addEventListener('click', () => {
+ validateBitcoinMethodCheckboxes(btcMethodCheckbox);
+ });
+}
+
+publishOfferButton.addEventListener('click', () => {
+ publishOffer();
+});
+
+updateBtcInput();
diff --git a/src/front/utils/formatNumbersWithSpaces.js b/src/public/javascript/utils.js
similarity index 71%
rename from src/front/utils/formatNumbersWithSpaces.js
rename to src/public/javascript/utils.js
index 1d1ee44..e8964e2 100644
--- a/src/front/utils/formatNumbersWithSpaces.js
+++ b/src/public/javascript/utils.js
@@ -1,5 +1,3 @@
function formatNumberWithSpaces(num) {
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ' ');
}
-
-module.exports = formatNumberWithSpaces;
diff --git a/src/public/kitty.jpeg b/src/public/kitty.jpeg
new file mode 100644
index 0000000..ed1ff6f
Binary files /dev/null and b/src/public/kitty.jpeg differ
diff --git a/src/routes/apiRoutes.js b/src/routes/apiRoutes.js
index 102cf6a..547cdb3 100644
--- a/src/routes/apiRoutes.js
+++ b/src/routes/apiRoutes.js
@@ -1,301 +1,237 @@
-class ApiRoutesProvider {
- constructor({ express, middlewares, services, errors }) {
- this.router = express.Router();
- this.middlewares = middlewares;
- this.services = services;
- this.errors = errors;
+const express = require('express');
+
+const invitesService = require('../services/invitesService');
+const nostrService = require('../services/nostrService');
+const loginService = require('../services/loginService');
+const sessionService = require('../services/sessionService');
+const profileService = require('../services/profileService');
+const offerService = require('../services/offerService');
+const errors = require('../errors');
+const attachPublicKeyMiddleware = require('../middlewares/attachPublicKeyMiddleware');
+const rejectIfNotAuthorizedMiddleware = require('../middlewares/rejectIfNotAuthorizedMiddleware');
+
+const router = express.Router();
+
+router.get('/signup/nostr-challenge', async (req, res) => {
+ const inviteUuid = req.cookies.inviteUuid;
+
+ let signUpChallenge;
+ try {
+ 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.',
+ });
+ }
+
+ if (error instanceof errors.AlreadyUsedError) {
+ return res.status(410).json({
+ success: false,
+ message: 'That invite has already been used.',
+ });
+ }
+
+ return res.status(500).json({
+ success: false,
+ message: 'Unexpected error.',
+ });
}
- provide() {
- this.router.get('/signup/nostr-challenge', async (req, res) => {
- const inviteUuid = req.cookies.inviteUuid;
-
- let signUpChallenge;
- try {
- signUpChallenge =
- await this.services.invitesService.createSignUpChallenge(inviteUuid);
- } catch (error) {
- if (error instanceof this.errors.NotFoundError) {
- return res.status(404).json({
- success: false,
- message: 'Could not find invite with that id.',
- });
- }
-
- if (error instanceof this.errors.AlreadyUsedError) {
- return res.status(410).json({
- success: false,
- message: 'That invite has already been used.',
- });
- }
-
- return res.status(500).json({
- success: false,
- message: 'Unexpected error.',
- });
- }
-
- let relatedNostrChallenge;
- try {
- relatedNostrChallenge =
- await this.services.nostrService.getNostrChallenge(
- signUpChallenge.nostr_challenge_uuid
- );
- } catch (error) {
- return res.status(500).json({
- success: false,
- message: `Unexpected error: ${error}`,
- });
- }
-
- return res
- .status(200)
- .json({ challenge: relatedNostrChallenge.challenge });
+ let relatedNostrChallenge;
+ try {
+ relatedNostrChallenge = await nostrService.getNostrChallenge(
+ signUpChallenge.nostr_challenge_uuid
+ );
+ } catch (error) {
+ return res.status(500).json({
+ success: false,
+ message: `Unexpected error: ${error}`,
});
-
- this.router.post('/signup/nostr-verify', async (req, res) => {
- const signedEvent = req.body;
- const sessionUuid = req.cookies.sessionUuid;
-
- let completedSignUpChallenge;
- try {
- completedSignUpChallenge =
- await this.services.invitesService.verifySignUpChallenge(signedEvent);
- } catch (error) {
- if (error instanceof this.errors.ExpiredError) {
- return res.status(410).json({
- success: false,
- message: 'The challenge has expired, request a new one.',
- });
- }
- if (error instanceof this.errors.AlreadyUsedError) {
- return res.status(410).json({
- success: false,
- message: 'The challenge has been used, request a new one.',
- });
- }
- if (error instanceof this.errors.InvalidSignatureError) {
- return res.status(400).json({
- success: false,
- message: 'The challenge signature is not valid.',
- });
- }
- }
-
- await this.services.sessionService.relateSessionToPublicKey(
- sessionUuid,
- completedSignUpChallenge.public_key
- );
-
- return res.status(200).json({ success: true });
- });
-
- this.router.get('/login/nostr-challenge', async (req, res) => {
- let loginChallenge;
- try {
- loginChallenge =
- await this.services.loginService.createLoginChallenge();
- } catch (error) {
- return res.status(500).json({
- success: false,
- message: 'Unexpected error.',
- });
- }
-
- let relatedNostrChallenge;
- try {
- relatedNostrChallenge =
- await this.services.nostrService.getNostrChallenge(
- loginChallenge.nostr_challenge_uuid
- );
- } catch (error) {
- return res.status(500).json({
- success: false,
- message: `Unexpected error: ${error}`,
- });
- }
-
- return res
- .status(200)
- .json({ challenge: relatedNostrChallenge.challenge });
- });
-
- this.router.post('/login/nostr-verify', async (req, res) => {
- const signedEvent = req.body;
- const sessionUuid = req.cookies.sessionUuid;
-
- let completedLoginChallenge;
- try {
- completedLoginChallenge =
- await this.services.loginService.verifyLoginChallenge(signedEvent);
- } catch (error) {
- if (error instanceof this.errors.ExpiredError) {
- return res.status(410).json({
- success: false,
- message: 'The challenge has expired, request a new one.',
- });
- }
- if (error instanceof this.errors.AlreadyUsedError) {
- return res.status(410).json({
- success: false,
- message: 'The challenge has been used, request a new one.',
- });
- }
- if (error instanceof this.errors.InvalidSignatureError) {
- return res.status(400).json({
- success: false,
- message: 'The challenge signature is not valid.',
- });
- }
- if (error instanceof this.errors.ForbiddenError) {
- return res.status(403).json({
- success: false,
- message: 'This public key is not authorized.',
- });
- }
-
- return res.status(500).json({
- success: false,
- message: 'Unexpected error.',
- });
- }
-
- await this.services.sessionService.relateSessionToPublicKey(
- sessionUuid,
- completedLoginChallenge.public_key
- );
-
- return res.status(200).json({ success: true });
- });
-
- this.router.post(
- '/set-contact-details',
- this.middlewares.rejectIfNotAuthorizedMiddleware,
- this.middlewares.attachPublicKeyMiddleware,
- async (req, res) => {
- const encryptedContactDetails = req.body.encryptedContactDetails;
- const publicKey = req.cookies.publicKey;
-
- if (!encryptedContactDetails) {
- return res.status(400).json({
- success: false,
- message: 'Missing contact details.',
- });
- }
-
- await this.services.profileService.setContactDetails(
- publicKey,
- encryptedContactDetails
- );
-
- return res.status(200).json({
- success: true,
- message: 'Contact details set successfully.',
- });
- }
- );
-
- this.router.post(
- '/set-nym',
- this.middlewares.rejectIfNotAuthorizedMiddleware,
- this.middlewares.attachPublicKeyMiddleware,
- async (req, res) => {
- const nym = req.body.nym;
- const publicKey = req.cookies.publicKey;
-
- if (!nym) {
- return res.status(400).json({
- success: false,
- message: 'Missing nym',
- });
- }
-
- await this.services.profileService.setNym(publicKey, nym);
-
- return res.status(200).json({
- success: true,
- message: 'Nym set successfully.',
- });
- }
- );
-
- this.router.post(
- '/offer',
- this.middlewares.rejectIfNotAuthorizedMiddleware,
- this.middlewares.attachPublicKeyMiddleware,
- async (req, res) => {
- const publicKey = req.cookies.publicKey;
- const offerDetails = req.body.offerDetails;
-
- await this.services.offerService.createOffer(publicKey, offerDetails);
-
- return res.status(200).json({
- success: true,
- message: 'Offer created successfully',
- });
- }
- );
-
- this.router.delete(
- '/offer/:offerUuid',
- this.middlewares.rejectIfNotAuthorizedMiddleware,
- this.middlewares.attachPublicKeyMiddleware,
- async (req, res) => {
- const offerUuid = req.params.offerUuid;
-
- try {
- await this.services.offerService.deleteOffer(offerUuid);
- } catch (error) {
- if (error instanceof this.errors.NotFoundError) {
- return res.status(404).json({
- success: false,
- message: 'Offer not found for the given public key.',
- });
- }
- return res.status(500).json({
- success: false,
- message: 'Unexpected error.',
- });
- }
-
- return res.status(204).json({
- success: true,
- message: 'Offer deleted successfully',
- });
- }
- );
-
- this.router.get(
- '/publickey-offers',
- this.middlewares.rejectIfNotAuthorizedMiddleware,
- this.middlewares.attachPublicKeyMiddleware,
- async (req, res) => {
- console.log('elo');
- const publicKey = req.cookies.publicKey;
-
- const offers =
- await this.services.offerService.getActiveOffersByPublicKey(
- publicKey
- );
-
- if (!offers) {
- return res.status(404).json({
- success: true,
- message: 'No offers posted by this public key.',
- });
- }
-
- if (offers) {
- return res.status(200).json({
- success: true,
- message: 'Offers found',
- data: offers,
- });
- }
- }
- );
-
- return this.router;
}
-}
-module.exports = ApiRoutesProvider;
+
+ return res.status(200).json({ challenge: relatedNostrChallenge.challenge });
+});
+
+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);
+ } catch (error) {
+ if (error instanceof errors.ExpiredError) {
+ return res.status(410).json({
+ success: false,
+ 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.',
+ });
+ }
+ if (error instanceof errors.InvalidSignatureError) {
+ 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 });
+});
+
+router.get('/login/nostr-challenge', async (req, res) => {
+ let loginChallenge;
+ try {
+ loginChallenge = await loginService.createLoginChallenge();
+ } catch (error) {
+ return res.status(500).json({
+ success: false,
+ message: 'Unexpected error.',
+ });
+ }
+
+ let relatedNostrChallenge;
+ try {
+ relatedNostrChallenge = await nostrService.getNostrChallenge(
+ loginChallenge.nostr_challenge_uuid
+ );
+ } catch (error) {
+ return res.status(500).json({
+ success: false,
+ message: `Unexpected error: ${error}`,
+ });
+ }
+
+ return res.status(200).json({ challenge: relatedNostrChallenge.challenge });
+});
+
+router.post('/login/nostr-verify', async (req, res) => {
+ const signedEvent = req.body;
+ const sessionUuid = req.cookies.sessionUuid;
+
+ let completedLoginChallenge;
+ try {
+ completedLoginChallenge =
+ await loginService.verifyLoginChallenge(signedEvent);
+ } catch (error) {
+ console.log('helo5');
+ console.log(error);
+ if (error instanceof errors.ExpiredError) {
+ return res.status(410).json({
+ success: false,
+ 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.',
+ });
+ }
+ if (error instanceof errors.InvalidSignatureError) {
+ return res.status(400).json({
+ success: false,
+ message: 'The challenge signature is not valid.',
+ });
+ }
+ if (error instanceof errors.ForbiddenError) {
+ console.log('helo?1');
+ return res.status(403).json({
+ success: false,
+ message: 'This public key is not authorized.',
+ });
+ }
+
+ return res.status(500).json({
+ success: false,
+ message: 'Unexpected error.',
+ });
+ }
+ console.log('helo?2');
+ console.log(completedLoginChallenge);
+ await sessionService.relateSessionToPublicKey(
+ sessionUuid,
+ completedLoginChallenge.public_key
+ );
+
+ return res.status(200).json({ success: true });
+});
+
+router.post(
+ '/set-contact-details',
+ rejectIfNotAuthorizedMiddleware,
+ attachPublicKeyMiddleware,
+ async (req, res) => {
+ const encryptedContactDetails = req.body.encryptedContactDetails;
+ const publicKey = req.cookies.publicKey;
+
+ if (!encryptedContactDetails) {
+ return res.status(400).json({
+ success: false,
+ message: 'Missing contact details.',
+ });
+ }
+
+ await profileService.setContactDetails(publicKey, encryptedContactDetails);
+
+ return res.status(200).json({
+ success: true,
+ message: 'Contact details set successfully.',
+ });
+ }
+);
+
+router.post(
+ '/set-nym',
+ rejectIfNotAuthorizedMiddleware,
+ attachPublicKeyMiddleware,
+ async (req, res) => {
+ const nym = req.body.nym;
+ const publicKey = req.cookies.publicKey;
+
+ if (!nym) {
+ return res.status(400).json({
+ success: false,
+ message: 'Missing nym',
+ });
+ }
+
+ await profileService.setNym(publicKey, nym);
+
+ return res.status(200).json({
+ success: true,
+ message: 'Nym set successfully.',
+ });
+ }
+);
+
+router.post(
+ '/offer',
+ rejectIfNotAuthorizedMiddleware,
+ attachPublicKeyMiddleware,
+ async (req, res) => {
+ const publicKey = req.cookies.publicKey;
+ const offerDetails = req.body.offerDetails;
+
+ await offerService.createOffer(publicKey, offerDetails);
+
+ return res.status(200).json({
+ success: true,
+ message: 'Offer created successfully',
+ });
+ }
+);
+
+module.exports = router;
diff --git a/src/routes/webRoutes.js b/src/routes/webRoutes.js
index b215aa5..fd6585e 100644
--- a/src/routes/webRoutes.js
+++ b/src/routes/webRoutes.js
@@ -1,88 +1,74 @@
-class WebRoutesProvider {
- constructor({ express, middlewares, invitesService }) {
- this.router = express.Router();
- this.middlewares = middlewares;
- this.invitesService = invitesService;
+const express = require('express');
+const router = express.Router();
+
+const redirectIfNotAuthorizedMiddleware = require('../middlewares/redirectIfNotAuthorizedMiddleware');
+const invitesService = require('../services/invitesService');
+const attachPublicKeyMiddleware = require('../middlewares/attachPublicKeyMiddleware');
+const redirectIfMissingProfileDetailsMiddleware = require('../middlewares/redirectIfMissingProfileDetailsMiddleware');
+const redirectHomeIfAuthorized = require('../middlewares/redirectHomeIfAuthorized');
+
+router.get(
+ '/',
+ redirectHomeIfAuthorized,
+ redirectIfNotAuthorizedMiddleware,
+ (req, res) => {
+ res.redirect('/login');
+ }
+);
+
+router.get('/login', redirectHomeIfAuthorized, (req, res) => {
+ res.render('login', { uuid: req.cookies.sessionUuid });
+});
+
+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' });
}
- provide() {
- this.router.get(
- '/',
- this.middlewares.redirectHomeIfAuthorized,
- this.middlewares.redirectIfNotAuthorizedMiddleware,
- (req, res) => {
- res.redirect('/login');
- }
- );
+ return res.render('invite', { invite });
+});
- this.router.get(
- '/login',
- this.middlewares.redirectHomeIfAuthorized,
- (req, res) => {
- res.render('login', { uuid: req.cookies.sessionUuid });
- }
- );
-
- this.router.get('/invite/:inviteUuid', async (req, res) => {
- const { inviteUuid } = req.params;
-
- res.cookie('inviteUuid', inviteUuid, {
- httpOnly: true,
- maxAge: 86400000,
- });
-
- let invite;
- try {
- invite = await this.invitesService.getAppInvite(inviteUuid);
- if (!invite) {
- return res
- .status(404)
- .render('error', { message: 'Invite not found.' });
- }
-
- if (await this.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 });
- });
-
- this.router.get(
- '/createProfile',
- this.middlewares.redirectIfNotAuthorizedMiddleware,
- async (req, res) => {
- return res.status(200).render('createProfile');
- }
- );
-
- this.router.get(
- '/home',
- this.middlewares.redirectIfNotAuthorizedMiddleware,
- this.middlewares.attachPublicKeyMiddleware,
- this.middlewares.redirectIfMissingProfileDetailsMiddleware,
- (req, res) => {
- res.render('home', {});
- }
- );
-
- this.router.get(
- '/offers',
- this.middlewares.redirectIfNotAuthorizedMiddleware,
- this.middlewares.attachPublicKeyMiddleware,
- this.middlewares.redirectIfMissingProfileDetailsMiddleware,
- (req, res) => {
- res.render('offers', {});
- }
- );
-
- return this.router;
+router.get(
+ '/createProfile',
+ redirectIfNotAuthorizedMiddleware,
+ async (req, res) => {
+ return res.status(200).render('createProfile');
}
-}
+);
-module.exports = WebRoutesProvider;
+router.get(
+ '/home',
+ redirectIfNotAuthorizedMiddleware,
+ attachPublicKeyMiddleware,
+ redirectIfMissingProfileDetailsMiddleware,
+ (req, res) => {
+ res.render('home', {});
+ }
+);
+
+router.get(
+ '/offers',
+ redirectIfNotAuthorizedMiddleware,
+ attachPublicKeyMiddleware,
+ redirectIfMissingProfileDetailsMiddleware,
+ (req, res) => {
+ res.render('offers', {});
+ }
+);
+
+module.exports = router;
diff --git a/src/services/index.js b/src/services/index.js
deleted file mode 100644
index 1ec7ea2..0000000
--- a/src/services/index.js
+++ /dev/null
@@ -1,61 +0,0 @@
-class ServicesProvider {
- constructor({ models, constants, errors, sequelize }) {
- this.models = models;
- this.constants = constants;
- this.errors = errors;
- this.sequelize = sequelize;
- }
-
- provide() {
- const NostrServiceProvider = require('../services/nostrService');
- const nostrService = new NostrServiceProvider({
- models: this.models,
- constants: this.constants,
- errors: this.errors,
- }).provide();
-
- const InvitesServiceProvider = require('../services/invitesService');
- const invitesService = new InvitesServiceProvider({
- models: this.models,
- errors: this.errors,
- nostrService: nostrService,
- }).provide();
-
- const LoginServiceProvider = require('../services/loginService');
- const loginService = new LoginServiceProvider({
- models: this.models,
- errors: this.errors,
- nostrService,
- invitesService,
- }).provide();
-
- const SessionServiceProvider = require('../services/sessionService');
- const sessionService = new SessionServiceProvider({
- models: this.models,
- constants: this.constants,
- invitesService,
- }).provide();
-
- const ProfileServiceProvider = require('../services/profileService');
- const profileService = new ProfileServiceProvider({
- models: this.models,
- }).provide();
- const OfferServiceProvider = require('../services/offerService');
- const offerService = new OfferServiceProvider({
- models: this.models,
- errors: this.errors,
- sequelize: this.sequelize,
- }).provide();
-
- return {
- invitesService,
- nostrService,
- loginService,
- sessionService,
- profileService,
- offerService,
- };
- }
-}
-
-module.exports = ServicesProvider;
diff --git a/src/services/invitesService.js b/src/services/invitesService.js
index df357e3..432633c 100644
--- a/src/services/invitesService.js
+++ b/src/services/invitesService.js
@@ -1,134 +1,119 @@
const uuid = require('uuid');
-class InvitesServiceProvider {
- constructor({ models, errors, nostrService }) {
- this.models = models;
- this.errors = errors;
- this.nostrService = nostrService;
- }
-
- provide() {
- const appInviteExists = async (inviteUuid) => {
- const invite = await this.models.AppInviteCreated.findOne({
- where: { uuid: inviteUuid },
- });
- if (invite) {
- return true;
- }
- return false;
- };
-
- const getAppInvite = async (inviteUuid) => {
- const invite = await this.models.AppInviteCreated.findOne({
- where: { uuid: inviteUuid },
- });
- return invite;
- };
-
- const isAppInviteSpent = async (appInviteUuid) => {
- const signUpChallengeCompleted =
- await this.models.SignUpChallengeCompleted.findOne({
- where: {
- app_invite_uuid: appInviteUuid,
- },
- });
-
- if (signUpChallengeCompleted) {
- return true;
- }
- return false;
- };
-
- const createAppInvite = async (inviterPubKey) => {
- return await this.models.AppInviteCreated.create({
- uuid: uuid.v7(),
- inviter_pub_key: inviterPubKey,
- created_at: new Date().toISOString(),
- });
- };
-
- const createSignUpChallenge = async (appInviteUuid) => {
- if (!(await appInviteExists(appInviteUuid))) {
- throw new this.errors.NotFoundError("Invite doesn't exist.");
- }
-
- if (await isAppInviteSpent(appInviteUuid)) {
- throw new this.errors.AlreadyUsedError('Invite has already been used.');
- }
-
- const nostrChallenge = await this.nostrService.createNostrChallenge();
-
- return await this.models.SignUpChallengeCreated.create({
- uuid: uuid.v7(),
- nostr_challenge_uuid: nostrChallenge.uuid,
- app_invite_uuid: appInviteUuid,
- created_at: new Date().toISOString(),
- });
- };
-
- const verifySignUpChallenge = async (signedEvent) => {
- const challengeTag = signedEvent.tags.find(
- (tag) => tag[0] === 'challenge'
- );
- const challenge = challengeTag[1];
-
- const nostrChallenge = await this.nostrService.getNostrChallenge(
- null,
- challenge
- );
-
- const signUpChallenge = await this.models.SignUpChallengeCreated.findOne({
- where: {
- nostr_challenge_uuid: nostrChallenge.uuid,
- },
- });
-
- if (await this.nostrService.hasNostrChallengeBeenCompleted(challenge)) {
- throw new this.errors.AlreadyUsedError(
- 'This challenge has already been used.'
- );
- }
-
- const completedNostrChallenge =
- await this.nostrService.verifyNostrChallenge(signedEvent);
-
- const completedSignUpChallenge =
- await this.models.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(),
- });
-
- return completedSignUpChallenge;
- };
-
- const isPublicKeySignedUp = async (publicKey) => {
- const signUpChallengeCompleted =
- await this.models.SignUpChallengeCompleted.findOne({
- where: {
- public_key: publicKey,
- },
- });
-
- if (signUpChallengeCompleted) {
- return true;
- }
-
- return false;
- };
-
- return {
- appInviteExists,
- getAppInvite,
- isAppInviteSpent,
- createAppInvite,
- createSignUpChallenge,
- verifySignUpChallenge,
- isPublicKeySignedUp,
- };
+const nostrService = require('./nostrService');
+const AppInviteCreated = require('../models/AppInviteCreated');
+const SignUpChallengeCreated = require('../models/SignUpChallengeCreated');
+const SignUpChallengeCompleted = require('../models/SignUpChallengeCompleted');
+
+const errors = require('../errors');
+
+async function appInviteExists(inviteUuid) {
+ const invite = await AppInviteCreated.findOne({
+ where: { uuid: inviteUuid },
+ });
+ if (invite) {
+ return true;
}
+ return false;
}
-module.exports = InvitesServiceProvider;
+async function getAppInvite(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,
+ },
+ });
+
+ if (signUpChallengeCompleted) {
+ return true;
+ }
+ return false;
+}
+
+async function createAppInvite(inviterPubKey) {
+ return await AppInviteCreated.create({
+ uuid: uuid.v7(),
+ inviter_pub_key: inviterPubKey,
+ created_at: new Date().toISOString(),
+ });
+}
+
+async function createSignUpChallenge(appInviteUuid) {
+ if (!(await appInviteExists(appInviteUuid))) {
+ throw new errors.NotFoundError("Invite doesn't exist.");
+ }
+
+ if (await isAppInviteSpent(appInviteUuid)) {
+ throw new errors.AlreadyUsedError('Invite has already been used.');
+ }
+
+ const nostrChallenge = await nostrService.createNostrChallenge();
+
+ return await SignUpChallengeCreated.create({
+ uuid: uuid.v7(),
+ nostr_challenge_uuid: nostrChallenge.uuid,
+ app_invite_uuid: appInviteUuid,
+ created_at: new Date().toISOString(),
+ });
+}
+
+async function verifySignUpChallenge(signedEvent) {
+ const challengeTag = signedEvent.tags.find((tag) => tag[0] === 'challenge');
+ const challenge = challengeTag[1];
+
+ const nostrChallenge = await nostrService.getNostrChallenge(null, challenge);
+
+ const signUpChallenge = await SignUpChallengeCreated.findOne({
+ where: {
+ nostr_challenge_uuid: nostrChallenge.uuid,
+ },
+ });
+
+ if (await nostrService.hasNostrChallengeBeenCompleted(challenge)) {
+ throw new errors.AlreadyUsedError('This challenge has already been used.');
+ }
+
+ const completedNostrChallenge =
+ await nostrService.verifyNostrChallenge(signedEvent);
+
+ 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(),
+ });
+
+ return completedSignUpChallenge;
+}
+
+async function isPublicKeySignedUp(publicKey) {
+ const signUpChallengeCompleted = await SignUpChallengeCompleted.findOne({
+ where: {
+ public_key: publicKey,
+ },
+ });
+
+ if (signUpChallengeCompleted) {
+ return true;
+ }
+
+ return false;
+}
+
+module.exports = {
+ appInviteExists,
+ getAppInvite,
+ isAppInviteSpent,
+ createAppInvite,
+ createSignUpChallenge,
+ verifySignUpChallenge,
+ isPublicKeySignedUp,
+};
diff --git a/src/services/loginService.js b/src/services/loginService.js
index 73a0b58..9d5f973 100644
--- a/src/services/loginService.js
+++ b/src/services/loginService.js
@@ -1,64 +1,58 @@
const uuid = require('uuid');
-class LoginServiceProvider {
- constructor({ models, errors, nostrService, invitesService }) {
- this.models = models;
- this.errors = errors;
- this.nostrService = nostrService;
- this.invitesService = invitesService;
- }
+const nostrService = require('./nostrService');
+const invitesService = require('./invitesService');
+const LoginChallengeCreated = require('../models/LoginChallengeCreated');
+const LoginChallengeCompleted = require('../models/LoginChallengeCompleted');
- provide() {
- const createLoginChallenge = async () => {
- const nostrChallenge = await this.nostrService.createNostrChallenge();
+const errors = require('../errors');
- return await this.models.LoginChallengeCreated.create({
- uuid: uuid.v7(),
- nostr_challenge_uuid: nostrChallenge.uuid,
- created_at: new Date().toISOString(),
- });
- };
+async function createLoginChallenge() {
+ const nostrChallenge = await nostrService.createNostrChallenge();
- const verifyLoginChallenge = async (signedEvent) => {
- const challengeTag = signedEvent.tags.find(
- (tag) => tag[0] === 'challenge'
- );
- const challenge = challengeTag[1];
-
- if (await this.nostrService.hasNostrChallengeBeenCompleted(challenge)) {
- throw new this.errors.AlreadyUsedError(
- 'This challenge has already been used.'
- );
- }
-
- const completedNostrChallenge =
- await this.nostrService.verifyNostrChallenge(signedEvent);
-
- if (
- !(await this.invitesService.isPublicKeySignedUp(
- completedNostrChallenge.public_key
- ))
- ) {
- throw new this.errors.ForbiddenError(
- `Public key ${completedNostrChallenge.public_key} is not authorized.`
- );
- }
-
- const completedLoginChallenge =
- await this.models.LoginChallengeCompleted.create({
- uuid: uuid.v7(),
- nostr_challenge_completed_uuid: completedNostrChallenge.uuid,
- public_key: completedNostrChallenge.public_key,
- created_at: new Date().toISOString(),
- });
-
- return completedLoginChallenge;
- };
-
- return {
- createLoginChallenge,
- verifyLoginChallenge,
- };
- }
+ return await LoginChallengeCreated.create({
+ uuid: uuid.v7(),
+ nostr_challenge_uuid: nostrChallenge.uuid,
+ created_at: new Date().toISOString(),
+ });
}
-module.exports = LoginServiceProvider;
+
+async function verifyLoginChallenge(signedEvent) {
+ const challengeTag = signedEvent.tags.find((tag) => tag[0] === 'challenge');
+ const challenge = challengeTag[1];
+
+ if (await nostrService.hasNostrChallengeBeenCompleted(challenge)) {
+ throw new errors.AlreadyUsedError('This challenge has already been used.');
+ }
+
+ const completedNostrChallenge =
+ await nostrService.verifyNostrChallenge(signedEvent);
+
+ if (
+ !(await invitesService.isPublicKeySignedUp(
+ completedNostrChallenge.public_key
+ ))
+ ) {
+ console.log('helo4');
+ throw new errors.ForbiddenError(
+ `Public key ${completedNostrChallenge.public_key} is not authorized.`
+ );
+ }
+
+ const completedLoginChallenge = await LoginChallengeCompleted.create({
+ uuid: uuid.v7(),
+ nostr_challenge_completed_uuid: completedNostrChallenge.uuid,
+ public_key: completedNostrChallenge.public_key,
+ created_at: new Date().toISOString(),
+ });
+
+ console.log('helo3');
+ console.log(completedLoginChallenge);
+
+ return completedLoginChallenge;
+}
+
+module.exports = {
+ createLoginChallenge,
+ verifyLoginChallenge,
+};
diff --git a/src/services/nostrService.js b/src/services/nostrService.js
index 7d87ea6..542ba1c 100644
--- a/src/services/nostrService.js
+++ b/src/services/nostrService.js
@@ -1,126 +1,113 @@
const uuid = require('uuid');
const crypto = require('crypto');
-const { Op } = require('sequelize');
+const { Op, TimeoutError } = require('sequelize');
const { verifyEvent } = require('nostr-tools');
-class NostrServiceProvider {
- constructor({ models, constants, errors }) {
- this.models = models;
- this.constants = constants;
- this.errors = errors;
- }
+const NostrChallengeCreated = require('../models/NostrChallengeCreated');
+const NostrChallengeCompleted = require('../models/NostrChallengeCompleted');
- provide() {
- const createNostrChallenge = async () => {
- const currentTimestamp = new Date();
- const expiryTimestamp = new Date(currentTimestamp.getTime());
- expiryTimestamp.setSeconds(
- expiryTimestamp.getSeconds() +
- this.constants.DEFAULT_NOSTR_CHALLENGE_DURATION_SECONDS
- );
+const constants = require('../constants');
+const errors = require('../errors');
- const nostrChallenge = await this.models.NostrChallengeCreated.create({
- uuid: uuid.v7(),
- challenge: crypto.randomBytes(32).toString('hex'),
- expires_at: expiryTimestamp.toISOString(),
- created_at: currentTimestamp.toISOString(),
- });
+async function createNostrChallenge() {
+ const currentTimestamp = new Date();
+ const expiryTimestamp = new Date(currentTimestamp.getTime());
+ expiryTimestamp.setSeconds(
+ expiryTimestamp.getSeconds() +
+ constants.DEFAULT_NOSTR_CHALLENGE_DURATION_SECONDS
+ );
- return nostrChallenge;
- };
+ const nostrChallenge = await NostrChallengeCreated.create({
+ uuid: uuid.v7(),
+ challenge: crypto.randomBytes(32).toString('hex'),
+ expires_at: expiryTimestamp.toISOString(),
+ created_at: currentTimestamp.toISOString(),
+ });
- const getNostrChallenge = async (
- nostrChallengeUuid = null,
- challenge = null
- ) => {
- if (nostrChallengeUuid) {
- return await this.models.NostrChallengeCreated.findOne({
- where: {
- uuid: nostrChallengeUuid,
- },
- });
- }
-
- if (challenge) {
- return await this.models.NostrChallengeCreated.findOne({
- where: {
- challenge,
- },
- });
- }
-
- throw Error('You need to pass a uuid or a challenge.');
- };
-
- const verifyNostrChallenge = async (signedEvent) => {
- const challengeTag = signedEvent.tags.find(
- (tag) => tag[0] === 'challenge'
- );
- const challenge = challengeTag[1];
-
- if (!(await isNostrChallengeFresh(challenge))) {
- throw new this.errors.ExpiredError(
- 'Challenge expired, request new one.'
- );
- }
-
- if (await hasNostrChallengeBeenCompleted(challenge)) {
- throw new this.errors.AlreadyUsedError(
- 'Challenge already used, request new one.'
- );
- }
-
- const isSignatureValid = verifyEvent(signedEvent);
- if (!isSignatureValid) {
- throw new this.errors.InvalidSignatureError('Signature is not valid.');
- }
-
- return await this.models.NostrChallengeCompleted.create({
- uuid: uuid.v7(),
- challenge: challenge,
- signed_event: signedEvent,
- public_key: signedEvent.pubkey,
- created_at: new Date().toISOString(),
- });
- };
-
- const isNostrChallengeFresh = async (challengeString) => {
- const nostrChallenge = await this.models.NostrChallengeCreated.findOne({
- where: {
- challenge: challengeString,
- expires_at: {
- [Op.gt]: new Date(),
- },
- },
- });
-
- if (nostrChallenge) {
- return true;
- }
- return false;
- };
-
- const hasNostrChallengeBeenCompleted = async (challengeString) => {
- const completedNostrChallenge =
- await this.models.NostrChallengeCompleted.findOne({
- where: {
- challenge: challengeString,
- },
- });
-
- if (completedNostrChallenge) {
- return true;
- }
- return false;
- };
-
- return {
- createNostrChallenge,
- getNostrChallenge,
- verifyNostrChallenge,
- isNostrChallengeFresh,
- hasNostrChallengeBeenCompleted,
- };
- }
+ return nostrChallenge;
}
-module.exports = NostrServiceProvider;
+
+async function getNostrChallenge(nostrChallengeUuid = null, challenge = null) {
+ if (nostrChallengeUuid) {
+ return await NostrChallengeCreated.findOne({
+ where: {
+ uuid: nostrChallengeUuid,
+ },
+ });
+ }
+
+ if (challenge) {
+ return await NostrChallengeCreated.findOne({
+ where: {
+ 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 challenge = challengeTag[1];
+
+ if (!(await isNostrChallengeFresh(challenge))) {
+ throw TimeoutError('Challenge expired, request new one.');
+ }
+
+ if (await hasNostrChallengeBeenCompleted(challenge)) {
+ throw new errors.AlreadyUsedError(
+ 'Challenge already used, request new one.'
+ );
+ }
+
+ const isSignatureValid = verifyEvent(signedEvent);
+ if (!isSignatureValid) {
+ throw new errors.InvalidSignatureError('Signature is not valid.');
+ }
+
+ return await NostrChallengeCompleted.create({
+ uuid: uuid.v7(),
+ challenge: challenge,
+ signed_event: signedEvent,
+ public_key: signedEvent.pubkey,
+ created_at: new Date().toISOString(),
+ });
+}
+
+async function isNostrChallengeFresh(challengeString) {
+ const nostrChallenge = await NostrChallengeCreated.findOne({
+ where: {
+ challenge: challengeString,
+ expires_at: {
+ [Op.gt]: new Date(),
+ },
+ },
+ });
+
+ if (nostrChallenge) {
+ return true;
+ }
+ return false;
+}
+
+async function hasNostrChallengeBeenCompleted(challengeString) {
+ const completedNostrChallenge = await NostrChallengeCompleted.findOne({
+ where: {
+ challenge: challengeString,
+ },
+ });
+
+ if (completedNostrChallenge) {
+ return true;
+ }
+ return false;
+}
+
+module.exports = {
+ createNostrChallenge,
+ getNostrChallenge,
+ verifyNostrChallenge,
+ isNostrChallengeFresh,
+ hasNostrChallengeBeenCompleted,
+};
diff --git a/src/services/offerService.js b/src/services/offerService.js
index bd65fd8..cca3b39 100644
--- a/src/services/offerService.js
+++ b/src/services/offerService.js
@@ -1,126 +1,30 @@
const uuid = require('uuid');
-class OfferServiceProvider {
- constructor({ models, errors, sequelize }) {
- this.models = models;
- this.errors = errors;
- this.sequelize = sequelize;
- }
- provide() {
- const createOffer = async (publicKey, offerDetails) => {
- const createOfferTransaction = await this.sequelize.transaction();
- try {
- const offerCreated = await this.models.OfferCreated.create(
- {
- uuid: uuid.v7(),
- public_key: publicKey,
- created_at: new Date().toISOString(),
- },
- { transaction: createOfferTransaction }
- );
+const OfferCreated = require('../models/OfferCreated');
+const OfferDetailsSet = require('../models/OfferDetailsSet');
- await this.models.OfferDetailsSet.create(
- {
- uuid: uuid.v7(),
- offer_uuid: offerCreated.uuid,
- wants: offerDetails.wants,
- premium: offerDetails.premium,
- trade_amount_eur: offerDetails.trade_amount_eur,
- location_details: offerDetails.location_details,
- time_availability_details: offerDetails.time_availability_details,
- show_offer_to_trusted: offerDetails.show_offer_to_trusted,
- show_offer_to_trusted_trusted:
- offerDetails.show_offer_to_trusted_trusted,
- show_offer_to_all_members: offerDetails.show_offer_to_all_members,
- is_onchain_accepted: offerDetails.is_onchain_accepted,
- is_lightning_accepted: offerDetails.is_lightning_accepted,
- are_big_notes_accepted: offerDetails.are_big_notes_accepted,
- created_at: new Date().toISOString(),
- },
- { transaction: createOfferTransaction }
- );
- await createOfferTransaction.commit();
- } catch (error) {
- await createOfferTransaction.rollback();
- }
- };
+async function createOffer(publicKey, offerDetails) {
+ const offerCreated = await OfferCreated.create({
+ uuid: uuid.v7(),
+ public_key: publicKey,
+ created_at: new Date().toISOString(),
+ });
- const deleteOffer = async (offerUuid) => {
- const offerExists = Boolean(
- await this.models.OfferCreated.findOne({ where: { uuid: offerUuid } })
- );
- const offerHasBeenDeleted = Boolean(
- await this.models.OfferDeleted.findOne({
- where: { offer_uuid: offerUuid },
- })
- );
-
- if (!offerExists || offerHasBeenDeleted) {
- throw new this.errors.NotFoundError(`Could not find the offer.`);
- }
-
- return this.models.OfferDeleted.create({
- uuid: uuid.v7(),
- offer_uuid: offerUuid,
- created_at: new Date().toISOString(),
- });
- };
-
- const getActiveOffersByPublicKey = async (publicKey) => {
- const activeOffers = await this.models.OfferCreated.findAll({
- where: {
- public_key: publicKey,
- '$OfferDeleted.uuid$': null,
- },
- include: { model: this.models.OfferDeleted, required: false },
- });
-
- console.log(activeOffers);
-
- if (!activeOffers) {
- return [];
- }
-
- const offersToReturn = [];
- if (activeOffers) {
- for (const someOffer of activeOffers) {
- const offerDetails = await this.models.OfferDetailsSet.findOne({
- where: {
- offer_uuid: someOffer.uuid,
- },
- order: [['created_at', 'DESC']],
- });
-
- offersToReturn.push({
- uuid: someOffer.uuid,
- public_key: someOffer.public_key,
- wants: offerDetails.wants,
- premium: offerDetails.premium,
- trade_amount_eur: offerDetails.trade_amount_eur,
- location_details: offerDetails.location_details,
- time_availability_details: offerDetails.time_availability_details,
- show_offer_to_trusted: offerDetails.show_offer_to_trusted,
- show_offer_to_trusted_trusted:
- offerDetails.show_offer_to_trusted_trusted,
- show_offer_to_all_members: offerDetails.show_offer_to_all_members,
- is_onchain_accepted: offerDetails.is_onchain_accepted,
- is_lightning_accepted: offerDetails.is_lightning_accepted,
- are_big_notes_accepted: offerDetails.are_big_notes_accepted,
- created_at: someOffer.created_at,
- last_updated_at: offerDetails.created_at,
- });
- }
- }
-
- return offersToReturn;
- };
-
- return {
- createOffer,
- getActiveOffersByPublicKey,
- deleteOffer,
- };
- }
+ const offerDetailsSet = await OfferDetailsSet.create({
+ uuid: uuid.v7(),
+ offer_uuid: offerCreated.uuid,
+ wants: offerDetails.wants,
+ premium: offerDetails.premium,
+ trade_amount_eur: offerDetails.trade_amount_eur,
+ location_details: offerDetails.location_details,
+ time_availability_details: offerDetails.time_availability_details,
+ show_offer_to_trusted: offerDetails.show_offer_to_trusted,
+ show_offer_to_trusted_trusted: offerDetails.show_offer_to_trusted_trusted,
+ show_offer_to_all_members: offerDetails.show_offer_to_all_members,
+ is_onchain_accepted: offerDetails.is_onchain_accepted,
+ is_lightning_accepted: offerDetails.is_lightning_accepted,
+ are_big_notes_accepted: offerDetails.are_big_notes_accepted,
+ created_at: new Date().toISOString(),
+ });
}
-
-module.exports = OfferServiceProvider;
+module.exports = { createOffer };
diff --git a/src/services/profileService.js b/src/services/profileService.js
index aca4247..5db0c24 100644
--- a/src/services/profileService.js
+++ b/src/services/profileService.js
@@ -1,44 +1,38 @@
const uuid = require('uuid');
+const ContactDetailsSet = require('../models/ContactDetailsSet');
+const NymSet = require('../models/NymSet');
-class ProfileServiceProvider {
- constructor({ models }) {
- this.models = models;
- }
- provide() {
- const setContactDetails = async (publicKey, encryptedContactDetails) => {
- return await this.models.ContactDetailsSet.create({
- uuid: uuid.v7(),
- public_key: publicKey,
- encrypted_contact_details: encryptedContactDetails,
- created_at: new Date().toISOString(),
- });
- };
-
- const setNym = async (publicKey, nym) => {
- return await this.models.NymSet.create({
- uuid: uuid.v7(),
- public_key: publicKey,
- nym: nym,
- created_at: new Date().toISOString(),
- });
- };
-
- const areProfileDetailsComplete = async (publicKey) => {
- console.log(this.models);
- const isNymSet = await this.models.NymSet.findOne({
- where: { public_key: publicKey },
- });
- const areContactDetailsSet = await this.models.ContactDetailsSet.findOne({
- where: {
- public_key: publicKey,
- },
- });
-
- return isNymSet && areContactDetailsSet;
- };
-
- return { setContactDetails, setNym, areProfileDetailsComplete };
- }
+async function setContactDetails(publicKey, encryptedContactDetails) {
+ return await ContactDetailsSet.create({
+ uuid: uuid.v7(),
+ public_key: publicKey,
+ encrypted_contact_details: encryptedContactDetails,
+ created_at: new Date().toISOString(),
+ });
}
-module.exports = ProfileServiceProvider;
+async function setNym(publicKey, nym) {
+ return await NymSet.create({
+ uuid: uuid.v7(),
+ public_key: publicKey,
+ nym: nym,
+ created_at: new Date().toISOString(),
+ });
+}
+
+async function areProfileDetailsComplete(publicKey) {
+ const isNymSet = await NymSet.findOne({ where: { public_key: publicKey } });
+ const areContactDetailsSet = await ContactDetailsSet.findOne({
+ where: {
+ public_key: publicKey,
+ },
+ });
+
+ return isNymSet && areContactDetailsSet;
+}
+
+module.exports = {
+ setContactDetails,
+ setNym,
+ areProfileDetailsComplete,
+};
diff --git a/src/services/sessionService.js b/src/services/sessionService.js
index e731846..452f390 100644
--- a/src/services/sessionService.js
+++ b/src/services/sessionService.js
@@ -1,101 +1,92 @@
const uuid = require('uuid');
-class SessionServiceProvider {
- constructor({ models, constants, invitesService }) {
- this.models = models;
- this.constants = constants;
- this.invitesService = invitesService;
- }
+const SessionCreated = require('../models/SessionCreated');
+const SessionRelatedToPublickey = require('../models/SessionRelatedToPublickey');
- provide() {
- const createSession = async (sessionUuid) => {
- const currentTimestamp = new Date();
- const expiryTimestamp = new Date(currentTimestamp.getTime());
- expiryTimestamp.setSeconds(
- expiryTimestamp.getSeconds() +
- this.constants.DEFAULT_SESSION_DURATION_SECONDS
- );
+const invitesService = require('./invitesService');
+const constants = require('../constants');
- return await this.models.SessionCreated.create({
- uuid: sessionUuid,
- created_at: currentTimestamp.toISOString(),
- expires_at: expiryTimestamp.toISOString(),
- });
- };
+async function createSession(sessionUuid) {
+ const currentTimestamp = new Date();
+ const expiryTimestamp = new Date(currentTimestamp.getTime());
+ expiryTimestamp.setSeconds(
+ expiryTimestamp.getSeconds() + constants.DEFAULT_SESSION_DURATION_SECONDS
+ );
- const isSessionValid = async (sessionUuid) => {
- const currentSession = await this.models.SessionCreated.findOne({
- where: {
- uuid: sessionUuid,
- },
- });
-
- if (!currentSession) {
- return false;
- }
-
- if (currentSession.expires_at <= new Date()) {
- return false;
- }
-
- return true;
- };
-
- const relateSessionToPublicKey = async (sessionUuid, publicKey) => {
- if (!(await isSessionValid(sessionUuid))) {
- throw Error('Session is not valid anymore.');
- }
-
- if (!(await this.invitesService.isPublicKeySignedUp(publicKey))) {
- throw Error('Public key is not signed up.');
- }
-
- return this.models.SessionRelatedToPublickey.create({
- uuid: uuid.v7(),
- session_uuid: sessionUuid,
- public_key: publicKey,
- created_at: new Date().toISOString(),
- });
- };
-
- const isSessionAuthorized = async (sessionUuid) => {
- const isSessionRelatedToPublicKey =
- await this.models.SessionRelatedToPublickey.findOne({
- where: {
- session_uuid: sessionUuid,
- },
- });
-
- if (isSessionRelatedToPublicKey) {
- return true;
- }
-
- return false;
- };
-
- const getPublicKeyRelatedToSession = async (sessionUuid) => {
- const sessionRelatedToPublickey =
- await this.models.SessionRelatedToPublickey.findOne({
- where: {
- session_uuid: sessionUuid,
- },
- });
-
- if (sessionRelatedToPublickey) {
- return sessionRelatedToPublickey.public_key;
- }
-
- return null;
- };
-
- return {
- createSession,
- isSessionValid,
- relateSessionToPublicKey,
- isSessionAuthorized,
- getPublicKeyRelatedToSession,
- };
- }
+ return await SessionCreated.create({
+ uuid: sessionUuid,
+ created_at: currentTimestamp.toISOString(),
+ expires_at: expiryTimestamp.toISOString(),
+ });
}
-module.exports = SessionServiceProvider;
+async function isSessionValid(sessionUuid) {
+ const currentSession = await SessionCreated.findOne({
+ where: {
+ uuid: sessionUuid,
+ },
+ });
+
+ if (!currentSession) {
+ return false;
+ }
+
+ if (currentSession.expires_at <= new Date()) {
+ return false;
+ }
+
+ return true;
+}
+
+async function relateSessionToPublicKey(sessionUuid, publicKey) {
+ 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(),
+ });
+}
+
+async function isSessionAuthorized(sessionUuid) {
+ const isSessionRelatedToPublicKey = await SessionRelatedToPublickey.findOne({
+ where: {
+ session_uuid: sessionUuid,
+ },
+ });
+
+ if (isSessionRelatedToPublicKey) {
+ return true;
+ }
+
+ return false;
+}
+
+async function getPublicKeyRelatedToSession(sessionUuid) {
+ const sessionRelatedToPublickey = await SessionRelatedToPublickey.findOne({
+ where: {
+ session_uuid: sessionUuid,
+ },
+ });
+
+ if (sessionRelatedToPublickey) {
+ return sessionRelatedToPublickey.public_key;
+ }
+
+ return null;
+}
+
+module.exports = {
+ createSession,
+ isSessionValid,
+ relateSessionToPublicKey,
+ isSessionAuthorized,
+ getPublicKeyRelatedToSession,
+};
diff --git a/src/views/createOffer.ejs b/src/views/createOffer.ejs
new file mode 100644
index 0000000..3ea5150
--- /dev/null
+++ b/src/views/createOffer.ejs
@@ -0,0 +1,25 @@
+
+
+
+ Seca home
+
+
+
+
+
+
+
+
la seca
+ Home
+ Ofertas
+ Red
+ Mi perfil
+
+
+ Crear oferta
+
+
+
Crear oferta
+
+
+
diff --git a/src/views/createProfile.ejs b/src/views/createProfile.ejs
index d4be5ec..87b57ef 100644
--- a/src/views/createProfile.ejs
+++ b/src/views/createProfile.ejs
@@ -4,131 +4,131 @@
Crear perfil
- <%- include("partials/commonStyles") %>
-
+
-
-
-
Crea tu perfil
-
Tu clave de Nostr ya es parte de la seca.
-
Añade detalles a tu perfil para poder empezar a comerciar.
-
-
-
-
-
Pseudónimo (Nym):
-
-
- Debe tener al menos 3 caracteres.
-
-
-
-
Métodos de contacto
-
-
- Crear perfil
-
-
+
+
Crea tu perfil
+
Tu clave de Nostr ya es parte de la seca.
+
Añade detalles a tu perfil para poder empezar a comerciar.
-
-
-
- ¡Bien! Tu perfil está completo. Te estamos llevando a la aplicación...
-
+
+
+
Perfil
+
Pseudónimo (Nym):
+
+
+ Debe tener al menos 3 caracteres.
+
+
+
+
+
+
Datos de contacto
+
+
+ Crear perfil
+
+
-
+