nostr icon indicating copy to clipboard operation
nostr copied to clipboard

Failed to parse nprofile

Open dluvian opened this issue 10 months ago • 5 comments

Describe the bug

The nprofile nprofile1qyxhwumn8ghj7cnjvghxjme0qyxhwumn8ghj7cnjvghxjme0qyt8wumn8ghj7etyv4hzumn0wd68ytnvv9hxgtcpzemhxue69uhk2er9dchxummnw3ezumrpdejz7qgwwaehxw309ahx7uewd3hkctcppemhxue69uhkummn9ekx7mp0qy08wumn8ghj7mn0wd68yttsw43zuam9d3kx7unyv4ezumn9wshsz8nhwden5te0dehhxarj94c82c3wwajkcmr0wfjx2u3wdejhgtcpr4mhxue69uhkummnw3ezucnfw33k76twv4ezuum0vd5kzmp0qyv8wumn8ghj7mn0wd68ytnxd46zuamf0ghxy6t69uq3samnwvaz7tmwdaehgu3wvekhgtnhd9azucnf0ghsz9mhwden5te0dehhxarj9eex2mrp09jhytnnv5hsz9mhwden5te0dehhxarj9eex2mrp09jhytnnv5hszythwden5te0dehhxarj9emkjmn99uq3gamnwvaz7tmwdaehgu3w0qcxvtn0wfnj7qgnwaehxw309ahkvenrdpskjm3wwp6kytcpzdmhxue69uhk7enxvd5xz6tw9ec82c30qyv8wumn8ghj7un9d3shjtnrw4e8yetwwshxv7tf9uq3samnwvaz7tmjv4kxz7fwvd6hyun9de6zuenedyhsz9thwden5te0wfjkccte9ejxzmt4wvhxjme0qy2hwumn8ghj7un9d3shjtnyv9kh2uewd9hj7qgkwaehxw309aex2mrp0yhx6mmnw3ezuur4vghsz9mhwden5te0wfjkccte9ehx7um5wghxyctwvshsz9mhwden5te0wfjkccte9ehx7um5wghxjmnxduhsz9mhwden5te0wfjkccte9ehx7um5wghxjmnxduhszxthwden5te0wfjkccte9ehx7umhdpjhyefwvdhk6tcpzamhxue69uhhyetvv9ujuurjd9kkzmpwdejhgtcpr9mhxue69uhhyetvv9ujuumwdae8gtnnda3kjctv9uq3jamnwvaz7tmjv4kxz7fwwdhx7un59eek7cmfv9kz7qpqsyluunzwwmc70d85d9alzqc2jrc6pdur7xrax2vqpfxas6tljavsrwlyyy fails to parse to a Nip19Profile with the error rust.nostr.sdk.NostrSdkException$Generic: no valid bech32 or bech32m checksum.

I found this nprofile while scrolling nostr (nevent1qqsw2w7ha4vn0cx4ygd4y9pxmypa8ctfgym52v3lpsjd7xk3rnryeagzyz7mj6knrtr27y3uw6pu24m4acsn3ks03uq3uwv5644zwfcwdyjh2qcyqqqqqqgpr3mhxue69uhkummnw3ezucnfw33k76twv4ezuum0vd5kzmquw82w6). Other clients have no problem parsing it so maybe failing the parse process is too harsh?

To Reproduce

Use nprofile above

Expected behavior

Ignore the error or keep it as is. If the nprofile really is invalid and you think failing is the correct move then close this issue, I just want to let you know that these nprofiles are out there

Build environment

  • Library: nostr-sdk
  • Language: Kotlin
  • Language version: v0.38.3
  • Tag/commit:
  • OS+version:

Additional context

dluvian avatar Jan 19 '25 01:01 dluvian

I think it's related to the same issue I mentioned here: https://github.com/rust-nostr/nostr/pull/394#pullrequestreview-1986706154

The bech32 crate check the string length from v0.11 (enforced by the BIP-173), and that nprofile is pretty long.

I receive this error:

Bech32Decode(Checksum(CodeLength(CodeLengthError { encoded_length: 1179, code_length: 1023 })))

yukibtc avatar Jan 19 '25 10:01 yukibtc

  • https://github.com/rust-bitcoin/rust-bech32/issues/140
  • https://github.com/rust-bitcoin/rust-bech32/pull/142
  • https://github.com/rust-bitcoin/rust-bech32/issues/156

yukibtc avatar Jan 19 '25 10:01 yukibtc

@yukibtc What do you think about forking rust-bech32 and revert the pull request?

TheAwiteb avatar Feb 28 '25 19:02 TheAwiteb

I tried the following change, it decode it right. But when I tried it with encode it produce a different nprofile.

impl FromBech32 for Nip19Profile {
    type Err = Error;

    fn from_bech32(profile: &str) -> Result<Self, Self::Err> {
        struct TestBech32;
        const GEN: [u32; 5] = [
            0x3b6a_57b2,
            0x2650_8e6d,
            0x1ea1_19fa,
            0x3d42_33dd,
            0x2a14_62b3,
        ];
        impl bech32::Checksum for TestBech32 {
            type MidstateRepr = u32;
            const CODE_LENGTH: usize = usize::MAX;
            const CHECKSUM_LENGTH: usize = 6;
            const GENERATOR_SH: [u32; 5] = GEN;
            const TARGET_RESIDUE: u32 = 1;
        }

        let hrp_str =
            bech32::primitives::decode::CheckedHrpstring::new::<TestBech32>(profile).unwrap();

        if hrp_str.hrp() != HRP_PROFILE {
            return Err(Error::WrongPrefix);
        }

        Self::from_bech32_data(hrp_str.byte_iter().collect())
        // let (hrp, data) = bech32::decode(profile)?;

        // if hrp != HRP_PROFILE {
        //     return Err(Error::WrongPrefix);
        // }

        // Self::from_bech32_data(data)
    }
}

TheAwiteb avatar Feb 28 '25 19:02 TheAwiteb

This is the encoding change, if you want to try it

impl ToBech32 for Nip19Profile {
    type Err = Error;

    fn to_bech32(&self) -> Result<String, Self::Err> {
        struct TestBech32;
        const GEN: [u32; 5] = [
            0x3b6a_57b2,
            0x2650_8e6d,
            0x1ea1_19fa,
            0x3d42_33dd,
            0x2a14_62b3,
        ];
        impl bech32::Checksum for TestBech32 {
            type MidstateRepr = u32;
            const CODE_LENGTH: usize = usize::MAX;
            const CHECKSUM_LENGTH: usize = 6;
            const GENERATOR_SH: [u32; 5] = GEN;
            const TARGET_RESIDUE: u32 = 1;
        }

        // Allocate capacity
        let relays_len: usize = self.relays.iter().map(|u| 2 + u.as_str().len()).sum();
        let mut bytes: Vec<u8> = Vec::with_capacity(FIXED_1_1_32_BYTES_TVL + relays_len);

        bytes.push(SPECIAL); // Type
        bytes.push(32); // Len
        bytes.extend(self.public_key.as_bytes()); // Value

        for relay in self.relays.iter() {
            let url: &[u8] = relay.as_str().as_bytes();
            bytes.push(RELAY); // Type
            bytes.push(url.len() as u8); // Len
            bytes.extend(url); // Value
        }

        Ok(bech32::encode::<TestBech32>(HRP_PROFILE, &bytes)?)
    }
}

TheAwiteb avatar Feb 28 '25 19:02 TheAwiteb

Closed as not planned for the reasons described at https://github.com/rust-nostr/nostr/pull/785#pullrequestreview-2728568914

yukibtc avatar May 19 '25 06:05 yukibtc