Package score
Deterministic risk scoring: domain-age check (contextual tiers with
stacking and shared-cert discount), certificate
downgrade check (+40), and registrar mismatch (+30), mapped onto a
four-tier verdict. Sources: internal/score/score.go,
internal/score/date.go.
DomainData
type DomainData struct {
Domain string // queried domain
Date string // YYYY-MM-DD, or sentinel on failure
Registrar string // "Unknown" when unavailable
Issuer string // "Unknown" when unavailable
Class string // EV, OV, IV, DV, or Unknown
SANs string // comma-joined, or "Unknown"
AgeDays int
AgeKnown bool
} |
Collected triage fields for one domain; the scoring input.
Result
type Result struct {
Score int
Findings []string
Verdict string
AgeFlag string // display suffix for young suspect domains
} |
ClassLong
func ClassLong(c string) string |
Human-readable validation name via lookup table: EV to
"Extended Validation", OV to "Organization Validated", DV
to "Domain Validated", IV to "Individual Validated",
anything else to "Unknown".
VerifyDataQuality
func VerifyDataQuality(target, suspect DomainData) error |
Fails closed: returns an error when either domain lacks a valid RDAP
date, a computable age, or any TLS signal (issuer and class both unknown).
The CLI aborts instead of printing a verdict built on missing data.
Score
func Score(target, suspect DomainData) Result |
Applies the signals. Identical domains force score zero and LEGITIMATE
while still attaching DNS NOTEs. Suspect age
is contextual: the full tier (< 30d: 80, 30-89d: 40) needs company
(registrar mismatch or cert downgrade), otherwise the next tier down;
shared certificate infrastructure (either domain in the other's SANs,
exactly or via parent wildcard) halves whatever remains. Target EV/OV versus
suspect DV adds 40 as DOWNGRADE; a same-class issuer difference is a
display-only NOTE (+0). Case-insensitive registrar mismatch adds 30,
skipped when either side is unknown. Suspect-side DNS suppression and NS
splits add 50; split-horizon shapes and anything target-side are
display-only NOTEs (+0). Identical domains force score zero and LEGITIMATE
while still attaching DNS NOTEs.
r := score.Score(target, suspect)
// r.Score, r.Findings, r.Verdict, r.AgeFlag |
Verdict
func Verdict(score int) string |
Maps the total via threshold table: 51+ phishing, 40+ suspicious, 15+
unrelated/misconfigured, otherwise legitimate.
ValidISODate
func ValidISODate(s string) bool |
True only for clean, calendar-valid YYYY-MM-DD strings. Any
sentinel or garbage value fails by design.
AgeDays
func AgeDays(ymd string, now time.Time) (days int, ok bool) |
Whole days between ymd and now; ok is false
when ymd is unparseable.
Licensed under the GNU General Public License v3 - Mark Robillard Jr (MARKMENTAL)