Esempio n. 1
0
        static public bool CopyFolder(string SourceFolder, string DestFolder, string DisplayDestFolder, bool bDeleteTarget, bool bLowercase)
        {
            if (DisplayDestFolder == null)
            {
                DisplayDestFolder = DestFolder;
            }

            DirectoryInfo SourceFolderInfo = new DirectoryInfo(SourceFolder);

            if (!SourceFolderInfo.Exists)
            {
                Program.Error("Source folder does not exist");
                return(false);
            }

            Program.Log(" ... '" + SourceFolder + "' -> '" + DisplayDestFolder + "'");

            DirectoryInfo DestFolderInfo = new DirectoryInfo(DestFolder);

            if (bDeleteTarget && DestFolderInfo.Exists)
            {
                DeleteDirectory(DestFolderInfo);
            }

            try
            {
                Directory.CreateDirectory(DestFolderInfo.FullName);
            }
            catch (Exception Ex)
            {
                Program.Error("Could not create folder: " + DestFolderInfo.FullName);
                Program.Error("    Exception: " + Ex.Message);
                Program.ReturnCode = (int)ErrorCodes.Error_CreateDirectory;
            }

            RecursiveFolderCopy(SourceFolderInfo, DestFolderInfo, bLowercase);

            return(true);
        }
Esempio n. 2
0
        public static MobileProvision ParseFile(byte[] RawData)
        {
            //@TODO: This file is just an ASN.1 stream, should find or make a raw ASN1 parser and use
            // that instead of this (theoretically fragile) code (particularly the length extraction)

            // Scan it for the start of the embedded blob of xml
            byte[] SearchPattern = Encoding.UTF8.GetBytes("<?xml");
            for (int TextStart = 2; TextStart < RawData.Length - SearchPattern.Length; ++TextStart)
            {
                // See if this point is a match
                bool bMatch = true;
                for (int PatternIndex = 0; bMatch && (PatternIndex < SearchPattern.Length); ++PatternIndex)
                {
                    bMatch = bMatch && (RawData[TextStart + PatternIndex] == SearchPattern[PatternIndex]);
                }

                if (bMatch)
                {
                    // Back up two bytes and read a two byte little endian plist size
                    int TextLength = (RawData[TextStart - 2] << 8) | (RawData[TextStart - 1]);

                    // Convert the data to a string
                    string PlistText = Encoding.UTF8.GetString(RawData, TextStart, TextLength);

                    //@TODO: Distribution provisions seem to be a byte too long, and it may be a general problem with interpreting the length
                    // For now, we just cut back to the end of the last tag.
                    int CutPoint = PlistText.LastIndexOf('>');
                    PlistText = PlistText.Substring(0, CutPoint + 1);

                    // Return the constructed 'mobile provision'
                    return(new MobileProvision(PlistText));
                }
            }

            // Unable to find the start of the plist data
            Program.Error("Failed to find embedded plist in .mobileprovision file");
            return(null);
        }
Esempio n. 3
0
            public override Stream OpenRead(string RelativeFilename)
            {
                string FullPath = InternalRootPath + RelativeFilename;

                Stream ReadStream;

                byte[] PreviousData;
                if (PendingWrites.TryGetValue(FullPath, out PreviousData))
                {
                    ReadStream = new MemoryStream(PreviousData);
                }
                else
                {
                    if (Zip.ContainsEntry(FullPath))
                    {
                        ZipEntry Entry = Zip[FullPath];
                        if (Entry.UncompressedSize >= (2L * 1024 * 1024 * 1024))
                        {
                            Entry.Extract(Path.GetTempPath());
                            ReadStream = File.OpenRead(Path.Combine(Path.GetTempPath(), Entry.FileName));
                        }
                        else
                        {
                            ReadStream = new MemoryStream((int)Entry.UncompressedSize);
                            Zip[FullPath].Extract(ReadStream);
                        }
                    }
                    else
                    {
                        string ErrorMessage = String.Format("Expected \"{0}\" in IPA but it was not found", FullPath);
                        Program.Error(ErrorMessage);
                        throw new Exception(ErrorMessage);
                    }
                }

                ReadStream.Position = 0;
                return(ReadStream);
            }
Esempio n. 4
0
        /// <summary>
        /// Export the certificate to a file
        /// </summary>
        static public void ExportCertificate()
        {
            string ProvisionWithPrefix;

            if (!FindMobileProvision("", out ProvisionWithPrefix))
            {
                Program.Error("Missing provision");
                return;
            }

            if (Config.Certificate == null)
            {
                Program.Error("Missing -Certificate=... argument");
                return;
            }

            // export the signing certificate to a file
            MobileProvision Provision   = MobileProvisionParser.ParseFile(ProvisionWithPrefix);
            var             Certificate = CodeSignatureBuilder.FindCertificate(Provision);

            byte[] Data = Certificate.Export(System.Security.Cryptography.X509Certificates.X509ContentType.Pkcs12, "A");
            File.WriteAllBytes(Config.Certificate, Data);
        }
        public static DeploymentInterface Get()
        {
            if (DeployTimeInstance == null)
            {
                if (DeploymentServerProcess == null)
                {
                    DeploymentServerProcess = CreateDeploymentServerProcess();
                }
                DeployTimeInstance = (DeploymentInterface)Activator.GetObject(
                    typeof(DeploymentInterface),
                    @"ipc://iPhonePackager/DeploymentServer_PID" + Process.GetCurrentProcess().Id.ToString());
            }

            if (DeployTimeInstance == null)
            {
                Program.Error("Failed to connect to deployment server");
                throw new Exception("Failed to connect to deployment server");
            }

            DeployTimeInstance.SetReportingInterface(Reporter);

            return(DeployTimeInstance);
        }
Esempio n. 6
0
		/**
		 * Safely delete a directory
		 */
		static public void DeleteDirectory( DirectoryInfo DirInfo )
		{
			if( DirInfo.Exists )
			{
				foreach( FileInfo Info in DirInfo.GetFiles() )
				{
					try
					{
						Info.IsReadOnly = false;
						Info.Delete();
					}
					catch( Exception Ex )
					{
						Program.Error( "Could not delete file: " + Info.FullName );
						Program.Error( "    Exception: " + Ex.Message );
						Program.ReturnCode = (int)ErrorCodes.Error_DeleteFile;
					}
				}

				foreach( DirectoryInfo SubDirInfo in DirInfo.GetDirectories() )
				{
					DeleteDirectory( SubDirInfo );
				}

				try
				{
					DirInfo.Delete();
				}
				catch( Exception Ex )
				{
					Program.Error( "Could not delete folder: " + DirInfo.FullName );
					Program.Error( "    Exception: " + Ex.Message );
					Program.ReturnCode = (int)ErrorCodes.Error_DeleteDirectory;
				}
			}
		}
Esempio n. 7
0
        /**
         * Handle spawning of the RPCUtility with parameters
         */
        public static bool RunRPCUtilty(string RPCCommand)
        {
            string CommandLine        = "";
            string WorkingFolder      = "";
            string DisplayCommandLine = "";

            switch (RPCCommand.ToLowerInvariant())
            {
            case "deletemacstagingfiles":
                Program.Log(" ... deleting staging files on the Mac");
                DisplayCommandLine = "rm -rf Payload";
                CommandLine        = "\"" + MacStagingRootDir + "\" " + DisplayCommandLine;
                WorkingFolder      = MacStagingRootDir;
                break;

            case "ensureprovisiondirexists":
                Program.Log(" ... creating provisioning profiles directory");

                DisplayCommandLine = String.Format("mkdir -p ~/Library/MobileDevice/Provisioning\\ Profiles");

                CommandLine   = "\"" + MacXcodeStagingDir + "\" " + DisplayCommandLine;
                WorkingFolder = MacXcodeStagingDir;
                break;

            case "installprovision":
                // Note: The provision must have already been copied over to the Mac
                Program.Log(" ... installing .mobileprovision");

                DisplayCommandLine = String.Format("cp -f {0} ~/Library/MobileDevice/Provisioning\\ Profiles", MacMobileProvisionFilename);

                CommandLine   = "\"" + MacXcodeStagingDir + "\" " + DisplayCommandLine;
                WorkingFolder = MacXcodeStagingDir;
                break;

            case "removeprovision":
                Program.Log(" ... removing .mobileprovision");
                DisplayCommandLine = String.Format("rm -f ~/Library/MobileDevice/Provisioning\\ Profiles/{0}", MacMobileProvisionFilename);
                CommandLine        = "\"" + MacXcodeStagingDir + "\" " + DisplayCommandLine;
                WorkingFolder      = MacXcodeStagingDir;
                break;

            case "setexec":
                // Note: The executable must have already been copied over
                Program.Log(" ... setting executable bit");
                DisplayCommandLine = "chmod a+x \'" + RemoteExecutablePath + "\'";
                CommandLine        = "\"" + MacStagingRootDir + "\" " + DisplayCommandLine;
                WorkingFolder      = MacStagingRootDir;
                break;

            case "prepackage":
                Program.Log(" ... running prepackage script remotely ");
                DisplayCommandLine = String.Format("sh prepackage.sh {0} IOS {1} {2}", Program.GameName, Program.GameConfiguration, Program.Architecture);
                CommandLine        = "\"" + MacXcodeStagingDir + "\" " + DisplayCommandLine;
                WorkingFolder      = MacXcodeStagingDir;
                break;

            case "makeapp":
                Program.Log(" ... making application (codesign, etc...)");
                Program.Log("  Using signing identity '{0}'", Config.CodeSigningIdentity);
                DisplayCommandLine = CurrentBaseXCodeCommandLine;
                CommandLine        = "\"" + MacXcodeStagingDir + "/..\" " + DisplayCommandLine;
                WorkingFolder      = "\"" + MacXcodeStagingDir + "/..\"";
                break;

            case "validation":
                Program.Log(" ... validating distribution package");
                DisplayCommandLine = XcodeDeveloperDir + "Platforms/iPhoneOS.platform/Developer/usr/bin/Validation " + RemoteAppDirectory;
                CommandLine        = "\"" + MacStagingRootDir + "\" " + DisplayCommandLine;
                WorkingFolder      = MacStagingRootDir;
                break;

            case "deleteipa":
                Program.Log(" ... deleting IPA on Mac");
                DisplayCommandLine = "rm -f " + Config.IPAFilenameOnMac;
                CommandLine        = "\"" + MacStagingRootDir + "\" " + DisplayCommandLine;
                WorkingFolder      = MacStagingRootDir;
                break;

            case "kill":
                Program.Log(" ... killing");
                DisplayCommandLine = "killall " + Program.GameName;
                CommandLine        = ". " + DisplayCommandLine;
                WorkingFolder      = ".";
                break;

            case "strip":
                Program.Log(" ... stripping");
                DisplayCommandLine = XcodeDeveloperDir + "Platforms/iPhoneOS.platform/Developer/usr/bin/strip '" + RemoteExecutablePath + "'";
                CommandLine        = "\"" + MacStagingRootDir + "\" " + DisplayCommandLine;
                WorkingFolder      = MacStagingRootDir;
                break;

            case "resign":
                Program.Log("... resigning");
                DisplayCommandLine = "bash -c '" + "chmod a+x ResignScript" + ";" + "./ResignScript" + "'";
                CommandLine        = "\"" + MacStagingRootDir + "\" " + DisplayCommandLine;
                WorkingFolder      = MacStagingRootDir;
                break;

            case "zip":
                Program.Log(" ... zipping");

                // NOTE: -y preserves symbolic links which is needed for iOS distro builds
                // -x excludes a file (excluding the dSYM keeps sizes smaller, and it shouldn't be in the IPA anyways)
                string dSYMName = "Payload/" + Program.GameName + Program.Architecture + ".app.dSYM";
                DisplayCommandLine = String.Format("zip -q -r -y -{0} -T {1} Payload iTunesArtwork -x {2}/ -x {2}/* " +
                                                   "-x {2}/Contents/ -x {2}/Contents/* -x {2}/Contents/Resources/ -x {2}/Contents/Resources/* " +
                                                   " -x {2}/Contents/Resources/DWARF/ -x {2}/Contents/Resources/DWARF/*",
                                                   (int)Config.RecompressionSetting,
                                                   Config.IPAFilenameOnMac,
                                                   dSYMName);

                CommandLine   = "\"" + MacStagingRootDir + "\" " + DisplayCommandLine;
                WorkingFolder = MacStagingRootDir;
                break;

            case "gendsym":
                Program.Log(" ... generating DSYM");

                string ExePath  = "Payload/" + Program.GameName + ".app/" + Program.GameName;
                string dSYMPath = Program.GameName + ".app.dSYM";
                DisplayCommandLine = String.Format("dsymutil -o {0} {1}", dSYMPath, ExePath);

                CommandLine   = "\"" + MacStagingRootDir + "\"" + DisplayCommandLine;
                WorkingFolder = MacStagingRootDir;
                break;

            default:
                Program.Error("Unrecognized RPC command");
                return(false);
            }

            Program.Log(" ... working folder: " + WorkingFolder);
            Program.Log(" ... " + DisplayCommandLine);
            Program.Log(" ... full command: " + MacName + " " + CommandLine);

            bool bSuccess = false;

            if (Config.bUseRPCUtil)
            {
                Program.Log("Running RPC on " + MacName + " ... ");

                Process RPCUtil = new Process();
                RPCUtil.StartInfo.FileName               = @"..\RPCUtility.exe";
                RPCUtil.StartInfo.UseShellExecute        = false;
                RPCUtil.StartInfo.Arguments              = MacName + " " + CommandLine;
                RPCUtil.StartInfo.RedirectStandardOutput = true;
                RPCUtil.StartInfo.RedirectStandardError  = true;
                RPCUtil.OutputDataReceived              += new DataReceivedEventHandler(OutputReceivedRemoteProcessCall);
                RPCUtil.ErrorDataReceived += new DataReceivedEventHandler(OutputReceivedRemoteProcessCall);

                RPCUtil.Start();

                RPCUtil.BeginOutputReadLine();
                RPCUtil.BeginErrorReadLine();

                RPCUtil.WaitForExit();

                bSuccess = (RPCUtil.ExitCode == 0);
                if (bSuccess == false)
                {
                    Program.Error("RPCCommand {0} failed with return code {1}", RPCCommand, RPCUtil.ExitCode);
                    switch (RPCCommand.ToLowerInvariant())
                    {
                    case "installprovision":
                        Program.Error("Ensure your access permissions for '~/Library/MobileDevice/Provisioning Profiles' are set correctly.");
                        break;

                    default:
                        break;
                    }
                }
            }
            else
            {
                Program.Log("Running SSH on " + MacName + " ... ");
                bSuccess = SSHCommandHelper.Command(MacName, DisplayCommandLine, WorkingFolder);
            }


            return(bSuccess);
        }
Esempio n. 8
0
        private void GenerateSigningRequestViaOpenSSL(string TargetCertRequestFileName, AsymmetricCipherKeyPair KeyPair)
        {
            // We expect openssl.exe to exist in the same directory as iPhonePackager
            string OpenSSLPath = Path.GetDirectoryName(Application.ExecutablePath) + @"\openssl.exe";

            if (!File.Exists(OpenSSLPath))
            {
                MessageBox.Show("A version of OpenSSL is required to generate certificate requests.  Please place OpenSSL.exe in Binaries\\DotNET\\IOS", Config.AppDisplayName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            string EffectiveBuildPath = (Program.GameName.Length > 0) ? Config.BuildDirectory : Path.GetFullPath(".");

            // Create a temporary file to write the key pair out to (in a format that OpenSSL understands)
            string     KeyFileName = Path.GetTempFileName();
            TextWriter KeyWriter   = new StreamWriter(KeyFileName);

            PemWriter KeyWriterPEM = new PemWriter(KeyWriter);

            KeyWriterPEM.WriteObject(KeyPair);
            KeyWriter.Close();

            // Create a temporary file containing the configuration settings to drive OpenSSL
            string     ConfigFileName = Path.GetTempFileName();
            TextWriter ConfigFile     = new StreamWriter(ConfigFileName);

            ConfigFile.WriteLine("[ req ]");
            ConfigFile.WriteLine("distinguished_name     = req_distinguished_name");
            ConfigFile.WriteLine("prompt                 = no");

            ConfigFile.WriteLine("[ req_distinguished_name ]");
            ConfigFile.WriteLine("emailAddress           = {0}", EMailEditBox.Text);
            ConfigFile.WriteLine("commonName             = {0}", CommonNameEditBox.Text);
            ConfigFile.WriteLine("countryName            = {0}", System.Globalization.CultureInfo.CurrentCulture.TwoLetterISOLanguageName);

            ConfigFile.Close();

            // Invoke OpenSSL to generate the certificate request
            Program.Log("Running OpenSSL to generate certificate request...");

            string ResultsText;
            string Executable = OpenSSLPath;
            string Arguments  = String.Format("req -new -nodes -out \"{0}\" -key \"{1}\" -config \"{2}\"",
                                              TargetCertRequestFileName, KeyFileName, ConfigFileName);

            Utilities.RunExecutableAndWait(Executable, Arguments, out ResultsText);

            Program.Log(ResultsText);

            if (!File.Exists(TargetCertRequestFileName))
            {
                Program.Error("... Failed to generate certificate request");
            }
            else
            {
                Program.Log("... Successfully generated certificate request '{0}'", TargetCertRequestFileName);
            }

            // Clean up the temporary files we created
            File.Delete(KeyFileName);
            File.Delete(ConfigFileName);
        }
Esempio n. 9
0
        /// <summary>
        /// Finds all valid installed provisions
        /// </summary>
        public static void FindProvisions(string CFBundleIdentifier)
        {
            if (!Directory.Exists(Config.ProvisionDirectory))
            {
                Program.Error("Could not find provision directory '{0}'.", Config.ProvisionDirectory);
                Program.ReturnCode = (int)ErrorCodes.Error_ProvisionNotFound;
                return;
            }
            // cache the provision library
            string SelectedProvision = "";
            string SelectedCert      = "";
            string SelectedFile      = "";
            int    FoundName         = -1;
            Dictionary <string, MobileProvision> ProvisionLibrary = new Dictionary <string, MobileProvision>();

            foreach (string Provision in Directory.EnumerateFiles(Config.ProvisionDirectory, "*.mobileprovision"))
            {
                MobileProvision p = MobileProvisionParser.ParseFile(Provision);

                DateTime EffectiveDate  = p.CreationDate;
                DateTime ExpirationDate = p.ExpirationDate;
                DateTime Now            = DateTime.UtcNow;

                bool             bCertTimeIsValid = (EffectiveDate < Now) && (ExpirationDate > Now);
                bool             bValid           = false;
                X509Certificate2 Cert             = FindCertificate(p);
                if (Cert != null)
                {
                    bValid = (Cert.NotBefore < Now) && (Cert.NotAfter > Now);
                }
                bool bPassesNameCheck     = p.ApplicationIdentifier.Substring(p.ApplicationIdentifierPrefix.Length + 1) == CFBundleIdentifier;
                bool bPassesCompanyCheck  = false;
                bool bPassesWildCardCheck = false;
                if (p.ApplicationIdentifier.Contains("*"))
                {
                    string CompanyName = p.ApplicationIdentifier.Substring(p.ApplicationIdentifierPrefix.Length + 1);
                    if (CompanyName != "*")
                    {
                        CompanyName         = CompanyName.Substring(0, CompanyName.LastIndexOf("."));
                        bPassesCompanyCheck = CFBundleIdentifier.StartsWith(CompanyName);
                    }
                    else
                    {
                        bPassesWildCardCheck = true;
                    }
                }
                bool bIsManaged = false;
                if (p.ProvisionName == "iOS Team Provisioning Profile: " + CFBundleIdentifier)
                {
                    bIsManaged = true;
                }
                bool   bDistribution = ((p.ProvisionedDeviceIDs.Count == 0) && !p.bDebug);
                string Validity      = "VALID";
                if (!bCertTimeIsValid)
                {
                    Validity = "EXPIRED";
                }
                else if (!bValid)
                {
                    Validity = "NO_CERT";
                }
                else if (!bPassesNameCheck && !bPassesWildCardCheck && !bPassesCompanyCheck)
                {
                    Validity = "NO_MATCH";
                }
                if (bIsManaged)
                {
                    Validity = "MANAGED";
                }
                if ((string.IsNullOrWhiteSpace(SelectedProvision) || FoundName < 2) && Validity == "VALID" && !bDistribution)
                {
                    int Prev = FoundName;
                    if (bPassesNameCheck)
                    {
                        FoundName = 2;
                    }
                    else if (bPassesCompanyCheck && FoundName < 1)
                    {
                        FoundName = 1;
                    }
                    else if (bPassesWildCardCheck && FoundName == -1)
                    {
                        FoundName = 0;
                    }
                    if (FoundName != Prev)
                    {
                        SelectedProvision = p.ProvisionName;
                        SelectedFile      = Path.GetFileName(Provision);
                        SelectedCert      = Cert.FriendlyName;
                    }
                }
                Program.LogVerbose("PROVISION-File:{0},Name:{1},Validity:{2},StartDate:{3},EndDate:{4},Type:{5}", Path.GetFileName(Provision), p.ProvisionName, Validity, EffectiveDate.ToString(), ExpirationDate.ToString(), bDistribution ? "DISTRIBUTION" : "DEVELOPMENT");
            }

            Program.LogVerbose("MATCHED-Provision:{0},File:{1},Cert:{2}", SelectedProvision, SelectedFile, SelectedCert);
        }
Esempio n. 10
0
 public void Error(string Line)
 {
     Program.Error(Line);
 }
Esempio n. 11
0
        public static bool ExecuteDeployCommand(string Command, string GamePath, string RPCCommand)
        {
            switch (Command.ToLowerInvariant())
            {
            case "backup":
            {
                string ApplicationIdentifier = RPCCommand;
                if (ApplicationIdentifier == null)
                {
                    ApplicationIdentifier = Utilities.GetStringFromPList("CFBundleIdentifier");
                }

                if (Config.FilesForBackup.Count > 0)
                {
                    if (!DeploymentHelper.Get().BackupFiles(ApplicationIdentifier, Config.FilesForBackup.ToArray()))
                    {
                        Program.Error("Failed to transfer manifest file from device to PC");
                        Program.ReturnCode = (int)ErrorCodes.Error_DeviceBackupFailed;
                    }
                }
                else if (!DeploymentHelper.Get().BackupDocumentsDirectory(ApplicationIdentifier, Config.GetRootBackedUpDocumentsDirectory()))
                {
                    Program.Error("Failed to transfer documents directory from device to PC");
                    Program.ReturnCode = (int)ErrorCodes.Error_DeviceBackupFailed;
                }
            }
            break;

            case "uninstall":
            {
                string ApplicationIdentifier = RPCCommand;
                if (ApplicationIdentifier == null)
                {
                    ApplicationIdentifier = Utilities.GetStringFromPList("CFBundleIdentifier");
                }

                if (!DeploymentHelper.Get().UninstallIPAOnDevice(ApplicationIdentifier))
                {
                    Program.Error("Failed to uninstall IPA on device");
                    Program.ReturnCode = (int)ErrorCodes.Error_AppUninstallFailed;
                }
            }
            break;

            case "deploy":
            case "install":
            {
                string IPAPath = GamePath;
                string AdditionalCommandline = Program.AdditionalCommandline;

                if (!String.IsNullOrEmpty(AdditionalCommandline) && !Config.bIterate)
                {
                    // Read the mobile provision to check for issues
                    FileOperations.ReadOnlyZipFileSystem Zip = new FileOperations.ReadOnlyZipFileSystem(IPAPath);
                    try
                    {
                        // Compare the commandline embedded to prevent us from any unnecessary writing.
                        byte[] CommandlineBytes    = Zip.ReadAllBytes("ue4commandline.txt");
                        string ExistingCommandline = Encoding.UTF8.GetString(CommandlineBytes, 0, CommandlineBytes.Length);
                        if (ExistingCommandline != AdditionalCommandline)
                        {
                            // Ensure we have a temp dir to stage our temporary ipa
                            if (!Directory.Exists(Config.PCStagingRootDir))
                            {
                                Directory.CreateDirectory(Config.PCStagingRootDir);
                            }

                            string TmpFilePath = Path.Combine(Path.GetDirectoryName(Config.PCStagingRootDir), Path.GetFileNameWithoutExtension(IPAPath) + ".tmp.ipa");
                            if (File.Exists(TmpFilePath))
                            {
                                File.Delete(TmpFilePath);
                            }

                            File.Copy(IPAPath, TmpFilePath);

                            // Get the project name:
                            string ProjectFile = ExistingCommandline.Split(' ').FirstOrDefault();

                            // Write out the new commandline.
                            FileOperations.ZipFileSystem WritableZip = new FileOperations.ZipFileSystem(TmpFilePath);
                            byte[] NewCommandline = Encoding.UTF8.GetBytes(ProjectFile + " " + AdditionalCommandline);
                            WritableZip.WriteAllBytes("ue4commandline.txt", NewCommandline);

                            // We need to residn the application after the commandline file has changed.
                            CodeSignatureBuilder CodeSigner = new CodeSignatureBuilder();
                            CodeSigner.FileSystem = WritableZip;

                            CodeSigner.PrepareForSigning();
                            CodeSigner.PerformSigning();

                            WritableZip.Close();

                            // Set the deploying ipa path to our new ipa
                            IPAPath = TmpFilePath;
                        }
                    }
                    catch (System.Exception ex)
                    {
                        Program.Warning(String.Format("Failed to override the commandline.txt file: ({0})", ex.Message));
                    }
                    Zip.Close();
                }

                if (Config.bIterate)
                {
                    string ApplicationIdentifier = RPCCommand;
                    if (String.IsNullOrEmpty(ApplicationIdentifier))
                    {
                        ApplicationIdentifier = Utilities.GetStringFromPList("CFBundleIdentifier");
                    }

                    DeploymentHelper.Get().DeviceId = Config.DeviceId;
                    if (!DeploymentHelper.Get().InstallFilesOnDevice(ApplicationIdentifier, Config.DeltaManifest))
                    {
                        Program.Error("Failed to install Files on device");
                        Program.ReturnCode = (int)ErrorCodes.Error_FilesInstallFailed;
                    }
                }
                else if (File.Exists(IPAPath))
                {
                    DeploymentHelper.Get().DeviceId = Config.DeviceId;
                    if (!DeploymentHelper.Get().InstallIPAOnDevice(IPAPath))
                    {
                        Program.Error("Failed to install IPA on device");
                        Program.ReturnCode = (int)ErrorCodes.Error_AppInstallFailed;
                    }
                }
                else
                {
                    Program.Error(String.Format("Failed to find IPA file: '{0}'", IPAPath));
                    Program.ReturnCode = (int)ErrorCodes.Error_AppNotFound;
                }
            }
            break;

            default:
                return(false);
            }

            return(true);
        }
Esempio n. 12
0
        public static void TryInstallingCertificate_PromptForKey(string CertificateFilename, bool ShowPrompt = true)
        {
            try
            {
                if (!String.IsNullOrEmpty(CertificateFilename) || ShowOpenFileDialog(CertificatesFilter, "Choose a code signing certificate to import", "", "", ref ChoosingFilesToInstallDirectory, out CertificateFilename))
                {
                    if (Environment.OSVersion.Platform == PlatformID.MacOSX || Environment.OSVersion.Platform == PlatformID.Unix)
                    {
                        // run certtool y to get the currently installed certificates
                        CertToolData = "";
                        Process CertTool = new Process();
                        CertTool.StartInfo.FileName               = "/usr/bin/security";
                        CertTool.StartInfo.UseShellExecute        = false;
                        CertTool.StartInfo.Arguments              = "import \"" + CertificateFilename + "\" -k login.keychain";
                        CertTool.StartInfo.RedirectStandardOutput = true;
                        CertTool.OutputDataReceived              += new DataReceivedEventHandler(OutputReceivedCertToolProcessCall);
                        CertTool.Start();
                        CertTool.BeginOutputReadLine();
                        CertTool.WaitForExit();
                        if (CertTool.ExitCode != 0)
                        {
                            // todo: provide some feedback that it failed
                        }
                        Console.Write(CertToolData);
                    }
                    else
                    {
                        // Load the certificate
                        string           CertificatePassword = "";
                        X509Certificate2 Cert = null;
                        try
                        {
                            Cert = new X509Certificate2(CertificateFilename, CertificatePassword, X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet);
                        }
                        catch (System.Security.Cryptography.CryptographicException ex)
                        {
                            // Try once with a password
                            if (PasswordDialog.RequestPassword(out CertificatePassword))
                            {
                                Cert = new X509Certificate2(CertificateFilename, CertificatePassword, X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet);
                            }
                            else
                            {
                                // User cancelled dialog, rethrow
                                throw ex;
                            }
                        }

                        // If the certificate doesn't have a private key pair, ask the user to provide one
                        if (!Cert.HasPrivateKey)
                        {
                            string ErrorMsg = "Certificate does not include a private key and cannot be used to code sign";

                            // Prompt for a key pair
                            if (MessageBox(new IntPtr(0), "Next, please choose the key pair that you made when generating the certificate request.",
                                           Config.AppDisplayName,
                                           0x00000000 | 0x00000040 | 0x00001000 | 0x00010000) == 1)
                            {
                                string KeyFilename;
                                if (ShowOpenFileDialog(KeysFilter, "Choose the key pair that belongs with the signing certificate", "", "", ref ChoosingFilesToInstallDirectory, out KeyFilename))
                                {
                                    Cert = CryptoAdapter.CombineKeyAndCert(CertificateFilename, KeyFilename);

                                    if (Cert.HasPrivateKey)
                                    {
                                        ErrorMsg = null;
                                    }
                                }
                            }

                            if (ErrorMsg != null)
                            {
                                throw new Exception(ErrorMsg);
                            }
                        }

                        // Add the certificate to the store
                        X509Store Store = new X509Store();
                        Store.Open(OpenFlags.ReadWrite);
                        Store.Add(Cert);
                        Store.Close();
                    }
                }
            }
            catch (Exception ex)
            {
                string ErrorMsg = String.Format("Failed to load or install certificate due to an error: '{0}'", ex.Message);
                Program.Error(ErrorMsg);
                System.Threading.Thread.Sleep(500);
                MessageBox(new IntPtr(0), ErrorMsg, Config.AppDisplayName, 0x00000000 | 0x00000010 | 0x00001000 | 0x00010000);
            }
        }
Esempio n. 13
0
        /// <summary>
        /// Copy the files always needed (even in a stub IPA)
        /// </summary>
        static public void CopyFilesNeededForMakeApp()
        {
            // Copy Info.plist over (modifiying it as needed)
            string SourcePListFilename = Utilities.GetPrecompileSourcePListFilename();

            Utilities.PListHelper Info = Utilities.PListHelper.CreateFromFile(SourcePListFilename);

            // Edit the plist
            CookTime.UpdateVersion(Info);

            // Write out the <GameName>-Info.plist file to the xcode staging directory
            string TargetPListFilename = Path.Combine(Config.PCXcodeStagingDir, Program.GameName + "-Info.plist");

            Directory.CreateDirectory(Path.GetDirectoryName(TargetPListFilename));
            string OutString = Info.SaveToString();

            OutString = OutString.Replace("${EXECUTABLE_NAME}", Program.GameName);
            OutString = OutString.Replace("${BUNDLE_IDENTIFIER}", Program.GameName.Replace("_", ""));

            // this is a temp way to inject the iphone 6 images without needing to upgrade everyone's plist
            // eventually we want to generate this based on what the user has set in the project settings
            string[] IPhoneConfigs =
            {
                "Default-IPhone6",               "Landscape", "{375, 667}",
                "Default-IPhone6",               "Portrait",  "{375, 667}",
                "Default-IPhone6Plus-Landscape", "Landscape", "{414, 736}",
                "Default-IPhone6Plus-Portrait",  "Portrait",  "{414, 736}",
                "Default",                       "Landscape", "{320, 480}",
                "Default",                       "Portrait",  "{320, 480}",
                "Default-568h",                  "Landscape", "{320, 568}",
                "Default-568h",                  "Portrait",  "{320, 568}",
                "Default-IPhoneX-Landscape",     "Landscape", "{375, 812}",
                "Default-IPhoneX-Portrait",      "Portrait",  "{375, 812}",
            };

            StringBuilder NewLaunchImagesString = new StringBuilder("<key>UILaunchImages~iphone</key>\n\t\t<array>\n");

            for (int ConfigIndex = 0; ConfigIndex < IPhoneConfigs.Length; ConfigIndex += 3)
            {
                NewLaunchImagesString.Append("\t\t\t<dict>\n");
                NewLaunchImagesString.Append("\t\t\t\t<key>UILaunchImageMinimumOSVersion</key>\n");
                NewLaunchImagesString.Append("\t\t\t\t<string>8.0</string>\n");
                NewLaunchImagesString.Append("\t\t\t\t<key>UILaunchImageName</key>\n");
                NewLaunchImagesString.AppendFormat("\t\t\t\t<string>{0}</string>\n", IPhoneConfigs[ConfigIndex + 0]);
                NewLaunchImagesString.Append("\t\t\t\t<key>UILaunchImageOrientation</key>\n");
                NewLaunchImagesString.AppendFormat("\t\t\t\t<string>{0}</string>\n", IPhoneConfigs[ConfigIndex + 1]);
                NewLaunchImagesString.Append("\t\t\t\t<key>UILaunchImageSize</key>\n");
                NewLaunchImagesString.AppendFormat("\t\t\t\t<string>{0}</string>\n", IPhoneConfigs[ConfigIndex + 2]);
                NewLaunchImagesString.Append("\t\t\t</dict>\n");
            }

            // close it out
            NewLaunchImagesString.Append("\t\t\t</array>\n\t\t<key>UILaunchImages~ipad</key>");
            OutString = OutString.Replace("<key>UILaunchImages~ipad</key>", NewLaunchImagesString.ToString());

            byte[] RawInfoPList = Encoding.UTF8.GetBytes(OutString);
            File.WriteAllBytes(TargetPListFilename, RawInfoPList);

            Program.Log("Updating .plist: {0} --> {1}", SourcePListFilename, TargetPListFilename);

            string FinalMobileProvisionFilename = null;

            CurrentBaseXCodeCommandLine = GetBaseXcodeCommandline();
            if (!Config.bAutomaticSigning)
            {
                // Copy the mobile provision file over
                string CFBundleIdentifier = null;
                Info.GetString("CFBundleIdentifier", out CFBundleIdentifier);

                string ProvisionWithPrefix;
                if (!FindMobileProvision(CFBundleIdentifier, out ProvisionWithPrefix))
                {
                    Program.Error("Unable to find mobileprovision");
                    return;
                }
                FinalMobileProvisionFilename = Path.Combine(Config.PCXcodeStagingDir, MacMobileProvisionFilename);
                FileOperations.CopyRequiredFile(ProvisionWithPrefix, FinalMobileProvisionFilename);

                // make sure this .mobileprovision file is newer than any other .mobileprovision file on the Mac (this file gets multiple games named the same file,
                // so the time stamp checking can fail when moving between games, a la the buildmachines!)
                File.SetLastWriteTime(FinalMobileProvisionFilename, DateTime.UtcNow);

                // copy the signing certificate over
                // export the signing certificate to a file
                MobileProvision Provision   = MobileProvisionParser.ParseFile(ProvisionWithPrefix);
                var             Certificate = CodeSignatureBuilder.FindCertificate(Provision);
                byte[]          Data        = Certificate.Export(System.Security.Cryptography.X509Certificates.X509ContentType.Pkcs12, "A");
                File.WriteAllBytes(Path.Combine(Config.PCXcodeStagingDir, MacSigningIdentityFilename), Data);
                Config.CodeSigningIdentity = Certificate.FriendlyName;                 // since the pipeline will use a temporary keychain that will contain only this certificate, this should be the only identity that will work

                if (Provision != null)
                {
                    Config.bForDistribution = !Provision.bDebug;
                }
                // regenerate command with new found identity
                CurrentBaseXCodeCommandLine = GetBaseXcodeCommandline();

                // get the UUID
                string AllText = File.ReadAllText(FinalMobileProvisionFilename);
                string UUID    = "";
                int    idx     = AllText.IndexOf("<key>UUID</key>");
                if (idx > 0)
                {
                    idx = AllText.IndexOf("<string>", idx);
                    if (idx > 0)
                    {
                        idx += "<string>".Length;
                        UUID = AllText.Substring(idx, AllText.IndexOf("</string>", idx) - idx);
                    }
                }

                CurrentBaseXCodeCommandLine += String.Format(" PROVISIONING_PROFILE=" + UUID);
            }
            else
            {
                CurrentBaseXCodeCommandLine += " DEVELOPMENT_TEAM=" + Config.TeamID + " CODE_SIGN_STYLE=\"Automatic\" -allowProvisioningUpdates";
            }

            // look for an entitlements file (optional)
            string SourceEntitlements = FileOperations.FindPrefixedFile(Config.BuildDirectory, Program.GameName + ".entitlements");

            // set where to make the entitlements file (
            string TargetEntitlements = Path.Combine(Config.PCXcodeStagingDir, Program.GameName + ".entitlements");

            if (File.Exists(SourceEntitlements))
            {
                FileOperations.CopyRequiredFile(SourceEntitlements, TargetEntitlements);
            }
            else
            {
                // we need to have something so Xcode will compile, so we just set the get-task-allow, since we know the value,
                // which is based on distribution or not (true means debuggable)
                File.WriteAllText(TargetEntitlements, string.Format("<plist><dict><key>get-task-allow</key><{0}/></dict></plist>",
                                                                    Config.bForDistribution ? "false" : "true"));
            }

            string ProjectFile = Config.RootRelativePath + @"Engine\Intermediate\ProjectFiles\UE4.xcodeproj\project.pbxproj";

            if (Program.GameName != "UE4Game")
            {
                ProjectFile = Path.GetDirectoryName(Config.IntermediateDirectory) + @"\ProjectFiles\" + Program.GameName + @".xcodeproj\project.pbxproj";
            }
            FileOperations.CopyRequiredFile(ProjectFile, Path.Combine(Config.PCXcodeStagingDir, @"project.pbxproj.datecheck"));

            // needs Mac line endings so it can be executed
            string SrcPath  = @"..\..\..\Build\" + Config.OSString + @"\XcodeSupportFiles\prepackage.sh";
            string DestPath = Path.Combine(Config.PCXcodeStagingDir, @"prepackage.sh");

            Program.Log(" ... '" + SrcPath + "' -> '" + DestPath + "'");
            string SHContents = File.ReadAllText(SrcPath);

            SHContents = SHContents.Replace("\r\n", "\n");
            File.WriteAllText(DestPath, SHContents);

            CookTime.CopySignedFiles();
        }
Esempio n. 14
0
        /// <summary>
        /// Finds all valid installed provisions
        /// </summary>
        public static void FindProvisions(string CFBundleIdentifier)
        {
            if (!Directory.Exists(Config.ProvisionDirectory))
            {
                Program.Error("Could not find provision directory '{0}'.", Config.ProvisionDirectory);
                Program.ReturnCode = (int)ErrorCodes.Error_ProvisionNotFound;
                return;
            }
            // cache the provision library
            string SelectedProvision = "";
            string SelectedCert      = "";
            string SelectedFile      = "";
            int    FoundName         = -1;

            Dictionary <string, MobileProvision> ProvisionLibrary = new Dictionary <string, MobileProvision>();

            foreach (string ProvisionFile in Directory.EnumerateFiles(Config.ProvisionDirectory, "*.mobileprovision"))
            {
                MobileProvision Provision = MobileProvisionParser.ParseFile(ProvisionFile);
                ProvisionLibrary.Add(ProvisionFile, Provision);
            }

            // first sort all profiles so we look at newer ones first.
            IEnumerable <string> ProfileKeys = ProvisionLibrary.Select(KV => KV.Key)
                                               .OrderByDescending(K => ProvisionLibrary[K].CreationDate)
                                               .ToArray();

            // note - all of this is a near duplicate of code in MobileProvisionUtilities, which other functions
            // in this class call to do similar work!
            // @todo - unify all of this.

            foreach (string ProvisionFile in ProfileKeys)
            {
                MobileProvision p = ProvisionLibrary[ProvisionFile];

                DateTime EffectiveDate  = p.CreationDate;
                DateTime ExpirationDate = p.ExpirationDate;
                DateTime Now            = DateTime.UtcNow;

                bool             bCertTimeIsValid = (EffectiveDate < Now) && (ExpirationDate > Now);
                bool             bValid           = false;
                X509Certificate2 Cert             = FindCertificate(p);
                if (Cert != null)
                {
                    bValid = (Cert.NotBefore.ToUniversalTime() < Now) && (Cert.NotAfter.ToUniversalTime() > Now);
                }
                bool bPassesNameCheck     = p.ApplicationIdentifier.Substring(p.ApplicationIdentifierPrefix.Length + 1) == CFBundleIdentifier;
                bool bPassesCompanyCheck  = false;
                bool bPassesWildCardCheck = false;
                if (p.ApplicationIdentifier.Contains("*"))
                {
                    string CompanyName = p.ApplicationIdentifier.Substring(p.ApplicationIdentifierPrefix.Length + 1);
                    if (CompanyName != "*")
                    {
                        CompanyName         = CompanyName.Substring(0, CompanyName.LastIndexOf("."));
                        bPassesCompanyCheck = CFBundleIdentifier.StartsWith(CompanyName);
                    }
                    else
                    {
                        bPassesWildCardCheck = true;
                    }
                }
                bool bIsManaged = false;
                if (p.ProvisionName == "iOS Team Provisioning Profile: " + CFBundleIdentifier)
                {
                    bIsManaged = true;
                }
                bool   bDistribution = ((p.ProvisionedDeviceIDs.Count == 0) && !p.bDebug);
                string Validity      = "VALID";
                if (!bCertTimeIsValid)
                {
                    Validity = "EXPIRED";
                }
                else if (!bValid)
                {
                    Validity = "NO_CERT";
                }
                else if (!bPassesNameCheck && !bPassesWildCardCheck && !bPassesCompanyCheck)
                {
                    Validity = "NO_MATCH";
                }
                if (bIsManaged)
                {
                    Validity = "MANAGED";
                }
                if ((string.IsNullOrWhiteSpace(SelectedProvision) || FoundName < 2) && Validity == "VALID" && !bDistribution)
                {
                    int Prev = FoundName;
                    if (bPassesNameCheck)
                    {
                        FoundName = 2;
                    }
                    else if (bPassesCompanyCheck && FoundName < 1)
                    {
                        FoundName = 1;
                    }
                    else if (bPassesWildCardCheck && FoundName == -1)
                    {
                        FoundName = 0;
                    }
                    if (FoundName != Prev)
                    {
                        SelectedProvision = p.ProvisionName;
                        SelectedFile      = Path.GetFileName(ProvisionFile);
                        SelectedCert      = CryptoAdapter.GetFriendlyNameFromCert(Cert);
                    }
                }
                Program.LogVerbose("PROVISION-File:{0},Name:{1},Validity:{2},StartDate:{3},EndDate:{4},Type:{5}", Path.GetFileName(ProvisionFile), p.ProvisionName, Validity, EffectiveDate.ToString(), ExpirationDate.ToString(), bDistribution ? "DISTRIBUTION" : "DEVELOPMENT");
            }

            Program.LogVerbose("MATCHED-Provision:{0},File:{1},Cert:{2}", SelectedProvision, SelectedFile, SelectedCert);
        }
Esempio n. 15
0
        /**
         * Using the stub IPA previously compiled on the Mac, create a new IPA with assets
         */
        static public void RepackageIPAFromStub()
        {
            if (string.IsNullOrEmpty(Config.RepackageStagingDirectory) || !Directory.Exists(Config.RepackageStagingDirectory))
            {
                Program.Error("Directory specified with -stagedir could not be found!");
                return;
            }


            DateTime             StartTime  = DateTime.Now;
            CodeSignatureBuilder CodeSigner = null;

            // Clean the staging directory
            Program.ExecuteCommand("Clean", null);

            // Create a copy of the IPA so as to not trash the original
            ZipFile Zip = SetupWorkIPA();

            if (Zip == null)
            {
                return;
            }

            string ZipWorkingDir = String.Format("Payload/{0}{1}.app/", Program.GameName, Program.Architecture);

            FileOperations.ZipFileSystem FileSystem = new FileOperations.ZipFileSystem(Zip, ZipWorkingDir);

            // Check for a staged plist that needs to be merged into the main one
            {
                // Determine if there is a staged one we should try to use instead
                string PossiblePList = Path.Combine(Config.RepackageStagingDirectory, "Info.plist");
                if (File.Exists(PossiblePList))
                {
                    if (Config.bPerformResignWhenRepackaging)
                    {
                        Program.Log("Found Info.plist ({0}) in stage, which will be merged in with stub plist contents", PossiblePList);

                        // Merge the two plists, using the staged one as the authority when they conflict
                        byte[] StagePListBytes = File.ReadAllBytes(PossiblePList);
                        string StageInfoString = Encoding.UTF8.GetString(StagePListBytes);

                        byte[] StubPListBytes          = FileSystem.ReadAllBytes("Info.plist");
                        Utilities.PListHelper StubInfo = new Utilities.PListHelper(Encoding.UTF8.GetString(StubPListBytes));

                        StubInfo.MergePlistIn(StageInfoString);

                        // Write it back to the cloned stub, where it will be used for all subsequent actions
                        byte[] MergedPListBytes = Encoding.UTF8.GetBytes(StubInfo.SaveToString());
                        FileSystem.WriteAllBytes("Info.plist", MergedPListBytes);
                    }
                    else
                    {
                        Program.Warning("Found Info.plist ({0}) in stage that will be ignored; IPP cannot combine it with the stub plist since -sign was not specified", PossiblePList);
                    }
                }
            }

            // Get the name of the executable file
            string CFBundleExecutable;

            {
                // Load the .plist from the stub
                byte[] RawInfoPList = FileSystem.ReadAllBytes("Info.plist");

                Utilities.PListHelper Info = new Utilities.PListHelper(Encoding.UTF8.GetString(RawInfoPList));

                // Get the name of the executable file
                if (!Info.GetString("CFBundleExecutable", out CFBundleExecutable))
                {
                    throw new InvalidDataException("Info.plist must contain the key CFBundleExecutable");
                }
            }

            // Tell the file system about the executable file name so that we can set correct attributes on
            // the file when zipping it up
            FileSystem.ExecutableFileName = CFBundleExecutable;

            // Prepare for signing if requested
            if (Config.bPerformResignWhenRepackaging)
            {
                // Start the resign process (load the mobileprovision and info.plist, find the cert, etc...)
                CodeSigner            = new CodeSignatureBuilder();
                CodeSigner.FileSystem = FileSystem;

                CodeSigner.PrepareForSigning();

                // Merge in any user overrides that exist
                UpdateVersion(CodeSigner.Info);
            }

            // Empty the current staging directory
            FileOperations.DeleteDirectory(new DirectoryInfo(Config.PCStagingRootDir));

            // we will zip files in the pre-staged payload dir
            string ZipSourceDir = Config.RepackageStagingDirectory;

            // Save the zip
            Program.Log("Saving IPA ...");

            FilesBeingModifiedToPrintOut.Clear();
            Zip.SaveProgress += UpdateSaveProgress;

            Zip.CompressionLevel = (Ionic.Zlib.CompressionLevel)Config.RecompressionSetting;

            // Add all of the payload files, replacing existing files in the stub IPA if necessary (should only occur for icons)
            {
                string   SourceDir    = Path.GetFullPath(ZipSourceDir);
                string[] PayloadFiles = Directory.GetFiles(SourceDir, "*.*", SearchOption.AllDirectories);
                foreach (string Filename in PayloadFiles)
                {
                    // Get the relative path to the file (this implementation only works because we know the files are all
                    // deeper than the base dir, since they were generated from a search)
                    string AbsoluteFilename = Path.GetFullPath(Filename);
                    string RelativeFilename = AbsoluteFilename.Substring(SourceDir.Length + 1).Replace('\\', '/');

                    string ZipAbsolutePath = String.Format("Payload/{0}{1}.app/{1}",
                                                           Program.GameName,
                                                           Program.Architecture,
                                                           RelativeFilename);

                    byte[] FileContents = File.ReadAllBytes(AbsoluteFilename);
                    if (FileContents.Length == 0)
                    {
                        // Zero-length files added by Ionic cause installation/upgrade to fail on device with error 0xE8000050
                        // We store a single byte in the files as a workaround for now
                        FileContents    = new byte[1];
                        FileContents[0] = 0;
                    }

                    FileSystem.WriteAllBytes(RelativeFilename, FileContents);

                    if ((FileContents.Length >= 1024 * 1024) || (Config.bVerbose))
                    {
                        FilesBeingModifiedToPrintOut.Add(ZipAbsolutePath);
                    }
                }
            }

            // Re-sign the executable if there is a signing context
            if (CodeSigner != null)
            {
                if (Config.OverrideBundleName != null)
                {
                    CodeSigner.Info.SetString("CFBundleDisplayName", Config.OverrideBundleName);
                    string CFBundleIdentifier;
                    if (CodeSigner.Info.GetString("CFBundleIdentifier", out CFBundleIdentifier))
                    {
                        CodeSigner.Info.SetString("CFBundleIdentifier", CFBundleIdentifier + "_" + Config.OverrideBundleName);
                    }
                }
                CodeSigner.PerformSigning();
            }

            // Stick in the iTunesArtwork PNG if available
            string iTunesArtworkPath = Path.Combine(Config.BuildDirectory, "iTunesArtwork");

            if (File.Exists(iTunesArtworkPath))
            {
                Zip.UpdateFile(iTunesArtworkPath, "");
            }

            // Save the Zip

            Program.Log("Compressing files into IPA (-compress={1}).{0}", Config.bVerbose ? "" : "  Only large files will be listed next, but other files are also being packaged.", Config.RecompressionSetting);
            FileSystem.Close();

            TimeSpan ZipLength = DateTime.Now - StartTime;

            FileInfo FinalZipInfo = new FileInfo(Zip.Name);


            Program.Log(String.Format("Finished repackaging into {2:0.00} MB IPA, written to '{0}' (took {1:0.00} s for all steps)",
                                      Zip.Name,
                                      ZipLength.TotalSeconds,
                                      FinalZipInfo.Length / (1024.0f * 1024.0f)));
        }
Esempio n. 16
0
		/**
		 * Copy a single file (deleting the existing file at the destination if it exists)
		 */
		static public bool CopyFile(FileInfo SourceFileInfo, string DestFileName, bool bCopyMustSucceed, int MaxRetryCount)
		{
			int CopyTryCount = 0;
			bool bFileCopiedSuccessfully = false;

			// if the file doesn't exist, but isn't needed, then just early out
			if (!bCopyMustSucceed && !SourceFileInfo.Exists)
			{
				return false;
			}

			if (Config.bVerbose)
			{
				Program.Log(String.Format("      Copy: {0} -> {1}, last modified at {2}", SourceFileInfo.FullName, DestFileName, SourceFileInfo.LastWriteTime));
			}

			do
			{
				// If this isn't the first time through, sleep a little before trying again
				if (CopyTryCount > 0)
				{
					Thread.Sleep(1000);
				}

				CopyTryCount++;

				try
				{
					// Delete the destination file if it exists
					FileInfo DestInfo = new FileInfo(DestFileName);
					if (DestInfo.Exists)
					{
						DestInfo.IsReadOnly = false;
						DestInfo.Delete();
					}

					Directory.CreateDirectory(Path.GetDirectoryName(DestFileName));

					// Copy over the new file
					SourceFileInfo.CopyTo(DestFileName);

					// Make sure the destination file is writable
					DestInfo = new FileInfo(DestFileName);
					DestInfo.IsReadOnly = false;
					DestInfo.LastWriteTime = SourceFileInfo.LastWriteTime;

					// Sanity check
					if (DestInfo.Length != SourceFileInfo.Length)
					{
						throw new Exception("Error: File copy failed (source and destination are different sizes)");
					}

					// Success!
					bFileCopiedSuccessfully = true;
				}
				catch( Exception Ex )
				{
					Program.Warning("Failed to copy file to '" + DestFileName + "'");
					Program.Warning("    Exception: " + Ex.Message + " (going to retry copy)");
				}
			}
			while (!bFileCopiedSuccessfully && (CopyTryCount < MaxRetryCount));

			if (!bFileCopiedSuccessfully)
			{
				string Msg = "Failed to copy file to " + DestFileName + " and there are no more retries!";
				if (bCopyMustSucceed)
				{
					Program.Error(Msg);
					Program.ReturnCode = (int)ErrorCodes.Error_CopyFile;
				}
				else
				{
					Program.Warning(Msg);
				}
			}

			return bFileCopiedSuccessfully;
		}
Esempio n. 17
0
        /**
         * Handle spawning of the RPCUtility with parameters
         */
        public static bool RunRPCUtilty(string RPCCommand, bool bIsSilent = false)
        {
            string     CommandLine        = "";
            string     WorkingFolder      = "";
            string     DisplayCommandLine = "";
            string     TempKeychain       = "$HOME/Library/Keychains/UE4TempKeychain.keychain";
            string     Certificate        = "XcodeSupportFiles/" + MacSigningIdentityFilename;
            string     LoginKeychain      = "$HOME/Library/Keychains/login.keychain";
            ErrorCodes Error = ErrorCodes.Error_Unknown;

            switch (RPCCommand.ToLowerInvariant())
            {
            case "deletemacstagingfiles":
                Program.Log(" ... deleting staging files on the Mac");
                DisplayCommandLine = "rm -rf Payload";
                CommandLine        = "\"" + MacStagingRootDir + "\" " + DisplayCommandLine;
                WorkingFolder      = "\"" + MacStagingRootDir + "\"";
                break;

            case "ensureprovisiondirexists":
                Program.Log(" ... creating provisioning profiles directory");

                DisplayCommandLine = String.Format("mkdir -p ~/Library/MobileDevice/Provisioning\\ Profiles");

                CommandLine   = "\"" + MacXcodeStagingDir + "\" " + DisplayCommandLine;
                WorkingFolder = "\"" + MacXcodeStagingDir + "\"";
                break;

            case "installprovision":
                // Note: The provision must have already been copied over to the Mac
                Program.Log(" ... installing .mobileprovision");

                DisplayCommandLine = String.Format("cp -f {0} ~/Library/MobileDevice/Provisioning\\ Profiles", MacMobileProvisionFilename);

                CommandLine   = "\"" + MacXcodeStagingDir + "\" " + DisplayCommandLine;
                WorkingFolder = "\"" + MacXcodeStagingDir + "\"";
                break;

            case "removeprovision":
                Program.Log(" ... removing .mobileprovision");
                DisplayCommandLine = String.Format("rm -f ~/Library/MobileDevice/Provisioning\\ Profiles/{0}", MacMobileProvisionFilename);
                CommandLine        = "\"" + MacXcodeStagingDir + "\" " + DisplayCommandLine;
                WorkingFolder      = "\"" + MacXcodeStagingDir + "\"";
                break;

            case "setexec":
                // Note: The executable must have already been copied over
                Program.Log(" ... setting executable bit");
                DisplayCommandLine = "chmod a+x \'" + RemoteExecutablePath + "\'";
                CommandLine        = "\"" + MacStagingRootDir + "\" " + DisplayCommandLine;
                WorkingFolder      = "\"" + MacStagingRootDir + "\"";
                break;

            case "prepackage":
                Program.Log(" ... running prepackage script remotely ");
                DisplayCommandLine = String.Format("sh prepackage.sh {0} " + Config.OSString + " {1} {2}", Program.GameName, Program.GameConfiguration, Program.Architecture);
                CommandLine        = "\"" + MacXcodeStagingDir + "\" " + DisplayCommandLine;
                WorkingFolder      = "\"" + MacXcodeStagingDir + "\"";
                break;

            case "makeapp":
                Program.Log(" ... making application (codesign, etc...)");
                Program.Log("  Using signing identity '{0}'", Config.CodeSigningIdentity);
                DisplayCommandLine = "security -v unlock-keychain -p \"A\" \"" + TempKeychain + "\" && " + CurrentBaseXCodeCommandLine;
                CommandLine        = "\"" + MacXcodeStagingDir + "/..\" " + DisplayCommandLine;
                WorkingFolder      = "\"" + MacXcodeStagingDir + "/..\"";
                Error = ErrorCodes.Error_RemoteCertificatesNotFound;
                break;

            case "createkeychain":
                Program.Log(" ... creating temporary key chain with signing certificate");
                Program.Log("  Using signing identity '{0}'", Config.CodeSigningIdentity);
                DisplayCommandLine = "security create-keychain -p \"A\" \"" + TempKeychain + "\" && security list-keychains -s \"" + TempKeychain + "\" && security list-keychains && security set-keychain-settings -t 3600 -l  \"" + TempKeychain + "\" && security -v unlock-keychain -p \"A\" \"" + TempKeychain + "\" && security import " + Certificate + " -k \"" + TempKeychain + "\" -P \"A\" -T /usr/bin/codesign -T /usr/bin/security -t agg && CERT_IDENTITY=$(security find-identity -v -p codesigning \"" + TempKeychain + "\" | head -1 | grep '\"' | sed -e 's/[^\"]*\"//' -e 's/\".*//') && security default-keychain -s \"" + TempKeychain + "\" && security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k \"A\" -D \"$CERT_IDENTITY\" -t private " + TempKeychain;
                CommandLine        = "\"" + MacXcodeStagingDir + "/..\" " + DisplayCommandLine;
                WorkingFolder      = "\"" + MacXcodeStagingDir + "/..\"";
                break;

            case "deletekeychain":
                Program.Log(" ... remove temporary key chain");
                Program.Log("  Using signing identity '{0}'", Config.CodeSigningIdentity);
                DisplayCommandLine = "security list-keychains -s \"" + LoginKeychain + "\" && security delete-keychain \"" + TempKeychain + "\"";
                CommandLine        = "\"" + MacXcodeStagingDir + "/..\" " + DisplayCommandLine;
                WorkingFolder      = "\"" + MacXcodeStagingDir + "/..\"";
                break;

            case "validation":
                Program.Log(" ... validating distribution package");
                DisplayCommandLine = XcodeDeveloperDir + "Platforms/iPhoneOS.platform/Developer/usr/bin/Validation " + RemoteAppDirectory;
                CommandLine        = "\"" + MacStagingRootDir + "\" " + DisplayCommandLine;
                WorkingFolder      = "\"" + MacStagingRootDir + "\"";
                break;

            case "deleteipa":
                Program.Log(" ... deleting IPA on Mac");
                DisplayCommandLine = "rm -f " + Config.IPAFilenameOnMac;
                CommandLine        = "\"" + MacStagingRootDir + "\" " + DisplayCommandLine;
                WorkingFolder      = "\"" + MacStagingRootDir + "\"";
                break;

            case "kill":
                Program.Log(" ... killing");
                DisplayCommandLine = "killall " + Program.GameName;
                CommandLine        = ". " + DisplayCommandLine;
                WorkingFolder      = ".";
                break;

            case "strip":
                Program.Log(" ... stripping");
                DisplayCommandLine = "/usr/bin/xcrun strip '" + RemoteExecutablePath + "'";
                CommandLine        = "\"" + MacStagingRootDir + "\" " + DisplayCommandLine;
                WorkingFolder      = "\"" + MacStagingRootDir + "\"";
                break;

            case "resign":
                Program.Log("... resigning");
                DisplayCommandLine = "bash -c '" + "chmod a+x ResignScript" + ";" + "./ResignScript" + "'";
                CommandLine        = "\"" + MacStagingRootDir + "\" " + DisplayCommandLine;
                WorkingFolder      = "\"" + MacStagingRootDir + "\"";
                break;

            case "zip":
                Program.Log(" ... zipping");

                // NOTE: -y preserves symbolic links which is needed for iOS distro builds
                // -x excludes a file (excluding the dSYM keeps sizes smaller, and it shouldn't be in the IPA anyways)
                string dSYMName = "Payload/" + Program.GameName + Program.Architecture + ".app.dSYM";
                DisplayCommandLine = String.Format("zip -q -r -y -{0} -T {1} Payload iTunesArtwork -x {2}/ -x {2}/* " +
                                                   "-x {2}/Contents/ -x {2}/Contents/* -x {2}/Contents/Resources/ -x {2}/Contents/Resources/* " +
                                                   " -x {2}/Contents/Resources/DWARF/ -x {2}/Contents/Resources/DWARF/*",
                                                   (int)Config.RecompressionSetting,
                                                   Config.IPAFilenameOnMac,
                                                   dSYMName);

                CommandLine   = "\"" + MacStagingRootDir + "\" " + DisplayCommandLine;
                WorkingFolder = "\"" + MacStagingRootDir + "\"";
                break;

            case "gendsym":
                Program.Log(" ... generating DSYM");

                string ExePath  = "Payload/" + Program.GameName + ".app/" + Program.GameName;
                string dSYMPath = Program.GameName + ".app.dSYM";
                DisplayCommandLine = String.Format("dsymutil -o {0} {1}", dSYMPath, ExePath);

                CommandLine   = "\"" + MacStagingRootDir + "\"" + DisplayCommandLine;
                WorkingFolder = "\"" + MacStagingRootDir + "\"";
                break;

            default:
                Program.Error("Unrecognized RPC command");
                return(false);
            }

            Program.Log(" ... working folder: " + WorkingFolder);
            Program.Log(" ... " + DisplayCommandLine);
            Program.Log(" ... full command: " + MacName + " " + CommandLine);

            bool bSuccess = false;

            if (Config.bUseRPCUtil)
            {
                Program.Log("Running RPC on " + MacName + " ... ");

                Process RPCUtil = new Process();
                RPCUtil.StartInfo.FileName               = @"..\RPCUtility.exe";
                RPCUtil.StartInfo.UseShellExecute        = false;
                RPCUtil.StartInfo.Arguments              = MacName + " " + CommandLine;
                RPCUtil.StartInfo.RedirectStandardOutput = true;
                RPCUtil.StartInfo.RedirectStandardError  = true;
                RPCUtil.OutputDataReceived              += new DataReceivedEventHandler(OutputReceivedRemoteProcessCall);
                RPCUtil.ErrorDataReceived += new DataReceivedEventHandler(OutputReceivedRemoteProcessCall);

                RPCUtil.Start();

                RPCUtil.BeginOutputReadLine();
                RPCUtil.BeginErrorReadLine();

                RPCUtil.WaitForExit();

                bSuccess = (RPCUtil.ExitCode == 0);
                if (bSuccess == false && !bIsSilent)
                {
                    Program.Error("RPCCommand {0} failed with return code {1}", RPCCommand, RPCUtil.ExitCode);
                    switch (RPCCommand.ToLowerInvariant())
                    {
                    case "installprovision":
                        Program.Error("Ensure your access permissions for '~/Library/MobileDevice/Provisioning Profiles' are set correctly.");
                        break;

                    default:
                        break;
                    }
                }
            }
            else
            {
                Program.Log("Running SSH on " + MacName + " ... ");
                bSuccess = SSHCommandHelper.Command(MacName, DisplayCommandLine, WorkingFolder);
                if (bSuccess == false && !bIsSilent)
                {
                    Program.Error("RPCCommand {0} failed with return code {1}", RPCCommand, Error);
                    Program.ReturnCode = (int)Error;
                }
            }


            return(bSuccess);
        }
Esempio n. 18
0
        public static void TryInstallingCertificate_PromptForKey()
        {
            try
            {
                string CertificateFilename;
                if (ShowOpenFileDialog(CertificatesFilter, "Choose a code signing certificate to import", "", "", ref ChoosingFilesToInstallDirectory, out CertificateFilename))
                {
                    // Load the certificate
                    string           CertificatePassword = "";
                    X509Certificate2 Cert = null;
                    try
                    {
                        Cert = new X509Certificate2(CertificateFilename, CertificatePassword, X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet);
                    }
                    catch (System.Security.Cryptography.CryptographicException ex)
                    {
                        // Try once with a password
                        if (PasswordDialog.RequestPassword(out CertificatePassword))
                        {
                            Cert = new X509Certificate2(CertificateFilename, CertificatePassword, X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet);
                        }
                        else
                        {
                            // User cancelled dialog, rethrow
                            throw ex;
                        }
                    }

                    // If the certificate doesn't have a private key pair, ask the user to provide one
                    if (!Cert.HasPrivateKey)
                    {
                        string ErrorMsg = "Certificate does not include a private key and cannot be used to code sign";

                        // Prompt for a key pair
                        if (MessageBox.Show("Next, please choose the key pair that you made when generating the certificate request.",
                                            Config.AppDisplayName,
                                            MessageBoxButtons.OK,
                                            MessageBoxIcon.Information) == DialogResult.OK)
                        {
                            string KeyFilename;
                            if (ShowOpenFileDialog(KeysFilter, "Choose the key pair that belongs with the signing certificate", "", "", ref ChoosingFilesToInstallDirectory, out KeyFilename))
                            {
                                Cert = CryptoAdapter.CombineKeyAndCert(CertificateFilename, KeyFilename);

                                if (Cert.HasPrivateKey)
                                {
                                    ErrorMsg = null;
                                }
                            }
                        }

                        if (ErrorMsg != null)
                        {
                            throw new Exception(ErrorMsg);
                        }
                    }

                    // Add the certificate to the store
                    X509Store Store = new X509Store();
                    Store.Open(OpenFlags.ReadWrite);
                    Store.Add(Cert);
                    Store.Close();
                }
            }
            catch (Exception ex)
            {
                string ErrorMsg = String.Format("Failed to load or install certificate due to an error: '{0}'", ex.Message);
                Program.Error(ErrorMsg);
                MessageBox.Show(ErrorMsg, Config.AppDisplayName, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }