web_lib

Common web application libraries
git clone https://radroots.dev/git/web_lib.git
Log | Files | Refs | LICENSE

commit 9b801589beba464868597350aa08ab890581a95f
parent 398f7600d774e9c28e043070a157c458a9b60304
Author: triesap <137732411+triesap@users.noreply.github.com>
Date:   Fri, 27 Dec 2024 02:20:38 +0000

utils: add/edit nostr utils. add ascii, model utils. edit regex

Diffstat:
Mutils/.gitignore | 3++-
Mutils/package.json | 2+-
Autils/src/ascii.ts | 3+++
Mutils/src/index.ts | 13++++++++-----
Autils/src/model.ts | 20++++++++++++++++++++
Autils/src/nostr-event-util/lib.ts | 114+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Autils/src/nostr-event-util/types.ts | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Autils/src/nostr-key-util/lib.ts | 148+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Autils/src/nostr-key-util/types.ts | 11+++++++++++
Autils/src/nostr-relay-util/lib.ts | 46++++++++++++++++++++++++++++++++++++++++++++++
Autils/src/nostr-relay-util/types.ts | 21+++++++++++++++++++++
Dutils/src/nostr/geotags.ts | 22----------------------
Dutils/src/nostr/lib.ts | 156-------------------------------------------------------------------------------
Dutils/src/nostr/lib2.ts | 147-------------------------------------------------------------------------------
Dutils/src/nostr/ndk.ts | 75---------------------------------------------------------------------------
Dutils/src/nostr/types.ts | 78------------------------------------------------------------------------------
Mutils/src/regex.ts | 13++++++++++---
17 files changed, 468 insertions(+), 488 deletions(-)

diff --git a/utils/.gitignore b/utils/.gitignore @@ -27,7 +27,8 @@ yarn-error.log* # turbo .turbo -_tmp +.tmp* +.dev* .vscode notes*.txt justfile diff --git a/utils/package.json b/utils/package.json @@ -24,7 +24,7 @@ "convert": "^5.5.1", "geohashing": "^2.0.1", "nostr-geotags": "^0.7.1", - "nostr-tools": "^2.7.2", + "nostr-tools": "^2.10.4", "uuid": "^10.0.0", "zod": "^3.23.8" } diff --git a/utils/src/ascii.ts b/utils/src/ascii.ts @@ -0,0 +1,2 @@ +export const root_symbol = "»-`--,"; +export const root_symbol_full = "»--`--,---"; +\ No newline at end of file diff --git a/utils/src/index.ts b/utils/src/index.ts @@ -1,3 +1,4 @@ +export * from "./ascii" export * from "./currency" export * from "./error" export * from "./file" @@ -6,11 +7,13 @@ export * from "./geolocation" export * from "./hash" export * from "./list" export * from "./math" -export * from "./nostr/geotags" -export * from "./nostr/lib" -export * from "./nostr/lib2" -export * from "./nostr/ndk" -export * from "./nostr/types" +export * from "./model" +export * from "./nostr-event-util/lib" +export * from "./nostr-event-util/types" +export * from "./nostr-key-util/lib" +export * from "./nostr-key-util/types" +export * from "./nostr-relay-util/lib" +export * from "./nostr-relay-util/types" export * from "./object" export * from "./regex" export * from "./time" diff --git a/utils/src/model.ts b/utils/src/model.ts @@ -0,0 +1,20 @@ +export type IModelsQueryValue = string | number | boolean; +export type IModelsQueryBindValue = string | number | boolean | null; +export type IModelsQueryBindValueTuple = [string, IModelsQueryBindValue]; +export type IModelsQueryBindValueOpt = (IModelsQueryBindValue | null); +export type IModelsSortCreatedAt = 'newest' | 'oldest'; +export type IModelsQueryParam = { query: string; bind_values: IModelsQueryBindValue[] }; +export type IModelsFormErrorTuple = [boolean, string]; +export type IModelsFormValidationTuple = [RegExp, string]; +export type IModelsSchemaErrors = { err_s: string[]; }; +export type IModelsForm = { + label?: string; + placeholder?: string; + validateKeypress?: boolean; + preventFocusRest?: boolean; + validation: RegExp; + charset: RegExp; + hidden?: boolean; + optional?: boolean; + default?: string | number; +}; diff --git a/utils/src/nostr-event-util/lib.ts b/utils/src/nostr-event-util/lib.ts @@ -0,0 +1,113 @@ +import { schnorr } from '@noble/curves/secp256k1'; +import { hexToBytes } from "@noble/hashes/utils"; +import { type NDKEvent } from "@nostr-dev-kit/ndk"; +import ngeotags, { type GeoTags as NostrGeotagsGeotags, type InputData as NostrGeotagsInputData } from "nostr-geotags"; +import { finalizeEvent, getEventHash, nip19, type NostrEvent as NostrToolsEvent } from "nostr-tools"; +import { uuidv4 } from ".."; +import type { INostrEventUtil, INostrEventUtilEventSign, INostrEventUtilFormatTagsBasisNip99, INostrEventUtilNeventEncode, NostrEventTagClient, NostrEventTagLocation, NostrEventTagMediaUpload, NostrEventTagPrice, NostrEventTagQuantity } from "./types"; + +export class NostrEventUtil implements INostrEventUtil { + public first_tag_value = (event: NDKEvent, tag_name: string): string => { + const tag = event.getMatchingTags(tag_name)[0]; + return tag ? tag[1] : ""; + } + + private fmt_tag_price = (opts: NostrEventTagPrice): string[] => { + const tag = [`price`, opts.amt, opts.currency, opts.qty_amt, opts.qty_unit]; + return tag; + }; + + + private fmt_tag_quantity = (opts: NostrEventTagQuantity): string[] => { + const tag = [`quantity`, opts.amt, opts.unit]; + if (opts.label) tag.push(opts.label); + return tag; + }; + + private fmt_tag_location = (opts: NostrEventTagLocation): string[] => { + const tag = [`location`]; + if (opts.city) tag.push(opts.city); + if (opts.region_code && !isNaN(parseInt(opts.region_code))) tag.push(opts.region_code); + else if (opts.region) tag.push(opts.region); //@todo + if (opts.country_code) tag.push(opts.country_code); + return tag; + }; + + private fmt_tag_image = (opts: NostrEventTagMediaUpload): string[] => { + const tag = [`image`, opts.url]; + if (opts.size) tag.push(`${opts.size.w}x${opts.size.h}`) + return tag; + }; + + private fmt_tag_client = (opts: NostrEventTagClient, d_tag?: string): string[] => { + const tag = [`client`, opts.name]; + if (d_tag) tag.push(`31990:${opts.pubkey}:${d_tag}`); + tag.push(opts.relay); + return tag; + }; + + private fmt_tag_geotags = (opts: NostrEventTagLocation): NostrGeotagsGeotags[] => { + const data: NostrGeotagsInputData = { + lat: opts.lat, + lon: opts.lng, + city: opts.city, + regionName: opts.region, + countryName: opts.country, + countryCode: opts.country_code + }; + return ngeotags(data, { + geohash: true, + gps: true, + city: true, + iso31662: true, + }); + }; + + public fmt_tags_basis_nip99 = (opts: INostrEventUtilFormatTagsBasisNip99): string[][] => { + const { d_tag, listing, quantity, price, location } = opts; + const tags: string[][] = [[`d`, d_tag]]; + if (opts.client) tags.push(this.fmt_tag_client(opts.client, opts.d_tag)); + for (const [k, v] of Object.entries(listing)) if (v) tags.push([k, v]); + tags.push(this.fmt_tag_quantity(quantity)); + tags.push(this.fmt_tag_price(price)); + tags.push(this.fmt_tag_location(location)); + if (opts.images) for (const image of opts.images) tags.push(this.fmt_tag_image(image)); + tags.push(...this.fmt_tag_geotags(location)); + return tags; + }; + + public nostr_event_sign = (opts: INostrEventUtilEventSign): NostrToolsEvent => { + return finalizeEvent(opts.event, hexToBytes(opts.secret_key)) + }; + + public nostr_event_sign_attest = (secret_key: string): NostrToolsEvent => { + return this.nostr_event_sign({ + secret_key, + event: { + kind: 1, + created_at: Math.floor(Date.now() / 1000), + tags: [], + content: uuidv4(), + }, + }); + }; + + public nostr_event_verify = (event: NostrToolsEvent): boolean => { + const hash = getEventHash(event); + if (hash !== event.id) return false + const valid = schnorr.verify(event.sig, hash, event.pubkey); + return valid; + }; + + public nostr_event_verify_serialized = (event_serialized: string): boolean => { + const event = JSON.parse(event_serialized); + const hash = getEventHash(event); + if (hash !== event.id) return false + const valid = schnorr.verify(event.sig, hash, event.pubkey); + return valid; + }; + + public nevent_encode = (opts: INostrEventUtilNeventEncode): string => { + return nip19.neventEncode(opts); + }; +} +\ No newline at end of file diff --git a/utils/src/nostr-event-util/types.ts b/utils/src/nostr-event-util/types.ts @@ -0,0 +1,84 @@ +import { NDKEvent } from "@nostr-dev-kit/ndk"; +import { type NostrEvent as NostrToolsEvent, type EventTemplate as NostrToolsEventTemplate } from "nostr-tools"; + +export type INostrEventUtilFormatTagsBasisNip99 = { + d_tag: string; + listing: NostrEventTagListing; + quantity: NostrEventTagQuantity; + price: NostrEventTagPrice; + location: NostrEventTagLocation; + images?: NostrEventTagMediaUpload[]; + client?: NostrEventTagClient; +}; + +export type INostrEventUtilNeventEncode = { + id: string; + relays: string[]; + author: string; + kind: number; +}; + +export type INostrEventUtilEventSign = { + secret_key: string; + event: NostrToolsEventTemplate; +} + +export type INostrEventUtil = { + first_tag_value(event: NDKEvent, tag_name: string): string; + fmt_tags_basis_nip99: (opts: INostrEventUtilFormatTagsBasisNip99) => string[][]; + nostr_event_sign: (opts: INostrEventUtilEventSign) => NostrToolsEvent; + nostr_event_sign_attest: (secret_key: string) => NostrToolsEvent; + nostr_event_verify_serialized: (event_serialized: string) => boolean; + nostr_event_verify: (event: NostrToolsEvent) => boolean; + nevent_encode: (opts: INostrEventUtilNeventEncode) => string; +}; + +export type NostrEventTagListing = { + key: string; + title: string; + category: string; + summary?: string; + process?: string; + lot?: string; + location?: string; + profile?: string; + year?: string; +}; + +export type NostrEventTagPrice = { + amt: string; + currency: string; + qty_amt: string; + qty_unit: string; +}; + +export type NostrEventTagQuantity = { + amt: string; + unit: string; + label?: string; +}; + +export type NostrEventTagLocation = { + city?: string; + region?: string; + region_code?: string; + country?: string; + country_code?: string; + lat: number; + lng: number; + geohash: string; +}; + +export type NostrEventTagMediaUpload = { + url: string; + size?: { + w: number; + h: number; + }; +}; + +export type NostrEventTagClient = { + name: string; + pubkey: string; + relay: string; +}; diff --git a/utils/src/nostr-key-util/lib.ts b/utils/src/nostr-key-util/lib.ts @@ -0,0 +1,148 @@ +import { bytesToHex, hexToBytes } from '@noble/hashes/utils'; +import { generateSecretKey, getPublicKey, nip19 } from 'nostr-tools'; +import type { INostrKeyUtil } from './types'; + +export class NostrKeyUtil implements INostrKeyUtil { + private generate_key_bytes(): Uint8Array { + const secret_key = generateSecretKey(); + return secret_key; + }; + + private get_key_hex(bytes: Uint8Array): string { + const hex = bytesToHex(bytes); + return hex; + }; + + private get_key_bytes(hex: string): Uint8Array { + const bytes = hexToBytes(hex); + return bytes; + }; + + /** + * + * @returns nostr secret key hex + */ + public generate_key(): string { + const bytes = this.generate_key_bytes(); + const hex = this.get_key_hex(bytes); + return hex; + }; + + /** + * + * @returns nostr public key hex + */ + public public_key(secret_key_hex: string | undefined): string { + try { + if (!secret_key_hex) return ``; + const bytes = this.get_key_bytes(secret_key_hex); + const hex = getPublicKey(bytes) + return hex; + } catch (e) { + return `` + } + } + + /** + * + * @returns nostr secret key to public key hex + */ + public publickey_decode(secret_key_hex?: string): string | undefined { + try { + if (secret_key_hex) { + return getPublicKey(this.get_key_bytes(secret_key_hex)) + } + return undefined; + } catch (e) { + return undefined; + } + } + + /** + * + * @returns nostr public key npub + */ + public npub(public_key_hex: string | undefined, fallback_to_hex?: boolean): string { + if (!public_key_hex) return ``; + const npub = nip19.npubEncode(public_key_hex); + return npub ? npub : fallback_to_hex ? public_key_hex : ``; + } + + /** + * + * @returns public key hex from npub + */ + public npub_decode(npub: string): string { + const decode = nip19.decode(npub); + console.log(`decode `, decode) + if (decode && decode.type === `npub` && decode.data) return decode.data + return ``; + } + + /** + * + * @returns nostr secret key nsec + */ + public nsec(secret_key_hex: string | undefined): string { + if (!secret_key_hex) return ``; + const bytes = this.get_key_bytes(secret_key_hex); + const nsec = nip19.nsecEncode(bytes); + return nsec; + } + + /** + * + * @returns nostr secret key hex from nsec + */ + public nsec_decode(nsec: string): string | undefined { + try { + if (!nsec) return undefined; + const decode = nip19.decode(nsec); + if (decode && decode.type === `nsec` && decode.data) return bytesToHex(decode.data); + return undefined; + } catch (e) { + return undefined; + } + } + + /** + * + * @returns + */ + public nevent(event_pointer: nip19.EventPointer, relays: string[]): string { + return nip19.neventEncode(event_pointer) + } + + /** + * + * @returns nostr public key nprofile + */ + public nprofile(public_key_hex: string, relays: string[]): string { + if (!public_key_hex || !relays.length) return ``; + return nip19.nprofileEncode({ pubkey: public_key_hex, relays }) + } + + /** + * + * @returns nostr public key nprofile + */ + public nprofile_decode(nprofile: string): [string, string[]] | undefined { + if (!nprofile) return undefined; + const decode = nip19.decode(nprofile); + if (decode && decode.type === `nprofile` && decode.data && decode.data.pubkey && decode.data.relays) return [decode.data.pubkey, decode.data.relays] + return undefined; + } + + /** + * + * @returns + */ + public secretkey_to_publickey(nsec_or_hex: string): string | undefined { + if (nsec_or_hex.startsWith(`nsec1`)) { + return this.nsec_decode(nsec_or_hex); + } else if (nsec_or_hex.length === 64) { + return this.publickey_decode(nsec_or_hex) + } + return undefined; + } +}; diff --git a/utils/src/nostr-key-util/types.ts b/utils/src/nostr-key-util/types.ts @@ -0,0 +1,11 @@ +export type INostrKeyUtil = { + generate_key(): string; + public_key(secret_key_hex: string | undefined): string; + npub(public_key_hex: string | undefined): string; + npub_decode(npub: string): string; + nsec(secret_key_hex: string | undefined): string; + nsec_decode(nsec: string): string | undefined; + nprofile(public_key_hex: string, relays: string[]): string; + nprofile_decode(nprofile: string): [string, string[]] | undefined; + secretkey_to_publickey(nsec_or_hex: string): string | undefined; +}; diff --git a/utils/src/nostr-relay-util/lib.ts b/utils/src/nostr-relay-util/lib.ts @@ -0,0 +1,45 @@ +import { type NDKEvent } from "@nostr-dev-kit/ndk"; +import type { INostrRealyUtil, NostrRelayInformationDocument, NostrRelayInformationDocumentFormFields } from "./types"; + +export class NostrRelayUtil implements INostrRealyUtil { + public first_tag_value(event: NDKEvent, tag_name: string): string { + const tag = event.getMatchingTags(tag_name)[0]; + return tag ? tag[1] : ""; + } + + private parse_nostr_relay_information_document = (data: any): NostrRelayInformationDocument | undefined => { + const obj = JSON.parse(data); + return { + id: typeof obj.id === 'string' ? obj.id : undefined, + name: typeof obj.name === 'string' ? obj.name : undefined, + description: typeof obj.description === 'string' ? obj.description : undefined, + pubkey: typeof obj.pubkey === 'string' ? obj.pubkey : undefined, + contact: typeof obj.contact === 'string' ? obj.contact : undefined, + supported_nips: Array.isArray(obj.supported_nips) && obj.supported_nips.every((nip: any) => typeof nip === 'number') + ? obj.supported_nips + : undefined, + software: typeof obj.software === 'string' ? obj.software : undefined, + version: typeof obj.version === 'string' ? obj.version : undefined, + limitation_payment_required: obj.limitation && typeof obj.limitation === 'object' && typeof obj.limitation.payment_required === 'string' ? obj.limitation.payment_required : undefined, + limitation_restricted_writes: obj.limitation && typeof obj.limitation === 'object' && typeof obj.limitation.restricted_writes === 'boolean' ? obj.limitation.restricted_writes : undefined, + }; + }; + + public parse_nostr_relay_information_document_fields = (data: any): NostrRelayInformationDocumentFormFields | undefined => { + const info_doc = this.parse_nostr_relay_information_document(data); + if (!info_doc) return; + const result: Partial<NostrRelayInformationDocumentFormFields> = {}; + Object.entries(info_doc).forEach(([key, value]) => { + if (typeof value === 'boolean') { + result[key as keyof NostrRelayInformationDocument] = value ? '1' : '0'; + } else if (Array.isArray(value)) { + result[key as keyof NostrRelayInformationDocument] = value.join(', '); + } else if (value === null || value === undefined) { + result[key as keyof NostrRelayInformationDocument] = ''; + } else { + result[key as keyof NostrRelayInformationDocument] = String(value); + } + }); + return result; + }; +} +\ No newline at end of file diff --git a/utils/src/nostr-relay-util/types.ts b/utils/src/nostr-relay-util/types.ts @@ -0,0 +1,21 @@ +import { NDKEvent } from "@nostr-dev-kit/ndk"; + +export type INostrRealyUtil = { + first_tag_value(event: NDKEvent, tag_name: string): string; + parse_nostr_relay_information_document_fields: (data: any) => NostrRelayInformationDocumentFormFields | undefined; +}; + +export type NostrRelayInformationDocument = { + id?: string; + name?: string; + description?: string; + pubkey?: string; + contact?: string; + supported_nips?: number[]; + software?: string; + version?: string; + limitation_payment_required?: string; + limitation_restricted_writes?: boolean; +} + +export type NostrRelayInformationDocumentFormFields = { [K in keyof NostrRelayInformationDocument]: string; }; diff --git a/utils/src/nostr/geotags.ts b/utils/src/nostr/geotags.ts @@ -1,21 +0,0 @@ -import ngeotags, { type GeoTags, type InputData, type Options } from 'nostr-geotags'; -import type { NostrTagLocation } from './types'; - -const options: Options = { - geohash: true, - gps: true, - city: true, - iso31662: true, -}; - -export const fmt_tag_geotags = (opts: NostrTagLocation): GeoTags[] => { - const data: InputData = { - lat: opts.lat, - lon: opts.lng, - city: opts.city, - regionName: opts.region, - countryName: opts.country, - countryCode: opts.country_code - }; - return ngeotags(data, options) -}; -\ No newline at end of file diff --git a/utils/src/nostr/lib.ts b/utils/src/nostr/lib.ts @@ -1,155 +0,0 @@ -import { schnorr } from '@noble/curves/secp256k1'; -import { hexToBytes } from '@noble/hashes/utils'; -import { type EventTemplate, finalizeEvent, getEventHash, nip19, type NostrEvent } from "nostr-tools"; -import { uuidv4 } from '../uuid'; -import { fmt_tag_geotags } from './geotags'; -import type { NostrRelayInformationDocument, NostrRelayInformationDocumentFormFields, NostrTagClient, NostrTagListing, NostrTagLocation, NostrTagMediaUpload, NostrTagPrice, NostrTagQuantity } from "./types"; - -export const parse_nostr_relay_information_document = (data: any): NostrRelayInformationDocument | undefined => { - const obj = JSON.parse(data); - return { - id: typeof obj.id === 'string' ? obj.id : undefined, - name: typeof obj.name === 'string' ? obj.name : undefined, - description: typeof obj.description === 'string' ? obj.description : undefined, - pubkey: typeof obj.pubkey === 'string' ? obj.pubkey : undefined, - contact: typeof obj.contact === 'string' ? obj.contact : undefined, - supported_nips: Array.isArray(obj.supported_nips) && obj.supported_nips.every((nip: any) => typeof nip === 'number') - ? obj.supported_nips - : undefined, - software: typeof obj.software === 'string' ? obj.software : undefined, - version: typeof obj.version === 'string' ? obj.version : undefined, - limitation_payment_required: obj.limitation && typeof obj.limitation === 'object' && typeof obj.limitation.payment_required === 'string' ? obj.limitation.payment_required : undefined, - limitation_restricted_writes: obj.limitation && typeof obj.limitation === 'object' && typeof obj.limitation.restricted_writes === 'boolean' ? obj.limitation.restricted_writes : undefined, - }; -}; - -export const parse_nostr_relay_information_document_fields = (data: any): NostrRelayInformationDocumentFormFields | undefined => { - const info_doc = parse_nostr_relay_information_document(data); - if (!info_doc) return; - const result: Partial<NostrRelayInformationDocumentFormFields> = {}; - Object.entries(info_doc).forEach(([key, value]) => { - if (typeof value === 'boolean') { - result[key as keyof NostrRelayInformationDocument] = value ? '1' : '0'; - } else if (Array.isArray(value)) { - result[key as keyof NostrRelayInformationDocument] = value.join(', '); - } else if (value === null || value === undefined) { - result[key as keyof NostrRelayInformationDocument] = ''; - } else { - result[key as keyof NostrRelayInformationDocument] = String(value); - } - }); - return result; -}; - - -export const fmt_tag_price = (opts: NostrTagPrice): string[] => { - const tag = [`price`, opts.amt, opts.currency, opts.qty_amt, opts.qty_unit]; - return tag; -}; - - -export const fmt_tag_quantity = (opts: NostrTagQuantity): string[] => { - const tag = [`quantity`, opts.amt, opts.unit]; - if (opts.label) tag.push(opts.label); - return tag; -}; - - -export const fmt_tag_location = (opts: NostrTagLocation): string[] => { - const tag = [`location`]; - if (opts.city) tag.push(opts.city); - if (opts.region_code && !isNaN(parseInt(opts.region_code))) tag.push(opts.region_code); - else if (opts.region) tag.push(opts.region); //@todo - if (opts.country_code) tag.push(opts.country_code); - return tag; -}; - -export const fmt_tag_image = (opts: NostrTagMediaUpload): string[] => { - const tag = [`image`, opts.url]; - if (opts.size) tag.push(`${opts.size.w}x${opts.size.h}`) - return tag; -}; - -export const fmt_tag_client = (opts: NostrTagClient, d_tag?: string): string[] => { - const tag = [`client`, opts.name]; - if (d_tag) tag.push(`31990:${opts.pubkey}:${d_tag}`); - tag.push(opts.relay); - return tag; -}; - -export const fmt_tags_basis_nip99 = (opts: { - d_tag: string; - listing: NostrTagListing; - quantity: NostrTagQuantity; - price: NostrTagPrice; - location: NostrTagLocation; - images?: NostrTagMediaUpload[]; - client?: NostrTagClient; -}): string[][] => { - const { d_tag, listing, quantity, price, location } = opts; - const tags: string[][] = [ - [`d`, d_tag] - ]; - if (opts.client) tags.push(fmt_tag_client(opts.client, opts.d_tag)); - for (const [k, v] of Object.entries(listing)) if (v) tags.push([k, v]); - tags.push(fmt_tag_quantity(quantity)); - tags.push(fmt_tag_price(price)); - tags.push(fmt_tag_location(location)); - if (opts.images) for (const image of opts.images) tags.push(fmt_tag_image(image)); - tags.push(...fmt_tag_geotags(location)); - return tags; -}; - -export const nostr_event_sign = (opts: { - secret_key: string; - event: EventTemplate; -}): NostrEvent => { - return finalizeEvent(opts.event, hexToBytes(opts.secret_key)) -}; - -export const nostr_event_sign_attest = (secret_key: string): NostrEvent => { - return nostr_event_sign({ - secret_key, - event: { - kind: 1, - created_at: Math.floor(Date.now() / 1000), - tags: [], - content: uuidv4(), - }, - }); -}; - - -export const nostr_event_verify = async (event: NostrEvent): Promise<boolean> => { - try { - const hash = getEventHash(event); - console.log(`hash `, hash) - if (hash !== event.id) return false - const valid = schnorr.verify(event.sig, hash, event.pubkey); - return valid; - } catch { - return false; - } -}; - -export const nostr_event_verify_serialized = async (event_serialized: string): Promise<boolean> => { - try { - const event = JSON.parse(event_serialized); - const hash = getEventHash(event); - console.log(`hash `, hash) - if (hash !== event.id) return false - const valid = schnorr.verify(event.sig, hash, event.pubkey); - return valid; - } catch { - return false; - } -}; - -export const nevent_encode = (opts: { - id: string; - relays: string[]; - author: string; - kind: number; -}): string => { - return nip19.neventEncode(opts) -}; -\ No newline at end of file diff --git a/utils/src/nostr/lib2.ts b/utils/src/nostr/lib2.ts @@ -1,147 +0,0 @@ -import { bytesToHex, hexToBytes } from '@noble/hashes/utils'; -import { generateSecretKey, getPublicKey, nip19 } from 'nostr-tools'; - -export class ClientNostrLib2 { - private generate_key_bytes(): Uint8Array { - const secret_key = generateSecretKey(); - return secret_key; - }; - - private get_key_hex(bytes: Uint8Array): string { - const hex = bytesToHex(bytes); - return hex; - }; - - private get_key_bytes(hex: string): Uint8Array { - const bytes = hexToBytes(hex); - return bytes; - }; - - /** - * - * @returns nostr secret key hex - */ - public generate_key(): string { - const bytes = this.generate_key_bytes(); - const hex = this.get_key_hex(bytes); - return hex; - }; - - /** - * - * @returns nostr public key hex - */ - public public_key(secret_key_hex: string | undefined): string { - try { - if (!secret_key_hex) return ``; - const bytes = this.get_key_bytes(secret_key_hex); - const hex = getPublicKey(bytes) - return hex; - } catch (e) { - return `` - } - } - - /** - * - * @returns nostr secret key to public key hex - */ - public publickey_decode(secret_key_hex?: string): string | undefined { - try { - if (secret_key_hex) { - return getPublicKey(this.get_key_bytes(secret_key_hex)) - } - return undefined; - } catch (e) { - return undefined; - } - } - - /** - * - * @returns nostr public key npub - */ - public npub(public_key_hex: string | undefined, fallback_to_hex?: boolean): string { - if (!public_key_hex) return ``; - const npub = nip19.npubEncode(public_key_hex); - return npub ? npub : fallback_to_hex ? public_key_hex : ``; - } - - /** - * - * @returns public key hex from npub - */ - public npub_decode(npub: string): string { - const decode = nip19.decode(npub); - console.log(`decode `, decode) - if (decode && decode.type === `npub` && decode.data) return decode.data - return ``; - } - - /** - * - * @returns nostr secret key nsec - */ - public nsec(secret_key_hex: string | undefined): string { - if (!secret_key_hex) return ``; - const bytes = this.get_key_bytes(secret_key_hex); - const nsec = nip19.nsecEncode(bytes); - return nsec; - } - - /** - * - * @returns nostr secret key hex from nsec - */ - public nsec_decode(nsec: string): string | undefined { - try { - if (!nsec) return undefined; - const decode = nip19.decode(nsec); - if (decode && decode.type === `nsec` && decode.data) return bytesToHex(decode.data); - return undefined; - } catch (e) { - return undefined; - } - } - - /** - * - * @returns - */ - public nevent(event_pointer: nip19.EventPointer, relays: string[]): string { - return nip19.neventEncode(event_pointer) - } - - /** - * - * @returns nostr public key nprofile - */ - public nprofile(public_key_hex: string, relays: string[]): string { - if (!public_key_hex || !relays.length) return ``; - return nip19.nprofileEncode({ pubkey: public_key_hex, relays }) - } - - /** - * - * @returns nostr public key nprofile - */ - public nprofile_decode(nprofile: string): [string, string[]] | undefined { - if (!nprofile) return undefined; - const decode = nip19.decode(nprofile); - if (decode && decode.type === `nprofile` && decode.data && decode.data.pubkey && decode.data.relays) return [decode.data.pubkey, decode.data.relays] - return undefined; - } - - /** - * - * @returns - */ - public secretkey_to_publickey(nsec_or_hex: string): string | undefined { - if (nsec_or_hex.startsWith(`nsec1`)) { - return this.nsec_decode(nsec_or_hex); - } else if (nsec_or_hex.length === 64) { - return this.publickey_decode(nsec_or_hex) - } - return undefined; - } -}; diff --git a/utils/src/nostr/ndk.ts b/utils/src/nostr/ndk.ts @@ -1,75 +0,0 @@ -import NDK, { NDKEvent, NDKKind, NDKPrivateKeySigner, NDKUser } from '@nostr-dev-kit/ndk'; -import { time_now_ms } from '../time'; -import type { NostrKind0Metadata } from './types'; - -export const ndk_init = async (opts: { - $ndk: NDK; - secret_key: string; -}): Promise<NDKUser | undefined> => { - try { - const { $ndk: ndk, secret_key } = opts; - const signer = new NDKPrivateKeySigner(secret_key); - ndk.signer = signer; - - const user = await signer.user(); - if (user) { - user.ndk = ndk; - return user; - } - } catch (e) { - console.log(`(error) ndk_init `, e); - }; -}; - -export const ndk_event_metadata = async (opts: { - $ndk: NDK; - $ndk_user: NDKUser; - metadata: NostrKind0Metadata -}): Promise<NDKEvent | undefined> => { - try { - const { $ndk, $ndk_user } = opts; - const ev = await ndk_event({ - $ndk, - $ndk_user, - basis: { - kind: NDKKind.Metadata, - content: JSON.stringify(opts.metadata), - }, - }); - return ev; - } catch (e) { - console.log(`(error) ndk_event_metadata `, e); - } -}; - -export const ndk_event = async (opts: { - $ndk: NDK; - $ndk_user: NDKUser; - basis: { - kind: number; - content: string; - tags?: string[][]; - } -}): Promise<NDKEvent | undefined> => { - try { - const { $ndk: ndk, $ndk_user: ndk_user, basis } = opts; - const time_now = time_now_ms(); - - const tags: string[][] = [ - ['published_at', time_now.toString()], - ]; - - if (basis.tags && basis.tags?.length > 0) for (const tag of basis.tags) tags.push(tag); - - const event: NDKEvent = new NDKEvent(ndk, { - kind: basis.kind, - pubkey: ndk_user.pubkey, - content: basis.content, - created_at: time_now, - tags - }); - return event; - } catch (e) { - console.log(`(error) ndk_event `, e); - }; -}; diff --git a/utils/src/nostr/types.ts b/utils/src/nostr/types.ts @@ -1,77 +0,0 @@ -export type NostrRelayInformationDocument = { - id?: string; - name?: string; - description?: string; - pubkey?: string; - contact?: string; - supported_nips?: number[]; - software?: string; - version?: string; - limitation_payment_required?: string; - limitation_restricted_writes?: boolean; -} - -export type NostrRelayInformationDocumentFormFields = { [K in keyof NostrRelayInformationDocument]: string; }; - -export type NostrTagListing = { - key: string; - title: string; - category: string; - summary?: string; - process?: string; - lot?: string; - location?: string; - profile?: string; - year?: string; -}; - -export type NostrTagPrice = { - amt: string; - currency: string; - qty_amt: string; - qty_unit: string; -}; - -export type NostrTagQuantity = { - amt: string; - unit: string; - label?: string; -}; - -export type NostrTagLocation = { - city?: string; - region?: string; - region_code?: string; - country?: string; - country_code?: string; - lat: number; - lng: number; - geohash: string; -}; - -export type NostrTagMediaUpload = { - url: string; - size?: { - w: number; - h: number; - }; -}; - -export type NostrTagClient = { - name: string; - pubkey: string; - relay: string; -}; - -export type NostrKind0Metadata = { - name?: string; - display_name?: string; - about?: string; - website?: string; - picture?: string; - banner?: string; - nip05?: string; - lud06?: string; - lud16?: string; - bot?: boolean; -}; -\ No newline at end of file diff --git a/utils/src/regex.ts b/utils/src/regex.ts @@ -1,4 +1,8 @@ export const regex = { + float: /^[+-]?(\d+(\.\d*)?|\.\d+)$/, + float_ch: /^[0-9\.\+\-]$/, + float_pos: /^\d+(\.\d+)?$/, + float_pos_ch: /^[0-9\.]$/, description: /^(?:\S+(?:\s+\S+)*)$/, description_ch: /[^a-zA-Z0-9.,!?;:'"(){}[]\s\u0600-\u06FF\u0900-\u097F\u0400-\u04FF\u0500-\u052F\u1F00-\u1FFF\u4E00-\u9FFF\uAC00-\uD7AF\u3040-\u309F\u30A0-\u30FF ]+/, nbsp: /[\u00A0]/g, @@ -11,9 +15,12 @@ export const regex = { alpha: /[a-zA-Z ]$/, alpha_ch: /[a-zA-Z ]$/, num: /^[0-9]+$/, + lat: /^[-+]?([1-8]?[0-9](\.\d{1,6})?|90(\.0{1,6})?)$/, + lat_ch: /^[\d\.\+\-]$/, + lng: /^[-+]?((1[0-7]?[0-9]|180)(\.\d{1,6})?|(\d{1,2})(\.\d{1,6})?)$/, + lng_ch: /^[\d\.\+\-]$/, alphanum: /[a-zA-Z0-9., ]$/, alphanum_ch: /[a-zA-Z0-9.,\s\u0600-\u06FF\u0900-\u097F\u0400-\u04FF\u0500-\u052F\u1F00-\u1FFF\u4E00-\u9FFF\uAC00-\uD7AF\u3040-\u309F\u30A0-\u30FF ]+/, - ///[a-zA-Z0-9., ]/, price: /^\d+(\.\d+)?$/, price_ch: /[0-9.]$/, profile_name: /^[a-zA-Z0-9._]{3,30}$/, @@ -21,6 +28,6 @@ export const regex = { trade_product_key: /^(?:[a-zA-Z0-9]+(?:\s+[a-zA-Z0-9]+){0,2})$/, trade_product_category: /^(?:[a-zA-Z0-9]+(?:\s+[a-zA-Z0-9]+){0,2})$/, currency_symbol: /(?:[A-Za-z]{3,5}\$|\p{Sc})/u, - currency_marker: /(?:[A-Za-z]{2,4}[^\d\s]+|[^\d\s]{1,3}[A-Za-z]{2,4})/ - ///(?:[A-Za-z]{2,4}\$|\$(?=[A-Za-z]{2,4}$))/ + currency_marker: /(?:[A-Za-z]{2,4}[^\d\s]+|[^\d\s]{1,3}[A-Za-z]{2,4})/, + ws_proto: /^(wss:\/\/|ws:\/\/)/, };