def checkDigest(self, downloadRetriesLeft=3): CraftCore.log.debug("ArchiveSource.checkDigest called") filenames = self.localFileNames() if self.subinfo.hasTargetDigestUrls(): CraftCore.log.debug("check digests urls") if not CraftHash.checkFilesDigests(self.__downloadDir, filenames): CraftCore.log.error("invalid digest file") redownload = downloadRetriesLeft and CraftChoicePrompt.promptForChoice( "Do you want to delete the files and redownload them?", [("Yes", True), ("No", False)], default="Yes") if redownload: for filename in filenames: CraftCore.log.info( f"Deleting downloaded file: {filename}") utils.deleteFile( os.path.join(self.__downloadDir, filename)) for digestAlgorithm, digestFileEnding in CraftHash.HashAlgorithm.fileEndings( ).items(): digestFileName = filename + digestFileEnding if os.path.exists( os.path.join(self.__downloadDir, digestFileName)): CraftCore.log.info( f"Deleting downloaded file: {digestFileName}" ) utils.deleteFile( os.path.join(self.__downloadDir, digestFileName)) return self.fetch() and self.checkDigest( downloadRetriesLeft - 1) return False elif self.subinfo.hasTargetDigests(): CraftCore.log.debug("check digests") digests, algorithm = self.subinfo.targetDigest() if not CraftHash.checkFilesDigests(self.__downloadDir, filenames, digests, algorithm): CraftCore.log.error("invalid digest file") redownload = downloadRetriesLeft and CraftChoicePrompt.promptForChoice( "Do you want to delete the files and redownload them?", [("Yes", True), ("No", False)], default="Yes") if redownload: for filename in filenames: CraftCore.log.info( f"Deleting downloaded file: {filename}") utils.deleteFile( os.path.join(self.__downloadDir, filename)) return self.fetch() and self.checkDigest( downloadRetriesLeft - 1) return False else: CraftCore.log.debug("print source file digests") CraftHash.printFilesDigests( self.__downloadDir, filenames, self.subinfo.buildTarget, algorithm=CraftHash.HashAlgorithm.SHA256) return True
def __retry(self, downloadRetriesLeft : int, func, **kw): downloadRetriesLeft -= 1 if downloadRetriesLeft >= 0 and CraftChoicePrompt.promptForChoice("Do you want to delete the files and redownload them?", [("Yes", True), ("No", False)], default="Yes"): return func(downloadRetriesLeft=downloadRetriesLeft, **kw) return False
def __unlock(self): if self._useCertFile: password = secrets.token_urlsafe(16) if not utils.system(["security", "create-keychain", "-p", password, self.loginKeychain], stdout=subprocess.DEVNULL, secret=[password]): return False # FIXME: Retain original list: security list-keychains -d user -s "${KEYCHAIN}" $(security list-keychains -d user | sed s/\"//g) if not utils.system(["security", "list-keychains", "-d", "user", "-s", self.loginKeychain], stdout=subprocess.DEVNULL, secret=[password]): return False def importCert(cert, pwKey): pw = CraftChoicePrompt.promptForPassword(message=f"Enter the password for certificate: {Path(cert).name}", key=pwKey) return utils.system(["security", "import", cert, "-k", self.loginKeychain, "-P", pw, "-T", "/usr/bin/codesign", "-T", "/usr/bin/productsign"], stdout=subprocess.DEVNULL, secret=[password, pw]) if self.certFileApplication: if not importCert(self.certFileApplication, "MAC_CERTIFICATE_APPLICATION_PASSWORD"): return False if self.certFilesInstaller: if not importCert(self.certFilesInstaller, "MAC_CERTIFICATE_INSTALLER_PASSWORD"): return False if not utils.system(["security", "set-key-partition-list", "-S", "apple-tool:,apple:,codesign:", "-s", "-k", password, self.loginKeychain], stdout=subprocess.DEVNULL, secret=[password]): CraftCore.log.error("Failed to set key partition list.") return False else: if CraftCore.settings.getboolean("CodeSigning", "Protected", False): password = CraftChoicePrompt.promptForPassword(message="Enter the password for your signing keychain", key="MAC_KEYCHAIN_PASSWORD") if not utils.system(["security", "unlock-keychain", "-p", password, self.loginKeychain], stdout=subprocess.DEVNULL, secret=[password]): CraftCore.log.error("Failed to unlock keychain.") return False return True
def importCert(cert, pwKey): pw = CraftChoicePrompt.promptForPassword( message= f"Enter the password for certificate: {Path(cert).name}", key=pwKey) return utils.system([ "security", "import", cert, "-k", self.loginKeychain, "-P", pw, "-T", "/usr/bin/codesign", "-T", "/usr/bin/productsign" ], stdout=subprocess.DEVNULL, secret=[password])
def signWindows(fileNames: [str]) -> bool: if not CraftCore.settings.getboolean("CodeSigning", "Enabled", False): return True if not CraftCore.compiler.isWindows: CraftCore.log.warning( "Code signing is currently only supported on Windows") return True signTool = CraftCore.cache.findApplication("signtool", forceCache=True) if not signTool: env = SetupHelper.getMSVCEnv() signTool = CraftCore.cache.findApplication("signtool", env["PATH"], forceCache=True) if not signTool: CraftCore.log.warning( "Code signing requires a VisualStudio installation") return False command = [ signTool, "sign", "/tr", "http://timestamp.digicert.com", "/td", "SHA256", "/fd", "SHA256", "/a" ] certFile = CraftCore.settings.get("CodeSigning", "Certificate", "") subjectName = CraftCore.settings.get("CodeSigning", "CommonName", "") certProtected = CraftCore.settings.getboolean("CodeSigning", "Protected", False) kwargs = dict() if certFile: command += ["/f", certFile] if subjectName: command += ["/n", subjectName] if certProtected: password = CraftChoicePrompt.promptForPassword( message='Enter the password for your package signing certificate', key="WINDOWS_CODE_SIGN_CERTIFICATE_PASSWORD") command += ["/p", password] kwargs["secret"] = [password] if True or CraftCore.debug.verbose() > 0: command += ["/v"] else: command += ["/q"] for args in utils.limitCommandLineLength(command, fileNames): if not utils.system(args, **kwargs): return False return True
def fetchBinary(self, downloadRetriesLeft=3) -> bool: if self.subinfo.options.package.disableBinaryCache: return False for url in [self.cacheLocation()] + self.cacheRepositoryUrls(): CraftCore.log.debug(f"Trying to restore {self} from cache: {url}.") if url == self.cacheLocation(): fileUrl = f"{url}/manifest.json" if os.path.exists(fileUrl): with open(fileUrl, "rt", encoding="UTF-8") as f: manifest = CraftManifest.fromJson(json.load(f)) else: continue else: manifest = CraftManifest.fromJson( CraftCore.cache.cacheJsonFromUrl(f"{url}/manifest.json")) fileEntry = manifest.get(str(self)).files files = [] for f in fileEntry: if f.version == self.version: files.append(f) if not files: CraftCore.log.info( f"Could not find {self}={self.version} in {url}") continue latest = files[0] if not self.subinfo.options.dynamic.compatible( latest.config, latest.configHash): CraftCore.log.info( "Failed to restore package, configuration missmatch") CraftCore.debug.debug_line() CraftCore.log.info("Cached config: {}".format(", ".join( f"{k}={v}" for k, v in latest.config.items()))) CraftCore.log.info( f"Local config: {self.subinfo.options.dynamic}") CraftCore.debug.debug_line() # try next cache continue # if we are creating the cache, a rebuild on a failed fetch would be suboptimal createingCache = CraftCore.settings.getboolean( "Packager", "CreateCache", False) if url != self.cacheLocation(): downloadFolder = self.cacheLocation( os.path.join(CraftCore.standardDirs.downloadDir(), "cache")) else: downloadFolder = self.cacheLocation() localArchiveAbsPath = OsUtils.toNativePath( os.path.join(downloadFolder, latest.fileName)) localArchivePath, localArchiveName = os.path.split( localArchiveAbsPath) if url != self.cacheLocation(): if not os.path.exists(localArchiveAbsPath): os.makedirs(localArchivePath, exist_ok=True) fileName = latest.fileName if CraftCore.compiler.isWindows: fileName = fileName.replace("\\", "/") fUrl = f"{url}/{fileName}" # try it up to 3 times retries = 3 while True: if GetFiles.getFile(fUrl, localArchivePath, localArchiveName): break msg = f"Failed to fetch {fUrl}" retries -= 1 if not retries: if createingCache: raise BlueprintException(msg, self.package) else: CraftCore.log.warning(msg) return False elif not os.path.isfile(localArchiveAbsPath): continue if not CraftHash.checkFilesDigests( localArchivePath, [localArchiveName], digests=latest.checksum, digestAlgorithm=CraftHash.HashAlgorithm.SHA256): msg = f"Hash did not match, {localArchiveName} might be corrupted" CraftCore.log.warning(msg) if downloadRetriesLeft and CraftChoicePrompt.promptForChoice( "Do you want to delete the files and redownload them?", [("Yes", True), ("No", False)], default="Yes"): return utils.deleteFile( localArchiveAbsPath) and self.fetchBinary( downloadRetriesLeft=downloadRetriesLeft - 1) if createingCache: raise BlueprintException(msg, self.package) return False self.subinfo.buildPrefix = latest.buildPrefix self.subinfo.isCachedBuild = True if not (self.cleanImage() and utils.unpackFile( localArchivePath, localArchiveName, self.imageDir()) and self.internalPostInstall() and self.postInstall() and self.qmerge() and self.internalPostQmerge() and self.postQmerge()): return False return True return False
def fetchBinary(self, downloadRetriesLeft=3) -> bool: if self.subinfo.options.package.disableBinaryCache: return False for url in [self.cacheLocation()] + self.cacheRepositoryUrls(): CraftCore.log.debug(f"Trying to restore {self} from cache: {url}.") if url == self.cacheLocation(): fileUrl = f"{url}/manifest.json" if os.path.exists(fileUrl): with open(fileUrl, "rt", encoding="UTF-8") as f: manifest = CraftManifest.fromJson(json.load(f)) else: continue else: manifest = CraftManifest.fromJson( CraftCore.cache.cacheJsonFromUrl(f"{url}/manifest.json")) fileEntry = manifest.get(str(self)).files files = [] for f in fileEntry: if f.version == self.version: files.append(f) latest = None if not files: CraftCore.log.debug( f"Could not find {self}={self.version} in {url}") continue latest = files[0] if url != self.cacheLocation(): downloadFolder = self.cacheLocation( os.path.join(CraftCore.standardDirs.downloadDir(), "cache")) else: downloadFolder = self.cacheLocation() localArchiveAbsPath = OsUtils.toNativePath( os.path.join(downloadFolder, latest.fileName)) localArchivePath, localArchiveName = os.path.split( localArchiveAbsPath) if url != self.cacheLocation(): if not os.path.exists(localArchiveAbsPath): os.makedirs(localArchivePath, exist_ok=True) fUrl = f"{url}/{latest.fileName}" if not GetFiles.getFile(fUrl, localArchivePath, localArchiveName): CraftCore.log.warning(f"Failed to fetch {fUrl}") return False elif not os.path.isfile(localArchiveAbsPath): continue if not CraftHash.checkFilesDigests( localArchivePath, [localArchiveName], digests=latest.checksum, digestAlgorithm=CraftHash.HashAlgorithm.SHA256): CraftCore.log.warning( f"Hash did not match, {localArchiveName} might be corrupted" ) if downloadRetriesLeft and CraftChoicePrompt.promptForChoice( "Do you want to delete the files and redownload them?", [("Yes", True), ("No", False)], default="Yes"): return utils.deleteFile( localArchiveAbsPath) and self.fetchBinary( downloadRetriesLeft=downloadRetriesLeft - 1) return False self.subinfo.buildPrefix = latest.buildPrefix self.subinfo.isCachedBuild = True if not (self.cleanImage() and utils.unpackFile( localArchivePath, localArchiveName, self.imageDir()) and self.internalPostInstall() and self.postInstall() and self.qmerge() and self.internalPostQmerge() and self.postQmerge()): return False return True return False