Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bot/modules/nostr: convert to TS #627

Merged
merged 4 commits into from
Feb 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions bot/modules/nostr/commands.js → bot/modules/nostr/commands.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
const Nostr = require('nostr-tools');
const { logger } = require('../../../logger');
const Config = require('./config');
import { nip19 } from 'nostr-tools';
import { logger } from '../../../logger';
import * as Config from './config';
import { MainContext } from '../../start';

exports.info = async ctx => {
export const info = async (ctx: MainContext) => {
try {
const publicKey = Config.getPublicKey();
if (!publicKey) return;
const info = {
publicKey,
npub: Nostr.nip19.npubEncode(publicKey),
npub: nip19.npubEncode(publicKey),
relays: Config.getRelays()
.map(r => `<code>${r}</code>`)
.join('\n'),
Expand Down
20 changes: 0 additions & 20 deletions bot/modules/nostr/config.js

This file was deleted.

21 changes: 21 additions & 0 deletions bot/modules/nostr/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { generateSecretKey, getPublicKey as nostrGetPublicKey } from 'nostr-tools';
import { SimplePool } from 'nostr-tools';

const nostrSkEnvVar = process.env.NOSTR_SK;
const sk = nostrSkEnvVar ? Buffer.from(nostrSkEnvVar, 'hex') : generateSecretKey();
const pk = nostrGetPublicKey(sk);
Comment on lines +4 to +6
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add validation for NOSTR_SK environment variable

The hex format of NOSTR_SK should be validated before usage.

 const nostrSkEnvVar = process.env.NOSTR_SK;
-const sk = nostrSkEnvVar ? Buffer.from(nostrSkEnvVar, 'hex') : generateSecretKey();
+const sk = nostrSkEnvVar 
+  ? (/^[0-9a-f]{64}$/i.test(nostrSkEnvVar) 
+      ? Buffer.from(nostrSkEnvVar, 'hex') 
+      : generateSecretKey())
+  : generateSecretKey();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const nostrSkEnvVar = process.env.NOSTR_SK;
const sk = nostrSkEnvVar ? Buffer.from(nostrSkEnvVar, 'hex') : generateSecretKey();
const pk = nostrGetPublicKey(sk);
const nostrSkEnvVar = process.env.NOSTR_SK;
const sk = nostrSkEnvVar
? (/^[0-9a-f]{64}$/i.test(nostrSkEnvVar)
? Buffer.from(nostrSkEnvVar, 'hex')
: generateSecretKey())
: generateSecretKey();
const pk = nostrGetPublicKey(sk);


export const getPrivateKey = () => sk;
export const getPublicKey = () => pk;

export const pool = new SimplePool();
const relays = (env => {
if (!env.RELAYS) return [];
return env.RELAYS.split(',');
})(process.env);
Comment on lines +11 to +15
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add type annotation for relays array and validate relay URLs

The relays array should be typed and URLs should be validated.

 export const pool = new SimplePool();
+const isValidRelayUrl = (url: string): boolean => {
+  try {
+    return new URL(url).protocol === 'wss:';
+  } catch {
+    return false;
+  }
+};
+
+const relays: string[] = ((env: NodeJS.ProcessEnv) => {
   if (!env.RELAYS) return [];
-  return env.RELAYS.split(',');
+  return env.RELAYS.split(',').filter(isValidRelayUrl);
 })(process.env);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const pool = new SimplePool();
const relays = (env => {
if (!env.RELAYS) return [];
return env.RELAYS.split(',');
})(process.env);
export const pool = new SimplePool();
const isValidRelayUrl = (url: string): boolean => {
try {
return new URL(url).protocol === 'wss:';
} catch {
return false;
}
};
const relays: string[] = ((env: NodeJS.ProcessEnv) => {
if (!env.RELAYS) return [];
return env.RELAYS.split(',').filter(isValidRelayUrl);
})(process.env);


export const addRelay = (relay: string) => {
relays.push(relay);
relays.map(relay => pool.ensureRelay(relay));
};
Comment on lines +17 to +20
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve relay management

The current implementation has potential issues:

  1. Duplicate relays aren't prevented
  2. No validation of relay URL format
  3. No cleanup of disconnected relays
-export const addRelay = (relay: string) => {
+export const addRelay = (relay: string): boolean => {
+  if (!isValidRelayUrl(relay) || relays.includes(relay)) {
+    return false;
+  }
   relays.push(relay);
-  relays.map(relay => pool.ensureRelay(relay));
+  pool.ensureRelay(relay);
+  return true;
 };

Committable suggestion skipped: line range outside the PR's diff.

export const getRelays = () => relays;
25 changes: 17 additions & 8 deletions bot/modules/nostr/events.js → bot/modules/nostr/events.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,31 @@
const { finalizeEvent, verifyEvent } = require('nostr-tools/pure');
const Config = require('./config');
import { finalizeEvent, verifyEvent } from 'nostr-tools';
import * as Config from './config';

const { Community } = require('../../../models');
const { toKebabCase, removeAtSymbol } = require('../../../util');
import { Community } from '../../../models';
import { toKebabCase, removeAtSymbol } from '../../../util';
import { IOrder } from '../../../models/order';

/// All events broadcasted are Parameterized Replaceable Events,
/// the event kind must be between 30000 and 39999
const kind = 38383;

const orderToTags = async order => {
const orderToTags = async (order: IOrder) => {
const orderPublishedExpirationWindow = process.env.ORDER_PUBLISHED_EXPIRATION_WINDOW;
if(orderPublishedExpirationWindow === undefined)
throw new Error("Environment variable ORDER_PUBLISHED_EXPIRATION_WINDOW is not defined");
const expiration =
Math.floor(Date.now() / 1000) +
parseInt(process.env.ORDER_PUBLISHED_EXPIRATION_WINDOW);
parseInt(orderPublishedExpirationWindow);
const fiat_amount = ['fa'];
if (order.fiat_amount === undefined) {
fiat_amount.push(order.min_amount.toString(), order.max_amount.toString());
} else {
fiat_amount.push(order.fiat_amount.toString());
}
const channel = removeAtSymbol(process.env.CHANNEL);
const channelEnvVar = process.env.CHANNEL;
if(channelEnvVar === undefined)
throw new Error("Environment variable CHANNEL is not defined")
const channel = removeAtSymbol(channelEnvVar);
let source = `https://t.me/${channel}/${order.tg_channel_message1}`;
const tags = [];
tags.push(['d', order.id]);
Expand All @@ -31,6 +38,8 @@ const orderToTags = async order => {
tags.push(['premium', order.price_margin.toString()]);
if (order.community_id) {
const community = await Community.findById(order.community_id);
if(community === null)
throw new Error("community was not found");
const group = removeAtSymbol(community.group);
source = `https://t.me/${group}/${order.tg_channel_message1}`;
tags.push(['community_id', order.community_id]);
Expand All @@ -45,7 +54,7 @@ const orderToTags = async order => {
return tags;
};

exports.createOrderEvent = async order => {
export const createOrderEvent = async (order: IOrder) => {
const myPrivKey = Config.getPrivateKey();
if (order.is_public === false) {
return;
Expand Down
19 changes: 11 additions & 8 deletions bot/modules/nostr/index.js → bot/modules/nostr/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
require('websocket-polyfill');
const { logger } = require('../../../logger');
const Config = require('./config');
const { createOrderEvent } = require('./events');
const Commands = require('./commands');
import { logger } from '../../../logger';
import * as Config from './config';
import { createOrderEvent } from './events';
import * as Commands from './commands';
import { Telegraf } from 'telegraf';
import { MainContext } from '../../start';
import { IOrder } from '../../../models/order';
const CommunityEvents = require('../events/community');

exports.configure = bot => {
export const configure = (bot: Telegraf<MainContext>) => {
bot.command('/nostr', Commands.info);

if (!Config.getRelays().length) {
Expand All @@ -13,14 +17,13 @@ exports.configure = bot => {
);
}

const CommunityEvents = require('../events/community');
CommunityEvents.onCommunityUpdated(async community => {
CommunityEvents.onCommunityUpdated(async (community: any) => {
// todo: notify users
});

const OrderEvents = require('../events/orders');

OrderEvents.onOrderUpdated(async order => {
OrderEvents.onOrderUpdated(async (order: IOrder) => {
try {
const event = await createOrderEvent(order);
if (event) {
Expand Down
11 changes: 0 additions & 11 deletions bot/modules/nostr/lib.js

This file was deleted.

11 changes: 11 additions & 0 deletions bot/modules/nostr/lib.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { nip19 } from 'nostr-tools';

Comment on lines +1 to +2
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add logger import

Import the logger module to support error logging in the decodeNpub function.

 import { nip19 } from 'nostr-tools';
+import { logger } from '../../../logger';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { nip19 } from 'nostr-tools';
import { nip19 } from 'nostr-tools';
import { logger } from '../../../logger';

export const decodeNpub = (npub: string) => {
try {
const { type, data } = nip19.decode(npub);
if (type === 'npub') return data;
} catch (err) {}
};
export const encodeNpub = (hex: string) => {
return nip19.npubEncode(hex);
};
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"esModuleInterop": true,
"resolveJsonModule": true,
"downlevelIteration": true,
"lib":["ES2021", "DOM"],
"outDir": "./dist",
"rootDir": ".",
"allowJs": true,
Expand Down
Loading