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
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}')
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
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)
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
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)))
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))
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))
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)
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)
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)
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)))
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
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
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
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
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()
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()
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)
async def analyzeFeed(self, ipfsop): statInfo = StatInfo(self.item.stat) if statInfo.valid and not statInfo.dataLargerThan(megabytes(4)): pass
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()