Skip to content

Privacy Score — C# source

One number for your privacy health: your browser fingerprint, a test password's strength and breach exposure, and a site's security headers — four checks, one score, concrete fixes. Runs in your browser; only a 5-character hash prefix ever leaves it.

This is the C# implementation — the same logic the interactive tool runs, in a shareable, citable form.

// privacy-score — composite privacy scoring engine.
//
// Language: C# (.NET 8, no dependencies)
// Source:   CosmoDev polyglot showcase port of the Privacy Score tool,
//           ported from src/lib/privacy-score.ts (canonical TypeScript).
// License:  display source — part of CosmoDev's polyglot tool pages.
//
// Four category checks, each scored out of 25; the overall percent is
// renormalized over the categories that actually ran — skipping a check
// never lowers your score. Letter bands: >=85 A, >=70 B, >=50 C, else D.

using System;
using System.Collections.Generic;
using System.Linq;

namespace PrivacyScore;

public static class Scorer
{
    // Round to the nearest point and pin into the 0..25 window.
    private static int Clamp25(double points) =>
        (int)Math.Clamp(Math.Round(points, MidpointRounding.AwayFromZero), 0, 25);

    public static string StatusFor(int points) =>
        points >= 20 ? "ok" : points >= 10 ? "warn" : "bad";
    // More distinguishable signals make a browser more unique: high-risk
    // signals cost 4 each, medium 1.5, and a large surface costs a little more.
    public static int FingerprintPoints(int signalCount, int highRisk, int mediumRisk) =>
        Clamp25(25 - highRisk * 4 - mediumRisk * 1.5 - Math.Max(0, signalCount - 12) * 0.5);

    public static int PasswordPoints(int score, bool breached)
    {
        double basis = Math.Clamp(score, 0, 4) / 4.0 * 25;
        // Breached is urgent regardless of strength: x0.32 floors even a
        // score-4 password at 8 points -> "bad" -> the change-it recommendation.
        return Clamp25(breached ? basis * 0.32 : basis);
    }
    public static int HeadersPoints(IReadOnlyList<char> grades)
    {
        if (grades.Contains('F')) return 0;
        if (grades.Contains('C')) return 10;
        if (grades.Contains('B')) return 18;
        return grades.Count > 0 ? 25 : 0;
    }

    public static int BreachPoints(bool pwned) => pwned ? 0 : 25;
    public static string LetterFor(int percent, int max) => max == 0 ? "—"
        : percent >= 85 ? "A"
        : percent >= 70 ? "B"
        : percent >= 50 ? "C"
        : "D";

    // Renormalize over the checks that ran and grade the overall letter.
    public static (int Total, int Max, int Percent, string Letter) Score(params int[] points)
    {
        int total = points.Sum();
        int max = points.Length * 25;
        int percent = max == 0
            ? 0
            : (int)Math.Round(total * 100.0 / max, MidpointRounding.AwayFromZero);
        return (total, max, percent, LetterFor(percent, max));
    }
}

public static class Program
{
    public static void Main()
    {
        int[] checks =
        [
            Scorer.FingerprintPoints(18, 2, 4),        // 8
            Scorer.PasswordPoints(4, breached: true),  // 8 (breach floor)
            Scorer.HeadersPoints(['A', 'A', 'B']),     // 18
            Scorer.BreachPoints(false),                // 25
        ];
        var (total, max, percent, letter) = Scorer.Score(checks);
        Console.WriteLine($"total {total}/{max} = {percent}% -> {letter}");
    }
}

Also available in 13 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →