Privacy Score — Rust 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 Rust implementation — the same logic the interactive tool runs, in a shareable, citable form.
//! privacy-score — composite privacy scoring engine.
//!
//! Language: Rust (edition 2021, 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.
/// Header grade from a security-headers scan.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Grade { A, B, C, F }
/// Round to the nearest point and pin into the 0..25 window.
fn clamp25(points: f64) -> i32 {
points.round().clamp(0.0, 25.0) as i32
}
/// 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.
fn fingerprint_points(signal_count: i32, high_risk: i32, medium_risk: i32) -> i32 {
let surface = (signal_count - 12).max(0) as f64 * 0.5;
clamp25(25.0 - high_risk as f64 * 4.0 - medium_risk as f64 * 1.5 - surface)
}
fn password_points(score: i32, breached: bool) -> i32 {
let base = score.clamp(0, 4) as f64 / 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.
clamp25(if breached { base * 0.32 } else { base })
}
fn headers_points(grades: &[Grade]) -> i32 {
let has = |g: Grade| grades.iter().any(|&x| x == g);
if has(Grade::F) { return 0; }
if has(Grade::C) { return 10; }
if has(Grade::B) { return 18; }
if grades.is_empty() { 0 } else { 25 }
}
fn breach_points(pwned: bool) -> i32 {
if pwned { 0 } else { 25 }
}
fn letter_for(percent: i32, max: i32) -> &'static str {
match (max == 0, percent >= 85, percent >= 70, percent >= 50) {
(true, ..) => "—",
(_, true, ..) => "A",
(_, _, true, _) => "B",
(_, _, _, true) => "C",
_ => "D",
}
}
/// Renormalize over the checks that ran and grade the overall letter.
fn score_privacy(points: &[i32]) -> (i32, i32, i32, &'static str) {
let total: i32 = points.iter().sum();
let max = points.len() as i32 * 25;
let percent = if max == 0 { 0 } else { (total as f64 / max as f64 * 100.0).round() as i32 };
(total, max, percent, letter_for(percent, max))
}
fn main() {
let checks = [
fingerprint_points(18, 2, 4), // 8
password_points(4, true), // 8 (breach floor)
headers_points(&[Grade::A, Grade::A, Grade::B]), // 18
breach_points(false), // 25
];
println!("{:?}", checks);
println!("{:?}", score_privacy(&checks));
}
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 →