RubyGems
SharpZipLib
Our great sponsors
RubyGems | SharpZipLib | |
---|---|---|
25 | 5 | |
2,291 | 3,591 | |
2.2% | 0.8% | |
9.8 | 5.1 | |
1 day ago | 5 months ago | |
Ruby | C# | |
MIT License | MIT License |
Stars - the number of stars that a project has on GitHub. Growth - month over month growth in stars.
Activity is a relative number indicating how actively a project is being developed. Recent commits have higher weight than older ones.
For example, an activity of 9.0 indicates that a project is amongst the top 10% of the most actively developed projects that we are tracking.
RubyGems
-
Phlex is the ruby way to build your views
However, let's examine a typical partial, such as the one from the . rubygems.org search show page
- Chrome considers gems to be dangerous?
-
OOP vs. services for organizing business logic: is there a third way?
github.com/rubygems/rubygems.org (26k lines): Where Ruby gems are hosted.
-
RubyGems now requires MFA for owners of top gems
If anyone is looking to do some open source contributions on a mature, production Ruby on Rails site, I highly recommend contributing to the rubygems.org project. The code is extremely clean and the repo is very, very well run.
-
Making popular Ruby packages more secure
In fact, you can now scope API tokens per-gem as well: https://github.com/rubygems/rubygems.org/pull/2944
RubyGems does have gem signing, but it's not widely used.
There's a proposal for a new "one button" approach using sigstore[0].
Other ecosystems are also looking at sigstore too, and a lot of us are cooperating in the OpenSSF Securing Software Repos WG [1]. Package signing is a regular topic of discussion and there are various efforts underway.
Disclosure: I am involved with both of these.
-
Unauthorized gem takeover for some gems
SSH is such a different use case that the analogies break down. With respect, thinking about this for a few minutes should convince you that while TOFU works fine for immutable artifact signatures, it is unworkable for a system where you ever upgrade packages.
Consider that most nontrivial projects on rubygems have multiple maintainers that can publish a version. Normal collaboration models would imply that they each have a personal signing key; sharing a single signing key per project isn’t realistic (as you mentioned, rotation is another reason for this). And TOFU doesn’t work when there are multiple possible keys, such a system requires an external trust chain.
Assume for the sake of argument the above is solved. What exactly do you do when tooling alerts you that an upgraded dependency has changed keys since the last publish? Either you blindly accept the new key or you investigate. If the latter hopefully you have a way to directly contact the author to verify that the rotation was legitimate. Since you probably don’t you should just compare the diff of the published artifacts. But you should have been doing this anyway, so what has the signature bought you here except false security?
I’m all for pragmatic solutions that measurably improve security. I just think changes like https://github.com/rubygems/rubygems.org/pull/2499 and https://github.com/rubygems/rubygems.org/pull/2242 qualify to a much greater extent than thinking of crypto as magic dust that can be sprinkled on a system to increase its security.
This test seems to be a good example of the vulnerability: https://github.com/rubygems/rubygems.org/commit/58c755a7a62a...
-
Ask HN: How many 2FA tokens do you have?
See https://github.com/rubygems/rubygems.org/pull/2865 for the web part
> From the replies it sounds like this is talking about client software?
Yes the command line is a client to the rubygems server
> An unattended client should not be able to do WebAuthn as the whole point is that a human is present and authorising the authentication step
You either need a PIN, a fingerprint, a press, or no action just owning the device or the software.
> if I have 100% full of Bob's device I still can't touch the sensor or button to authenticate as Bob.
If you have a perfect copy of a Yubikey or the same fingerprint you should be able to authenticate I think
> OpenSSH works with Yubikeys
Nice, I will look into it
SharpZipLib
-
Best practice to generate ZIP file for client side download?
public class DownloadStreamedZippedFilesActionResult : FileResult { private const int Zip64CentralDirectoryRecordSize = 56; private const int Zip64CentralDirectoryLocatorSize = 20; /// /// This was obtained by debugging DotNetZip. It might change in newer versions of the library. The size is hardcoded with no constant available, not even a private one. /// private const int DotNetZipLocalFileHeaderExtraFieldLength = 20; private const int DotNetZipCentralDirectoryHeaderExtraFieldLength = 32; private const string ZipExtension = ".zip"; private static readonly ILogger Logger = ApplicationLogging.CreateLogger(); private readonly IReadOnlyCollection files; private readonly CancellationToken cancellationToken; public DownloadStreamedZippedFilesActionResult(string fileName, IEnumerable files, CancellationToken cancellationToken) : base(MediaTypeConverter.GetMimeType(ZipExtension)) { this.files = files.ToArray(); FileDownloadName = fileName + ZipExtension; this.cancellationToken = cancellationToken; } public DownloadStreamedZippedFilesActionResult(string fileName, IEnumerable files) : this(fileName, files, new CancellationToken(false)) { } public override Task ExecuteResultAsync(ActionContext context) { var response = context.HttpContext.Response; response.OnStarting(() => { var contentDisposition = new ContentDispositionHeaderValue("attachment"); contentDisposition.SetHttpFileName(FileDownloadName); response.Headers.Add("access-control-expose-headers", new[] { "content-disposition", "content-length" }); response.Headers.Add("content-disposition", contentDisposition.ToString()); response.Headers.ContentLength = CalculateContentLength(); return Task.FromResult(0); }); var callback = GetCallback(); return callback(response.Body); } private Func GetCallback() { return async (outputStream) => { byte[] buffer = new byte[4096]; try { var countingStream = new CountingStream(outputStream); using (outputStream) using (var zipStream = new Ionic.Zip.ZipOutputStream(countingStream, true)) { zipStream.CompressionLevel = Ionic.Zlib.CompressionLevel.Level0; zipStream.CompressionMethod = Ionic.Zip.CompressionMethod.None; zipStream.EnableZip64 = Zip64Option.Always; foreach (var file in files) { using (var fileContent = await file.GetContentAsync()) { zipStream.PutNextEntry(file.Name); StreamUtils.Copy(fileContent, zipStream, buffer); zipStream.Flush(); outputStream.Flush(); } cancellationToken.ThrowIfCancellationRequested(); } zipStream.Flush(); zipStream.Close(); outputStream.Flush(); } } catch (Exception e) { Logger.LogError(e, "Unexpected error streaming {FileName}", FileDownloadName); throw; } }; } private long CalculateContentLength() { /* ZIP file size constants according to the specification https://users.cs.jmu.edu/buchhofp/forensics/formats/pkzip.html and https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT * Please note this only works with compression type 0 (store, no compression). * This formula also takes into account the additional content DotNetZip adds in the extra fields. It might be different for other zip providers. * ZIP constants come from SharpZipLib https://github.com/icsharpcode/SharpZipLib/blob/master/src/ICSharpCode.SharpZipLib/Zip/ZipConstants.cs */ return files.Count * (ZipConstants.LocalHeaderBaseSize + ZipConstants.Zip64DataDescriptorSize + ZipConstants.CentralHeaderBaseSize + DotNetZipLocalFileHeaderExtraFieldLength + DotNetZipCentralDirectoryHeaderExtraFieldLength) + 2 * files.Sum(f => f.Name.Length) + files.Sum(f => f.Size) + ZipConstants.EndOfCentralRecordBaseSize + Zip64CentralDirectoryRecordSize + Zip64CentralDirectoryLocatorSize; } } public record class StreamedFile { private readonly Func> fileFunc; public StreamedFile(string name, long size, Func> fileFunc) { this.fileFunc = fileFunc; Name = name; Size = size; } public string Name { get; } public long Size { get; } /// /// Callback to get the file from S3, Azure Storage or wherever /// public Task GetContentAsync() => fileFunc(); }
-
Malware downloaded from PyPI 41,000 times was surprisingly stealthy
Not python but I have story of team that depended on a C# library for saving zip files (SharpZipLib); turns out SharpZipLib had an issue: it could corrupt zip files ( https://github.com/icsharpcode/SharpZipLib/issues/391 ). This was a desktop app and reports from users came pouring in about they not being able to open their files. In response the company had to first manually recover their user's data; and nowadays they stress test sharpziplib to make sure it does not produce corrupted files in newer versions.
What are some alternatives?
SharpCompress - SharpCompress is a fully managed C# library to deal with many compression types and formats.
DotNetZip.Semverd - A fork of the DotNetZip project without signing with a solution that compiles cleanly. This project aims to follow semver to avoid versioning conflicts. DotNetZip is a FAST, FREE class library and toolset for manipulating zip files. Use VB, C# or any .NET language to easily create, extract, or update zip files.
Bundler
Snappy.Sharp - An implementation of google's Snappy compression format in C#
gemdiff - Find source repositories for ruby gems. Open, compare, and update outdated gem versions
Gem in a Box - Really simple rubygem hosting
Snappy for Windows
gemstash - A RubyGems.org cache and private gem server
ZipWrapper - A simple zip wrapper based on Lzma and Zlib compress algorithm
passwordless - 🗝 Authentication for your Rails app without the icky-ness of passwords
Owin.Compression - Compression (Deflate / GZip) module for Microsoft OWIN filesystem pipeline. Works with Selfhost and also on AspNetCore.
rbs - Type Signature for Ruby