diff --git a/android/app/release/output-metadata.json b/android/app/release/output-metadata.json new file mode 100644 index 0000000000..d7df8dfc05 --- /dev/null +++ b/android/app/release/output-metadata.json @@ -0,0 +1,20 @@ +{ + "version": 3, + "artifactType": { + "type": "APK", + "kind": "Directory" + }, + "applicationId": "org.cardanofoundation.idw", + "variantName": "release", + "elements": [ + { + "type": "SINGLE", + "filters": [], + "attributes": [], + "versionCode": 1, + "versionName": "1.0", + "outputFile": "app-release.apk" + } + ], + "elementType": "File" +} \ No newline at end of file diff --git a/services/cip45-sample-dapp/src/pages/Demo.tsx b/services/cip45-sample-dapp/src/pages/Demo.tsx index 60420a49e4..06b1c73b58 100644 --- a/services/cip45-sample-dapp/src/pages/Demo.tsx +++ b/services/cip45-sample-dapp/src/pages/Demo.tsx @@ -101,13 +101,20 @@ const Demo: React.FC = () => { } }, []); - const disconnectWallet = () => { + const disconnectWallet = async () => { disconnect(); setPeerConnectWalletInfo(defautlWallet); setShowAcceptButton(false); setWalletIsConnected(false); setError(""); + + const api = + window.cardano && window.cardano[peerConnectWalletInfo.name]; + if (!api) return; + const enabledApi = await api.enable(); + await enabledApi.experimental.disable(); } + const handleAcceptWallet = () => { if (peerConnectWalletInfo) { onPeerConnectAccept(); @@ -119,7 +126,6 @@ const Demo: React.FC = () => { const checkApi = setInterval(async () => { const api = - // @ts-ignore window.cardano && window.cardano[peerConnectWalletInfo.name]; if (api || Date.now() - start > timeout) { clearInterval(checkApi); @@ -201,7 +207,7 @@ const Demo: React.FC = () => { showAcceptButton ? : walletIsConnected ? : null diff --git a/src/core/cardano/walletConnect/identityWalletConnect.ts b/src/core/cardano/walletConnect/identityWalletConnect.ts index 5bd50570fc..68ec2d9a39 100644 --- a/src/core/cardano/walletConnect/identityWalletConnect.ts +++ b/src/core/cardano/walletConnect/identityWalletConnect.ts @@ -5,7 +5,6 @@ import { IWalletInfo, } from "@fabianbormann/cardano-peer-connect/dist/src/types"; import { CardanoPeerConnect } from "@fabianbormann/cardano-peer-connect"; -import { Signer } from "signify-ts"; import { Agent } from "../../agent/agent"; import { PeerConnectSigningEvent, @@ -14,6 +13,7 @@ import { TxSignError, } from "./peerConnection.types"; import { CoreEventEmitter } from "../../agent/event"; +import {PeerConnection} from "./peerConnection"; class IdentityWalletConnect extends CardanoPeerConnect { private selectedAid: string; @@ -25,7 +25,7 @@ class IdentityWalletConnect extends CardanoPeerConnect { identifier: string, payload: string ) => Promise; - + disable: () => void; constructor( walletInfo: IWalletInfo, seed: string | null, @@ -38,7 +38,7 @@ class IdentityWalletConnect extends CardanoPeerConnect { seed: seed, announce: announce, discoverySeed: discoverySeed, - logLevel: "info", + logLevel: "debug", }); this.selectedAid = selectedAid; this.eventEmitter = eventService; @@ -91,6 +91,11 @@ class IdentityWalletConnect extends CardanoPeerConnect { return { error: TxSignError.UserDeclined }; } }; + + this.disable = (): void => { + PeerConnection.peerConnection.disconnectDApp(null, false); + }; + } protected getNetworkId(): Promise { @@ -134,6 +139,7 @@ class IdentityWalletConnect extends CardanoPeerConnect { protected submitTx(tx: string): Promise { throw new Error("Method not implemented."); } + } export { IdentityWalletConnect }; diff --git a/src/core/cardano/walletConnect/peerConnection.ts b/src/core/cardano/walletConnect/peerConnection.ts index 34e2665953..d89ebce97f 100644 --- a/src/core/cardano/walletConnect/peerConnection.ts +++ b/src/core/cardano/walletConnect/peerConnection.ts @@ -7,10 +7,10 @@ import {KeyStoreKeys, SecureStorage} from "../../storage"; import { CoreEventEmitter } from "../../agent/event"; import { ExperimentalAPIFunctions, - PeerConnectSigningEvent, PeerConnectedEvent, PeerConnectionBrokenEvent, PeerConnectionEventTypes, + PeerConnectSigningEvent, PeerDisconnectedEvent, } from "./peerConnection.types"; import { Agent } from "../../agent/agent"; @@ -28,9 +28,13 @@ class PeerConnection { requestAutoconnect: true, }; + // Trackers repositories + private static trackersFileUrls: string[] = [ + "https://raw.githubusercontent.com/cardano-foundation/cf-identity-wallet/refs/heads/main/trackers.txt" + ]; + private announce = [ - "wss://tracker.webtorrent.dev:443/announce", - "wss://dev.btt.cf-identity-wallet.metadata.dev.cf-deployments.org" + "wss://tracker.webtorrent.dev:443/announce" ]; private identityWalletConnect: IdentityWalletConnect | undefined; @@ -78,6 +82,8 @@ class PeerConnection { async start(selectedAid: string) { + + const meerkatSeed = await SecureStorage.get( KeyStoreKeys.MEERKAT_SEED ); @@ -88,6 +94,9 @@ class PeerConnection { ) { this.disconnectDApp(this.connectedDAppAddress); } + + this.announce = await this.getTrackersFromRemoteFiles(); + this.identityWalletConnect = new IdentityWalletConnect( this.walletInfo, meerkatSeed, @@ -95,6 +104,7 @@ class PeerConnection { selectedAid, this.eventEmitter ); + this.identityWalletConnect.setOnConnect( async (connectMessage: IConnectMessage) => { if (!connectMessage.error) { @@ -146,6 +156,7 @@ class PeerConnection { new ExperimentalContainer({ getKeriIdentifier: this.identityWalletConnect.getKeriIdentifier, signKeri: this.identityWalletConnect.signKeri, + disable: this.identityWalletConnect.disable }) ); } @@ -162,7 +173,7 @@ class PeerConnection { error.message === PeerConnectionStorage.PEER_CONNECTION_METADATA_RECORD_MISSING ) { - return undefined; + return Promise.resolve(undefined); } else { throw error; } @@ -183,11 +194,11 @@ class PeerConnection { SecureStorage.set(KeyStoreKeys.MEERKAT_SEED, seed); } - disconnectDApp(dAppIdentifier: string, isBroken?: boolean) { + disconnectDApp(dAppIdentifier?: string | null, isBroken?: boolean) { if (this.identityWalletConnect === undefined) { throw new Error(PeerConnection.PEER_CONNECTION_START_PENDING); } - this.identityWalletConnect.disconnect(dAppIdentifier); + this.identityWalletConnect.disconnect(dAppIdentifier ? dAppIdentifier : this.connectedDAppAddress); if (isBroken) { this.eventEmitter.emit({ @@ -207,6 +218,41 @@ class PeerConnection { } return this.identityWalletConnect.getKeriIdentifier(); } + + private async getTrackersFromRemoteFiles(): Promise { + const validUrlRegex = /^(wss|https|udp):\/\/[^/\s?#]+(:\d+)?(\/|$)/; + + for (const fileUrl of PeerConnection.trackersFileUrls) { + try { + const response = await fetch(fileUrl); + if (!response.ok) { + // eslint-disable-next-line no-console + console.warn(`Error loading file ${fileUrl}: Status code ${response.status}`); + continue; + } + + const text = await response.text(); + const trackers = text + .split("\n") + .map(line => line.trim()) + .filter(line => line && !line.startsWith("#")) + .filter(line => validUrlRegex.test(line)); + + if (trackers.length > 0) { + return trackers; + } else { + // eslint-disable-next-line no-console + console.warn(`File ${fileUrl} loaded successfully but contains no valid trackers.`); + } + } catch (error) { + // eslint-disable-next-line no-console + console.error(`Error processing file ${fileUrl}:`, error); + } + } + + return this.announce; // Fallback + } + } export { PeerConnection }; diff --git a/src/core/cardano/walletConnect/peerConnection.types.ts b/src/core/cardano/walletConnect/peerConnection.types.ts index 7a03bdfc9d..0f87593c63 100644 --- a/src/core/cardano/walletConnect/peerConnection.types.ts +++ b/src/core/cardano/walletConnect/peerConnection.types.ts @@ -9,6 +9,7 @@ interface ExperimentalAPIFunctions { identifier: string, payload: string ) => Promise; + disable: () => void; } enum PeerConnectionEventTypes { diff --git a/src/ui/App.tsx b/src/ui/App.tsx index bf154496ee..107bb7a50c 100644 --- a/src/ui/App.tsx +++ b/src/ui/App.tsx @@ -10,6 +10,7 @@ import { } from "@ionic/react"; import { IonReactRouter } from "@ionic/react-router"; import { StrictMode, useEffect, useState } from "react"; +import EventEmitter from "events"; import { Routes } from "../routes"; import { useAppDispatch, useAppSelector } from "../store/hooks"; import { @@ -35,6 +36,7 @@ import { SecureStorage } from "../core/storage"; import { compareVersion } from "./utils/version"; import { ANDROID_MIN_VERSION, IOS_MIN_VERSION, WEBVIEW_MIN_VERSION } from "./globals/constants"; + setupIonicReact(); const App = () => { @@ -49,14 +51,21 @@ const App = () => { const handleUnknownPromiseError = (event: PromiseRejectionEvent) => { // prevent log error to console. event.preventDefault(); - event.promise.catch((e) => showError("Unhandled error", e, dispatch)); + const reasonMessage = event.reason?.message || JSON.stringify(event.reason); + if (reasonMessage.includes("No torrent with id")) return; // TODO: refactor error + + event.promise.catch((e) => { + showError("Unhandled error", e, dispatch) + }); } window.addEventListener("unhandledrejection", handleUnknownPromiseError); const handleUnknownError = (event: ErrorEvent) => { event.preventDefault(); - showError("Unhandled error", event.error, dispatch); + /* eslint-disable no-console */ + console.error("Unhandled error222", event.error); + // showError("Unhandled error", event.error, dispatch); } window.addEventListener("error", handleUnknownError) diff --git a/src/ui/pages/Menu/components/ConfirmConnectModal/ConfirmConnectModal.tsx b/src/ui/pages/Menu/components/ConfirmConnectModal/ConfirmConnectModal.tsx index e4c009f16c..10e76ce9dc 100644 --- a/src/ui/pages/Menu/components/ConfirmConnectModal/ConfirmConnectModal.tsx +++ b/src/ui/pages/Menu/components/ConfirmConnectModal/ConfirmConnectModal.tsx @@ -22,6 +22,7 @@ const ConfirmConnectModal = ({ isConnectModal, closeModal, onConfirm, + onReconnect, connectionData, onDeleteConnection, }: ConfirmConnectModalProps) => { @@ -77,6 +78,12 @@ const ConfirmConnectModal = ({ onConfirm(); }; + + const reconnect = () => { + closeModal(); + onReconnect && onReconnect(); + }; + const confirmClass = combineClassNames("confirm-connect-submit", { "primary-button": isConnectModal, "secondary-button": !isConnectModal, @@ -150,6 +157,14 @@ const ConfirmConnectModal = ({ > {buttonTitle} + + Reconnect + ); }; diff --git a/src/ui/pages/Menu/components/ConfirmConnectModal/ConfirmConnectModal.types.ts b/src/ui/pages/Menu/components/ConfirmConnectModal/ConfirmConnectModal.types.ts index f856c1662a..d17da60476 100644 --- a/src/ui/pages/Menu/components/ConfirmConnectModal/ConfirmConnectModal.types.ts +++ b/src/ui/pages/Menu/components/ConfirmConnectModal/ConfirmConnectModal.types.ts @@ -4,6 +4,7 @@ interface ConfirmConnectModalProps { openModal: boolean; closeModal: () => void; onConfirm: () => void; + onReconnect?: () => void; onDeleteConnection: (data: ConnectionData) => void; isConnectModal: boolean; connectionData?: ConnectionData; diff --git a/src/ui/pages/Menu/components/ConnectWallet/ConnectWallet.tsx b/src/ui/pages/Menu/components/ConnectWallet/ConnectWallet.tsx index f4dc8a150f..ab5e81a4e5 100644 --- a/src/ui/pages/Menu/components/ConnectWallet/ConnectWallet.tsx +++ b/src/ui/pages/Menu/components/ConnectWallet/ConnectWallet.tsx @@ -153,8 +153,13 @@ const ConnectWallet = forwardRef( const disconnectWallet = () => { if (!connectedWallet) return; PeerConnection.peerConnection.disconnectDApp(connectedWallet?.id); + }; + const reconnect = async () => { + if (!connectedWallet) return; + await PeerConnection.peerConnection.connectWithDApp(connectedWallet?.id); + } const toggleConnected = () => { if (defaultIdentifierCache.length === 0) { setOpenIdentifierMissingAlert(true); @@ -337,6 +342,7 @@ const ConnectWallet = forwardRef( openModal={openConfirmConnectModal} closeModal={() => setOpenConfirmConnectModal(false)} onConfirm={toggleConnected} + onReconnect={reconnect} connectionData={actionInfo.data} onDeleteConnection={handleOpenDeleteAlert} /> diff --git a/trackers.txt b/trackers.txt new file mode 100644 index 0000000000..d31a297a10 --- /dev/null +++ b/trackers.txt @@ -0,0 +1,8 @@ +wss://tracker.webtorrent.dev:443/announce +wss://dev.btt.cf-identity-wallet.metadata.dev.cf-deployments.org + +# Trackers lists +# https://raw.githubusercontent.com/ngosang/trackerslist/refs/heads/master/trackers_all_ws.txt +# https://raw.githubusercontent.com/ngosang/trackerslist/refs/heads/master/trackers_all_udp.txt +# https://raw.githubusercontent.com/ngosang/trackerslist/refs/heads/master/trackers_all_https.txt +# https://raw.githubusercontent.com/XIU2/TrackersListCollection/refs/heads/master/best.txt \ No newline at end of file