mirror of
https://github.com/nbd-wtf/nostr-tools.git
synced 2025-12-09 08:38:50 +00:00
added NIP-55
This commit is contained in:
committed by
fiatjaf_
parent
a0b950ab12
commit
3266b4d4c2
183
nip55.test.ts
Normal file
183
nip55.test.ts
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
import { test, expect } from 'bun:test'
|
||||||
|
import * as nip55 from './nip55.js'
|
||||||
|
|
||||||
|
// Function to parse the NostrSigner URI
|
||||||
|
function parseNostrSignerUri(uri) {
|
||||||
|
const [base, query] = uri.split('?')
|
||||||
|
const basePart = base.replace('nostrsigner:', '')
|
||||||
|
|
||||||
|
let jsonObject = null
|
||||||
|
if (basePart) {
|
||||||
|
try {
|
||||||
|
jsonObject = JSON.parse(decodeURIComponent(basePart))
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Failed to parse base JSON:', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const urlSearchParams = new URLSearchParams(query)
|
||||||
|
const queryParams = Object.fromEntries(urlSearchParams.entries())
|
||||||
|
if (queryParams.permissions) {
|
||||||
|
queryParams.permissions = JSON.parse(decodeURIComponent(queryParams.permissions))
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
base: jsonObject,
|
||||||
|
...queryParams,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test cases
|
||||||
|
test('Get Public Key URI', () => {
|
||||||
|
const permissions = [{ type: 'sign_event', kind: 22242 }, { type: 'nip44_decrypt' }]
|
||||||
|
const callbackUrl = 'https://example.com/?event='
|
||||||
|
|
||||||
|
const uri = nip55.getPublicKeyUri({
|
||||||
|
permissions,
|
||||||
|
callbackUrl,
|
||||||
|
})
|
||||||
|
|
||||||
|
const jsonObject = parseNostrSignerUri(uri)
|
||||||
|
|
||||||
|
expect(jsonObject).toHaveProperty('type', 'get_public_key')
|
||||||
|
expect(jsonObject).toHaveProperty('compressionType', 'none')
|
||||||
|
expect(jsonObject).toHaveProperty('returnType', 'signature')
|
||||||
|
expect(jsonObject).toHaveProperty('callbackUrl', 'https://example.com/?event=')
|
||||||
|
expect(jsonObject).toHaveProperty('permissions[0].type', 'sign_event')
|
||||||
|
expect(jsonObject).toHaveProperty('permissions[0].kind', 22242)
|
||||||
|
expect(jsonObject).toHaveProperty('permissions[1].type', 'nip44_decrypt')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('Sign Event URI', () => {
|
||||||
|
const eventJson = { kind: 1, content: 'test' }
|
||||||
|
|
||||||
|
const uri = nip55.signEventUri({
|
||||||
|
eventJson,
|
||||||
|
id: 'some_id',
|
||||||
|
currentUser: 'hex_pub_key',
|
||||||
|
})
|
||||||
|
|
||||||
|
const jsonObject = parseNostrSignerUri(uri)
|
||||||
|
|
||||||
|
expect(jsonObject).toHaveProperty('base.kind', 1)
|
||||||
|
expect(jsonObject).toHaveProperty('base.content', 'test')
|
||||||
|
expect(jsonObject).toHaveProperty('type', 'sign_event')
|
||||||
|
expect(jsonObject).toHaveProperty('compressionType', 'none')
|
||||||
|
expect(jsonObject).toHaveProperty('returnType', 'signature')
|
||||||
|
expect(jsonObject).toHaveProperty('id', 'some_id')
|
||||||
|
expect(jsonObject).toHaveProperty('current_user', 'hex_pub_key')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('Get Relays URI', () => {
|
||||||
|
const uri = nip55.getRelaysUri({
|
||||||
|
id: 'some_id',
|
||||||
|
currentUser: 'hex_pub_key',
|
||||||
|
appName: 'test app name',
|
||||||
|
})
|
||||||
|
|
||||||
|
const jsonObject = parseNostrSignerUri(uri)
|
||||||
|
|
||||||
|
expect(jsonObject).toHaveProperty('type', 'get_relays')
|
||||||
|
expect(jsonObject).toHaveProperty('compressionType', 'none')
|
||||||
|
expect(jsonObject).toHaveProperty('returnType', 'signature')
|
||||||
|
expect(jsonObject).toHaveProperty('id', 'some_id')
|
||||||
|
expect(jsonObject).toHaveProperty('current_user', 'hex_pub_key')
|
||||||
|
expect(jsonObject).toHaveProperty('appName', 'test app name')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('Encrypt NIP-04 URI', () => {
|
||||||
|
const callbackUrl = 'https://example.com/?event='
|
||||||
|
|
||||||
|
const uri = nip55.encryptNip04Uri({
|
||||||
|
callbackUrl,
|
||||||
|
pubKey: 'hex_pub_key',
|
||||||
|
content: 'plainText',
|
||||||
|
})
|
||||||
|
|
||||||
|
const jsonObject = parseNostrSignerUri(uri)
|
||||||
|
|
||||||
|
expect(jsonObject).toHaveProperty('type', 'nip04_encrypt')
|
||||||
|
expect(jsonObject).toHaveProperty('compressionType', 'none')
|
||||||
|
expect(jsonObject).toHaveProperty('returnType', 'signature')
|
||||||
|
expect(jsonObject).toHaveProperty('callbackUrl', callbackUrl)
|
||||||
|
expect(jsonObject).toHaveProperty('pubKey', 'hex_pub_key')
|
||||||
|
expect(jsonObject).toHaveProperty('plainText', 'plainText')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('Decrypt NIP-04 URI', () => {
|
||||||
|
const uri = nip55.decryptNip04Uri({
|
||||||
|
id: 'some_id',
|
||||||
|
currentUser: 'hex_pub_key',
|
||||||
|
pubKey: 'hex_pub_key',
|
||||||
|
content: 'encryptedText',
|
||||||
|
})
|
||||||
|
|
||||||
|
const jsonObject = parseNostrSignerUri(uri)
|
||||||
|
|
||||||
|
expect(jsonObject).toHaveProperty('type', 'nip04_decrypt')
|
||||||
|
expect(jsonObject).toHaveProperty('compressionType', 'none')
|
||||||
|
expect(jsonObject).toHaveProperty('returnType', 'signature')
|
||||||
|
expect(jsonObject).toHaveProperty('id', 'some_id')
|
||||||
|
expect(jsonObject).toHaveProperty('current_user', 'hex_pub_key')
|
||||||
|
expect(jsonObject).toHaveProperty('pubKey', 'hex_pub_key')
|
||||||
|
expect(jsonObject).toHaveProperty('encryptedText', 'encryptedText')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('Encrypt NIP-44 URI', () => {
|
||||||
|
const uri = nip55.encryptNip44Uri({
|
||||||
|
id: 'some_id',
|
||||||
|
currentUser: 'hex_pub_key',
|
||||||
|
pubKey: 'hex_pub_key',
|
||||||
|
content: 'plainText',
|
||||||
|
})
|
||||||
|
|
||||||
|
const jsonObject = parseNostrSignerUri(uri)
|
||||||
|
|
||||||
|
expect(jsonObject).toHaveProperty('type', 'nip44_encrypt')
|
||||||
|
expect(jsonObject).toHaveProperty('compressionType', 'none')
|
||||||
|
expect(jsonObject).toHaveProperty('returnType', 'signature')
|
||||||
|
expect(jsonObject).toHaveProperty('id', 'some_id')
|
||||||
|
expect(jsonObject).toHaveProperty('current_user', 'hex_pub_key')
|
||||||
|
expect(jsonObject).toHaveProperty('pubKey', 'hex_pub_key')
|
||||||
|
expect(jsonObject).toHaveProperty('plainText', 'plainText')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('Decrypt NIP-44 URI', () => {
|
||||||
|
const uri = nip55.decryptNip44Uri({
|
||||||
|
id: 'some_id',
|
||||||
|
currentUser: 'hex_pub_key',
|
||||||
|
pubKey: 'hex_pub_key',
|
||||||
|
content: 'encryptedText',
|
||||||
|
})
|
||||||
|
|
||||||
|
const jsonObject = parseNostrSignerUri(uri)
|
||||||
|
|
||||||
|
expect(jsonObject).toHaveProperty('type', 'nip44_decrypt')
|
||||||
|
expect(jsonObject).toHaveProperty('compressionType', 'none')
|
||||||
|
expect(jsonObject).toHaveProperty('returnType', 'signature')
|
||||||
|
expect(jsonObject).toHaveProperty('id', 'some_id')
|
||||||
|
expect(jsonObject).toHaveProperty('current_user', 'hex_pub_key')
|
||||||
|
expect(jsonObject).toHaveProperty('pubKey', 'hex_pub_key')
|
||||||
|
expect(jsonObject).toHaveProperty('encryptedText', 'encryptedText')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('Decrypt Zap Event URI', () => {
|
||||||
|
const eventJson = { kind: 1, content: 'test' }
|
||||||
|
|
||||||
|
const uri = nip55.decryptZapEventUri({
|
||||||
|
eventJson,
|
||||||
|
id: 'some_id',
|
||||||
|
currentUser: 'hex_pub_key',
|
||||||
|
returnType: 'event',
|
||||||
|
compressionType: 'gzip',
|
||||||
|
})
|
||||||
|
|
||||||
|
const jsonObject = parseNostrSignerUri(uri)
|
||||||
|
|
||||||
|
expect(jsonObject).toHaveProperty('type', 'decrypt_zap_event')
|
||||||
|
expect(jsonObject).toHaveProperty('compressionType', 'gzip')
|
||||||
|
expect(jsonObject).toHaveProperty('returnType', 'event')
|
||||||
|
expect(jsonObject).toHaveProperty('base.kind', 1)
|
||||||
|
expect(jsonObject).toHaveProperty('id', 'some_id')
|
||||||
|
expect(jsonObject).toHaveProperty('current_user', 'hex_pub_key')
|
||||||
|
})
|
||||||
127
nip55.ts
Normal file
127
nip55.ts
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
type BaseParams = {
|
||||||
|
callbackUrl?: string
|
||||||
|
returnType?: 'signature' | 'event'
|
||||||
|
compressionType?: 'none' | 'gzip'
|
||||||
|
}
|
||||||
|
|
||||||
|
type PermissionsParams = BaseParams & {
|
||||||
|
permissions?: { type: string; kind?: number }[]
|
||||||
|
}
|
||||||
|
|
||||||
|
type EventUriParams = BaseParams & {
|
||||||
|
eventJson: Record<string, unknown>
|
||||||
|
id?: string
|
||||||
|
currentUser?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
type EncryptDecryptParams = BaseParams & {
|
||||||
|
pubKey: string
|
||||||
|
content: string
|
||||||
|
id?: string
|
||||||
|
currentUser?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
type UriParams = BaseParams & {
|
||||||
|
base: string
|
||||||
|
type: string
|
||||||
|
id?: string
|
||||||
|
currentUser?: string
|
||||||
|
permissions?: { type: string; kind?: number }[]
|
||||||
|
pubKey?: string
|
||||||
|
plainText?: string
|
||||||
|
encryptedText?: string
|
||||||
|
appName?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
function encodeParams(params: Record<string, unknown>): string {
|
||||||
|
return new URLSearchParams(params as Record<string, string>).toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterUndefined<T extends Record<string, unknown>>(obj: T): T {
|
||||||
|
return Object.fromEntries(Object.entries(obj).filter(([, value]) => value !== undefined)) as T
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildUri({
|
||||||
|
base,
|
||||||
|
type,
|
||||||
|
callbackUrl,
|
||||||
|
returnType = 'signature',
|
||||||
|
compressionType = 'none',
|
||||||
|
...params
|
||||||
|
}: UriParams): string {
|
||||||
|
const baseParams = {
|
||||||
|
type,
|
||||||
|
compressionType,
|
||||||
|
returnType,
|
||||||
|
callbackUrl,
|
||||||
|
id: params.id,
|
||||||
|
current_user: params.currentUser,
|
||||||
|
permissions:
|
||||||
|
params.permissions && params.permissions.length > 0
|
||||||
|
? encodeURIComponent(JSON.stringify(params.permissions))
|
||||||
|
: undefined,
|
||||||
|
pubKey: params.pubKey,
|
||||||
|
plainText: params.plainText,
|
||||||
|
encryptedText: params.encryptedText,
|
||||||
|
appName: params.appName,
|
||||||
|
}
|
||||||
|
|
||||||
|
const filteredParams = filterUndefined(baseParams)
|
||||||
|
return `${base}?${encodeParams(filteredParams)}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildDefaultUri(type: string, params: Partial<UriParams>): string {
|
||||||
|
return buildUri({
|
||||||
|
base: 'nostrsigner:',
|
||||||
|
type,
|
||||||
|
...params,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPublicKeyUri({ permissions = [], ...params }: PermissionsParams): string {
|
||||||
|
return buildDefaultUri('get_public_key', { permissions, ...params })
|
||||||
|
}
|
||||||
|
|
||||||
|
export function signEventUri({ eventJson, ...params }: EventUriParams): string {
|
||||||
|
return buildUri({
|
||||||
|
base: `nostrsigner:${encodeURIComponent(JSON.stringify(eventJson))}`,
|
||||||
|
type: 'sign_event',
|
||||||
|
...params,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getRelaysUri(params: BaseParams & { id?: string; currentUser?: string }): string {
|
||||||
|
return buildDefaultUri('get_relays', params)
|
||||||
|
}
|
||||||
|
|
||||||
|
function encryptUri(type: 'nip44_encrypt' | 'nip04_encrypt', params: EncryptDecryptParams): string {
|
||||||
|
return buildDefaultUri(type, { ...params, plainText: params.content })
|
||||||
|
}
|
||||||
|
|
||||||
|
function decryptUri(type: 'nip44_decrypt' | 'nip04_decrypt', params: EncryptDecryptParams): string {
|
||||||
|
return buildDefaultUri(type, { ...params, encryptedText: params.content })
|
||||||
|
}
|
||||||
|
|
||||||
|
export function encryptNip04Uri(params: EncryptDecryptParams): string {
|
||||||
|
return encryptUri('nip04_encrypt', params)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function decryptNip04Uri(params: EncryptDecryptParams): string {
|
||||||
|
return decryptUri('nip04_decrypt', params)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function encryptNip44Uri(params: EncryptDecryptParams): string {
|
||||||
|
return encryptUri('nip44_encrypt', params)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function decryptNip44Uri(params: EncryptDecryptParams): string {
|
||||||
|
return decryptUri('nip44_decrypt', params)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function decryptZapEventUri({ eventJson, ...params }: EventUriParams): string {
|
||||||
|
return buildUri({
|
||||||
|
base: `nostrsigner:${encodeURIComponent(JSON.stringify(eventJson))}`,
|
||||||
|
type: 'decrypt_zap_event',
|
||||||
|
...params,
|
||||||
|
})
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user