mirror of
https://github.com/massgravel/Microsoft-Activation-Scripts.git
synced 2026-08-08 10:23:35 +00:00
HWID: port the verbatim key/edition table + fallback resolution
Add src/data/hwid_keys.rs — the 34-row HWID key/edition table and the 5-row
alternate-edition fallback table, transcribed verbatim from HWID_Activation.cmd
(:hwiddata / :hwidfallback, git history f34d025). Generated programmatically
from the source rows (split on the batch's collapsed `_` delimiters, `%f%`
splitter stripped) so no key was hand-typed; a test shape-checks every product
key (5x5 groups) and asserts the row counts.
Wire it into hwid.rs via resolve_key(sku, edition): prefer the working primary
key, else the alternate-edition fallback (the script's :dk_checksku selection
for the common single-branch case; multi-branch SKUs like EnterpriseS=125 are
noted for version refinement).
53 tests pass (36 mas + 17 libtsforge), clippy clean, offline.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
5d6812d379
commit
99d211a1bf
|
|
@ -14,6 +14,7 @@ MAS/
|
||||||
model.rs Product / Method / LicenseStatus enums + the real SPP GUIDs
|
model.rs Product / Method / LicenseStatus enums + the real SPP GUIDs
|
||||||
error.rs typed Error/Result (replaces errorlevel + colored echoes)
|
error.rs typed Error/Result (replaces errorlevel + colored echoes)
|
||||||
data/kms_hosts.rs ported data tables
|
data/kms_hosts.rs ported data tables
|
||||||
|
data/hwid_keys.rs 34-row HWID key/edition table + 5-row fallback (verbatim)
|
||||||
platform/
|
platform/
|
||||||
mod.rs `Spp` trait — the ONE seam to Windows; safe API over FFI
|
mod.rs `Spp` trait — the ONE seam to Windows; safe API over FFI
|
||||||
stub.rs non-Windows backend (read-only no-ops; privileged ops error)
|
stub.rs non-Windows backend (read-only no-ops; privileged ops error)
|
||||||
|
|
@ -38,13 +39,13 @@ MAS/
|
||||||
|
|
||||||
Every Windows effect — WMI, ClipUp/ClipSVC, registry — lives behind
|
Every Windows effect — WMI, ClipUp/ClipSVC, registry — lives behind
|
||||||
[`platform::Spp`]. The rest of the crate is OS-independent and unit-tested
|
[`platform::Spp`]. The rest of the crate is OS-independent and unit-tested
|
||||||
(**48 tests**: 31 in `mas`, 17 in `libtsforge`), zero dependencies, offline.
|
(**53 tests**: 36 in `mas`, 17 in `libtsforge`), zero dependencies, offline.
|
||||||
|
|
||||||
## Build & test
|
## Build & test
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cd MAS
|
cd MAS
|
||||||
cargo test # 48 passing — portable core, any OS, no Windows required
|
cargo test # 53 passing — portable core, any OS, no Windows required
|
||||||
cargo clippy --workspace # clean
|
cargo clippy --workspace # clean
|
||||||
|
|
||||||
# Real Windows backend (WMI/COM via the `windows` crate):
|
# Real Windows backend (WMI/COM via the `windows` crate):
|
||||||
|
|
@ -64,7 +65,7 @@ Ported and tested (pure logic — the Windows effects sit behind `Spp`):
|
||||||
|------------|--------------------------------------------------------------------------------------|
|
|------------|--------------------------------------------------------------------------------------|
|
||||||
| status | Read path: SPP query → typed `LicenseStatus` → formatted report. |
|
| status | Read path: SPP query → typed `LicenseStatus` → formatted report. |
|
||||||
| online_kms | GVLK install → KMS host fallback loop → activate. |
|
| online_kms | GVLK install → KMS host fallback loop → activate. |
|
||||||
| hwid | Region decision (30-country skip → GeoId 244) + two-method apply (ClipSVC restart → `clipup -v -o`, success = `tokens.dat`). |
|
| hwid | Region decision (30-country skip → GeoId 244) + two-method apply (ClipSVC restart → `clipup -v -o`, success = `tokens.dat`) + the verbatim 34-row key/edition table with alternate-edition fallback resolution. |
|
||||||
| kms38 | Eligibility gate (build ≥ 14393, EnterpriseG/GN excluded), KMS38-lease detection (>180 days), loopback `127.0.0.2` pin, skip-reactivate. |
|
| kms38 | Eligibility gate (build ≥ 14393, EnterpriseG/GN excluded), KMS38-lease detection (>180 days), loopback `127.0.0.2` pin, skip-reactivate. |
|
||||||
| libtsforge | CRC-32/BZIP2, SHA-256, `PsVersion` detection, alignment, UTF-16, the Vista/Win7 physical-store dialects and both VariableBag CRC dialects — all round-trip/vector tested. |
|
| libtsforge | CRC-32/BZIP2, SHA-256, `PsVersion` detection, alignment, UTF-16, the Vista/Win7 physical-store dialects and both VariableBag CRC dialects — all round-trip/vector tested. |
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
//! unit-tested here.
|
//! unit-tested here.
|
||||||
|
|
||||||
use crate::activation::Activator;
|
use crate::activation::Activator;
|
||||||
|
use crate::data::hwid_keys::{entry_for_sku, fallback_for};
|
||||||
use crate::error::{Error, Result};
|
use crate::error::{Error, Result};
|
||||||
use crate::model::{Method, Product};
|
use crate::model::{Method, Product};
|
||||||
use crate::platform::Spp;
|
use crate::platform::Spp;
|
||||||
|
|
@ -42,6 +43,21 @@ pub fn should_change_region(current_geo_name: &str) -> bool {
|
||||||
.any(|c| c.eq_ignore_ascii_case(current_geo_name.trim()))
|
.any(|c| c.eq_ignore_ascii_case(current_geo_name.trim()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resolve which (activation ID, product key) to install for the running
|
||||||
|
/// edition, applying the alternate-edition fallback when the primary key is
|
||||||
|
/// absent or marked not-working (the script's `:dk_checksku` selection). Notes:
|
||||||
|
/// multi-branch SKUs (e.g. EnterpriseS = 125) may need `version` refinement;
|
||||||
|
/// this handles the common single-branch case.
|
||||||
|
pub fn resolve_key(sku: u32, edition: &str) -> Option<(&'static str, &'static str)> {
|
||||||
|
if let Some(e) = entry_for_sku(sku) {
|
||||||
|
if e.works {
|
||||||
|
return Some((e.activation_id, e.product_key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let f = fallback_for(sku, edition)?;
|
||||||
|
Some((f.alt_activation_id, f.alt_key))
|
||||||
|
}
|
||||||
|
|
||||||
/// Generate the ticket, drop it, and apply it via the two ClipSVC methods.
|
/// Generate the ticket, drop it, and apply it via the two ClipSVC methods.
|
||||||
/// Returns `Ok(())` once `tokens.dat` is present.
|
/// Returns `Ok(())` once `tokens.dat` is present.
|
||||||
fn apply_ticket(spp: &dyn Spp) -> Result<()> {
|
fn apply_ticket(spp: &dyn Spp) -> Result<()> {
|
||||||
|
|
@ -90,6 +106,19 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::platform::test_util::FakeSpp;
|
use crate::platform::test_util::FakeSpp;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn resolve_key_uses_primary_then_fallback() {
|
||||||
|
// SKU 48 (Professional) has a working primary key.
|
||||||
|
let (act, key) = resolve_key(48, "Professional").unwrap();
|
||||||
|
assert!(!act.is_empty());
|
||||||
|
assert_eq!(key.split('-').count(), 5);
|
||||||
|
// SKU 138 (ProfessionalSingleLanguage) has no primary — falls back.
|
||||||
|
let (_, alt) = resolve_key(138, "ProfessionalSingleLanguage").unwrap();
|
||||||
|
assert_eq!(alt.split('-').count(), 5);
|
||||||
|
// Unknown SKU with no fallback → None.
|
||||||
|
assert!(resolve_key(99999, "Nope").is_none());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn region_switches_only_outside_top_countries() {
|
fn region_switches_only_outside_top_countries() {
|
||||||
assert!(!should_change_region("US"));
|
assert!(!should_change_region("US"));
|
||||||
|
|
|
||||||
136
MAS/src/data/hwid_keys.rs
Normal file
136
MAS/src/data/hwid_keys.rs
Normal file
|
|
@ -0,0 +1,136 @@
|
||||||
|
//! HWID key/edition tables, generated verbatim from `HWID_Activation.cmd`
|
||||||
|
//! (`:hwiddata` / `:hwidfallback`, git history `f34d025`).
|
||||||
|
//!
|
||||||
|
//! The script stores keys with a `%f%` empty-var splitter as light
|
||||||
|
//! obfuscation; it is stripped here. Rows are keyed by the SPP SKU id, which
|
||||||
|
//! is matched against the running edition's SKU. SKU ids are **not unique**
|
||||||
|
//! (e.g. the EnterpriseS branches all share SKU 125); the script disambiguates
|
||||||
|
//! by OS build/version, so [`entry_for_sku`] returns the first match and
|
||||||
|
//! callers refine by `version` when needed.
|
||||||
|
|
||||||
|
/// One HWID key/edition row.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub struct HwidEntry {
|
||||||
|
pub sku: u32,
|
||||||
|
pub activation_id: &'static str,
|
||||||
|
/// GVLK/generic product key (the `%f%` splitter already stripped).
|
||||||
|
pub product_key: &'static str,
|
||||||
|
pub key_part: &'static str,
|
||||||
|
/// `false` if the script marks this key as not working (`%%E == 1`).
|
||||||
|
pub works: bool,
|
||||||
|
pub key_type: &'static str,
|
||||||
|
pub edition_id: &'static str,
|
||||||
|
/// Build/branch tag, or empty (e.g. `RS5`, `Ge`, `Zn`).
|
||||||
|
pub version: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Alternate-edition fallback: when the current edition lacks a working HWID
|
||||||
|
/// key, activate as the mapped alternate edition instead.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub struct HwidFallback {
|
||||||
|
pub cur_sku: u32,
|
||||||
|
pub cur_edition: &'static str,
|
||||||
|
pub cur_activation_id: &'static str,
|
||||||
|
pub alt_activation_id: &'static str,
|
||||||
|
pub alt_key: &'static str,
|
||||||
|
pub alt_edition: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The 34 HWID key/edition rows, verbatim.
|
||||||
|
pub const HWID_KEYS: &[HwidEntry] = &[
|
||||||
|
HwidEntry { sku: 4, activation_id: "8b351c9c-f398-4515-9900-09df49427262", product_key: "XGVPP-NMH47-7TTHJ-W3FW7-8HV2C", key_part: "X19-99683", works: true, key_type: "OEM:NONSLP", edition_id: "Enterprise", version: "" },
|
||||||
|
HwidEntry { sku: 27, activation_id: "c83cef07-6b72-4bbc-a28f-a00386872839", product_key: "3V6Q6-NQXCX-V8YXR-9QCYV-QPFCT", key_part: "X19-98746", works: true, key_type: "Volume:MAK", edition_id: "EnterpriseN", version: "" },
|
||||||
|
HwidEntry { sku: 48, activation_id: "4de7cb65-cdf1-4de9-8ae8-e3cce27b9f2c", product_key: "VK7JG-NPHTM-C97JM-9MPGT-3V66T", key_part: "X19-98841", works: true, key_type: "Retail", edition_id: "Professional", version: "" },
|
||||||
|
HwidEntry { sku: 49, activation_id: "9fbaf5d6-4d83-4422-870d-fdda6e5858aa", product_key: "2B87N-8KFHP-DKV6R-Y2C8J-PKCKT", key_part: "X19-98859", works: true, key_type: "Retail", edition_id: "ProfessionalN", version: "" },
|
||||||
|
HwidEntry { sku: 98, activation_id: "f742e4ff-909d-4fe9-aacb-3231d24a0c58", product_key: "4CPRK-NM3K3-X6XXQ-RXX86-WXCHW", key_part: "X19-98877", works: true, key_type: "Retail", edition_id: "CoreN", version: "" },
|
||||||
|
HwidEntry { sku: 99, activation_id: "1d1bac85-7365-4fea-949a-96978ec91ae0", product_key: "N2434-X9D7W-8PF6X-8DV9T-8TYMD", key_part: "X19-99652", works: true, key_type: "Retail", edition_id: "CoreCountrySpecific", version: "" },
|
||||||
|
HwidEntry { sku: 100, activation_id: "3ae2cc14-ab2d-41f4-972f-5e20142771dc", product_key: "BT79Q-G7N6G-PGBYW-4YWX6-6F4BT", key_part: "X19-99661", works: true, key_type: "Retail", edition_id: "CoreSingleLanguage", version: "" },
|
||||||
|
HwidEntry { sku: 101, activation_id: "2b1f36bb-c1cd-4306-bf5c-a0367c2d97d8", product_key: "YTMG3-N6DKC-DKB77-7M9GH-8HVX7", key_part: "X19-98868", works: true, key_type: "Retail", edition_id: "Core", version: "" },
|
||||||
|
HwidEntry { sku: 119, activation_id: "2a6137f3-75c0-4f26-8e3e-d83d802865a4", product_key: "XKCNC-J26Q9-KFHD2-FKTHY-KD72Y", key_part: "X19-99606", works: true, key_type: "OEM:NONSLP", edition_id: "PPIPro", version: "" },
|
||||||
|
HwidEntry { sku: 121, activation_id: "e558417a-5123-4f6f-91e7-385c1c7ca9d4", product_key: "YNMGQ-8RYV3-4PGQ3-C8XTP-7CFBY", key_part: "X19-98886", works: true, key_type: "Retail", edition_id: "Education", version: "" },
|
||||||
|
HwidEntry { sku: 122, activation_id: "c5198a66-e435-4432-89cf-ec777c9d0352", product_key: "84NGF-MHBT6-FXBX8-QWJK7-DRR8H", key_part: "X19-98892", works: true, key_type: "Retail", edition_id: "EducationN", version: "" },
|
||||||
|
HwidEntry { sku: 125, activation_id: "f6e29426-a256-4316-88bf-cc5b0f95ec0c", product_key: "PJB47-8PN2T-MCGDY-JTY3D-CBCPV", key_part: "X23-50331", works: false, key_type: "Volume:MAK", edition_id: "EnterpriseS", version: "Ge" },
|
||||||
|
HwidEntry { sku: 125, activation_id: "cce9d2de-98ee-4ce2-8113-222620c64a27", product_key: "KCNVH-YKWX8-GJJB9-H9FDT-6F7W2", key_part: "X22-66075", works: false, key_type: "Volume:MAK", edition_id: "EnterpriseS", version: "VB" },
|
||||||
|
HwidEntry { sku: 125, activation_id: "d06934ee-5448-4fd1-964a-cd077618aa06", product_key: "43TBQ-NH92J-XKTM7-KT3KK-P39PB", key_part: "X21-83233", works: true, key_type: "OEM:NONSLP", edition_id: "EnterpriseS", version: "RS5" },
|
||||||
|
HwidEntry { sku: 125, activation_id: "706e0cfd-23f4-43bb-a9af-1a492b9f1302", product_key: "NK96Y-D9CD8-W44CQ-R8YTK-DYJWX", key_part: "X21-05035", works: true, key_type: "OEM:NONSLP", edition_id: "EnterpriseS", version: "RS1" },
|
||||||
|
HwidEntry { sku: 125, activation_id: "faa57748-75c8-40a2-b851-71ce92aa8b45", product_key: "FWN7H-PF93Q-4GGP8-M8RF3-MDWWW", key_part: "X19-99617", works: true, key_type: "OEM:NONSLP", edition_id: "EnterpriseS", version: "TH" },
|
||||||
|
HwidEntry { sku: 126, activation_id: "3d1022d8-969f-4222-b54b-327f5a5af4c9", product_key: "2DBW3-N2PJG-MVHW3-G7TDK-9HKR4", key_part: "X21-04921", works: true, key_type: "Volume:MAK", edition_id: "EnterpriseSN", version: "RS1" },
|
||||||
|
HwidEntry { sku: 126, activation_id: "60c243e1-f90b-4a1b-ba89-387294948fb6", product_key: "NTX6B-BRYC2-K6786-F6MVQ-M7V2X", key_part: "X19-98770", works: true, key_type: "Volume:MAK", edition_id: "EnterpriseSN", version: "TH" },
|
||||||
|
HwidEntry { sku: 139, activation_id: "01eb852c-424d-4060-94b8-c10d799d7364", product_key: "3XP6D-CRND4-DRYM2-GM84D-4GG8Y", key_part: "X23-37869", works: false, key_type: "Retail", edition_id: "ProfessionalCountrySpecific", version: "Zn" },
|
||||||
|
HwidEntry { sku: 161, activation_id: "eb6d346f-1c60-4643-b960-40ec31596c45", product_key: "DXG7C-N36C4-C4HTG-X4T3X-2YV77", key_part: "X21-43626", works: true, key_type: "Retail", edition_id: "ProfessionalWorkstation", version: "" },
|
||||||
|
HwidEntry { sku: 162, activation_id: "89e87510-ba92-45f6-8329-3afa905e3e83", product_key: "WYPNQ-8C467-V2W6J-TX4WX-WT2RQ", key_part: "X21-43644", works: true, key_type: "Retail", edition_id: "ProfessionalWorkstationN", version: "" },
|
||||||
|
HwidEntry { sku: 164, activation_id: "62f0c100-9c53-4e02-b886-a3528ddfe7f6", product_key: "8PTT6-RNW4C-6V7J2-C2D3X-MHBPB", key_part: "X21-04955", works: true, key_type: "Retail", edition_id: "ProfessionalEducation", version: "" },
|
||||||
|
HwidEntry { sku: 165, activation_id: "13a38698-4a49-4b9e-8e83-98fe51110953", product_key: "GJTYN-HDMQY-FRR76-HVGC7-QPF8P", key_part: "X21-04956", works: true, key_type: "Retail", edition_id: "ProfessionalEducationN", version: "" },
|
||||||
|
HwidEntry { sku: 175, activation_id: "df96023b-dcd9-4be2-afa0-c6c871159ebe", product_key: "NJCF7-PW8QT-3324D-688JX-2YV66", key_part: "X21-41295", works: true, key_type: "Retail", edition_id: "ServerRdsh", version: "" },
|
||||||
|
HwidEntry { sku: 178, activation_id: "d4ef7282-3d2c-4cf0-9976-8854e64a8d1e", product_key: "V3WVW-N2PV2-CGWC3-34QGF-VMJ2C", key_part: "X21-32983", works: true, key_type: "Retail", edition_id: "Cloud", version: "" },
|
||||||
|
HwidEntry { sku: 179, activation_id: "af5c9381-9240-417d-8d35-eb40cd03e484", product_key: "NH9J3-68WK7-6FB93-4K3DF-DJ4F6", key_part: "X21-32987", works: true, key_type: "Retail", edition_id: "CloudN", version: "" },
|
||||||
|
HwidEntry { sku: 188, activation_id: "8ab9bdd1-1f67-4997-82d9-8878520837d9", product_key: "XQQYW-NFFMW-XJPBH-K8732-CKFFD", key_part: "X21-99378", works: true, key_type: "OEM:DM", edition_id: "IoTEnterprise", version: "" },
|
||||||
|
HwidEntry { sku: 191, activation_id: "ed655016-a9e8-4434-95d9-4345352c2552", product_key: "QPM6N-7J2WJ-P88HH-P3YRH-YY74H", key_part: "X21-99682", works: true, key_type: "OEM:NONSLP", edition_id: "IoTEnterpriseS", version: "VB" },
|
||||||
|
HwidEntry { sku: 191, activation_id: "6c4de1b8-24bb-4c17-9a77-7b939414c298", product_key: "CGK42-GYN6Y-VD22B-BX98W-J8JXD", key_part: "X23-12617", works: true, key_type: "OEM:NONSLP", edition_id: "IoTEnterpriseS", version: "Ge" },
|
||||||
|
HwidEntry { sku: 202, activation_id: "d4bdc678-0a4b-4a32-a5b3-aaa24c3b0f24", product_key: "K9VKN-3BGWV-Y624W-MCRMQ-BHDCD", key_part: "X22-53884", works: true, key_type: "Retail", edition_id: "CloudEditionN", version: "" },
|
||||||
|
HwidEntry { sku: 203, activation_id: "92fb8726-92a8-4ffc-94ce-f82e07444653", product_key: "KY7PN-VR6RX-83W6Y-6DDYQ-T6R4W", key_part: "X22-53847", works: true, key_type: "Retail", edition_id: "CloudEdition", version: "" },
|
||||||
|
HwidEntry { sku: 205, activation_id: "5a85300a-bfce-474f-ac07-a30983e3fb90", product_key: "N979K-XWD77-YW3GB-HBGH6-D32MH", key_part: "X23-15042", works: true, key_type: "OEM:DM", edition_id: "IoTEnterpriseSK", version: "" },
|
||||||
|
HwidEntry { sku: 206, activation_id: "80083eae-7031-4394-9e88-4901973d56fe", product_key: "P8Q7T-WNK7X-PMFXY-VXHBG-RRK69", key_part: "X23-62084", works: true, key_type: "OEM:DM", edition_id: "IoTEnterpriseK", version: "" },
|
||||||
|
HwidEntry { sku: 210, activation_id: "1bc2140b-285b-4351-b99c-26a126104b29", product_key: "TMP2N-KGFHJ-PWM6F-68KCQ-3PJBP", key_part: "X23-60513", works: true, key_type: "Retail", edition_id: "WNC", version: "" },
|
||||||
|
];
|
||||||
|
|
||||||
|
/// The 5 alternate-edition fallback rows, verbatim.
|
||||||
|
pub const HWID_FALLBACK: &[HwidFallback] = &[
|
||||||
|
HwidFallback { cur_sku: 125, cur_edition: "EnterpriseS-2021", cur_activation_id: "cce9d2de-98ee-4ce2-8113-222620c64a27", alt_activation_id: "ed655016-a9e8-4434-95d9-4345352c2552", alt_key: "QPM6N-7J2WJ-P88HH-P3YRH-YY74H", alt_edition: "IoTEnterpriseS-2021" },
|
||||||
|
HwidFallback { cur_sku: 125, cur_edition: "EnterpriseS-2024", cur_activation_id: "f6e29426-a256-4316-88bf-cc5b0f95ec0c", alt_activation_id: "6c4de1b8-24bb-4c17-9a77-7b939414c298", alt_key: "CGK42-GYN6Y-VD22B-BX98W-J8JXD", alt_edition: "IoTEnterpriseS-2024" },
|
||||||
|
HwidFallback { cur_sku: 138, cur_edition: "ProfessionalSingleLanguage", cur_activation_id: "a48938aa-62fa-4966-9d44-9f04da3f72f2", alt_activation_id: "4de7cb65-cdf1-4de9-8ae8-e3cce27b9f2c", alt_key: "VK7JG-NPHTM-C97JM-9MPGT-3V66T", alt_edition: "Professional" },
|
||||||
|
HwidFallback { cur_sku: 139, cur_edition: "ProfessionalCountrySpecific", cur_activation_id: "f7af7d09-40e4-419c-a49b-eae366689ebd", alt_activation_id: "4de7cb65-cdf1-4de9-8ae8-e3cce27b9f2c", alt_key: "VK7JG-NPHTM-C97JM-9MPGT-3V66T", alt_edition: "Professional" },
|
||||||
|
HwidFallback { cur_sku: 139, cur_edition: "ProfessionalCountrySpecific-Zn", cur_activation_id: "01eb852c-424d-4060-94b8-c10d799d7364", alt_activation_id: "4de7cb65-cdf1-4de9-8ae8-e3cce27b9f2c", alt_key: "VK7JG-NPHTM-C97JM-9MPGT-3V66T", alt_edition: "Professional" },
|
||||||
|
];
|
||||||
|
|
||||||
|
/// First HWID entry for a SKU id (refine by `version` for multi-branch SKUs).
|
||||||
|
pub fn entry_for_sku(sku: u32) -> Option<&'static HwidEntry> {
|
||||||
|
HWID_KEYS.iter().find(|e| e.sku == sku)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fallback mapping for a current SKU + edition, if one exists.
|
||||||
|
pub fn fallback_for(cur_sku: u32, cur_edition: &str) -> Option<&'static HwidFallback> {
|
||||||
|
HWID_FALLBACK
|
||||||
|
.iter()
|
||||||
|
.find(|f| f.cur_sku == cur_sku && f.cur_edition == cur_edition)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn tables_have_the_expected_counts() {
|
||||||
|
assert_eq!(HWID_KEYS.len(), 34);
|
||||||
|
assert_eq!(HWID_FALLBACK.len(), 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn every_key_is_a_well_formed_product_key() {
|
||||||
|
// 5 groups of 5 uppercase alphanumerics, hyphen-separated.
|
||||||
|
let ok = |k: &str| {
|
||||||
|
let groups: Vec<&str> = k.split('-').collect();
|
||||||
|
groups.len() == 5
|
||||||
|
&& groups.iter().all(|g| {
|
||||||
|
g.len() == 5 && g.chars().all(|c| c.is_ascii_uppercase() || c.is_ascii_digit())
|
||||||
|
})
|
||||||
|
};
|
||||||
|
assert!(HWID_KEYS.iter().all(|e| ok(e.product_key)), "malformed key");
|
||||||
|
assert!(HWID_FALLBACK.iter().all(|f| ok(f.alt_key)), "malformed fallback key");
|
||||||
|
// The %f% splitter must be gone.
|
||||||
|
assert!(HWID_KEYS.iter().all(|e| !e.product_key.contains('%')));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lookup_resolves_known_editions() {
|
||||||
|
assert_eq!(entry_for_sku(48).unwrap().edition_id, "Professional");
|
||||||
|
assert_eq!(entry_for_sku(101).unwrap().edition_id, "Core");
|
||||||
|
assert!(entry_for_sku(99999).is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fallback_maps_professional_single_language() {
|
||||||
|
let f = fallback_for(138, "ProfessionalSingleLanguage").unwrap();
|
||||||
|
assert_eq!(f.alt_edition, "Professional");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
//! Ported data tables (verbatim from the scripts where it matters).
|
//! Ported data tables (verbatim from the scripts where it matters).
|
||||||
|
|
||||||
|
pub mod hwid_keys;
|
||||||
pub mod kms_hosts;
|
pub mod kms_hosts;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue