package gci import ( "math" "time" ) const ( // GracePeriodDays is the number of days after expiry during which // the certificate still contributes (with declining factor) GracePeriodDays = 180 // DecayStartDays is how many days before expiry the linear decay begins DecayStartDays = 180 ) // CalculateValidityFactor computes the validity factor for a certificate // based on its expiry date. // // Rules: // - Certificate not yet expiring (>6 months): factor = 1.0 // - Certificate expiring within 6 months: linear decay from 1.0 to 0.5 // - Certificate expired: linear decay from 0.5 to 0.0 over grace period // - Certificate expired beyond grace period: factor = 0.0 func CalculateValidityFactor(validUntil time.Time, now time.Time) float64 { daysUntilExpiry := validUntil.Sub(now).Hours() / 24.0 if daysUntilExpiry > float64(DecayStartDays) { // Not yet in decay window return 1.0 } if daysUntilExpiry > 0 { // In pre-expiry decay window: linear from 1.0 to 0.5 fraction := daysUntilExpiry / float64(DecayStartDays) return 0.5 + 0.5*fraction } // Certificate is expired daysExpired := -daysUntilExpiry if daysExpired > float64(GracePeriodDays) { return 0.0 } // In grace period: linear from 0.5 to 0.0 fraction := 1.0 - (daysExpired / float64(GracePeriodDays)) return math.Max(0, 0.5*fraction) } // IsExpired returns true if the certificate is past its validity date func IsExpired(validUntil time.Time, now time.Time) bool { return now.After(validUntil) } // IsExpiringSoon returns true if the certificate expires within the decay window func IsExpiringSoon(validUntil time.Time, now time.Time) bool { daysUntil := validUntil.Sub(now).Hours() / 24.0 return daysUntil > 0 && daysUntil <= float64(DecayStartDays) }