Skip to content

Privacy Score — Kotlin 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 Kotlin implementation — the same logic the interactive tool runs, in a shareable, citable form.

// privacy-score — composite privacy scoring engine.
//
// Language: Kotlin (2.x, standard library only)
// 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.

import kotlin.math.max
import kotlin.math.roundToInt

/** Round to the nearest point and pin into the 0..25 window. */
fun clamp25(points: Double): Int = points.roundToInt().coerceIn(0, 25)

enum class Grade { A, B, C, F }

/** 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. */
fun fingerprintPoints(signalCount: Int, highRisk: Int, mediumRisk: Int): Int {
    val surface = max(0, signalCount - 12) * 0.5
    return clamp25(25.0 - highRisk * 4.0 - mediumRisk * 1.5 - surface)
}

fun passwordPoints(score: Int, breached: Boolean): Int {
    val base = score.coerceIn(0, 4) / 4.0 * 25.0
    // Breached is urgent regardless of strength: x0.32 floors even a
    // score-4 password at 8 points -> "bad" -> the change-it recommendation.
    return clamp25(if (breached) base * 0.32 else base)
}

fun headersPoints(grades: List<Grade>): Int = when {
    Grade.F in grades -> 0
    Grade.C in grades -> 10
    Grade.B in grades -> 18
    grades.isNotEmpty() -> 25
    else -> 0
}

fun breachPoints(pwned: Boolean): Int = if (pwned) 0 else 25

fun letterFor(percent: Int, max: Int): String = when {
    max == 0 -> "—"
    percent >= 85 -> "A"
    percent >= 70 -> "B"
    percent >= 50 -> "C"
    else -> "D"
}

/** Renormalize over the checks that ran and grade the overall letter. */
fun scorePrivacy(vararg points: Int): String {
    val total = points.sum()
    val max = points.size * 25
    val percent = if (max == 0) 0 else (total.toDouble() / max * 100).roundToInt()
    return "total $total/$max = $percent% -> ${letterFor(percent, max)}"
}

fun main() {
    val report = scorePrivacy(
        fingerprintPoints(signalCount = 18, highRisk = 2, mediumRisk = 4),  // 8
        passwordPoints(score = 4, breached = true),                         // 8 (breach floor)
        headersPoints(listOf(Grade.A, Grade.A, Grade.B)),                   // 18
        breachPoints(pwned = false),                                        // 25
    )
    println(report)
}

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 →