SystemLocker.Nightflyer 0.2.0

dotnet add package SystemLocker.Nightflyer --version 0.2.0
                    
NuGet\Install-Package SystemLocker.Nightflyer -Version 0.2.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="SystemLocker.Nightflyer" Version="0.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="SystemLocker.Nightflyer" Version="0.2.0" />
                    
Directory.Packages.props
<PackageReference Include="SystemLocker.Nightflyer" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add SystemLocker.Nightflyer --version 0.2.0
                    
#r "nuget: SystemLocker.Nightflyer, 0.2.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package SystemLocker.Nightflyer@0.2.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=SystemLocker.Nightflyer&version=0.2.0
                    
Install as a Cake Addin
#tool nuget:?package=SystemLocker.Nightflyer&version=0.2.0
                    
Install as a Cake Tool

System Locker Nightflyer — .NET

Official .NET 8+ client for System Locker Nightflyer, an offline authorization lease protocol for desktop software. Nightflyer proves possession of an installation P-256 key on every request and accepts only Ed25519-signed leases, statuses, decisions, and key transitions from locally pinned keys.

Install

dotnet add package SystemLocker.Nightflyer

Quickstart

using SystemLocker.Nightflyer;

var config = new NightflyerConfig {
    SystemId = "abcdefghijklmnopqrst",
    TrustedSigningKeys = new Dictionary<string, string> { ["YOUR_KID"] = "YOUR_BASE64URL_ED25519_KEY" },
};
using var session = NightflyerAuthorizationSession.CreateMemory(config);

var result = await session.EasyAuthorizeAsync(
    new NightflyerBinding("1.0.0", "", myHwid),
    requestedOfflineSeconds: 86400,
    licenseKey: enteredKey); // Omit after the key has been retained.

if (result.CanProceed)
    StartProtectedWork(result.Lease!);
else if (result.ShouldPromptForKey)
    ShowLicenseKeyPrompt();

For a Windows persistent session, use OpenPersistent with a WindowsDpapiStateStore. State is protected with per-user DPAPI, atomically replaced, and signed by the separately stored, non-exportable CNG installation key. The record contains the lease, time checkpoint, retained license key, authenticated signing-key transition history, and status high-water marks. The retained key lets an inactive installation request a fresh lease without asking the user to type it again. Nightflyer erases it only after the server returns the definitive KEY_NOT_FOUND result. On macOS and Linux, provide an INightflyerStateStore backed by Keychain or Secret Service; the SDK intentionally does not silently fall back to plaintext files.

EasyAuthorize and persistent startup

EasyAuthorizeAsync() is the recommended startup API. With a newly entered key it requests a fresh lease. Without one, it loads protected state, renews a due lease or calls SynchronizeStatusAsync() for a strict status check, finishes any exact pending end request, and requests a new lease with the retained key when the old lease is inactive, ended, or expired.

The result makes application policy explicit: CanProceed, IsOffline, CredentialPresent, ShouldPromptForKey, RetryAfter, and a typed RecommendedAction. A NetworkUnavailable result with CanProceed == true means the online check did not finish but the existing signed offline lease is still usable. The application can continue and retry after the reported delay.

If a developer unbinds a lease, the old lease is reported as revoked and surfaces locally as Inactive; this is not a permanent ban on the installation or key. EasyAuthorizeAsync() immediately tries to obtain a new lease with the retained key. A successful signed response starts a new lease epoch. A signed KEY_NOT_FOUND result clears the retained key and sets ShouldPromptForKey; other denials retain it while still allowing the user to enter a replacement.

var startup = await session.EasyAuthorizeAsync(binding, 86400);
if (!startup.CanProceed)
    Handle(startup.RecommendedAction, startup.Diagnostic, startup.RetryAfter);

Alternatively, the lower-level Load(), RenewIfDueAsync(), SynchronizeStatusAsync(), and AuthorizeWithStoredKeyAsync() operations are available for any application that needs more control over the process.

What the client enforces

  • HTTPS-only endpoints, no redirects, and a fresh ES256 installation proof.
  • Canonical request binding and access-token binding for renewal, status, and end.
  • Ed25519 verification before token claims are consumed, with fixed JWS types.
  • Exact lease, status, and transition profiles; a status or decision cannot be substituted for a lease.
  • Request-JTI, system, installation-thumbprint, expiry, and key-transition checks.
  • Installation-key-signed state, replayable server-signed key transitions, persisted high-water marks, revocation enforcement, and per-boot time checks.
  • A renewal state machine with cross-process installation coordination, terminal end tombstones, and offline-on-network-failure behavior.

Offline time and travel

A valid cached lease can be used without connectivity, including while traveling. During the same OS boot, lease time advances from verified server UTC using an elapsed-time clock that includes sleep. Time-zone changes and wall-clock corrections do not shorten or extend the signed lease lifetime.

After a reboot, a persisted lease remains usable by default when UTC is consistent with the installation-key-signed high-water checkpoint. This keeps normal restarts and time-zone changes offline while rejecting a simple clock rollback. Set RequireOnlineAfterReboot = true when a deployment prefers the stronger policy of requiring one signed online response after every OS boot. Software-only storage cannot detect every coordinated rollback of both an old signed state snapshot and the OS clock. A successful signed online response repairs a bad local time checkpoint but does not extend an existing lease's signed expiry. Memory-only sessions are not persisted across application or OS restarts.

Security addendum

Watch this repository (Watch → Custom → Releases) and update your dependency when a release ships: releases regularly add security enhancements.

Pinned server keys are a developer-provided trust root. The session persists the signed transition chain rather than a derived key-ring snapshot, then replays it from those roots on every open. Version 3 state is migrated by retaining only the installation identity and stored license credential; cached authorization is reacquired online. The session rejects revoked keys, devices, grants, rollback, and stale leases. It uses the signed server-time anchor plus a suspend-aware monotonic clock within a boot. Nightflyer cannot immediately revoke a device that is offline, and even though it increases resilience to cracking, it is not a substitute for proper obfuscation and other protections.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net8.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.2.0 40 9/15/2026