/// <summary> /// Create a signed package /// </summary> private static AppletPackage CreateSignedPackage(AppletManifest mfst, ConsoleParameters parameters) { try { if (String.IsNullOrEmpty(parameters.SignPassword)) { using (var frmKey = new frmKeyPassword(parameters.SignKey)) if (frmKey.ShowDialog() == DialogResult.OK) { parameters.SignPassword = frmKey.Password; } } else if (File.Exists(parameters.SignPassword)) { parameters.SignPassword = File.ReadAllText(parameters.SignPassword); } X509Certificate2 signCert = new X509Certificate2(parameters.SignKey, parameters.SignPassword); mfst.Info.PublicKeyToken = signCert.Thumbprint; var retVal = mfst.CreatePackage(parameters.Compression); retVal.Meta.Hash = SHA256.Create().ComputeHash(retVal.Manifest); retVal.Meta.PublicKeyToken = signCert.Thumbprint; if (parameters.EmbedCertificate) { retVal.PublicKey = signCert.Export(X509ContentType.Cert); } if (!signCert.HasPrivateKey) { throw new SecurityException($"Provided key {parameters.SignKey} has no private key"); } RSACryptoServiceProvider rsa = signCert.PrivateKey as RSACryptoServiceProvider; retVal.Meta.Signature = rsa.SignData(retVal.Manifest, CryptoConfig.MapNameToOID("SHA1")); return(retVal); } catch (Exception e) { Console.WriteLine("Error signing package: {0}", e); return(null); } }
/// <summary> /// Create a signed package /// </summary> public AppletPackage CreateSignedPackage(AppletManifest mfst) { try { X509Certificate2 signCert = this.GetSigningCert(); if (!signCert.HasPrivateKey) { throw new InvalidOperationException($"You do not have the private key for certificiate {signCert.Subject}"); } mfst.Info.TimeStamp = DateTime.Now; // timestamp mfst.Info.PublicKeyToken = signCert.Thumbprint; var retVal = mfst.CreatePackage(); retVal.Meta.Hash = SHA256.Create().ComputeHash(retVal.Manifest); retVal.Meta.PublicKeyToken = signCert.Thumbprint; if (this.m_parms.EmbedCertificate) { retVal.PublicKey = signCert.Export(X509ContentType.Cert); } if (!signCert.HasPrivateKey) { throw new SecurityException($"Provided key {this.m_parms.SignKeyFile} has no private key"); } RSACryptoServiceProvider rsa = signCert.PrivateKey as RSACryptoServiceProvider; retVal.Meta.Signature = rsa.SignData(retVal.Manifest, CryptoConfig.MapNameToOID("SHA1")); return(retVal); } catch (Exception e) { Emit.Message("ERROR", "Error signing package: {0}", e); return(null); } }
/// <summary> /// Compile /// </summary> static int Compile(ConsoleParameters parameters) { int retVal = 0; // First is there a Manifest.xml? if (!Path.IsPathRooted(parameters.Source)) { parameters.Source = Path.Combine(Environment.CurrentDirectory, parameters.Source); } // Applet collection AppletCollection ac = new AppletCollection(); XmlSerializer xsz = new XmlSerializer(typeof(AppletManifest)); XmlSerializer xpz = new XmlSerializer(typeof(AppletPackage)); if (parameters.References != null) { foreach (var itm in parameters.References) { if (File.Exists(itm)) { using (var fs = File.OpenRead(itm)) { if (Path.GetExtension(itm) == ".pak") { using (var gzs = new GZipStream(fs, CompressionMode.Decompress)) { var pack = xpz.Deserialize(gzs) as AppletPackage; var mfst = pack.Unpack(); mfst.Initialize(); ac.Add(mfst); Console.WriteLine("Added reference to {0}; v={1}", mfst.Info.Id, mfst.Info.Version); } } else { var mfst = xsz.Deserialize(fs) as AppletManifest; mfst.Initialize(); ac.Add(mfst); Console.WriteLine("Added reference to {0}; v={1}", mfst.Info.Id, mfst.Info.Version); } } } } } Console.WriteLine("Processing {0}...", parameters.Source); String manifestFile = Path.Combine(parameters.Source, "manifest.xml"); if (!File.Exists(manifestFile)) { Console.WriteLine("Directory must have manifest.xml"); } else { Console.WriteLine("\t Reading Manifest...", parameters.Source); using (var fs = File.OpenRead(manifestFile)) { AppletManifest mfst = xsz.Deserialize(fs) as AppletManifest; mfst.Assets.AddRange(ProcessDirectory(parameters.Source, parameters.Source, parameters)); foreach (var i in mfst.Assets) { i.Name = i.Name.Substring(1); } if (mfst.Info.Version.Contains("*")) { mfst.Info.Version = mfst.Info.Version.Replace("*", (((DateTime.Now.Subtract(new DateTime(DateTime.Now.Year, 1, 1)).Ticks >> 24) % 10000)).ToString("0000")); } if (!Directory.Exists(Path.GetDirectoryName(parameters.Output)) && !String.IsNullOrEmpty(Path.GetDirectoryName(parameters.Output))) { Directory.CreateDirectory(Path.GetDirectoryName(parameters.Output)); } AppletPackage pkg = null; // Is there a signature? if (!String.IsNullOrEmpty(parameters.SignKey)) { pkg = CreateSignedPackage(mfst, parameters); if (pkg == null) { return(-102); } } else { Console.WriteLine("WARNING:>>> THIS PACKAGE IS NOT SIGNED - MOST OPEN IZ TOOLS WILL NOT LOAD IT"); mfst.Info.PublicKeyToken = null; pkg = mfst.CreatePackage(parameters.Compression); //pkg.Meta.PublicKeyToken = null; } pkg.Meta.Hash = SHA256.Create().ComputeHash(pkg.Manifest); using (var ofs = File.Create(Path.ChangeExtension(parameters.Output ?? "out.pak", ".pak"))) { pkg.Save(ofs); } // Render the build directory if (!String.IsNullOrEmpty(parameters.Deploy)) { var bindir = Path.Combine(Path.GetDirectoryName(parameters.Output), "bin"); if (String.IsNullOrEmpty(parameters.Deploy)) { if (Directory.Exists(bindir) && parameters.Clean) { Directory.Delete(bindir, true); } bindir = Path.Combine(bindir, mfst.Info.Id); Directory.CreateDirectory(bindir); } else { bindir = parameters.Deploy; } mfst.Initialize(); ac.Add(mfst); foreach (var lang in mfst.Strings) { string wd = Path.Combine(bindir, lang.Language); if (String.IsNullOrEmpty(parameters.Lang)) { Directory.CreateDirectory(wd); } else if (parameters.Lang == lang.Language) { wd = bindir; } else { continue; } foreach (var m in ac) { foreach (var itm in m.Assets) { try { String fn = Path.Combine(wd, m.Info.Id, itm.Name.Replace("/", "\\")); Console.WriteLine("\tRendering {0}...", fn); if (!Directory.Exists(Path.GetDirectoryName(fn))) { Directory.CreateDirectory(Path.GetDirectoryName(fn)); } File.WriteAllBytes(fn, ac.RenderAssetContent(itm, lang.Language)); } catch (Exception e) { Console.WriteLine("E: {0}: {1} {2}", itm, e.GetType().Name, e); retVal = -1000; } } } } } } } return(retVal); }
/// <summary> /// Compose multiple PAK files into a solution /// </summary> public int Compose() { try { AppletManifest mfst = null; using (FileStream fs = File.OpenRead(this.m_parms.Source)) mfst = AppletManifest.Load(fs); var slnPak = mfst.CreatePackage(); AppletSolution sln = new AppletSolution(); sln.Meta = slnPak.Meta; sln.PublicKey = slnPak.PublicKey; sln.Manifest = slnPak.Manifest; if (sln.Meta.Uuid == Guid.Empty) { Emit.Message("WARN", "The package does not carry a UUID! You should add a UUID to your solution manifest"); } sln.Include = new List <AppletPackage>(); foreach (var pfile in sln.Meta.Dependencies.ToArray()) { AppletPackage pkg = null; if (!String.IsNullOrEmpty(pfile.Version)) // specific version { pkg = PackageRepositoryUtil.GetFromAny(pfile.Id, new Version(pfile.Version)); } else if (!String.IsNullOrEmpty(m_parms.Version)) { pkg = PackageRepositoryUtil.GetFromAny(pfile.Id, new Version(m_parms.Version)) ?? PackageRepositoryUtil.GetFromAny(pfile.Id, null); } else { pkg = PackageRepositoryUtil.GetFromAny(pfile.Id, null); } if (pkg == null) { throw new KeyNotFoundException($"Package {pfile.Id} ({pfile.Version ?? m_parms.Version ?? "latest"}) not found"); } else { Emit.Message("INFO", "Including {0} version {1}..", pkg.Meta.Id, pkg.Meta.Version); sln.Meta.Dependencies.RemoveAll(o => o.Id == pkg.Meta.Id); if (this.m_parms.Sign && pkg.Meta.Signature == null) { Emit.Message("WARN", "Package {0} is not signed, but you're signing your package. We'll sign it using your key", pkg.Meta.Id); pkg = new Signer(this.m_parms).CreateSignedPackage(pkg.Unpack()); } sln.Include.Add(pkg); } } // Emit i18n file? if (!String.IsNullOrEmpty(this.m_parms.InternationalizationFile)) { Emit.Message("INFO", $"Writing string manifest to {this.m_parms.InternationalizationFile}"); using (var fs = File.Create(this.m_parms.InternationalizationFile)) using (var tw = new StreamWriter(fs, System.Text.Encoding.UTF8)) { // tx translations var mfsts = sln.Include.Select(o => o.Unpack()).ToList(); var appletStrings = mfsts.SelectMany(o => o.Strings).ToArray(); var stringKeys = appletStrings.SelectMany(o => o.String).Select(o => o.Key).Distinct(); var langs = appletStrings.Select(o => o.Language).Distinct().ToArray(); tw.Write("key,"); tw.WriteLine(String.Join(",", langs)); foreach (var str in stringKeys) { tw.Write($"{str},"); foreach (var lang in langs) { tw.Write($"\"{appletStrings.Where(o => o.Language == lang).SelectMany(s => s.String).FirstOrDefault(o => o.Key == str)?.Value}\","); } tw.WriteLine(); } } } sln.Meta.Hash = SHA256.Create().ComputeHash(sln.Include.SelectMany(o => o.Manifest).ToArray()); // Sign the signature package if (this.m_parms.Sign) { new Signer(this.m_parms).CreateSignedSolution(sln); } // Now save using (FileStream fs = File.Create(this.m_parms.Output ?? Path.ChangeExtension(sln.Meta.Id, ".sln.pak"))) sln.Save(fs); return(0); } catch (System.Exception e) { Emit.Message("ERROR", e.Message); //Console.Error.WriteLine("Cannot compose solution {0}: {1}", this.m_parms.Source, e); return(-1); } }
/// <summary> /// Compile /// </summary> public int Compile() { int retVal = 0; // First is there a Manifest.xml? if (!Path.IsPathRooted(this.m_parms.Source)) { this.m_parms.Source = Path.Combine(Environment.CurrentDirectory, this.m_parms.Source); } Console.WriteLine("Processing {0}...", this.m_parms.Source); String manifestFile = this.m_parms.Source; if (!File.Exists(manifestFile) && Directory.Exists(manifestFile)) { manifestFile = Path.Combine(this.m_parms.Source, "manifest.xml"); } if (!File.Exists(manifestFile)) { throw new InvalidOperationException($"Directory {this.m_parms.Source} must have manifest.xml"); } else { Console.WriteLine("\t Reading Manifest...", manifestFile); using (var fs = File.OpenRead(manifestFile)) { AppletManifest mfst = AppletManifest.Load(fs); mfst.Assets.AddRange(this.ProcessDirectory(Path.GetDirectoryName(manifestFile), Path.GetDirectoryName(manifestFile))); foreach (var i in mfst.Assets) { if (i.Name.StartsWith("/")) { i.Name = i.Name.Substring(1); } } if (!string.IsNullOrEmpty(this.m_parms.Version)) { mfst.Info.Version = this.m_parms.Version; } mfst.Info.Version = PakManTool.ApplyVersion(mfst.Info.Version); if (!Directory.Exists(Path.GetDirectoryName(this.m_parms.Output)) && !String.IsNullOrEmpty(Path.GetDirectoryName(this.m_parms.Output))) { Directory.CreateDirectory(Path.GetDirectoryName(this.m_parms.Output)); } AppletPackage pkg = null; // Is there a signature? if (this.m_parms.Sign) { pkg = new Signer(this.m_parms).CreateSignedPackage(mfst); if (pkg == null) { return(-102); } } else { Emit.Message("WARN", "THIS PACKAGE IS NOT SIGNED - MOST OPEN IZ TOOLS WILL NOT LOAD IT"); mfst.Info.PublicKeyToken = null; pkg = mfst.CreatePackage(); //pkg.Meta.PublicKeyToken = null; } pkg.Meta.Hash = SHA256.Create().ComputeHash(pkg.Manifest); var outFile = this.m_parms.Output ?? mfst.Info.Id + ".pak"; using (var ofs = File.Create(outFile)) pkg.Save(ofs); if (this.m_parms.Install) { Emit.Message("INFO", "INSTALLING PACKAGE {0}", pkg.Meta.Id); PackageRepositoryUtil.InstallCache(pkg); } if (this.m_parms.Publish) { try { Emit.Message("INFO", "PUBLISHING PACKAGE TO {0}", this.m_parms.PublishServer); PackageRepositoryUtil.Publish(this.m_parms.PublishServer, pkg); } catch (Exception e) { Emit.Message("ERROR", "ERROR PUBLISHING PACKAGE - {0}", e.Message); } } } } return(retVal); }