--- phase: 08-license-integration plan: 01 type: execute wave: 1 depends_on: ["07-01"] files_modified: - Program.cs autonomous: true --- ## Goal Wire the Phase 07 RSA license core into Program.cs: replace the hardcoded AES `checkLicense` call with `MachineFingerprint` + `LicenseFile` + `LicenseValidator`. Keep `-chiave=` as the CLI arg — it now carries a path to a `.lic` file instead of the AES key string. ## Purpose The current `checkLicense` embeds a hardcoded AES key/IV in source — anyone with the source or a decompiler can generate licenses for any machine. The Phase 07 RSA core is built but not yet wired in. This phase closes the gap: the app will reject any run where the `.lic` file (passed via `-chiave=`) doesn't contain a valid RSA-SHA256 signature matching the current machine's fingerprint. ## Output - `Program.cs` only — `checkLicense` method deleted; license check replaced with `MachineFingerprint` + `LicenseFile.TryRead` + `LicenseValidator.Validate`; `inputArgs.chiave` now treated as `.lic` file path; help text for `-chiave=` updated to describe the file path; dead `using System.Management` and `using System.Security.Cryptography` removed; `using NcProgramManager.Licensing` added - `InputArgs.cs` — NO CHANGE (`chiave` field stays as-is) - Docker build + all 118 tests still pass ## Project Context @.paul/PROJECT.md @.paul/STATE.md ## Phase 07 Output (direct inputs) @Licensing/IMachineFingerprint.cs @Licensing/ILicenseValidator.cs @Licensing/LicenseFile.cs @Licensing/MachineFingerprint.cs @Licensing/LicenseValidator.cs ## File Being Modified @Program.cs ## AC-1: -chiave= arg still parsed, value treated as .lic file path ```gherkin Given Program.cs parseArgomenti is called with args containing "-chiave=C:\license.lic" When the arg is parsed Then inputArgs.chiave equals "C:\license.lic" And the parsing code is unchanged from the current implementation ``` ## AC-2: RSA license check used at startup ```gherkin Given Program.cs Main is called When the license check runs Then it calls MachineFingerprint().GetFingerprint(), LicenseFile.TryRead(inputArgs.chiave), and LicenseValidator.Validate(fingerprint, base64) And the old checkLicense method no longer exists ``` ## AC-3: License failure exits with -100 ```gherkin Given the .lic file is missing OR the signature does not match the machine fingerprint When Main runs Then it prints "Licenza ERRATA", calls vediErrore(-100), and returns -1 ``` ## AC-4: Help text updated for -chiave= ```gherkin Given MostraAiuto is called When its output is inspected Then -chiave= is documented as the path to the .lic license file ``` Task 1: Wire RSA license check into Program.cs Program.cs **1. Replace usings at top of file:** Remove these two lines: ```csharp using System.Management; using System.Security.Cryptography; ``` Add: ```csharp using NcProgramManager.Licensing; ``` Keep all other existing usings unchanged. **2. Replace the license check call in Main:** Remove: ```csharp if (!checkLicense(inputArgs.chiave)) { Console.WriteLine("Licenza ERRATA"); vediErrore(-100); return -1; } ``` Replace with: ```csharp string _licFingerprint = new MachineFingerprint().GetFingerprint(); string _licBase64; if (!LicenseFile.TryRead(inputArgs.chiave, out _licBase64) || !new LicenseValidator().Validate(_licFingerprint, _licBase64)) { Console.WriteLine("Licenza ERRATA"); vediErrore(-100); return -1; } ``` `inputArgs.chiave` carries the `.lic` file path — parsing in `parseArgomenti` is unchanged. **3. Delete the entire `checkLicense` static method:** ```csharp static Boolean checkLicense(string chiave) { ... } ``` Remove from first line to closing brace entirely. **4. Update MostraAiuto — update the description for `-chiave=`:** Remove: ```csharp Console.WriteLine("-chiave="); Console.WriteLine(" la stringa chiave per eseguire il software."); ``` Replace with: ```csharp Console.WriteLine("-chiave="); Console.WriteLine(" Path del file di licenza (.lic) per autenticare il software."); ``` Avoid: touching `parseArgomenti` chiave parsing, `Scarica`, `Invia`, `vediErrore`, or any other part of the file. ```bash grep -n "checkLicense\|System\.Management\|System\.Security\.Cryptography" Program.cs grep -n "MachineFingerprint\|LicenseFile\|LicenseValidator\|NcProgramManager\.Licensing" Program.cs grep -n "chiave" Program.cs InputArgs.cs ``` First grep: zero hits. Second grep: 4+ hits. Third grep: `chiave` present in both files (parsing in Program.cs unchanged, field in InputArgs.cs unchanged). AC-2 satisfied: RSA check wired. AC-3 satisfied: failure path unchanged (-1 return). AC-4 satisfied: help text updated. AC-1 satisfied: -chiave= parsing untouched. ## DO NOT CHANGE - `InputArgs.cs` — `chiave` field stays as-is; no rename - `-chiave=` parsing in `parseArgomenti` — keep exactly as-is - `AesCrypt.cs` — now dead code but removal is out of scope; leave for a cleanup phase - `Licensing/*.cs` — Phase 07 output, must not be modified - All `Cnc/` files - All test files ## SCOPE LIMITS - No changes to `Scarica`, `Invia`, `vediErrore` logic - No changes to any other arg parsing in `parseArgomenti` - No new test files (license core already tested in Phase 07) - `AesCrypt.cs` stays in csproj and on disk Before declaring plan complete: - [ ] `grep "checkLicense" Program.cs` — zero hits - [ ] `grep "System.Management\|System.Security.Cryptography" Program.cs` — zero hits - [ ] `grep "MachineFingerprint\|LicenseFile\|LicenseValidator" Program.cs` — 3 hits - [ ] `grep "NcProgramManager.Licensing" Program.cs` — 1 hit - [ ] `grep "chiave" InputArgs.cs` — still present (field unchanged) - [ ] `grep "\-chiave=" Program.cs` — still present in parseArgomenti AND in MostraAiuto - [ ] Docker build passes, all 118 tests pass - All tasks completed - All verification checks pass - `checkLicense` method gone - `-chiave=` CLI arg and `inputArgs.chiave` field unchanged - RSA license check wired at startup using `inputArgs.chiave` as .lic path - Help text describes `-chiave=` as the .lic file path - No test regressions After completion, create `.paul/phases/08-license-integration/08-01-SUMMARY.md`