예제 #1
0
    async def resolve(self, ipfsop, noCache=False, timeout=10):
        """
        Resolve this object's path to a CID
        """

        if self.resolvedCid and noCache is False:
            # Return cached value
            return self.resolvedCid

        haveResolve = await ipfsop.hasCommand('resolve')

        try:
            if haveResolve:
                # Use /api/vx/resolve as the preferred resolve strategy

                resolved = await ipfsop.resolve(self.objPath, timeout=timeout)
                if resolved and isIpfsPath(resolved):
                    resolved = stripIpfs(resolved)

                    if cidValid(resolved):
                        self._resolvedCid = resolved
                        return self.resolvedCid

            # Use object stat
            info = StatInfo(await ipfsop.objStat(self.objPath,
                                                 timeout=timeout))

            if info.valid and cidValid(info.cid):
                self._resolvedCid = info.cid
                return self.resolvedCid
        except aioipfs.APIError:
            log.debug('Error resolving {0}'.format(self.objPath))
            return None
예제 #2
0
    async def fetchAvatar(self, ipfsop):
        avatarServiceId = self.ipid.didUrl(path='/avatar')
        service = await self.ipid.searchServiceById(avatarServiceId)

        if service:
            avatarPath = IPFSPath(service.endpoint)

            if not avatarPath.valid:
                log.debug(f'Invalid avatar for peer {self.peerId}')

            self._avatarPath = avatarPath

            statInfo = StatInfo(
                await ipfsop.objStat(str(avatarPath),
                                     timeout=15)
            )

            if not statInfo.valid or statInfo.dataLargerThan(
                    kilobytes(768)):
                log.debug(f'Invalid avatar for peer {self.peerId}')
                return

            await ipfsop.ctx.pin(str(avatarPath), qname='ipid-avatar')

            log.debug(
                f'Getting avatar for peer {self.peerId} from {avatarPath}')

            image = await getImageFromIpfs(str(avatarPath))

            if image and not image.isNull():
                self._avatarImage = image
            else:
                log.debug(f'Could not fetch avatar for peer {self.peerId}')
예제 #3
0
    async def findIcon(self,
                       ipfsop,
                       ipfsPath,
                       rscStat,
                       mimeType,
                       maxIconSize=kilobytes(512)):
        icon = None
        statInfo = StatInfo(rscStat)

        if statInfo.valid and mimeType.isImage:
            if statInfo.dataSmallerThan(maxIconSize):
                await ipfsop.sleep()

                data = await ipfsop.catObject(str(ipfsPath), timeout=5)
                if data:
                    icon = getIconFromImageData(data)
            else:
                icon = getMimeIcon('image/x-generic')
        elif mimeType.isDir:
            favIcon = await getFavIconFromDir(ipfsop, ipfsPath)
            if favIcon:
                icon = favIcon
            else:
                icon = getMimeIcon('inode/directory')
        else:
            await ipfsop.sleep()
            icon = getIconFromMimeType(mimeType)

        if icon is None:
            icon = getIcon('unknown-file.png')

        return icon
예제 #4
0
    async def sendCyberHit(self, hit):
        hitHash = hit.get('hash')

        ipfsPath = IPFSPath(hitHash)
        if not ipfsPath.valid:
            return

        mType, stat = await self.app.rscAnalyzer(ipfsPath,
                                                 fetchExtraMetadata=True)

        if not mType or not stat:
            return

        sInfo = StatInfo(stat)

        pHit = {
            'hash': hitHash,
            'path': str(ipfsPath),
            'cyberlink': hit['cyberlink'],
            'url': ipfsPath.ipfsUrl,
            'mimetype': str(mType),
            'title': hitHash,
            'size': sInfo.totalSize,
            'sizeformatted': sizeFormat(sInfo.totalSize),
            'description': None,
            'type': iUnknown(),
            'first-seen': iUnknown()
        }

        self.resultReady.emit('cyber', hitHash, QVariant(pHit))
        self.objectStatAvailable.emit(hitHash, stat)
예제 #5
0
    async def makePinRequest(self,
                             op,
                             title,
                             descr,
                             objects,
                             priority=0,
                             tags=None):
        async with self.profile.dagUser as dag:
            # objects needs to be a list of IPFS objects paths

            if not isinstance(objects, list):
                return False

            username = self.profile.userInfo.iphandle
            uid = str(uuid.uuid4())
            now = datetime.now(timezone.utc)

            objsReq = []

            for obj in objects:
                path = IPFSPath(obj)
                if not path.valid:
                    continue

                try:
                    mType, stat = await self._rscAnalyzer(path)
                except:
                    continue

                statInfo = StatInfo(stat)
                if not statInfo.valid:
                    continue

                objsReq.append({
                    'path': path.objPath,
                    'totalsize': statInfo.totalSize,
                    'content_type': str(mType) if mType else None
                })

            pinRequest = {
                'pinrequest': {
                    'body': None,
                    'title': title,
                    'description': descr,
                    'objects': objsReq,
                    'uuid': uid,
                    'tags': tags if tags else [],
                    'author': username,
                    'priority': priority,
                    'date_published': isoformat(now),
                    'version': 1
                }
            }

            dag.dagRoot[PINREQS_NODEKEY].append(pinRequest)

        await self.update()
        return True
예제 #6
0
    def onProgress(self, read):
        statInfo = StatInfo(self.stat)

        self.readBytes = read
        size = sizeFormat(statInfo.totalSize) if statInfo.valid else \
            iUnknown()

        self.setToolTip('{path} (size: {size}): downloaded {dl}'.format(
            path=self.path, size=size, dl=sizeFormat(self.readBytes)))
예제 #7
0
    async def registerHashmark(self,
                               ipfsop,
                               mark,
                               button=None,
                               maxIconSize=512 * 1024):
        """
        Register an object in the toolbar with an associated hashmark
        """

        await mark._fetch_all()

        ipfsPath = IPFSPath(mark.path)
        if not ipfsPath.valid:
            return

        result = await self.analyzer(ipfsPath)
        if result is None:
            return

        mimeType, rscStat = result

        mIcon = mark.icon.path if mark.icon else None
        icon = None

        if mIcon and IPFSPath(mIcon).valid:
            stat = await ipfsop.objStat(mIcon)

            statInfo = StatInfo(stat)

            # Check filesize from the stat on the object
            if statInfo.valid and statInfo.dataSmallerThan(maxIconSize):
                icon = await getIconFromIpfs(ipfsop, mIcon)

                if icon is None:
                    icon = getIcon('unknown-file.png')
                else:
                    if not await ipfsop.isPinned(mIcon):
                        log.debug('Pinning icon {0}'.format(mIcon))
                        await ipfsop.ctx.pin(mIcon)
        elif mimeType:
            icon = await self.findIcon(ipfsop, ipfsPath, rscStat, mimeType)
        else:
            icon = getIcon('unknown-file.png')

        if not button:
            button = HashmarkToolButton(mark, parent=self, icon=icon)
            action = self.addWidget(button)
            button.setToolTip(iHashmarkInfoToolTipShort(mark))
            button.clicked.connect(lambda: ensure(
                self.app.resourceOpener.open(str(ipfsPath), openingFrom='qa')))
            button.deleteRequest.connect(
                lambda: ensure(self.onDelete(button, action)))
        else:
            if icon:
                button.setIcon(icon)

            button.setToolTip(iHashmarkInfoToolTipShort(mark))
예제 #8
0
    async def showImage(self, ipfsop, imgPath, fromBlock=False, timeout=10):
        try:
            if fromBlock is True:
                imgData = await ipfsop.waitFor(
                    ipfsop.client.block.get(imgPath), timeout)
            else:
                imgData = await ipfsop.waitFor(ipfsop.catObject(imgPath),
                                               timeout)

            if not imgData:
                raise Exception('Failed to load image')

            mimeType, statInfo = await self.app.rscAnalyzer(IPFSPath(imgPath))

            if mimeType is None:
                raise Exception('Failed to load image')

            stat = StatInfo(statInfo)

            if mimeType.isAnimation:
                fp = self.app.tempDir.filePath(stat.cid)
                tmpFile = QFile(fp)

                if not tmpFile.exists() and tmpFile.open(QFile.ReadWrite):
                    tmpFile.write(imgData)
                    tmpFile.close()

                self.clip.stop()
                self.clip.setFileName(fp)
                self.labelImage.setMovie(self.clip)
                self.clip.frameChanged.connect(self.onMovieFrameChanged)
                self.clip.error.connect(self.onMovieError)
                self.clip.start()
                self.labelImage.adjustSize()
            else:
                img = QImage()
                img.loadFromData(imgData)
                self.image = img

                self.labelImage.setPixmap(QPixmap.fromImage(self.image))
                self.labelImage.adjustSize()
                self.resizePixmap()

                if self.qrDecoder:
                    # See if we have any QR codes in the image
                    urls = self.qrDecoder.decode(imgData)
                    if urls:
                        self.qrCodesPresent.emit(urls)

            self.labelImage.adjustSize()
            self.currentImgPath = IPFSPath(imgPath)
            self.imageLoaded.emit(self.currentImgPath, mimeType)

        except Exception:
            logUser.debug('Failed to load image: {path}'.format(path=imgPath))
            messageBox(iImageCannotLoad(imgPath))
예제 #9
0
    async def showFromPath(self, ipfsop, ipfsPath):
        if not await self.checkChanges():
            return

        if not ipfsPath.valid:
            return

        self.busy()

        try:
            dstdir = self.sessionNew()
            mimeType, stat = await self.app.rscAnalyzer(ipfsPath)

            if not stat:
                self.busy(False)
                messageBox('Object stat failed')
                return

            sInfo = StatInfo(stat)

            if not await ipfsop.client.get(
                ipfsPath.objPath,
                dstdir=dstdir
            ):
                raise Exception('Fetch failed')
        except Exception as err:
            self.busy(False)
            messageBox('Error fetching object: {}'.format(str(err)))
        else:
            rooted = os.path.join(dstdir, ipfsPath.basename)

            if os.path.isdir(rooted):
                path = rooted
            elif os.path.isfile(rooted):
                path = dstdir
            else:
                path = dstdir

            self.checkoutPath = path
            self.sessionViewUpdate(self.checkoutPath)

            for file in os.listdir(self.checkoutPath):
                await asyncio.sleep(0)

                fp = os.path.join(self.checkoutPath, file)
                mtype = await detectMimeTypeFromFile(fp)

                # Open first text file we find
                if mtype and (mtype.isText or mtype.isHtml):
                    await self.openFileFromCheckout(file)
                    break

            self.fsViewButton.setChecked(True)
            self.rootMultihashChanged.emit(sInfo.cid)

        self.busy(False)
예제 #10
0
    async def listObject(self,
                         ipfsop,
                         objPath,
                         parentItem,
                         autoexpand=False,
                         timeout=60 * 10):
        """ Lists contents of IPFS object referenced by objPath,
            and change the tree's model afterwards.

            We first try with resolve-type set to true, and if that gets a
            timeout do the same call but without resolving nodes types
        """

        self.statusLoading(True)

        try:
            self.setInfo(iLoading())

            await self.list(ipfsop,
                            objPath,
                            parentItem=parentItem,
                            autoexpand=autoexpand,
                            resolve_type=True)
        except asyncio.TimeoutError:
            self.setInfo(iTimeoutTryNoResolve())

            try:
                await self.list(ipfsop,
                                objPath,
                                parentItem=parentItem,
                                autoexpand=autoexpand,
                                resolve_type=False)
            except asyncio.TimeoutError:
                # That's a dead end .. bury that hash please ..
                self.setInfo(iTimeoutInvalidHash())
                return
        except aioipfs.APIError as err:
            self.setInfo(iIpfsError(err.message))
        except UnixFSTimeoutError:
            self.setInfo(iTimeoutInvalidHash())
            self.buttonRetry.show()
        except Exception as e:
            self.setInfo(iGeneralError(str(e)))
        else:
            rStat = await ipfsop.objStat(objPath)
            statInfo = StatInfo(rStat)

            if statInfo.valid and self.cid:
                self.setInfo(
                    iCIDInfo(self.cid.version, statInfo.numLinks,
                             sizeFormat(statInfo.totalSize)))

        self.statusLoading(False)
예제 #11
0
    async def fetchMetadata(self, path, stat):
        sInfo = StatInfo(stat)

        cidobj = getCID(sInfo.cid)
        cid = cidDowngrade(cidobj)

        if not cid:
            return

        metadata = await objectMetadata(str(cid))

        if metadata:
            await self.app.multihashDb.store(path, objmetadata=metadata)
예제 #12
0
    async def listMultihash(self,
                            ipfsop,
                            objPath,
                            parentItem,
                            autoexpand=False):
        """ Lists contents of IPFS object referenced by objPath,
            and change the tree's model afterwards.

            We first try with resolve-type set to true, and if that gets a
            timeout do the same call but without resolving nodes types
        """

        try:
            self.setInfo(iLoading())
            await self.timedList(ipfsop, objPath, parentItem, autoexpand, 25,
                                 True)
        except asyncio.TimeoutError:
            self.setInfo(iTimeoutTryNoResolve())

            try:
                await self.timedList(ipfsop, objPath, parentItem, autoexpand,
                                     15, False)
            except asyncio.TimeoutError:
                # That's a dead end .. bury that hash please ..
                self.setInfo(iTimeoutInvalidHash())
                return

        except aioipfs.APIError:
            self.setInfo(iErrNoCx())
            return

        self.tree.setModel(self.model)
        self.tree.header().setSectionResizeMode(self.model.COL_NAME,
                                                QHeaderView.ResizeToContents)
        self.tree.header().setSectionResizeMode(self.model.COL_MIME,
                                                QHeaderView.ResizeToContents)
        self.tree.sortByColumn(self.model.COL_NAME, Qt.AscendingOrder)

        if self.app.settingsMgr.hideHashes or self.hideHashes:
            self.tree.hideColumn(self.model.COL_HASH)

        rStat = await ipfsop.objStat(objPath)
        statInfo = StatInfo(rStat)

        if statInfo.valid and self.cid:
            self.setInfo(
                iCIDInfo(self.cid.version, statInfo.numLinks,
                         sizeFormat(statInfo.totalSize)))
예제 #13
0
async def getIconFromIpfs(ipfsop,
                          ipfsPath,
                          scaleWidth=None,
                          sizeMax=kilobytes(256),
                          timeout=10):
    """
    We cache the icons that we got out of the IPFS repo by their path
    Max icons cached is set by 'ipfsIconsCacheMax' in the app object
    """
    app = QApplication.instance()
    iconsCache = app.ipfsIconsCache

    if ipfsPath in iconsCache:
        # Already cached
        return iconsCache[ipfsPath]

    if len(iconsCache) >= app.ipfsIconsCacheMax:
        # FIFO 1/8
        for icount in range(0, int(app.ipfsIconsCacheMax / 8)):
            out = list(iconsCache.keys())[0]
            del iconsCache[out]

    try:
        mimeType, stat = await app.rscAnalyzer(ipfsPath)
        if not mimeType or not stat:
            return None

        statInfo = StatInfo(stat)

        if not statInfo.valid or statInfo.dataLargerThan(sizeMax):
            return None
        elif not mimeType.isImage:
            return None

        imgData = await ipfsop.waitFor(ipfsop.client.cat(ipfsPath), timeout)

        if not imgData:
            return None

        icon = getIconFromImageData(imgData, scaleWidth=scaleWidth)
        if icon:
            iconsCache[ipfsPath] = icon
            return icon
    except BaseException:
        return None
예제 #14
0
 def tooltipMessage(self):
     statInfo = StatInfo(self.item.stat)
     message = '{path} (type: {mimetype})'.format(
         path=self.item.fullPath,
         mimetype=str(self.item.mimeType) if self.item.mimeType else
         iUnknown()
     )
     if statInfo.valid:
         if self.item.mimeType and self.item.mimeType.isDir:
             message += '\n\nTotal size: {total}, links: {links}'.format(
                 total=sizeFormat(statInfo.totalSize),
                 links=statInfo.numLinks
             )
         else:
             message += '\n\nTotal size: {total}'.format(
                 total=sizeFormat(statInfo.totalSize)
             )
     else:
         message += '\n\nNo information on object'
     return message
예제 #15
0
    async def analyzeImage(self, ipfsop):
        statInfo = StatInfo(self.item.stat)

        if statInfo.valid:
            size = statInfo.dataSize

            if isinstance(size, int):
                # don't scan anything larger than 4Mb
                if statInfo.dataLargerThan(megabytes(4)):
                    log.debug('{path}: Image too large, not scanning')
                    return
        else:
            # Don't trust this one
            log.debug('No object info for image, bailing out')
            return

        try:
            data = await ipfsop.catObject(self.item.path)

            if data is None:
                return

            icon = getIconFromImageData(data)
            if icon:
                self.updateIcon(icon)

            # Decode the QR codes in the image if there's any
            qrDecoder = IPFSQrDecoder()
            if not qrDecoder:
                return

            urls = qrDecoder.decode(data)
            if isinstance(urls, list):
                # Display the QR codes in a separate menu
                menu = qrCodesMenuBuilder(urls, self.app.resourceOpener,
                                          parent=self)
                self.menu.addSeparator()
                self.menu.addMenu(menu)

        except aioipfs.APIError:
            pass
예제 #16
0
    async def update(self, ipfsop):
        try:
            oController = ObjectActionsWidget(self, self.objdescr)
            oController.fLayout()
            self.treeWidget().setItemWidget(
                self, self.COL_ACTIONS, oController)

            sInfo = StatInfo(self.objdescr['stat'])

            if sInfo.valid:
                self.fileDetails(sizeFormat(sInfo.totalSize))
                self.setToolTip(self.COL_NAME, sInfo.cid)
            else:
                self.fileDetails('Unknown')

            mType = self.objdescr.get('mimetype')
            if validMimeType(mType):
                mIcon = getMimeIcon(mType)
                if mIcon:
                    self.setIcon(self.COL_NAME, mIcon)

            whoHasC = len(
                await ipfsop.whoProvides(
                    self.objdescr['path'],
                    numproviders=500,
                    timeout=15
                )
            )

            if whoHasC == 0:
                self.status(iUnavailShortUpper())
            elif whoHasC > 0:
                self.status(iProvidedByPeersShort(whoHasC))
        except asyncio.CancelledError:
            pass
        except Exception:
            pass
예제 #17
0
    async def getResource(self, ipfsop, rPath, dest, rStat):
        """
        Get the resource referenced by rPath to directory dest
        """

        statInfo = StatInfo(rStat)
        if not statInfo.valid:
            return

        self.getProgress.show()

        async def onGetProgress(ref, bytesRead, arg):
            per = int((bytesRead / statInfo.totalSize) * 100)
            self.getLabel.setText('Downloaded: {0}'.format(
                sizeFormat(bytesRead)))
            self.getProgress.setValue(per)

        await ipfsop.client.get(rPath,
                                dstdir=dest,
                                progress_callback=onGetProgress,
                                chunk_size=524288)

        self.getLabel.setText('Download finished')
        self.getProgress.hide()
예제 #18
0
    async def registerFromIdent(self, ipfsop, sender, iMsg):
        profile = ipfsop.ctx.currentProfile

        log.debug(f'registerFromIdent ({iMsg.peer}): '
                  f'DID: {iMsg.personDid}, handle: {iMsg.iphandle}')

        try:
            inGraph = await profile.dagNetwork.byDid(iMsg.personDid)
        except Exception:
            # network dag not ready ..
            log.debug(f'registerFromIdent {iMsg.personDid}: '
                      'network DAG not loaded yet ?')
            return

        if not inGraph:
            if isinstance(iMsg, PeerIdentMessageV4) and \
                    sender != ipfsop.ctx.node.id:
                pubKeyPem = await ipfsop.rsaPubKeyCheckImport(
                    iMsg.defaultRsaPubKeyCid)

                if not pubKeyPem:
                    log.debug(
                        f'Invalid RSA pub key .. {iMsg.defaultRsaPubKeyCid}')
                    return

                sigBlob = await ipfsop.catObject(iMsg.pssSigCurDid)
                if sigBlob is None:
                    log.debug(
                        f'Cannot get pss SIG {iMsg.pssSigCurDid}')
                    return

                if not await ipfsop.ctx.rsaExec.pssVerif(
                    iMsg.personDid.encode(),
                    sigBlob,
                    pubKeyPem
                ):
                    log.debug(f'Invalid PSS sig for peer {sender}')
                    return
                else:
                    log.debug(f'Valid PSS sig for {sender} !')

            peerValidated = False
            personDid = iMsg.personDid

            if not ipidFormatValid(personDid):
                log.debug('Invalid DID: {}'.format(personDid))
                return

            inProgress = self._didAuthInp.get(personDid, False)

            if inProgress is True:
                log.debug(f'registerFromIdent {iMsg.personDid}: '
                          f'authentication in progress')
                return

            self._didAuthInp[personDid] = True

            try:
                mType, stat = await self.app.rscAnalyzer(iMsg.iphandleqrpngcid)
            except Exception:
                log.debug('Cannot stat QR: {}'.format(iMsg.iphandleqrpngcid))
                self._didAuthInp[personDid] = False
                return
            else:
                statInfo = StatInfo(stat)

                if not statInfo.valid or statInfo.dataLargerThan(
                        kilobytes(512)) or not mType or not mType.isImage:
                    log.debug('Invalid stat for QR: {}'.format(
                        iMsg.iphandleqrpngcid))
                    self._didAuthInp[personDid] = False
                    return

                if not await self.validateQr(
                        iMsg.iphandleqrpngcid, iMsg) is True:
                    log.debug('Invalid QR: {}'.format(iMsg.iphandleqrpngcid))
                    peerValidated = False
                    self._didAuthInp[personDid] = False
                    return
                else:
                    log.debug('Ident QR {qr} for {peer} seems valid'.format(
                        qr=iMsg.iphandleqrpngcid, peer=iMsg.peer))
                    peerValidated = True

                await ipfsop.ctx.pin(iMsg.iphandleqrpngcid)

            # Load the IPID

            loadAttempts = cGet('peers.didLoadAttempts')

            for attempt in range(0, loadAttempts):
                ipid = await self.app.ipidManager.load(
                    personDid,
                    localIdentifier=(iMsg.peer == ipfsop.ctx.node.id)
                )

                if ipid:
                    break

            if not ipid:
                log.debug(f'Cannot load DID: {personDid}')
                self._didAuthInp[personDid] = False
                return

            async with self.lock.writer_lock:
                piCtx = self.getByHandle(iMsg.iphandle)

                if not piCtx:
                    log.debug(f'Creating new PeerIdentityCtx for '
                              f'{iMsg.iphandle} ({personDid})')

                    piCtx = PeerIdentityCtx(
                        self.ctx, iMsg.peer, iMsg.iphandle,
                        ipid,
                        validated=peerValidated
                    )

                    ipid.sChanged.connectTo(partialEnsure(
                        self.onPeerDidModified, piCtx))
                    piCtx.sStatusChanged.connectTo(partialEnsure(
                        self.peerModified.emit, piCtx))

                piCtx.ident = iMsg

                if not piCtx.authFailedRecently:
                    ensure(self.didPerformAuth(piCtx, iMsg))

                self._byHandle[iMsg.iphandle] = piCtx
        else:
            # This peer is already registered in the network graph
            # What we ought to do here is just to refresh the DID document

            async with self.lock.writer_lock:
                piCtx = self.getByHandle(iMsg.iphandle)

                if piCtx:
                    self._byPeerId[piCtx.peerId] = piCtx

                    piCtx.ident = iMsg
                    await piCtx.ipid.refresh()

                    await self.peerModified.emit(piCtx)

        await self.changed.emit()
예제 #19
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)
예제 #20
0
    async def analyzeFeed(self, ipfsop):
        statInfo = StatInfo(self.item.stat)

        if statInfo.valid and not statInfo.dataLargerThan(megabytes(4)):
            pass
예제 #21
0
    async def registerFromIdent(self, op, iMsg):
        # iMsg is a PeerIdentMessage

        if iMsg.peer not in self.byPeerId:
            peerValidated = False

            now = int(time.time())
            avgPing = await op.waitFor(op.pingAvg(iMsg.peer, count=2), 5)

            personDid = iMsg.personDid

            if not ipidFormatValid(personDid):
                log.debug('Invalid DID: {}'.format(personDid))
                return

            try:
                mType, stat = await self.app.rscAnalyzer(iMsg.iphandleqrpngcid)
            except Exception:
                log.debug('Invalid QR: {}'.format(iMsg.iphandleqrpngcid))
            else:
                statInfo = StatInfo(stat)

                if not statInfo.valid or statInfo.dataLargerThan(
                        kilobytes(512)) or not mType or not mType.isImage:
                    log.debug('Invalid stat for QR: {}'.format(
                        iMsg.iphandleqrpngcid))
                    return

                if not await self.validateQr(
                        iMsg.iphandleqrpngcid, iMsg) is True:
                    log.debug('Invalid QR: {}'.format(iMsg.iphandleqrpngcid))
                    peerValidated = False
                else:
                    log.debug('Ident QR {qr} for {peer} seems valid'.format(
                        qr=iMsg.iphandleqrpngcid, peer=iMsg.peer))
                    peerValidated = True

                ensure(op.ctx.pin(iMsg.iphandleqrpngcid))

            # Load the IPID
            ipid = await self.app.ipidManager.load(
                personDid,
                initialCid=iMsg.personDidCurCid,
                track=True
            )

            if not ipid:
                log.debug('Cannot load DID: {}'.format(personDid))
                return

            async with self.lock:
                pCtx = PeerCtx(self.ctx, iMsg.peer, iMsg, ipid,
                               pingavg=avgPing if avgPing else 0,
                               pinglast=now if avgPing else 0,
                               validated=peerValidated
                               )
                ipid.sChanged.connectTo(partialEnsure(
                    self.onPeerDidModified, pCtx))
                pCtx.sInactive.connectTo(self.onUnresponsivePeer)

                ensure(self.didPerformAuth(pCtx))

                self._byPeerId[iMsg.peer] = pCtx
                ensureLater(60, pCtx.watch)

            await self.peerAdded.emit(iMsg.peer)
        else:
            # This peer is already registered
            # What we ought to do here is just to refresh the DID document

            async with self.lock:
                pCtx = self.getByPeerId(iMsg.peer)
                if pCtx:
                    log.debug('Updating ident for peer {}'.format(iMsg.peer))
                    pCtx.ident = iMsg

                    log.debug('Refreshing DID: {}'.format(pCtx.ipid))
                    await pCtx.ipid.refresh()

                    await self.peerModified.emit(iMsg.peer)

        await self.changed.emit()