Example #1
0
    async def handleRequest(self, request):
        rUrl = request.requestUrl()
        if not rUrl.isValid():
            return self.urlInvalid(request)

        domain = rUrl.host()
        uPath = rUrl.path()

        if not domain or len(domain) > 512 or not domainValid(domain):
            log.info('EthDNS: invalid domain request')
            return self.urlInvalid(request)

        pathRaw = await self.ethResolver.resolveEnsDomain(domain)
        path = IPFSPath(pathRaw, autoCidConv=True)

        if path and path.valid:
            await ensDomainResolved.emit(domain, path)

            sPath = path.child(uPath) if uPath else path
            log.debug('EthDNS: {domain} resolved to {res}'.format(
                domain=domain, res=sPath.ipfsUrl))
            return request.redirect(QUrl(sPath.dwebUrl))
        else:
            log.info('EthDNS: {domain} resolve failed'.format(domain=domain))
            return self.urlNotFound(request)
Example #2
0
    async def startVideoCall(self, ipfsop, rvTopic):
        rootPath = IPFSPath(ipfsop.ctx.resources['app-videocall']['Hash'])
        offerPath = rootPath.child('offer.html')
        offerPath.fragment = rvTopic

        tab = self.app.mainWindow.addBrowserTab()
        tab.browseFsPath(offerPath)
Example #3
0
    async def dagCompact(self, ipfsPath: IPFSPath, context=None):
        """
        Compact a DAG
        """
        try:
            # Note: we still do the schemas inlining (when
            # a @context is referenced with IPLD) to
            # support DAGs which weren't upgraded yet
            dag = await self.operator.ldInline(
                await self.operator.dagGet(str(ipfsPath))
            )
            assert dag is not None

            if not context:
                # Get the @context we'll compact with
                context = await self.operator.dagGet(
                    str(ipfsPath.child('@context'))
                )

            compacted = await jsonld.compact(
                dag, context,
                {
                    'base': gLdBaseUri,
                    'documentLoader': self.ldLoader,
                    'compactArrays': True
                }
            )
        except Exception as err:
            self.operator.debug(f'Error expanding : {err}')
            raise err
        except aioipfs.APIError as err:
            self.operator.debug(f'IPFS error expanding : {err.message}')
            raise err
        else:
            return compacted
Example #4
0
    async def urlProxiedPath(self, rUrl):
        domain = rUrl.host()
        uPath = rUrl.path()

        if not domain or len(domain) > 512 or not domainValid(domain):
            return None

        pathRaw = await self.ethResolver.resolveEnsDomain(domain)
        path = IPFSPath(pathRaw, autoCidConv=True)

        if path and path.valid:
            return path.child(uPath) if uPath else path
Example #5
0
    def browseManualPage(self, pagePath, fragment=None):
        manual = self.registry.get(self.defaultManualLang)
        if not manual:
            return False

        manualPath = IPFSPath(manual['Hash'])
        if not manualPath.valid:
            return False

        ipfsPath = manualPath.child(pagePath)
        ipfsPath.fragment = fragment

        ensure(self.app.resourceOpener.open(ipfsPath))
Example #6
0
    async def renderDirectory(self, request, ipfsop, path):
        ipfsPath = IPFSPath(path)
        indexPath = ipfsPath.child('index.html')

        try:
            data = await ipfsop.catObject(str(indexPath))
        except aioipfs.APIError as exc:
            dec = APIErrorDecoder(exc)

            if dec.errNoSuchLink():
                return await self.directoryListing(request, ipfsop, path)

            return self.urlInvalid(request)
        else:
            return data
Example #7
0
    async def open(self,
                   ipfsop,
                   pathRef,
                   mimeType=None,
                   openingFrom=None,
                   pyramidOrigin=None,
                   minWebProfile='ipfs',
                   schemePreferred=None,
                   tryDecrypt=False,
                   fromEncrypted=False,
                   editObject=False,
                   pin=False,
                   burnAfterReading=False,
                   useWorkspace=None):
        """
        Open the resource referenced by rscPath according
        to its MIME type

        :param pathRef: IPFS object's path (can be str or IPFSPath)
        :param openingFrom str: UI component making the open request
        :param minWebProfile str: Minimum Web profile to use
        :param tryDecrypt bool: Try to decrypt the object or not
        :param editObject bool: Set Text Editor in edit mode for text files
        :param MIMEType mimeType: MIME type
        """

        ipfsPath = None
        statInfo = None

        if isinstance(pathRef, IPFSPath):
            ipfsPath = pathRef
        elif isinstance(pathRef, str):
            url = QUrl(pathRef)

            if isEnsUrl(url):
                return self.openEnsUrl(url, pin=pin)
            if isUrlSupported(url):
                return self.openUrl(url)

            ipfsPath = IPFSPath(pathRef, autoCidConv=True)
        else:
            raise ValueError(f'Invalid input value: {pathRef}')

        if not ipfsPath.valid:
            return False

        rscPath = ipfsPath.objPath

        if self.app.mainWindow.pinAllGlobalChecked:
            ensure(
                ipfsop.ctx.pinner.queue(rscPath, False, None, qname='default'))

        rscShortName = ipfsPath.shortRepr()

        if ipfsPath.isIpfs:
            # Try to reuse metadata from the multihash store
            rscMeta = await self.app.multihashDb.get(rscPath)
            if rscMeta:
                cachedMime = rscMeta.get('mimetype')
                cachedStat = rscMeta.get('stat')
                if cachedMime:
                    mimeType = MIMEType(cachedMime)
                if cachedStat:
                    statInfo = StatInfo(cachedStat)

        wsSwitch = True
        mtConfig = self.cObjectOpener.mimeTypes.default

        if mimeType is None:
            ltBefore = loopTime()
            mimeType = await detectMimeType(rscPath)
            spent = loopTime() - ltBefore

            if spent > mtConfig.slowObjectTimer:
                # We won't switch workspaces
                wsSwitch = False

        if mimeType and mimeType.valid:
            logUser.info('{path} ({type}): opening'.format(path=rscPath,
                                                           type=str(mimeType)))
        else:
            logUser.info(iResourceCannotOpen(rscPath))
            return

        hashmark = await hashmarksByPath(rscPath)
        if hashmark and not useWorkspace:
            await hashmark._fetch_all()
            useWorkspace = self.app.mainWindow.stack.wsHashmarkTagRulesRun(
                hashmark)

        if mimeType == mimeTypeDagUnknown:
            indexPath = ipfsPath.child('index.html')
            stat = await ipfsop.objStat(indexPath.objPath, timeout=8)

            if stat:
                # Browse the index
                return self.app.mainWindow.addBrowserTab(
                    minProfile=minWebProfile, pinBrowsed=pin).browseFsPath(
                        indexPath, schemePreferred=schemePreferred)

            # Otherwise view the DAG
            view = DAGViewer(rscPath, self.app.mainWindow)
            self.app.mainWindow.registerTab(view,
                                            iDagViewer(),
                                            current=True,
                                            icon=getIcon('ipld.png'),
                                            tooltip=rscPath)
            return

        if mimeType.type == 'application/octet-stream' and not fromEncrypted:
            # Try to decode it with our key if it's a small file
            if statInfo is None:
                statInfo = StatInfo(await ipfsop.objStat(rscPath, timeout=5))

            profile = ipfsop.ctx.currentProfile
            if profile and statInfo.valid and \
                    (statInfo.dataSmallerThan(megabytes(8)) or tryDecrypt):
                data = await ipfsop.catObject(ipfsPath.objPath, timeout=30)
                if not data:
                    # XXX
                    return

                decrypted = await profile.rsaAgent.decrypt(data)

                if decrypted:
                    #
                    # "Good evening, 007"
                    #
                    # Create a short-lived IPFS offline file (not announced)
                    # with the decrypted content and open it
                    #

                    logUser.info('{path}: RSA OK'.format(path=rscPath))

                    # This one won't be announced or pinned
                    entry = await ipfsop.addBytes(decrypted,
                                                  offline=True,
                                                  pin=False)
                    if not entry:
                        logUser.info(
                            '{path}: cannot import decrypted file'.format(
                                path=rscPath))
                        return

                    # Open the decrypted file
                    return ensure(
                        self.open(entry['Hash'],
                                  fromEncrypted=True,
                                  burnAfterReading=True))
                else:
                    logUser.debug(
                        '{path}: decryption impossible'.format(path=rscPath))

        if mimeType.isText or editObject:
            tab = TextEditorTab(parent=self.app.mainWindow,
                                editing=editObject,
                                pyramidOrigin=pyramidOrigin)
            tab.editor.display(ipfsPath)
            self.objectOpened.emit(ipfsPath)
            return self.app.mainWindow.registerTab(
                tab,
                rscShortName,
                icon=getMimeIcon('text/x-generic'),
                tooltip=rscPath,
                current=True,
                workspace=WS_EDIT)

        if mimeType.isImage or mimeType.isAnimation:
            tab = ImageViewerTab(self.app.mainWindow)
            ensure(tab.view.showImage(rscPath))
            self.objectOpened.emit(ipfsPath)

            return self.app.mainWindow.registerTab(
                tab,
                rscShortName,
                icon=getMimeIcon('image/x-generic'),
                tooltip=rscPath,
                current=True)

        if mimeType.isVideo or mimeType.isAudio:
            tab = self.app.mainWindow.getMediaPlayer()
            if tab:
                tab.playFromPath(rscPath)
            return

        if mimeType == 'application/pdf' and 0:  # not usable yet
            tab = WebTab(self.app.mainWindow)
            tab.attach(DWebView(page=PDFViewerPage(rscPath)))
            self.objectOpened.emit(ipfsPath)
            return self.app.mainWindow.registerTab(
                tab,
                rscShortName,
                icon=getMimeIcon('application/pdf'),
                tooltip=rscPath,
                current=True)

        if mimeType.isHtml:
            self.objectOpened.emit(ipfsPath)
            return self.app.mainWindow.addBrowserTab(
                minProfile=minWebProfile,
                pinBrowsed=pin,
                workspace=useWorkspace,
                wsSwitch=wsSwitch).browseFsPath(
                    ipfsPath, schemePreferred=schemePreferred)

        if mimeType.isDir:
            indexPath = ipfsPath.child('index.html')
            stat = await ipfsop.objStat(indexPath.objPath, timeout=8)

            if stat:
                self.objectOpened.emit(ipfsPath)
                return self.app.mainWindow.addBrowserTab(
                    minProfile=minWebProfile,
                    pinBrowsed=pin,
                    workspace=useWorkspace,
                    wsSwitch=wsSwitch).browseFsPath(
                        ipfsPath, schemePreferred=schemePreferred)
            else:
                return await self.app.mainWindow.exploreIpfsPath(ipfsPath)

        if mimeType.isBitTorrent:
            wStack = self.app.mainWindow.stack

            with wStack.workspaceCtx(WS_FILES, show=True) as ws:
                btClient = await ws.getTorrentClient()
                return await btClient.addTorrentFromIpfs(ipfsPath)

        if openingFrom in ['filemanager', 'qa', 'didlocal']:
            await self.needUserConfirm.emit(ipfsPath, mimeType, True)
        else:
            await self.needUserConfirm.emit(ipfsPath, mimeType, False)