Skip to content

Commit e00656d

Browse files
committed
fix: handling of https://zeusln.com/e/ links
1 parent 81adcf7 commit e00656d

File tree

2 files changed

+65
-24
lines changed

2 files changed

+65
-24
lines changed

utils/handleAnything.test.ts

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1546,11 +1546,14 @@ describe('handleAnything', () => {
15461546
});
15471547
});
15481548

1549+
// IMPORTANT: zeusln.com/e/ URLs must be checked BEFORE the lnurl block in handleAnything,
1550+
// because findlnurl() from js-lnurl can match patterns in Cashu tokens that look like bech32 lnurls.
1551+
// These tests verify the correct route is returned when findlnurl might otherwise match.
15491552
describe('zeusln.com ecash gift URLs', () => {
15501553
const validCashuToken =
15511554
'cashuBo2FteCJodHRwczovL21pbnQubWluaWJpdHMuY2FzaC9CaXRjb2luYXVjc2F0YXSComFpSAAQeTfbDMhlYXCCpGFhCGFzeEAxOWQ3YmRiNTIwMzRmOWQ5OGQwZTU5OTEwM2FkMTlmZTAyODc1ODQ2MThlYmViYTFkNzExM2FiMjI4MDM0YjNlYWNYIQI5u9Nss3cyYXJoLTwRMY4qgCNL7-J7EtBFnGOIeq6tcWFko2FlWCBYlzHfzFSuLuI31zvZGHme0QGeeEjNoGhIs6l2fbbHH2FzWCA2ecAUKZWjtQagWP7wOUVRgsHYlyOG7CUhUFdQjUed2GFyWCC67afI6qoB6bISgCWK24JOdD_-gxUyaSrgfrZJmHsBh6RhYQRhc3hANWYzMGRlMDA1NjVkYTRhZDg2Yzk1MzljYzYzMGE3NTBlYWU2OTJiY2Q5ODgwMWI0OTI0NDA1ZDAxN2UzNGE5MWFjWCECN8hTvJgIFBwN0QY3prfyf4z7BxPVLBPptzKcnb_OupNhZKNhZVggcx4XGwTyM4riizWgckD44KUJQtKHUGGjHIJHFKdPE31hc1ggqASxqD7ZTbA59c7SAHgQvLdLq_xYLL2rAVr2ziIGfkRhclgg-bTi6nbDj8Mdq9rnKhAGgrQ4w6ihk9pvu9xUommg6V-iYWlIAFAFUPBJQUZhcIGkYWEEYXN4QDBlMzhhZWIxYzIxMTk1N2U5Njg4YTdlY2YzNzQ4Y2E2MTA0MDMzNmZjZWJmMzE4M2EwMDAwOWFiYzJiMjcxNWFhY1ghAu0yuRBFejZTitq8LJufeiB2CUAEk-pHTIWqYtFcqtCSYWSjYWVYIDhNUWOMw2xaCZT4Ob8bdV5CxkErkHh-m2XUUqCKZS3WYXNYIBUltNlKIUTrHi4M1Z8SL3l3_EPp-5eOPltdS648bpVGYXJYIFZdUQc6c-waYIhOMSS_-cS19HiHZn4xZe4s65dGN8u5';
15521555

1553-
it('should handle valid zeusln.com/e/ URL with Cashu token', async () => {
1556+
it('should route to CashuToken view for valid zeusln.com/e/ URL', async () => {
15541557
const url = `${ZEUS_ECASH_GIFT_URL}${validCashuToken}`;
15551558
mockProcessBIP21Uri.mockReturnValue({ value: url });
15561559
mockIsValidCashuToken = true;
@@ -1566,9 +1569,42 @@ describe('handleAnything', () => {
15661569

15671570
const result = await handleAnything(url);
15681571

1569-
expect(result[0]).toBe('CashuToken');
1570-
expect(result[1].token).toBe(validCashuToken);
1571-
expect(result[1].decoded).toBeDefined();
1572+
expect(result).toEqual([
1573+
'CashuToken',
1574+
{
1575+
token: validCashuToken,
1576+
decoded: expect.any(Object)
1577+
}
1578+
]);
1579+
});
1580+
1581+
it('should route to CashuToken even when findlnurl would match token content', async () => {
1582+
// This test simulates the bug where findlnurl matched patterns in Cashu tokens
1583+
const url = `${ZEUS_ECASH_GIFT_URL}${validCashuToken}`;
1584+
mockProcessBIP21Uri.mockReturnValue({ value: url });
1585+
mockIsValidCashuToken = true;
1586+
mockDecodedCashuToken = {
1587+
token: [
1588+
{
1589+
mint: 'https://mint.minibits.cash/Bitcoin',
1590+
proofs: [{ amount: 16 }]
1591+
}
1592+
],
1593+
unit: 'sat'
1594+
};
1595+
// Simulate findlnurl returning a match (which would happen with some Cashu tokens)
1596+
mockFindLnurl.mockReturnValue('lnurl1somefalsepositive');
1597+
1598+
const result = await handleAnything(url);
1599+
1600+
// Should still route to CashuToken, NOT to lnurl handling
1601+
expect(result).toEqual([
1602+
'CashuToken',
1603+
{
1604+
token: validCashuToken,
1605+
decoded: expect.any(Object)
1606+
}
1607+
]);
15721608
});
15731609

15741610
it('should return true for valid zeusln.com/e/ URL from clipboard', async () => {
@@ -1590,7 +1626,7 @@ describe('handleAnything', () => {
15901626
expect(result).toBe(true);
15911627
});
15921628

1593-
it('should handle short zeusln.com/e/ URL with simple token', async () => {
1629+
it('should route to CashuToken for V3 token (cashuA prefix)', async () => {
15941630
const simpleToken =
15951631
'cashuAeyJ0b2tlbiI6IFt7InByb29mcyI6IFtdLCAibWludCI6ICJodHRwczovL21pbnQuZXhhbXBsZS5jb20ifV19';
15961632
const url = `${ZEUS_ECASH_GIFT_URL}${simpleToken}`;
@@ -1607,8 +1643,13 @@ describe('handleAnything', () => {
16071643

16081644
const result = await handleAnything(url);
16091645

1610-
expect(result[0]).toBe('CashuToken');
1611-
expect(result[1].token).toBe(simpleToken);
1646+
expect(result).toEqual([
1647+
'CashuToken',
1648+
{
1649+
token: simpleToken,
1650+
decoded: expect.any(Object)
1651+
}
1652+
]);
16121653
});
16131654

16141655
it('should throw error for zeusln.com/e/ URL with invalid token', async () => {

utils/handleAnything.ts

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,23 @@ const handleAnything = async (
734734
{ cancelable: false }
735735
);
736736
});
737+
} else if (value.startsWith(ZEUS_ECASH_GIFT_URL)) {
738+
// Handle zeusln.com ecash gift URLs - check before lnurl to avoid false matches
739+
const cashuToken = value.replace(ZEUS_ECASH_GIFT_URL, '');
740+
if (CashuUtils.isValidCashuToken(cashuToken)) {
741+
if (isClipboardValue) return true;
742+
const tokenObj = CashuUtils.decodeCashuToken(cashuToken);
743+
const decoded = new CashuToken(tokenObj);
744+
return [
745+
'CashuToken',
746+
{
747+
token: cashuToken,
748+
decoded
749+
}
750+
];
751+
}
752+
if (isClipboardValue) return false;
753+
throw new Error(localeString('utils.handleAnything.notValid'));
737754
} else if (
738755
!!findlnurl(value) ||
739756
!!lnurl ||
@@ -941,23 +958,6 @@ const handleAnything = async (
941958
extended_public_key: value
942959
}
943960
];
944-
} else if (value.startsWith(ZEUS_ECASH_GIFT_URL)) {
945-
// Handle zeusln.com ecash gift URLs
946-
const cashuToken = value.replace(ZEUS_ECASH_GIFT_URL, '');
947-
if (CashuUtils.isValidCashuToken(cashuToken)) {
948-
if (isClipboardValue) return true;
949-
const tokenObj = CashuUtils.decodeCashuToken(cashuToken);
950-
const decoded = new CashuToken(tokenObj);
951-
return [
952-
'CashuToken',
953-
{
954-
token: cashuToken,
955-
decoded
956-
}
957-
];
958-
}
959-
if (isClipboardValue) return false;
960-
throw new Error(localeString('utils.handleAnything.notValid'));
961961
} else if (CashuUtils.isValidCashuToken(value)) {
962962
const tokenObj = CashuUtils.decodeCashuToken(value);
963963
const decoded = new CashuToken(tokenObj);

0 commit comments

Comments
 (0)