Skip to content

Commit

Permalink
Add security token on disputes (#546)
Browse files Browse the repository at this point in the history
* Implement security tokens on disputes

lnp2pbot creates different tokens for each party to add
another security layer on dispute taken by a solver

Each party must ask for this token to the dispute solver
to be sure this is the real solver who took the order

* Add locales for dispute token implementation

* More fixes on dispute token

* Add env var to set dispute start window
* Add new seller/buyer token fields to order document
* Set tokens when dispute starts
* Add locales for new dispute token messages
* bumps new version
  • Loading branch information
grunch authored Jul 30, 2024
1 parent 8a95e54 commit 8d4bbf6
Show file tree
Hide file tree
Showing 15 changed files with 106 additions and 57 deletions.
5 changes: 4 additions & 1 deletion .env-sample
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,7 @@ NOSTR_SK=''
COMMUNITY_CURRENCIES=20

# List of relays to connect to
RELAYS='ws://localhost:7000,ws://localhost:8000,ws://localhost:9000'
RELAYS='ws://localhost:7000,ws://localhost:8000,ws://localhost:9000'

# Seconds to wait to allow disputes to be started
DISPUTE_START_WINDOW=600
6 changes: 5 additions & 1 deletion bot/modules/dispute/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const dispute = async ctx => {

if (!order) return;
// Users can't initiate a dispute before this time
const secsUntilDispute = 1800;
const secsUntilDispute = parseInt(process.env.DISPUTE_START_WINDOW);
const time = new Date();
time.setSeconds(time.getSeconds() - secsUntilDispute);
if (order.taken_at > time) {
Expand All @@ -36,6 +36,10 @@ const dispute = async ctx => {

order[`${initiator}_dispute`] = true;
order.status = 'DISPUTE';
const sellerToken = Math.floor(Math.random() * 899 + 100);
const buyerToken = Math.floor(Math.random() * 899 + 100);
order.buyer_dispute_token = buyerToken;
order.seller_dispute_token = sellerToken;
await order.save();
OrderEvents.orderUpdated(order);

Expand Down
26 changes: 22 additions & 4 deletions bot/modules/dispute/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,40 @@ exports.beginDispute = async (ctx, initiator, order, buyer, seller) => {
try {
let initiatorUser = buyer;
let counterPartyUser = seller;

if (initiator === 'seller') {
initiatorUser = seller;
counterPartyUser = buyer;
}
if (initiator === 'buyer') {
await ctx.telegram.sendMessage(
initiatorUser.tg_id,
ctx.i18n.t('you_started_dispute_to_buyer')
ctx.i18n.t('dispute_started', {
who: ctx.i18n.t('you_started', { orderId: order._id }),
token: order.buyer_dispute_token,
})
);
await ctx.telegram.sendMessage(
counterPartyUser.tg_id,
ctx.i18n.t('buyer_started_dispute_to_seller', { orderId: order._id })
ctx.i18n.t('dispute_started', {
who: ctx.i18n.t('counterpart_started', { orderId: order._id }),
token: order.seller_dispute_token,
})
);
} else {
await ctx.telegram.sendMessage(
initiatorUser.tg_id,
ctx.i18n.t('you_started_dispute_to_seller')
ctx.i18n.t('dispute_started', {
who: ctx.i18n.t('you_started', { orderId: order._id }),
token: order.seller_dispute_token,
})
);
await ctx.telegram.sendMessage(
counterPartyUser.tg_id,
ctx.i18n.t('seller_started_dispute_to_buyer', { orderId: order._id })
ctx.i18n.t('dispute_started', {
who: ctx.i18n.t('counterpart_started', { orderId: order._id }),
token: order.buyer_dispute_token,
})
);
}
} catch (error) {
Expand Down Expand Up @@ -72,6 +85,7 @@ exports.disputeData = async (
initiatorUser = seller;
counterPartyUser = buyer;
}

const detailedOrder = getDetailedOrder(ctx.i18n, order, buyer, seller);
await ctx.telegram.sendMessage(
solver.tg_id,
Expand All @@ -84,6 +98,8 @@ exports.disputeData = async (
sellerDisputes,
detailedOrder,
type,
sellerToken: order.seller_dispute_token,
buyerToken: order.buyer_dispute_token,
}),
{ parse_mode: 'MarkdownV2' }
);
Expand All @@ -93,12 +109,14 @@ exports.disputeData = async (
buyer.tg_id,
ctx.i18n.t('dispute_solver', {
solver: solver.username,
token: order.buyer_dispute_token,
})
);
await ctx.telegram.sendMessage(
seller.tg_id,
ctx.i18n.t('dispute_solver', {
solver: solver.username,
token: order.seller_dispute_token,
})
);
} catch (error) {
Expand Down
12 changes: 7 additions & 5 deletions locales/de.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -194,12 +194,14 @@ dispute_started_channel: |
${detailedOrder}
Seller Token: ${sellerToken}
Buyer Token: ${buyerToken}
@${initiatorUser.username} war an ${initiatorUser.disputes} Streitfällen beteiligt
@${counterPartyUser.username} war an ${counterPartyUser.disputes} Streitfällen beteiligt
you_started_dispute_to_buyer: 🥴 Du hast einen Streitfall für deinen Kaufauftrag ausgelöst. Warten Sie, bis der Bot Ihnen den Benutzernamen des zugewiesenen Lösers mitteilt. Nur Er/Sie kann Ihnen helfen. Schreiben Sie Ihm/Ihr. Wenn Er/Sie Sie zuerst kontaktiert, überprüfen Sie, ob Sein/Ihr Benutzername mit dem übereinstimmt, den der Bot Ihnen gegeben hat.
buyer_started_dispute_to_seller: '🥴 Der Käufer hat einen Streitfall für deinen Auftrag mit der Id: ${orderId} eröffnet. Warten Sie, bis der Bot Ihnen den Benutzernamen des zugewiesenen Lösers mitteilt. Nur Er/Sie kann Ihnen helfen. Schreiben Sie Ihm/Ihr. Wenn Er/Sie Sie zuerst kontaktiert, überprüfen Sie, ob Sein/Ihr Benutzername mit dem übereinstimmt, den der Bot Ihnen gegeben hat.'
you_started_dispute_to_seller: 🥴 Du hast einen Streitfall für deinen Verkaufsauftrag ausgelöst. Warten Sie, bis der Bot Ihnen den Benutzernamen des zugewiesenen Lösers mitteilt. Nur Er/Sie kann Ihnen helfen. Schreiben Sie Ihm/Ihr. Wenn Er/Sie Sie zuerst kontaktiert, überprüfen Sie, ob Sein/Ihr Benutzername mit dem übereinstimmt, den der Bot Ihnen gegeben hat.
seller_started_dispute_to_buyer: '🥴 Der Verkäufer hat einen Streitfall für deinen Auftrag mit der Id: ${orderId} eröffnet. Warten Sie, bis der Bot Ihnen den Benutzernamen des zugewiesenen Lösers mitteilt. Nur Er/Sie kann Ihnen helfen. Schreiben Sie Ihm/Ihr. Wenn Er/Sie Sie zuerst kontaktiert, überprüfen Sie, ob Sein/Ihr Benutzername mit dem übereinstimmt, den der Bot Ihnen gegeben hat.'
you_started: '🥴 Sie haben einen Streitfall zu Ihrer Bestellnummer begonnen: ${orderId}.'
counterpart_started: '🥴 Ihre Gegenpartei hat einen Streit über Ihre Bestellungsnummer begonnen: ${orderId}.'
dispute_started: '${who} Wenn er/sie Ihrem Streitfall zugewiesen wird, teilt der Bot Ihnen seinen/ihren Benutzernamen mit, und nur er/sie kann Sie betreuen. Sie können ihm/ihr direkt schreiben, aber wenn er/sie Sie zuerst kontaktiert, müssen Sie ihn/sie bitten, Ihnen den Token Ihres Streitfalls mitzuteilen, Ihr Token ist: ${token}.'
must_be_valid_currency: 'Fiat_code muss ein gültiger Code sein, zum Beispiel: USD, EUR, eine vollständige Liste kannst du unter /listcurrencies sehen.'
must_be_number_or_range: 'Fiat_amount muss eine Zahl oder ein numerischer Bereich im Format <minimum>-<maximum> sein'
invalid_lightning_address: Ungültige Lightning-Adresse
Expand Down Expand Up @@ -591,6 +593,6 @@ disclaimer: |
Weder die Entwickler noch die Streitschlichter sind für Verluste oder Schäden verantwortlich, die dem Benutzer durch die Nutzung des Bots entstehen können.
order_frozen: Sie haben die Bestellung eingefroren
dispute_solver: 👮‍♂️ Der Solver @${solver} kümmert sich um Ihren Streit. Sie können ihm/ihr schreiben oder darauf warten, dass er/sie Ihnen schreibt
dispute_solver: 👮‍♂️ Ein Löser wird sich um Ihren Streitfall kümmern, Sie können ihn/sie direkt anschreiben, indem Sie auf seinen/ihren Benutzernamen tippen => @${solver} <=, wenn der Löser Sie zuerst anschreibt, sollten Sie ihn/sie bitten, Ihnen mitzuteilen, was das Token Ihres Streitfalls ist, Ihr Token ist ${token}.
setinvoice_no_response: Sie haben keine zu bezahlenden Aufträge
already_cancelled: Die Bestellung wurde bereits storniert!
12 changes: 7 additions & 5 deletions locales/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -196,12 +196,14 @@ dispute_started_channel: |
${detailedOrder}
Seller Token: ${sellerToken}
Buyer Token: ${buyerToken}
@${initiatorUser.username} has been involved in ${initiatorUser.disputes} disputes
@${counterPartyUser.username} has been involved in ${counterPartyUser.disputes} disputes
you_started_dispute_to_buyer: 🥴 You have started a dispute for your buy order. Wait for the bot to tell you the username of the assigned solver, only He/She can assist you. Write to Him/Her. If He/She contacts you first, verify that His/Her username matches the one the bot gave you.
buyer_started_dispute_to_seller: '🥴 The buyer has initiated a dispute for your order with ID: ${orderId}. Wait for the bot to tell you the username of the assigned solver, only He/She can assist you. Write to Him/Her. If He/She contacts you first, verify that His/Her username matches the one the bot gave you.'
you_started_dispute_to_seller: 🥴 You have started a dispute for your sell order. Wait for the bot to tell you the username of the assigned solver, only He/She can assist you. Write to Him/Her. If He/She contacts you first, verify that His/Her username matches the one the bot gave you.
seller_started_dispute_to_buyer: '🥴 The Seller has initiated a dispute for your order with ID: ${orderId}. Wait for the bot to tell you the username of the assigned solver, only He/She can assist you. Write to Him/Her. If He/She contacts you first, verify that His/Her username matches the one the bot gave you.'
you_started: '🥴 You have started a dispute on your order Id: ${orderId}.'
counterpart_started: '🥴 Your counterparty started a dispute on your order Id: ${orderId}.'
dispute_started: '${who} A solver will attend you soon, when he/she is assigned to your dispute the bot will tell you his/her username, only he/she will be able to attend you. You can write to him/her directly, but if he/she contacts you first, you must ask him/her to tell you what is the token of your dispute, your token is: ${token}.'
must_be_valid_currency: 'Fiat_code must be a valid code, for example: USD, EUR. Check the full list with the command /listcurrencies'
must_be_number_or_range: 'Fiat_amount must be a number or numeric range in the <minimum>-<maximum> format'
invalid_lightning_address: Invalid lightning address
Expand Down Expand Up @@ -592,5 +594,5 @@ disclaimer: |
Neither the developers nor the dispute resolvers are responsible for any losses or damages that the user may suffer as a result of using the bot.
order_frozen: You have frozen the order
dispute_solver: 👮‍♂️ The solver @${solver} will be attending to your dispute, you can write to him/her or wait for him/her to write to you
dispute_solver: 👮‍♂️ A solver will be attending your dispute, you can write to him/her directly by tapping his/her username => @${solver} <=, if the solver writes to you first, you should ask him/her to tell you what is the token of your dispute, your token is ${token}.
setinvoice_no_response: You have no orders to be paid
12 changes: 7 additions & 5 deletions locales/es.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -194,12 +194,14 @@ dispute_started_channel: |
${detailedOrder}
Seller Token: ${sellerToken}
Buyer Token: ${buyerToken}
@${buyer.username} ya tiene ${buyerDisputes} disputas
@${seller.username} ya tiene ${sellerDisputes} disputas
you_started_dispute_to_buyer: 🥴 Has iniciado una disputa por tu compra. Espera a que el bot te diga el username de El/La solver asignado/a, solo Él/Ella podrá atenderte. Escríbele, si Él/Ella te contacta primero, verifica que su nombre de usuario coincida con el que te dio el bot.
buyer_started_dispute_to_seller: '🥴 El comprador ha iniciado una disputa por tu orden con Id: ${orderId}. Espera a que el bot te diga el username de El/La solver asignado/a, solo Él/Ella podrá atenderte. Escríbele, si Él/Ella te contacta primero, verifica que su nombre de usuario coincida con el que te dio el bot.'
you_started_dispute_to_seller: 🥴 Has iniciado una disputa por tu venta. Espera a que el bot te diga el username de El/La solver asignado/a, solo Él/Ella podrá atenderte. Escríbele, si Él/Ella te contacta primero, verifica que su nombre de usuario coincida con el que te dio el bot.
seller_started_dispute_to_buyer: '🥴 El vendedor ha iniciado una disputa por tu orden con Id: ${orderId}. Espera a que el bot te diga el username de El/La solver asignado/a, solo Él/Ella podrá atenderte. Escríbele, si Él/Ella te contacta primero, verifica que su nombre de usuario coincida con el que te dio el bot.'
you_started: '🥴 Has iniciado una disputa en tu orden con Id: ${orderId}.'
counterpart_started: '🥴 Tu contraparte ha iniciado una disputa en tu orden con Id: ${orderId}.'
dispute_started: '${who} Un solver te atenderá pronto, cuando él/la solver sea asignado a tu disputa el bot te dirá su username, solo él/ella podrá atenderte. Puedes escribirle directamente, pero si él/ella te contacta primero, debes pedirle que te diga cuál es el token de tu disputa, tu token es: ${token}.'
must_be_valid_currency: 'codigo_fiat debe ser un código de moneda válido, ejemplo: USD, EUR, puedes ver una lista completa ejecutando /listcurrencies'
must_be_number_or_range: 'monto_en_fiat debe ser un número o un rango numerico de la forma: <mínimo>-<máximo>.'
invalid_lightning_address: Dirección lightning no válida
Expand Down Expand Up @@ -593,6 +595,6 @@ disclaimer: |
Ni los desarrolladores ni los árbitros de disputas son responsables de las pérdidas o daños que el usuario pueda sufrir como resultado del uso del bot.
order_frozen: Has congelado la orden
dispute_solver: 👮‍♂️ El solver @${solver} estará atendiendo tu disputa, puedes escribirle o esperar que te escriba
dispute_solver: 👮‍♂️ Un solver estará atendiendo tu disputa, puedes escribirle directamente tocando su username => @${solver} <=, si el/la solver te escribe primero, debes pedirle que te diga cuál es el token de tu disputa, tu token es ${token}.
setinvoice_no_response: No tienes ordenes a ser pagadas
already_cancelled: ¡La orden ya ha sido cancelada!
12 changes: 7 additions & 5 deletions locales/fa.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -196,12 +196,14 @@ dispute_started_channel: |
${detailedOrder}
Seller Token: ${sellerToken}
Buyer Token: ${buyerToken}
کابر@${initiatorUser.username} بابت ${initiatorUser.disputes} به اختلاف خورده
کاربر@${counterPartyUser.username} بابت ${counterPartyUser.disputes} به اختلاف خورده
you_started_dispute_to_buyer: 🥴 شما برای خرید خود اختلاف ایجاد کرده‌اید. منتظر بمانید تا ربات نام کاربری حل‌کننده‌ی تعیین‌شده را به شما بگوید، فقط او می‌تواند به شما کمک کند. به او پیام دهید. اگر او ابتدا با شما تماس گرفت، اطمینان حاصل کنید که نام کاربری او با نام کاربری که ربات به شما داده است، مطابقت دارد.
buyer_started_dispute_to_seller: '🥴 خریدار برای سفارش شما با شناسه: ${orderId} اختلاف ایجاد کرده است. منتظر بمانید تا ربات نام کاربری حل‌کننده‌ی تعیین‌شده را به شما بگوید، فقط او می‌تواند به شما کمک کند. به او پیام دهید. اگر او ابتدا با شما تماس گرفت، اطمینان حاصل کنید که نام کاربری او با نام کاربری که ربات به شما داده است، مطابقت دارد.'
you_started_dispute_to_seller: 🥴 شما برای فروش خود اختلاف ایجاد کرده‌اید. منتظر بمانید تا ربات نام کاربری حل‌کننده‌ی تعیین‌شده را به شما بگوید، فقط او می‌تواند به شما کمک کند. به او پیام دهید. اگر او ابتدا با شما تماس گرفت، اطمینان حاصل کنید که نام کاربری او با نام کاربری که ربات به شما داده است، مطابقت دارد.
seller_started_dispute_to_buyer: '🥴 فروشنده برای سفارش شما با شناسه: ${orderId} اختلاف ایجاد کرده است. منتظر بمانید تا ربات نام کاربری حل‌کننده‌ی تعیین‌شده را به شما بگوید، فقط او می‌تواند به شما کمک کند. به او پیام دهید. اگر او ابتدا با شما تماس گرفت، اطمینان حاصل کنید که نام کاربری او با نام کاربری که ربات به شما داده است، مطابقت دارد.'
you_started: '🥴 شما در مورد شناسه سفارش خود اختلاف نظر شروع کرده اید: ${orderId}.'
counterpart_started: '🥴 طرف مقابل شما یک اختلاف بر سر شناسه سفارش شما شروع کرد: ${orderId}.'
dispute_started: '${who} یک حل کننده به زودی در شما حضور خواهد یافت، هنگامی که او به منازعه شما منصوب شد، ربات نام کاربری خود را به شما می گوید، فقط او می تواند در شما حضور داشته باشد. شما می توانید مستقیماً برای او نامه بنویسید، اما اگر ابتدا با شما تماس گرفت، باید از او بخواهید که به شما بگوید نشانه اختلاف شما چیست، رمز شما این است: ${token}.'
must_be_valid_currency: 'کد فیات باید یک کد معتبر باشد، به عنوان مثال: USD، IRT. لیست کامل را با دستور /listcurrencies بررسی کنید'
must_be_number_or_range: 'مقدار فیات باید یک عدد یا محدوده عددی در قالب <حداقل>-<حداکثر> باشد.'
invalid_lightning_address: آدرس لایتنینگ نامعتبر است
Expand Down Expand Up @@ -590,6 +592,6 @@ disclaimer: |
نه توسعه‌دهندگان و نه حل‌کننده‌های اختلاف، مسئولیتی در قبال ضرر و زیان‌هایی که ممکن است کاربر در اثر استفاده از ربات متحمل شود، ندارند.
order_frozen: شما سفارش را مسدود کردید
dispute_solver: 👮‍♂️ حل‌کننده @${solver} به اختلاف شما رسیدگی می‌کند، می‌توانید به او نامه بنویسید یا منتظر بمانید تا برای شما بنویسد.
dispute_solver: 👮‍♂️ یک حل‌کننده در دعوای شما شرکت خواهد کرد، می‌توانید با ضربه زدن روی نام کاربری او مستقیماً برای او بنویسید => @${solver} <=، اگر حل‌کننده ابتدا برای شما نامه نوشت، باید از او بخواهید که به شما بگویم که نشانه اختلاف شما چیست، رمز شما ${token} است.
setinvoice_no_response: هیچ سفارشی برای پرداخت ندارید
already_cancelled: سفارش قبلاً لغو شده است!
Loading

0 comments on commit 8d4bbf6

Please sign in to comment.