Skip to content

Instantly share code, notes, and snippets.

<Project>
<!--
Look in an external deployment folder (intended for build secrets) with the same name as the solution folder
for any appsettings.json files where the environment name matches the publish profile. Include them as links
under each .pubxml file so that they can be easily edited and accessed outside of the current repository.
-->
<ItemGroup>
<None Include="..\..\Deployment\$([System.IO.Path]::GetFileName($(SolutionDir.TrimEnd('\\'))))\appsettings.*.json">
<Link>Properties\PublishProfiles\%(Filename)%(Extension)</Link>
@jonathanduke
jonathanduke / vpn-bridge.md
Last active April 21, 2025 16:48
How to route traffic from the public Internet over two routers connected via VPN

VPN Bridge Setup: DD-WRT to Asus (Merlin)

I needed to create a VPN bridge from my network, which has a public IP, to an internal network, which is behind CGNAT and does not have a routable IP. The routers involved were an R6700v3 running DD-WRT and an RT-N66U running the Merlin 380.70 firmware, but the firewall rules should apply for any similar router. While this is not a comprehensive guide, I needed to record the details of the custom steps here in case I have to set up something similar in the future.

1. OpenVPN Setup

Setting up an OpenVPN server on the DD-WRT side and connecting it to the Asus is mostly straightforward using the GUI, but some manual steps were required. I did notice that the Asus had some issues with a few of the OpenVPN parameters, and it had trouble connecting in TCP mode, so I used UDP.

To set up OpenVPN with TLS authentication and X.509 certificates, I used Easy-RSA to generate a certificate authority and required certs:

@jonathanduke
jonathanduke / async_image.dart
Last active May 2, 2025 16:06
Wraps a Dart image so that it can be passed as a parameter to synchronous methods while loading asynchronously
/*
* Based on: https://gist.github.com/jonathanduke/b3385b350b7fa02019ba9927c5fa3f5a
* Public domain: http://unlicense.org/
* Modify as you wish, but you are encouraged to leave this comment for future reference in case the original is updated.
*/
import 'dart:async';
import 'dart:convert';
import 'dart:typed_data';
import 'dart:ui';
@jonathanduke
jonathanduke / offstage_value_listenable_builder.dart
Last active March 20, 2024 19:44
ValueListenableBuilder that wraps an Offstage widget and exposes whether it will be offstage before building completes
import 'package:flutter/material.dart';
typedef OffstageEvaluator<T> = bool Function(T value);
class OffstageValueListenableBuilder<T> extends ValueListenableBuilder<T> {
final Key? offstageKey;
final OffstageEvaluator<T> offstageEvaluator;
OffstageValueListenableBuilder({
super.key,
import 'package:flutter/material.dart';
extension LocaleFallbackExtensions on Locale {
/// Look up the most specific version of a localized string, falling back through the BCP 47 language-script-region hierarchy.
String? getString(String? key, String? Function(String k) lookup) {
final prefix = key != null ? '${key}_' : "";
String? text;
if (null != (text = lookup('$prefix${toString()}'))) {
// full locale code (en_US, es_MX, fr_CA, zh_Hans_CN, zh_Hant_TW)
@jonathanduke
jonathanduke / ffmpeg.txt
Last active January 21, 2024 22:55
ffmpeg commands that I need to remember
# This is for converting a ripped movie to a 480p size so my kids can watch it on their tablets in the car.
# I'm cropping off 276 pixels from the top and bottom, which means it's a 3840x2160 image with a 2.39:1 letterboxed video.
# The width can vary based on the aspect ratio, but the height should always be 480px.
# I'm hard-coding it to use H.264 and yuv420p and to downmix surround sound to regular stereo channels.
# On some movies, I had to use -map 0:2 to get the 5.1 audio stream if the 7.1 was truehd and ffmpeg didn't like that.
ffmpeg -i "4k.mkv" -vf "crop=iw:ih-552:0:276,scale=1146:480" -c:v libx264 -c:a copy -ac 2 -sn -pix_fmt yuv420p -map 0:0 -map 0:2 -crf 18 -map_chapters -1 "480p.mp4"
# After getting the resolution right, follow this process to reduce the size of the video: https://trac.ffmpeg.org/wiki/Encode/H.264#twopass
ffmpeg -y -i original.mp4 -c:v libx264 -b:v 1000k -pass 1 -an -f null NULL && ffmpeg -i original.mp4 -c:v libx264 -b:v 1000k -pass 2 -c:a aac -b:a 128k shrink.mp4
@jonathanduke
jonathanduke / int_range.dart
Last active January 18, 2024 20:30
Implementation for int.minValue and int.maxValue in Dart
// https://dartpad.dev/?id=dad879af094b27b24fd6070e1175e791
// Pending feature request: https://github.com/dart-lang/sdk/issues/41717
// Note: this requires Dart 2.14 and above (to support the >>> operator)
class IntRange {
// based on: https://stackoverflow.com/a/75928881
static const int maxValue = (-1 >>> 1);
static const int minValue = -1 - maxValue;
}
@jonathanduke
jonathanduke / git-list-worktrees.bat
Last active November 16, 2024 17:05
List all Git worktrees recursively with the location of the repository (either a .git directory or the gitdir location specified in the .git file)
::::
:: Original source: https://gist.github.com/jonathanduke/92eac20fe8a85eff8e8840b5d56551f9#file-git-list-worktrees-bat
:: Public domain: http://unlicense.org/
:: Modify as you wish, but you are encouraged to leave this comment for future reference in case the original is updated.
::::
@echo off
setlocal EnableDelayedExpansion
for /f "tokens=*" %%f in ('dir /a /s /b .git') do (
if exist "%%f\*" (
set "_dir=%%~dpf"
@jonathanduke
jonathanduke / ddwrt_nvram.cs
Created June 10, 2022 00:09
C# code to read a binary DD-WRT backup file and export commands to set the values on the router
// read a DD-WRT nvrambak_xyz.bin backup file and create "nvram set" commands FOR COMPARISON ONLY
// NOTE: some values may have issues, so you can't just copy and paste the whole output or it can mess up your router
// The format should be similar to processes to export from the router via the command line:
// https://gist.github.com/Aikhjarto/5b1c6b5e5d373d8d60c004e075b29acc
// https://gist.github.com/rambotech/d1e2486228c5e972c3c9c8936920f2fc
var set = new List<string>();
using var file = System.IO.File.OpenRead(args[0]);
var buffer = new byte[0xFFFF];
int len = 6;
int count = file.Read(buffer, 0, len);
@jonathanduke
jonathanduke / tsig.md
Last active June 1, 2022 12:42
Deferred Proof of Authorship using Digital Signatures and Blockchain Timestamps

Deferred Proof of Authorship using Digital Signatures and Blockchain Timestamps

by Jonathan Duke

Abstract. Suppose an author has created a document that he wants to publish anonymously, but at some point in the future he would like to have the option to prove both his identity and the time of creation. A digital signature can be used to sign the document's content, but there is no mechanism to prevent another person from spoofing the timestamp and signing their own version of the document to claim they are the original author. Using a public, permanent blockchain such as bitcoin could allow the author to augment the digital signature with a timestamp that could be proven to match the document signature. The signature and timestamp could be stored privately until the author wishes to claim ownership at a later date. This might be compared to a privately-held NFT.

1. Introduction

Will anyone ever prove the identity of [Satoshi Nakamoto](https