Programming in C#, Java, and god knows what not

Native PNG in C# .NET

It all started with a simple barcode. I was refactoring my old Code128 barcode class to work in .NET 5 and faced an interesting issue - there was no option to output barcode as an image. Yes, on Windows you could rely on System.Drawing but .NET is supposedly multiplatform environment these days. And no, System.Drawing is not supported in Linux - you only get error CS0234: The type or namespace name 'Drawing' does not exist in the namespace 'System' (are you missing an assembly reference?.

If you’re thinking to yourself “Wait, I remember Microsoft’s System.Drawing.Common working on Linux”, you don’t have a bad memory. However, Microsoft since made a small update and, with a stroke of a pen, decided to abandon it. Yes, you can use runtime options as a workaround but official support is no longer there.

Alternatives do exist. Most notably both ImageSharp and SkiaSharp would satisfy any graphic need I might have. But both also present quite a big dependency to pull for what is essentially a trivial task. I mean, how difficult can it be to implement PNG writer?

It turns out, not difficult at all. If you go over specification you’ll notice there are only three chunks you need to support: IHDR, IDAT, and IEND. If you know how to write those three, you can output PNG image that’s readable by all. Literally the only two things that are not straightforward were deflate compression that required an extra header and dealing with CRC.

Most of my debugging time was actually spend dealing with output not showing properly in IrfanView. I could read my output image in Paint.NET, Paint, Gimp, and multitude of other programs I’ve tried. It took me a while before I figured out that IrfanView 4.54 is actually one with the issue. Update to the latest version sorted that one out.

In any case, I successfully added PNG support to by barcode class.

And then I started thinking… Why not make a simple PNG image reader/writer? Well, answers are numerous. First of all, alternatives exist and a lone developer can never hope to have such level of completeness. Secondly, I don’t deal with graphics on a daily basis and thus features would be few and far between. And lastly, while PNG is a relatively simple specification to start with, it has a lot of optional complexity. And some of that complexity would require me to learn much more than I ever want to know (yes, ICC profiles - I’m looking at you).

However, logic be damned. What’s the better use of an afternoon than writing a PNG parser?

In any case, the final product is here and while as simple as it gets it’s relatively feature complete when it comes to loading plain old PNG images. The only mandatory feature I failed to implement is support for interlaced images.

Expectedly, the end result is usable for changing a pixel or two but not for much more as all infrastructure is missing. I will add some of the missing functionality in the future, resize and interlacing support coming first, but I consider this class reasonably feature complete for what I both need and can do without making a full blown library. And I haven’t had as much fun programming in a while.

Overescaping By Default

Writing JSON has became trivial in C# and there’s no class I like better for that purpose than Utf8JsonWriter. Just look at a simple example:

var jsonUtf8 = new Utf8JsonWriter(Console.OpenStandardOutput(),
                                  new JsonWriterOptions() { Indented = true });
jsonUtf8.WriteStartObject();
jsonUtf8.WriteString("Test", "2+2");
jsonUtf8.WriteEndObject();
jsonUtf8.Flush();

This simple code will produce perfectly valid JSON:

{
  "Test": "2\u002B2"
}

While valid, you’ll notice this is slightly different than any other programming language would do. A single plus character became escape sequence \u002B.

In their eternal wisdom, .NET architects decided that, by default, JSON should be over-escaped and they “explained” their reasoning in the ticket. Essentially they did it out of abundance of caution to avoid any issues if someone puts JSON where it might not be expected.

Mind you, in 99% of cases JSON is used in HTTP body and thus doesn’t need this but I guess one odd case justifies this non-standard but valid output in their minds. And no, other JSON encoders don’t behave this way either. Only .NET as far as I can tell.

Fortunately, some time later, they also implemented what I (alongside probably 90% of developers) consider the proper JSON encoder which escapes just mandatory characters and leaves the rest of text alone. It just requires a small extra parameter.

var jsonUtf8 = new Utf8JsonWriter(Console.OpenStandardOutput(),
                                  new JsonWriterOptions() { Indented = true,
                                    ^^Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping^^});
jsonUtf8.WriteStartObject();
jsonUtf8.WriteString("Test", "2+2");
jsonUtf8.WriteEndObject();
jsonUtf8.Flush();

Using UnsafeRelaxedJsonEscaping is not unsafe despite it’s name; darn it, it’s not even relaxed as compared to the specification. It’s just a properly implemented JSON encoder without any extra nonsense thrown in.

Web Server Certificate From a File

If one desires to run HTTPs server from C#, they might get the following warning:

Unable to configure HTTPS endpoint. No server certificate was specified, and the default developer certificate could not be found or is out of date. To generate a developer certificate run 'dotnet dev-certs https'. To trust the certificate (Windows and macOS only) run 'dotnet dev-certs https --trust'. For more information on configuring HTTPS see https://go.microsoft.com/fwlink/?linkid=848054.

And yes, once could follow instructions and have everything running. But where’s the fun in that?

Alternative approach would be to load certificate from the file and .NET makes that really easy.

private static X509Certificate2? GetCertificate() {
  var certFilename = Path.Combine(AppContext.BaseDirectory, "my.pfx");
  if (File.Exists(certFilename)) {
    try {
      return new X509Certificate2(certFilename);
    } catch (CryptographicException ex) {
      // log error or whatever
    }
  }
  return null;
}

So, when bringing server up we can just call it using something like this:

var cert = GetCertificate();
options.Listen(IPAddress.Any, 443, listenOptions => {
  listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
  if (cert != null) {
    listenOptions.UseHttps(cert);
  } else {
    listenOptions.UseHttps();
  }
});

Network Share Login via C#

Accessing remote share programmatically from Windows is easy. Just use \\machine\share notation and you’re golden. Except if you need to access it with a specific user. While PrincipalContext can often help, for samba shares hosted by Linux, that doesn’t necessarily work.

bool Login(string path, string user, string password) {
  var nr = new NativeMethods.NETRESOURCE {
    dwType = NativeMethods.RESOURCETYPE_DISK,
    lpRemoteName = path
  };
  var result = NativeMethods.WNetUseConnection(IntPtr.Zero, nr, password, name, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
  return (result == NativeMethods.NO_ERROR);
}

And, of course, we also need our definitions:

private static class NativeMethods {
    internal const Int32 NO_ERROR = 0;
    internal const Int32 RESOURCETYPE_DISK = 0x00000001;

    [StructLayout(LayoutKind.Sequential)]
    internal class NETRESOURCE {
        public Int32 dwScope = 0;
        public Int32 dwType = 0;
        public Int32 dwDisplayType = 0;
        public Int32 dwUsage = 0;
        public IntPtr lpLocalName;
        public String lpRemoteName;
        public IntPtr lpComment;
        public IntPtr lpProvider;
    }

    [DllImport("mpr.dll", CharSet = CharSet.Ansi)]
    internal static extern Int32 WNetUseConnection(
        IntPtr hwndOwner,
        NETRESOURCE lpNetResource,
        String lpPassword,
        String lpUserId,
        Int32 dwFlags,
        IntPtr lpAccessName,
        IntPtr lpBufferSize,
        IntPtr lpResult
    );

}

And that should be enough for access.

Web Server Certificate From a File

If you’re dealing with HTTPS on .NET 5, you might have seen the following message: Unable to configure HTTPS endpoint. No server certificate was specified, and the default developer certificate could not be found or is out of date. Recommendation to solve this is also clear To generate a developer certificate run 'dotnet dev-certs https'. To trust the certificate (Windows and macOS only) run 'dotnet dev-certs https --trust' And you’re pointed toward Microsoft docs for more information.

What’s not clear is that you can also load certificate from file and skip the whole system configuration - really useful if you don’t have the full system access. For that just configure your builder appropriately:

Builder = Host.CreateDefaultBuilder()
    .ConfigureWebHostDefaults(webBuilder => {
        webBuilder.ConfigureKestrel(options => {
        var cert = GetCertificate();
        options.Listen(IPAddress.Any, 443, listenOptions => {
            listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
            listenOptions.UseHttps(cert);
        });
    });
})
.Build();

In example code above, loading the certificate is done from GetCertificate function; something like this:

private static X509Certificate2 GetCertificate() {
    return new X509Certificate2("mycertificate.pfx", "");
}

Own Pwned

For a while now ';–have i been pwned? has been providing two services. One more known is informing people of data breaches. One slightly less known is their API. My personal favorite are their password search interface. So, I was really sad to see when Troy started charging for it.

While I understand Troy’s reasons, I used this API in freeware application. And yes, I could “swallow” $3.50 this service cost but I wasn’t willing to. My freeware hobby is already costing me enough. :)

Fortunately, Troy is allowing download of password hashes so one could easily make API on their own server. So, over a weekend I did. In my OwnPwned GitHub repository there’s everything you might need to create your own verification service. But there are some differences.

First of all, this is not a substitution for ';–have i been pwned? API as due to dependency on the data from it, it will ALWAYS be one step behind. Also, I haven’t implemented full API as I only needed the password verification portion. Even for password verification portion, I trimmed all extra data (e.g. password breach count) and focused only on passwords themselves.

To make use of the project, you first need to download the latest password dump (ordered by hash). Once you unpack that file, you would use PwnedRepack to convert this to a binary file. I found this step necessary for both speed (as you can use binary search) and for size (as it brought 25 GB file to slightly more manageable but still huge 12 GB).

With file in hand, there are two ways to search data. The first one would be PwnedServe application that will simply expose interface on localhost. Second way forward it serving PwnedPhp on Apache server. Either way, you can do k-anonymity search over a range using the first 5 hexadecimal characters of password’s SHA-1 hash.

Something like this /range/12345/.

And yes, code is not optimized and probably will never be due to the lack of free time on my side. But it does solve my issue. Your mileage may vary.


PS: Please note, Tray Hunt has opensourced some elements of HIBP with more to come. If you need fully-featured interface that’s probably what you should keep eye on.

Small C# InfluxDB client

Well, after doing InfluxDB client bash and Go, time came to do the same in C#.

I will not go too much into details as you can see the source code yourself. Suffice it to say it supports both v1 and v2 line protocol. And usage is simple as it gets:

var measurement = new InfluxMeasurement("Tick")
  .AddTag("t1", "Tag1")
  .AddTag("t2", "Tag2")
  .AddField("f1", 42)
  .AddField("f2", true);
client.Queue(measurement);

Source code is of course on GitHub and project is available and NuGet package.

The Minimal InfluxDB Client in Go

While you can get a proper InfluxDB client library for Go, sometime there’s no substitution for rolling one yourself - especially since InfluxDB’s Line Protocol is really easy.

It’s just a matter of constructing a correct URL and setting up just two headers. Something like this:

func sendInfluxData(line string, baseUrl string, org string, bucket string, token string) {
    var url string
    if len(org) > 0 {
        url = fmt.Sprintf("%s/api/v2/write?org=%s&bucket=%s",
			  baseUrl, org, bucket)
    } else {
        url = fmt.Sprintf("%s/api/v2/write?bucket=%s",
			  baseUrl, bucket)
    }

    request, _ := http.NewRequest("POST", url, strings.NewReader(line))
    request.Header.Set("Content-Type", "text/plain")
    if len(token) > 0 {
        request.Header.Set("Authorization", "Token " + token)
    }

    response, _ := http.DefaultClient.Do(request)
}

And yes, code doesn’t do error checking nor it has any comments. Deal with it. ;)

On Air

Illustration

Working from home requires a bit of synchronization between occupants. Especially if one member of family spends a lot of time on calls. Quite early into the work-at-home adventure, my wife found a solution. She bought a lighted “On Air” sign.

Idea was good. Whenever I am in conference call, I just light up the sign and everybody knows to keep quiet as our words are not private anymore. In reality most of the time I would either leave sign on longer than needed or forger to turn it off when I’m done speaking.

And pretty much all issues could be traced to the position of the sign. While it was visible to everybody else in the room, it wasn’t directly visible to me. And to make it more annoying, turning it off and on required me to get off the chair. Excellent for physical activity but annoying to do if I need to turn it on/off multiple times in a call.

So I decided to automatize this a bit.

I first repurposed one of the Wyze Plug devices I had around and went about looking for API. Unfortunately, Wyze doesn’t offer public API at this time but other people already reverse-engineered it. But alas, all those ports were outdated. Until I found a gem in comments. With those changes it was easy enough to make my own mini application.

While this would be enough for turning on/off the light, I was after something a bit more fine-grained. In quite a few conference calls I might not speak a lot. For them I just usually hit Mute Mic button on my Lenovo P70 and unmute only when I need to actually speak. So it seemed like a good compromise to only light up the sign when I am unmuted. If I’m muted, other family members can have their conversations without impacting my call.

And the following script was the last piece of the puzzle:

#!/bin/bash

LAST_MIC_STATUS=
while (true); do
  CURR_MIC_STATUS=`/usr/bin/amixer get Capture | grep -q '\[off\]' && echo 0 || echo 1`

  if [[ "$LAST_MIC_STATUS" != "$CURR_MIC_STATUS" ]]; then
    LAST_MIC_STATUS=$CURR_MIC_STATUS
    if [[ "$CURR_MIC_STATUS" -ne 0 ]]; then NEW_STATE=true; else NEW_STATE=false; fi

    WYZE_EMAIL="^^unknown@example.com^^" \
    WYZE_PASSWORD="^^changeme^^" \
    WyzePlugControl ^^2CAA8E6616D2^^ $NEW_STATE
  fi

  sleep 1
done

It will essentially just check for the status of my mute button and adjust Wyze Plug accordingly. At least until Wyze changes API again.

Always Pushing Tags

Tagging is nice but I always forget to push the darn things. And yes, I am one of those guys that push all local tags - so what? We’re all kinky in our ways.

There are many ways you can ensure you push tags with your regular push but my favorite is just editing .gitconfig. In the [remote "origin"] section I just add the following two lines:

push = +refs/heads/*:refs/heads/*
push = +refs/tags/*:refs/tags/*

Now each push will come with a bit of extra.