diff --git a/utils/ConnectionFormatUtils.test.ts b/utils/ConnectionFormatUtils.test.ts index 4145c0ded..da51d9a0d 100644 --- a/utils/ConnectionFormatUtils.test.ts +++ b/utils/ConnectionFormatUtils.test.ts @@ -152,4 +152,48 @@ describe('ConnectionFormatUtils', () => { }); }); }); + + describe('processCLNRestConnectUrl', () => { + it('handles plainnet properly - w/o http forced', () => { + expect( + ConnectionFormatUtils.processCLNRestConnectUrl( + 'clnrest://8.8.0.0:2056?&rune=OSqc7ixY6F-gjcigBfxtzKUI54uzgFSA6YfBQoWGDV89MA==&protocol=http' + ) + ).toEqual({ + host: 'https://8.8.0.0', + rune: 'OSqc7ixY6F-gjcigBfxtzKUI54uzgFSA6YfBQoWGDV89MA==', + port: '2056', + enableTor: false, + implementation: 'cln-rest' + }); + }); + + it('handles plainnet properly - with http forced', () => { + expect( + ConnectionFormatUtils.processCLNRestConnectUrl( + 'clnrest://http://8.8.0.0:2056?&rune=OSqc7ixY6F-gjcigBfxtzKUI54uzgFSA6YfBQoWGDV89MA==&protocol=http' + ) + ).toEqual({ + host: 'http://8.8.0.0', + rune: 'OSqc7ixY6F-gjcigBfxtzKUI54uzgFSA6YfBQoWGDV89MA==', + port: '2056', + enableTor: false, + implementation: 'cln-rest' + }); + }); + + it('handles Tor properly', () => { + expect( + ConnectionFormatUtils.processCLNRestConnectUrl( + 'clnrest://http://y7enfk2mdfawf.onion:2056?&rune=OSqc7ixY6F-gjcigBfxtzKUI54uzgFSA6YfBQoWGDV89MA==&protocol=http' + ) + ).toEqual({ + host: 'http://y7enfk2mdfawf.onion', + rune: 'OSqc7ixY6F-gjcigBfxtzKUI54uzgFSA6YfBQoWGDV89MA==', + port: '2056', + enableTor: true, + implementation: 'cln-rest' + }); + }); + }); }); diff --git a/utils/ConnectionFormatUtils.ts b/utils/ConnectionFormatUtils.ts index 950cdb2b5..b219f3551 100644 --- a/utils/ConnectionFormatUtils.ts +++ b/utils/ConnectionFormatUtils.ts @@ -110,6 +110,58 @@ class ConnectionFormatUtils { implementation: 'c-lightning-REST' }; }; + + processCLNRestConnectUrl = (input: string) => { + let host, port; + const forceHttp = input.includes('clnrest://http://'); + const clrConnectionString = forceHttp + ? input.replace('clnrest://http://', '') + : input.split('clnrest://')[1]; + const params = input.split('?')[1]; + + const result: any = {}; + if (params) { + params.split('&').forEach(function (part) { + // split on only the first = sign + const item = part.split(/=(.*)/s); + result[item[0]] = decodeURIComponent(item[1]); + }); + } + + // is IPv6 + if (input.includes('[')) { + host = + clrConnectionString && clrConnectionString.split(']:')[0] + ']'; + port = + clrConnectionString && + clrConnectionString.split(']:')[1] && + clrConnectionString.split(']:')[1].split('?')[0]; + } else { + host = clrConnectionString && clrConnectionString.split(':')[0]; + port = + clrConnectionString && + clrConnectionString.split(':')[1] && + clrConnectionString.split(':')[1].split('?')[0]; + } + const rune = result.rune; + + // prepend https by default + host = host.includes('://') + ? host + : forceHttp + ? 'http://' + host + : 'https://' + host; + + const enableTor: boolean = host.includes('.onion'); + + return { + host, + port, + rune, + enableTor, + implementation: 'cln-rest' + }; + }; } const connectionFormatUtils = new ConnectionFormatUtils(); diff --git a/utils/handleAnything.ts b/utils/handleAnything.ts index e403f5421..ee83937e8 100644 --- a/utils/handleAnything.ts +++ b/utils/handleAnything.ts @@ -226,6 +226,33 @@ const handleAnything = async ( { cancelable: false } ); } + } else if (value.includes('clnrest://')) { + if (isClipboardValue) return true; + const { host, port, rune, implementation, enableTor } = + ConnectionFormatUtils.processCLNRestConnectUrl(value); + + if (host && port && rune) { + return [ + 'NodeConfiguration', + { + node: { + host, + port, + rune, + implementation, + enableTor + }, + isValid: true + } + ]; + } else { + Alert.alert( + localeString('general.error'), + localeString('views.LNDConnectConfigQRScanner.error'), + [{ text: localeString('general.ok'), onPress: () => void 0 }], + { cancelable: false } + ); + } } else if ( value.includes('https://terminal.lightning.engineering#/connect/pair/') ) {