Compare commits
4 commits
f3f895df82
...
3312a57757
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3312a57757 | ||
|
|
39a9566858 | ||
|
|
a5d73db69a | ||
|
|
9bb65c4748 |
81 changed files with 1860 additions and 1412 deletions
|
|
@ -1,8 +1,8 @@
|
||||||
# FanucProgramManager
|
# NcProgramManager
|
||||||
|
|
||||||
## What This Is
|
## What This Is
|
||||||
|
|
||||||
Console EXE (C# .NET 4.7.2) for upload/download of CNC programs to/from machine controllers. Targets any CN manufacturer, not Fanuc-only. Runs on Windows, distributed to licensed machine operators and integrators.
|
Console EXE (C# .NET 4.7.2) for upload/download of CNC programs to/from machine controllers. Supports Fanuc FOCAS, Heidenhain LSV2, Siemens Sinumerik FTP, and Mitsubishi FTP. Runs on Windows, distributed to licensed machine operators and integrators.
|
||||||
|
|
||||||
## Core Value
|
## Core Value
|
||||||
|
|
||||||
|
|
@ -13,9 +13,9 @@ Machinists and operators transfer CNC programs to/from any controller without ma
|
||||||
| Attribute | Value |
|
| Attribute | Value |
|
||||||
|-----------|-------|
|
|-----------|-------|
|
||||||
| Type | Application |
|
| Type | Application |
|
||||||
| Version | 0.0.0 |
|
| Version | 0.2.0-dev |
|
||||||
| Status | In development |
|
| Status | v0.2 in progress — Phase 07 complete |
|
||||||
| Last Updated | 2026-05-13 |
|
| Last Updated | 2026-05-17 |
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
|
|
@ -31,12 +31,20 @@ Machinists and operators transfer CNC programs to/from any controller without ma
|
||||||
- [x] AES encryption for program files
|
- [x] AES encryption for program files
|
||||||
- [x] CLI argument parsing
|
- [x] CLI argument parsing
|
||||||
- [x] Machine-bound license check (hardcoded)
|
- [x] Machine-bound license check (hardcoded)
|
||||||
|
- [x] Multi-CN support — Fanuc, Heidenhain, Siemens, Mitsubishi — Phase 1–4
|
||||||
|
- [x] 3-file management mode (Fanuc) via IFanucMachine — Phase 4
|
||||||
|
- [x] NC program validation before upload (all 4 manufacturers) — Phase 5
|
||||||
|
- [x] Project renamed FanucProgramManager → NcProgramManager — Phase 6
|
||||||
|
|
||||||
### Active (In Progress)
|
### Validated (Shipped) — continued
|
||||||
- [ ] 3-file management mode — branch `3FilesManagement`
|
- [x] RSA offline license core: IMachineFingerprint, ILicenseValidator, LicenseValidator, LicenseFile — Phase 7
|
||||||
|
|
||||||
### Planned (Next)
|
### Planned (Next)
|
||||||
- To be defined during /paul:plan
|
- [ ] Wire license into Program.cs — replace checkLicense, replace -chiave= with -licfile= (Phase 08)
|
||||||
|
- [ ] License generator tool — sign fingerprint with RSA private key, write .lic file (Phase 09)
|
||||||
|
- [ ] Replace PublicKeyXml PLACEHOLDER with real vendor key pair (Phase 09 output)
|
||||||
|
- [ ] ReadActiveProgramAsync / SelectMainProgram for Heidenhain and Siemens
|
||||||
|
- [ ] Integration test against real hardware (Heidenhain, Siemens, Mitsubishi)
|
||||||
|
|
||||||
### Out of Scope
|
### Out of Scope
|
||||||
- Cloud sync
|
- Cloud sync
|
||||||
|
|
@ -63,14 +71,21 @@ Machinists and operators transfer CNC programs to/from any controller without ma
|
||||||
| .NET 4.7.2 | Max compatibility with operator machines | 2026-05-13 | Active |
|
| .NET 4.7.2 | Max compatibility with operator machines | 2026-05-13 | Active |
|
||||||
| Console EXE output | Simple deployment, scriptable | 2026-05-13 | Active |
|
| Console EXE output | Simple deployment, scriptable | 2026-05-13 | Active |
|
||||||
| Offline license only | Operators may have no internet on shop floor | 2026-05-13 | Active |
|
| Offline license only | Operators may have no internet on shop floor | 2026-05-13 | Active |
|
||||||
|
| `#` = Warning in Fanuc/Mitsubishi | Macro variable indicator — valid in context | 2026-05-13 | Active |
|
||||||
|
| Constructor injection for validator | Internal ctor accepts mock — enables unit testing without Windows DLL | 2026-05-13 | Active |
|
||||||
|
| RSA asymmetric licensing | Private key vendor-only; public key embedded in binary — decompiler can't forge licenses | 2026-05-17 | Active |
|
||||||
|
| PublicKeyXml PLACEHOLDER until Phase 09 | Real key pair not yet generated; prevents blocking Phase 07 on Phase 09 | 2026-05-17 | Active |
|
||||||
|
| Heidenhain LSV2 port 19000 | Standard LSV2 port; needs real hardware verification | 2026-05-13 | Active |
|
||||||
|
| Siemens FTP dir `/_N_MPF_DIR/` | Sinumerik standard MPF directory; FTP option must be enabled | 2026-05-13 | Active |
|
||||||
|
|
||||||
## Success Metrics
|
## Success Metrics
|
||||||
|
|
||||||
| Metric | Target | Current | Status |
|
| Metric | Target | Current | Status |
|
||||||
|--------|--------|---------|--------|
|
|--------|--------|---------|--------|
|
||||||
| Program transfer correctness | 100% (byte-verified) | Unknown | Not measured |
|
| Program transfer correctness | 100% (byte-verified) | Unknown | Pending hardware test |
|
||||||
| License validation (offline) | Works without network | Hardcoded | At risk |
|
| License validation (offline) | Works without network | RSA core built, wiring Phase 08 | In progress |
|
||||||
| Multi-CN support | ≥2 manufacturers | Fanuc only | In progress |
|
| Multi-CN support | ≥2 manufacturers | 4 (Fanuc/Heidenhain/Siemens/Mitsubishi) | Done |
|
||||||
|
| NC validation coverage | All manufacturers | 4 manufacturers, 30+ tests | Done |
|
||||||
|
|
||||||
## Tech Stack / Tools
|
## Tech Stack / Tools
|
||||||
|
|
||||||
|
|
@ -78,11 +93,15 @@ Machinists and operators transfer CNC programs to/from any controller without ma
|
||||||
|-------|------------|-------|
|
|-------|------------|-------|
|
||||||
| Language | C# | .NET Framework 4.7.2 |
|
| Language | C# | .NET Framework 4.7.2 |
|
||||||
| UI | Console EXE | CLI args via InputArgs.cs |
|
| UI | Console EXE | CLI args via InputArgs.cs |
|
||||||
| CN Protocol (Fanuc) | FOCAS fwlib32 | 32-bit DLL |
|
| CN Protocol (Fanuc) | FOCAS fwlib32 | 32-bit DLL, Windows-only |
|
||||||
| CN Protocol (others) | To be defined | Multi-CN expansion |
|
| CN Protocol (Heidenhain) | LSV2 over TCP | Port 19000, CRC-16/CCITT |
|
||||||
|
| CN Protocol (Siemens) | FTP (FtpWebRequest) | ASCII mode, passive, `/_N_MPF_DIR/` |
|
||||||
|
| CN Protocol (Mitsubishi) | FTP (FtpWebRequest) | Port 21, `/PRG/`, no extensions |
|
||||||
|
| Validation | NcProgramValidator | Universal + per-manufacturer rules |
|
||||||
| Encryption | AES (AesCrypt.cs) | Program file protection |
|
| Encryption | AES (AesCrypt.cs) | Program file protection |
|
||||||
| Licensing | Machine fingerprint | Hardcoded now, needs design |
|
| Licensing | RSA-SHA256 asymmetric | IMachineFingerprint + ILicenseValidator; wiring in Phase 08 |
|
||||||
|
| Testing | NUnit 3.13.3 + Moq 4.18.4 | .NET 4.7.2 test project |
|
||||||
|
|
||||||
---
|
---
|
||||||
*PROJECT.md — Updated when requirements or context change*
|
*PROJECT.md — Updated when requirements or context change*
|
||||||
*Last updated: 2026-05-13*
|
*Last updated: 2026-05-17 after Phase 7 (License Core)*
|
||||||
|
|
|
||||||
133
.paul/ROADMAP.md
133
.paul/ROADMAP.md
|
|
@ -2,82 +2,117 @@
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
Console tool for CNC program transfer and file management. Fanuc FOCAS base, expanding to multi-CN (Heidenhain LSV2, Siemens FTP) with robust offline licensing.
|
Console tool for CNC program transfer and file management. Fanuc FOCAS base, expanding to multi-CN (Heidenhain LSV2, Siemens FTP, Mitsubishi FTP) with NC program validation.
|
||||||
|
|
||||||
## Current Milestone
|
## Current Milestone
|
||||||
|
|
||||||
**v0.1 Multi-CN Release** (v0.1.0)
|
**v0.1 Multi-CN Release** (v0.1.0)
|
||||||
Status: In progress
|
Status: ✅ Complete
|
||||||
Phases: 0 of 4 complete
|
Phases: 5 of 5 complete
|
||||||
|
Completed: 2026-05-13
|
||||||
|
|
||||||
## Phases
|
## Phases
|
||||||
|
|
||||||
| Phase | Name | Plans | Status | Completed |
|
| Phase | Name | Plans | Status | Completed |
|
||||||
|-------|------|-------|--------|-----------|
|
|-------|------|-------|--------|-----------|
|
||||||
| 1 | cnc-abstraction | 2 | In progress | - |
|
| 1 | cnc-abstraction | 1 | ✅ Complete | 2026-05-13 |
|
||||||
| 2 | heidenhain | 1 | Not started | - |
|
| 2 | heidenhain | 1 | ✅ Complete | 2026-05-13 |
|
||||||
| 3 | siemens | 1 | Not started | - |
|
| 3 | siemens | 1 | ✅ Complete | 2026-05-13 |
|
||||||
| 4 | program-wiring | 1 | Not started | - |
|
| 4 | program-wiring | 1 | ✅ Complete | 2026-05-13 |
|
||||||
|
| 5 | nc-validator | 1 | ✅ Complete | 2026-05-13 |
|
||||||
|
|
||||||
## Phase Details
|
## Phase Details
|
||||||
|
|
||||||
### Phase 1: cnc-abstraction
|
### Phase 1: cnc-abstraction ✅
|
||||||
|
|
||||||
**Goal:** Fix namespace, add all Cnc/ files to csproj, complete ICncMachine + IFanucMachine with 3-file support
|
**Goal:** Fix namespace, add all Cnc/ files to csproj, complete ICncMachine + IFanucMachine with 3-file support
|
||||||
**Depends on:** Nothing
|
**Completed:** 2026-05-13
|
||||||
**Research:** Unlikely
|
|
||||||
|
|
||||||
**Scope:**
|
**Delivered:**
|
||||||
- Fix namespace Fanuc_integration → FanucProgramManager.Cnc
|
- Namespace `Fanuc_integration.Cnc.*` → `FanucProgramManager.Cnc.*` (29 files)
|
||||||
- Add using FanucProgramManager to Fanuc-specific files
|
- `IFocasDialect` extended: `UploadStart`/`DownloadStart` accept `short fileType`
|
||||||
- Extend IFocasDialect to accept fileType for tool/work data
|
- `IFanucMachine` interface: extends `ICncMachine` with tool offset + work zero R/W
|
||||||
- Add IFanucMachine interface with tool offset + work zero ops
|
- `CncManufacturer` enum: Fanuc, Heidenhain, Siemens
|
||||||
- Add CncManufacturer enum, CncMachineFactory stub
|
- All 29 `Cnc/**/*.cs` files added to csproj
|
||||||
- Add all Cnc/ to csproj
|
|
||||||
|
|
||||||
**Plans:**
|
### Phase 2: heidenhain ✅
|
||||||
- [ ] 01-01: Fix namespace, extend dialect interface, IFanucMachine
|
|
||||||
- [ ] 01-02: CncManufacturer, CncMachineFactory, add to csproj
|
|
||||||
|
|
||||||
### Phase 2: heidenhain
|
|
||||||
|
|
||||||
**Goal:** Implement ICncMachine for Heidenhain TNC via LSV2 protocol
|
**Goal:** Implement ICncMachine for Heidenhain TNC via LSV2 protocol
|
||||||
**Depends on:** Phase 1
|
**Completed:** 2026-05-13
|
||||||
**Research:** Likely (LSV2 binary protocol)
|
|
||||||
|
|
||||||
**Scope:**
|
**Delivered:**
|
||||||
- HeidenhainConnectionConfig
|
- `HeidenhainConnectionConfig` — IP, port 19000, credentials, timeout
|
||||||
- Lsv2Client (TCP framing, CRC16, commands)
|
- `Lsv2Client` — TCP framing, CRC-16/CCITT, login (SELECT+LOG_IN), ReceiveFile/SendFile
|
||||||
- HeidenhainMachine : ICncMachine
|
- `HeidenhainMachine : ICncMachine` — RunGuardedAsync pattern, state machine
|
||||||
|
|
||||||
**Plans:**
|
### Phase 3: siemens ✅
|
||||||
- [ ] 02-01: Heidenhain LSV2 full implementation
|
|
||||||
|
|
||||||
### Phase 3: siemens
|
|
||||||
|
|
||||||
**Goal:** Implement ICncMachine for Siemens Sinumerik via FTP
|
**Goal:** Implement ICncMachine for Siemens Sinumerik via FTP
|
||||||
**Depends on:** Phase 1
|
**Completed:** 2026-05-13
|
||||||
**Research:** Unlikely (standard FTP)
|
|
||||||
|
|
||||||
**Scope:**
|
**Delivered:**
|
||||||
- SiemensConnectionConfig
|
- `SiemensConnectionConfig` — IP, port 21, creds, program dir `/_N_MPF_DIR/`
|
||||||
- SiemensMachine : ICncMachine via FtpWebRequest
|
- `SiemensFtpClient` — FtpWebRequest wrapper, ASCII mode, passive
|
||||||
|
- `SiemensMachine : ICncMachine`
|
||||||
|
|
||||||
**Plans:**
|
**Bonus (post-apply):**
|
||||||
- [ ] 03-01: Siemens FTP implementation
|
- `MitsubishiConnectionConfig` / `MitsubishiFtpClient` / `MitsubishiMachine : ICncMachine`
|
||||||
|
- `CncManufacturer.Mitsubishi` added to enum + factory + CLI
|
||||||
|
|
||||||
### Phase 4: program-wiring
|
### Phase 4: program-wiring ✅
|
||||||
|
|
||||||
**Goal:** Wire all 3 manufacturers into Program.cs + InputArgs, replace old FANUCMachine
|
**Goal:** Wire all manufacturers into Program.cs + InputArgs
|
||||||
**Depends on:** Phase 1, 2, 3
|
**Completed:** 2026-05-13
|
||||||
|
|
||||||
**Scope:**
|
**Delivered:**
|
||||||
- Update InputArgs with -manufacturer= param
|
- `CncMachineFactory` — creates right `ICncMachine` from `InputArgs`
|
||||||
- Refactor Program.cs to use ICncMachine factory
|
- `InputArgs` — added `manufacturer`, `username`, `password` fields
|
||||||
- Keep 3-file logic for Fanuc only
|
- `Program.cs` — full rewrite using `ICncMachine` factory; Fanuc 3-file via `IFanucMachine` cast
|
||||||
|
|
||||||
**Plans:**
|
### Phase 5: nc-validator ✅
|
||||||
- [ ] 04-01: InputArgs + Program.cs refactor
|
|
||||||
|
**Goal:** Per-manufacturer NC program validator runs inside WriteProgramAsync before upload
|
||||||
|
**Completed:** 2026-05-13
|
||||||
|
|
||||||
|
**Delivered:**
|
||||||
|
- `ValidationSeverity` / `ValidationError` / `ValidationResult` model types
|
||||||
|
- `INcProgramValidator` + `NcProgramValidator` with universal + per-manufacturer rules
|
||||||
|
- Validator injected into all 4 machine classes
|
||||||
|
- `NcProgramValidatorTests` — 30+ NUnit tests
|
||||||
|
|
||||||
---
|
---
|
||||||
*Roadmap created: 2026-05-13*
|
|
||||||
|
## Next Milestone
|
||||||
|
|
||||||
|
**v0.2 NcProgramManager** (in progress)
|
||||||
|
Status: In Progress
|
||||||
|
Phases: 3 of 4 complete
|
||||||
|
|
||||||
|
| Phase | Name | Plans | Status |
|
||||||
|
|-------|------|-------|--------|
|
||||||
|
| 06 | rename-cleanup | 1 | ✅ Complete |
|
||||||
|
| 07 | license-core | 1 | ✅ Complete |
|
||||||
|
| 08 | license-integration | 1 | ✅ Complete | 2026-05-17 |
|
||||||
|
| 09 | license-generator | 1 | Not started |
|
||||||
|
|
||||||
|
### Phase 06: rename-cleanup ✅
|
||||||
|
**Goal:** Rename FanucProgramManager → NcProgramManager (namespace, project files, test folder). Delete dead FANUCMachine.cs.
|
||||||
|
**Completed:** 2026-05-17
|
||||||
|
**Plans:** [x] 06-01: Namespace + file rename
|
||||||
|
|
||||||
|
### Phase 07: license-core ✅
|
||||||
|
**Goal:** `IMachineFingerprint`, `ILicenseValidator`, RSA signature verification, `.lic` file model
|
||||||
|
**Completed:** 2026-05-17
|
||||||
|
**Plans:** [x] 07-01: RSA core + interfaces + 6 unit tests
|
||||||
|
|
||||||
|
### Phase 08: license-integration ✅
|
||||||
|
**Goal:** Wire license system into Program.cs, delete `checkLicense`, remove `-chiave=`, hardcode `license.lic` next to EXE
|
||||||
|
**Completed:** 2026-05-17
|
||||||
|
**Plans:** [x] 08-01: Program.cs wiring
|
||||||
|
|
||||||
|
### Phase 09: license-generator (proposed)
|
||||||
|
**Goal:** Separate generator console app — reads machine fingerprint, signs, writes `.lic` file
|
||||||
|
**Depends on:** Phase 07
|
||||||
|
|
||||||
|
---
|
||||||
|
*Roadmap updated: 2026-05-17 — Phase 08 license-integration complete*
|
||||||
|
|
|
||||||
143
.paul/STATE.md
143
.paul/STATE.md
|
|
@ -2,110 +2,127 @@
|
||||||
|
|
||||||
## Project Reference
|
## Project Reference
|
||||||
|
|
||||||
See: .paul/PROJECT.md (updated 2026-05-13)
|
See: .paul/PROJECT.md (updated 2026-05-17)
|
||||||
|
|
||||||
**Core value:** Machinists transfer CNC programs to/from any controller without manual steps or internet
|
**Core value:** Machinists transfer CNC programs to/from any controller without manual steps or internet
|
||||||
**Current focus:** 4-CN implementation complete — awaiting user verification and UNIFY
|
**Current focus:** v0.2 — Phase 08 complete, Phase 09 (license-generator) next
|
||||||
|
|
||||||
## Current Position
|
## Current Position
|
||||||
|
|
||||||
Milestone: v0.1 Multi-CN Release
|
Milestone: v0.2 NcProgramManager
|
||||||
Phase: 5 of 5 — Applied
|
Phase: 4 of 4 (09-license-generator) — Not started
|
||||||
Plan: All plans applied, awaiting user UNIFY
|
Status: Phase 08 complete, ready to plan Phase 09
|
||||||
Status: APPLY complete, ready for UNIFY
|
Last activity: 2026-05-17 — Phase 08 license-integration complete (UNIFY done)
|
||||||
Last activity: 2026-05-13 — Phase 5 NC Validator applied by agent
|
|
||||||
|
|
||||||
Progress:
|
Progress:
|
||||||
- Milestone: [█████████░] 90%
|
- Milestone v0.1: [██████████] 100% (complete)
|
||||||
|
- Milestone v0.2: [███████░░░] 75%
|
||||||
|
- Phase 09: [░░░░░░░░░░] 0%
|
||||||
|
|
||||||
## Loop Position
|
## Loop Position
|
||||||
|
|
||||||
Current loop state:
|
|
||||||
```
|
```
|
||||||
PLAN ──▶ APPLY ──▶ UNIFY
|
PLAN ──▶ APPLY ──▶ UNIFY
|
||||||
✓ ✓ ○ [Awaiting user verification + /paul:unify]
|
✓ ✓ ✓ [Phase 08 closed]
|
||||||
```
|
```
|
||||||
|
|
||||||
## What was built (all 4 phases)
|
## What Was Built (v0.1 Multi-CN Release)
|
||||||
|
|
||||||
### Phase 1 — Cnc abstraction fixed
|
### Phase 1 — CNC Abstraction
|
||||||
- Namespace: `Fanuc_integration.Cnc.*` → `FanucProgramManager.Cnc.*` across 29 files
|
- Namespace: `Fanuc_integration.Cnc.*` → `FanucProgramManager.Cnc.*` (29 files)
|
||||||
- `using FanucProgramManager;` added to all FOCAS-using files
|
- `IFocasDialect` extended: `UploadStart`/`DownloadStart` accept `short fileType`
|
||||||
- `IFocasDialect` extended: `UploadStart`/`DownloadStart` now accept `short fileType`
|
|
||||||
- `IFanucMachine` created: extends `ICncMachine` with tool offset + work zero R/W
|
- `IFanucMachine` created: extends `ICncMachine` with tool offset + work zero R/W
|
||||||
- `FanucMachine` now implements `IFanucMachine`
|
- `CncManufacturer` enum: Fanuc, Heidenhain, Siemens, Mitsubishi
|
||||||
- `CncManufacturer` enum: Fanuc, Heidenhain, Siemens
|
- All 29 `Cnc/**/*.cs` files added to csproj
|
||||||
- All 29 `Cnc/**/*.cs` files added to `.csproj` (36 total Compile entries)
|
|
||||||
|
|
||||||
### Phase 2 — Heidenhain LSV2
|
### Phase 2 — Heidenhain LSV2
|
||||||
- `HeidenhainConnectionConfig` — IP, port 19000, credentials, timeout
|
- `HeidenhainConnectionConfig` — IP, port 19000, credentials, timeout
|
||||||
- `Lsv2Client` — TCP framing, CRC-16/CCITT, login (SELECT+LOG_IN), ReceiveFile/SendFile
|
- `Lsv2Client` — TCP framing, CRC-16/CCITT, login (SELECT+LOG_IN), ReceiveFile/SendFile
|
||||||
- `HeidenhainMachine : ICncMachine` — RunGuardedAsync pattern, state machine
|
- `HeidenhainMachine : ICncMachine` — RunGuardedAsync pattern, state machine
|
||||||
|
|
||||||
### Phase 3.1 — Mitsubishi M-series (added post-apply)
|
### Phase 3 — Siemens + Mitsubishi FTP
|
||||||
- `MitsubishiConnectionConfig` — port 21, dir `/PRG/` (no file extensions)
|
- `SiemensConnectionConfig` / `SiemensFtpClient` / `SiemensMachine : ICncMachine`
|
||||||
- `MitsubishiFtpClient` / `MitsubishiMachine : ICncMachine` — FTP, same pattern as Siemens
|
- `MitsubishiConnectionConfig` / `MitsubishiFtpClient` / `MitsubishiMachine : ICncMachine`
|
||||||
- `CncManufacturer.Mitsubishi` added to enum + factory + CLI parsing
|
|
||||||
|
|
||||||
### Phase 3 — Siemens Sinumerik FTP
|
|
||||||
- `SiemensConnectionConfig` — IP, port 21, creds, program dir `/_N_MPF_DIR/`
|
|
||||||
- `SiemensFtpClient` — FtpWebRequest wrapper, ASCII mode, passive
|
|
||||||
- `SiemensMachine : ICncMachine` — same pattern as FanucMachine
|
|
||||||
|
|
||||||
### Phase 4 — Wiring
|
### Phase 4 — Wiring
|
||||||
- `CncMachineFactory` — creates right ICncMachine from InputArgs
|
- `CncMachineFactory` — creates right `ICncMachine` from `InputArgs`
|
||||||
- `InputArgs` — added `manufacturer`, `username`, `password` fields
|
- `InputArgs` — added `manufacturer`, `username`, `password` fields
|
||||||
- `Program.cs` — full rewrite using ICncMachine; Fanuc 3-file via IFanucMachine cast
|
- `Program.cs` — full rewrite using `ICncMachine`; Fanuc 3-file via `IFanucMachine` cast
|
||||||
|
|
||||||
### Phase 5 — NC Validator
|
### Phase 5 — NC Validator
|
||||||
- `ValidationSeverity` enum (Error/Warning)
|
- `ValidationSeverity` / `ValidationError` / `ValidationResult` model types
|
||||||
- `ValidationError` — Line, Message, Severity
|
- `INcProgramValidator` + `NcProgramValidator` (5 universal + per-manufacturer rules)
|
||||||
- `ValidationResult` — Success + IReadOnlyList<ValidationError>, static Ok()/Fail()
|
- Validator injected into all 4 machine classes; upload blocked on Error severity
|
||||||
- `INcProgramValidator` interface
|
- `NcProgramValidatorTests` — 30+ NUnit tests
|
||||||
- `NcProgramValidator` — universal rules (block length ≤80, no lowercase, no tabs, no nested parens, comment ≤32); per-manufacturer name format + forbidden char rules; `#` in Fanuc/Mitsubishi is Warning not Error
|
|
||||||
- All 4 machines injected: public constructor creates `NcProgramValidator(manufacturer)`, internal constructor accepts `INcProgramValidator` for testing
|
|
||||||
- All 4 machines call validator in `WriteProgramAsync` before upload; fail on any Error-severity violation
|
|
||||||
- `NcProgramValidatorTests` — 30+ test cases covering all rules and all manufacturers
|
|
||||||
- Existing machine unit tests updated: inject always-ok mock validator to preserve existing behaviour tests
|
|
||||||
- Integration tests updated: content+names corrected to pass validation per manufacturer
|
|
||||||
- 5 new Compile entries in main csproj + 1 in tests csproj
|
|
||||||
|
|
||||||
## New CLI args
|
### Test Infrastructure
|
||||||
- `-manufacturer=fanuc|heidenhain|siemens` (default: fanuc)
|
- `NcProgramManager.Tests/` — NUnit 3.13.3 + Moq 4.18.4, .NET 4.7.2
|
||||||
- `-username=` (Heidenhain/Siemens)
|
- `FtpServerStub` + `Lsv2ServerStub` — in-process TCP stubs
|
||||||
- `-password=` (Heidenhain/Siemens)
|
- Unit + integration tests; Fanuc FOCAS tests `[Ignore]`d (Windows-only DLL)
|
||||||
|
|
||||||
|
## What Was Built (v0.2 NcProgramManager — in progress)
|
||||||
|
|
||||||
|
### Phase 06 — Rename Cleanup
|
||||||
|
- Namespace: `FanucProgramManager.*` → `NcProgramManager.*` (all files)
|
||||||
|
- Project renamed, test folder renamed, dead `FANUCMachine.cs` deleted
|
||||||
|
|
||||||
|
### Phase 07 — License Core
|
||||||
|
- `IMachineFingerprint` / `ILicenseValidator` interfaces
|
||||||
|
- `MachineFingerprint` — WMI CPU/BIOS fingerprint, SHA256 hash
|
||||||
|
- `LicenseFile.TryRead` — reads `.lic` file, returns base64 signature
|
||||||
|
- `LicenseValidator.Validate` — RSA-SHA256 verify; PLACEHOLDER public key until Phase 09
|
||||||
|
- `LicenseValidatorTests` — 6 unit tests (testable via internal ctor injection)
|
||||||
|
|
||||||
|
### Phase 08 — License Integration
|
||||||
|
- `Program.cs` — `checkLicense` deleted; RSA check wired at startup:
|
||||||
|
```csharp
|
||||||
|
string _licPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "license.lic");
|
||||||
|
if (!LicenseFile.TryRead(_licPath, out _licBase64)
|
||||||
|
|| !new LicenseValidator().Validate(_licFingerprint, _licBase64)) { ... }
|
||||||
|
```
|
||||||
|
- `InputArgs.cs` — `chiave` field removed
|
||||||
|
- `-chiave=` CLI arg removed; license file hardcoded next to EXE as `license.lic`
|
||||||
|
- `MostraAiuto` updated: instructs user to place `license.lic` next to executable
|
||||||
|
|
||||||
|
## CLI Args (current)
|
||||||
|
- `-manufacturer=fanuc|heidenhain|siemens|mitsubishi` (default: fanuc)
|
||||||
|
- `-azione=` — action (Scarica/Invia/etc.)
|
||||||
|
- `-ip=` — CNC IP
|
||||||
|
- `-porta=` — port
|
||||||
|
- `-username=` (Heidenhain/Siemens/Mitsubishi)
|
||||||
|
- `-password=` (Heidenhain/Siemens/Mitsubishi)
|
||||||
|
- License: place `license.lic` next to the EXE (no CLI arg)
|
||||||
|
|
||||||
## Accumulated Context
|
## Accumulated Context
|
||||||
|
|
||||||
### Decisions
|
### Decisions
|
||||||
- .NET 4.7.2 locked — max compatibility
|
- .NET 4.7.2 locked — max compatibility
|
||||||
- Offline-only license check (AES, unchanged)
|
- RSA asymmetric offline licensing: private key vendor-only, public key embedded in binary
|
||||||
|
- `license.lic` always at `AppDomain.CurrentDomain.BaseDirectory` — no CLI override
|
||||||
|
- `RSACryptoServiceProvider` + `SHA256CryptoServiceProvider` (not HashAlgorithmName) — .NET 4.7.2 compat
|
||||||
|
- Constructor injection pattern: internal ctor accepts key XML — testable without Windows WMI
|
||||||
|
- PublicKeyXml = PLACEHOLDER until Phase 09 generates real key pair
|
||||||
- Heidenhain: LSV2 port 19000, needs real hardware testing
|
- Heidenhain: LSV2 port 19000, needs real hardware testing
|
||||||
- Siemens: FTP /_N_MPF_DIR/, needs Sinumerik FTP option enabled on machine
|
- Siemens: FTP `/_N_MPF_DIR/`, needs Sinumerik FTP option enabled on machine
|
||||||
|
- `#` = Warning in Fanuc/Mitsubishi — macro variable indicator
|
||||||
### Phase 5 — Test project (added post-apply)
|
|
||||||
- `FanucProgramManager.Tests/` — NUnit 3.13.3 + Moq 4.18.4, .NET 4.7.2
|
|
||||||
- 7 unit test files (14+ tests on `FanucProgram`, `IsoProgramFormatter`, factory, all 4 machines)
|
|
||||||
- `FtpServerStub` — in-process TCP FTP (PASV); `Lsv2ServerStub` — in-process LSV2 TCP
|
|
||||||
- 3 integration test files — write→read round-trips against local stubs
|
|
||||||
- `InternalsVisibleTo("FanucProgramManager.Tests")` added to `AssemblyInfo.cs`
|
|
||||||
- Fanuc FOCAS tests that need Windows DLL are `[Ignore]`-d with explanation
|
|
||||||
|
|
||||||
### Deferred Issues
|
### Deferred Issues
|
||||||
- License system: still hardcoded AES key/IV — needs Phase 2.x redesign
|
- Real RSA key pair — Phase 09 output; copy PublicKeyXml into LicenseValidator.cs
|
||||||
- Heidenhain LSV2: ReadActiveProgramAsync / SelectMainProgram not supported
|
- `AesCrypt.cs` dead code — remove in future cleanup phase
|
||||||
- Siemens FTP: ReadActiveProgramAsync / SelectMainProgram not supported
|
- Heidenhain: `ReadActiveProgramAsync` / `SelectMainProgram` not implemented
|
||||||
- Build not verifiable on Linux (fwlib32 is Windows-only DLL)
|
- Siemens: same as Heidenhain
|
||||||
|
- Build + integration not verifiable on Linux (fwlib32 Windows-only)
|
||||||
|
- MachineFingerprint WMI — code-review verified, needs real Windows hardware test
|
||||||
|
|
||||||
### Blockers/Concerns
|
### Blockers/Concerns
|
||||||
None — code complete, pending hardware testing.
|
None — Phase 09 can start.
|
||||||
|
|
||||||
## Session Continuity
|
## Session Continuity
|
||||||
|
|
||||||
Last session: 2026-05-13
|
Last session: 2026-05-17
|
||||||
Stopped at: Phase 5 (NC Validator) applied — all 12 files created/modified
|
Stopped at: Phase 08 UNIFY complete
|
||||||
Next action: Build to verify compilation; run unit tests; /paul:unify when ready
|
Next action: /paul:plan phase 09 license-generator
|
||||||
Resume file: .paul/STATE.md
|
Resume file: .paul/ROADMAP.md
|
||||||
|
|
||||||
---
|
---
|
||||||
*STATE.md — Updated after every significant action*
|
*STATE.md — Updated after every significant action*
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
{
|
{
|
||||||
"name": "FanucProgramManager",
|
"name": "NcProgramManager",
|
||||||
"version": "0.0.0",
|
"version": "0.2.0-dev",
|
||||||
"milestone": {
|
"milestone": {
|
||||||
"name": "None",
|
"name": "v0.2 NcProgramManager",
|
||||||
"version": "0.0.0",
|
"version": "0.2.0",
|
||||||
"status": "not_started"
|
"status": "in_progress"
|
||||||
},
|
},
|
||||||
"phase": {
|
"phase": {
|
||||||
"number": 0,
|
"number": 8,
|
||||||
"name": "None",
|
"name": "license-integration",
|
||||||
"status": "not_started"
|
"status": "complete"
|
||||||
},
|
},
|
||||||
"loop": {
|
"loop": {
|
||||||
"plan": null,
|
"plan": null,
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
},
|
},
|
||||||
"timestamps": {
|
"timestamps": {
|
||||||
"created_at": "2026-05-13T00:00:00Z",
|
"created_at": "2026-05-13T00:00:00Z",
|
||||||
"updated_at": "2026-05-13T00:00:00Z"
|
"updated_at": "2026-05-17T22:00:00Z"
|
||||||
},
|
},
|
||||||
"satellite": {
|
"satellite": {
|
||||||
"groom": true
|
"groom": true
|
||||||
|
|
|
||||||
134
.paul/phases/05-nc-validator/05-01-SUMMARY.md
Normal file
134
.paul/phases/05-nc-validator/05-01-SUMMARY.md
Normal file
|
|
@ -0,0 +1,134 @@
|
||||||
|
---
|
||||||
|
phase: 05-nc-validator
|
||||||
|
plan: 01
|
||||||
|
subsystem: validation
|
||||||
|
tags: [nc-program, validation, csharp, dotnet472, nunit]
|
||||||
|
|
||||||
|
requires:
|
||||||
|
- phase: 04-program-wiring
|
||||||
|
provides: ICncMachine implementations for all 4 manufacturers
|
||||||
|
|
||||||
|
provides:
|
||||||
|
- INcProgramValidator interface + NcProgramValidator implementation
|
||||||
|
- Pre-upload validation in all 4 machine WriteProgramAsync methods
|
||||||
|
- 30+ unit tests covering all rules and all manufacturers
|
||||||
|
|
||||||
|
affects: []
|
||||||
|
|
||||||
|
tech-stack:
|
||||||
|
added: []
|
||||||
|
patterns:
|
||||||
|
- "Validator injected via constructor (public creates default, internal accepts mock)"
|
||||||
|
- "ValidationResult static factory: Ok() / Fail(errors)"
|
||||||
|
|
||||||
|
key-files:
|
||||||
|
created:
|
||||||
|
- Cnc/Models/ValidationSeverity.cs
|
||||||
|
- Cnc/Models/ValidationError.cs
|
||||||
|
- Cnc/Models/ValidationResult.cs
|
||||||
|
- Cnc/INcProgramValidator.cs
|
||||||
|
- Cnc/NcProgramValidator.cs
|
||||||
|
- FanucProgramManager.Tests/Unit/NcProgramValidatorTests.cs
|
||||||
|
modified:
|
||||||
|
- Cnc/Fanuc/FanucMachine.cs
|
||||||
|
- Cnc/Heidenhain/HeidenhainMachine.cs
|
||||||
|
- Cnc/Siemens/SiemensMachine.cs
|
||||||
|
- Cnc/Mitsubishi/MitsubishiMachine.cs
|
||||||
|
- FanucProgramManager.csproj
|
||||||
|
- FanucProgramManager.Tests/FanucProgramManager.Tests.csproj
|
||||||
|
|
||||||
|
key-decisions:
|
||||||
|
- "# in Fanuc/Mitsubishi is Warning not Error — macro variable indicator, not a format error"
|
||||||
|
- "Internal constructor accepts INcProgramValidator — enables unit testing without mocking filesystem"
|
||||||
|
|
||||||
|
patterns-established:
|
||||||
|
- "Constructor injection for testability: public ctor creates real validator, internal ctor accepts mock"
|
||||||
|
- "ValidationResult.Ok() / Fail(errors) static factory pattern"
|
||||||
|
|
||||||
|
duration: unknown
|
||||||
|
started: 2026-05-13T00:00:00Z
|
||||||
|
completed: 2026-05-13T00:00:00Z
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 5 Plan 1: NC Validator Summary
|
||||||
|
|
||||||
|
**Per-manufacturer NC program validator integrated into all 4 machine WriteProgramAsync methods, with 30+ unit tests.**
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
| Metric | Value |
|
||||||
|
|--------|-------|
|
||||||
|
| Duration | ~2h (estimated) |
|
||||||
|
| Started | 2026-05-13 |
|
||||||
|
| Completed | 2026-05-13 |
|
||||||
|
| Tasks | 12 files created/modified |
|
||||||
|
| Files modified | 12 |
|
||||||
|
|
||||||
|
## Acceptance Criteria Results
|
||||||
|
|
||||||
|
| Criterion | Status | Notes |
|
||||||
|
|-----------|--------|-------|
|
||||||
|
| NcProgramValidator validates all 4 manufacturers | Pass | Fanuc, Heidenhain, Siemens, Mitsubishi |
|
||||||
|
| Universal rules: block ≤80, no lowercase, no tabs, no nested parens, comment ≤32 | Pass | All rules implemented |
|
||||||
|
| Per-manufacturer name format + forbidden chars | Pass | Per spec |
|
||||||
|
| Fanuc # char is Warning not Error | Pass | Mitsubishi same |
|
||||||
|
| All 4 machines call validator in WriteProgramAsync | Pass | Verified by grep |
|
||||||
|
| Unit tests cover all rules + all manufacturers | Pass | 30+ test cases |
|
||||||
|
| csproj Compile entries added (5 main + 1 test) | Pass | Verified by grep count |
|
||||||
|
|
||||||
|
## Accomplishments
|
||||||
|
|
||||||
|
- `NcProgramValidator` with 5 universal + 4 per-manufacturer rule sets
|
||||||
|
- All 4 machine classes fail upload on any Error-severity violation
|
||||||
|
- Constructor injection pattern enables testability without test pollution
|
||||||
|
- 30+ NUnit test cases; existing machine tests updated with always-ok mock validator
|
||||||
|
|
||||||
|
## Files Created/Modified
|
||||||
|
|
||||||
|
| File | Change | Purpose |
|
||||||
|
|------|--------|---------|
|
||||||
|
| `Cnc/Models/ValidationSeverity.cs` | Created | Error/Warning enum |
|
||||||
|
| `Cnc/Models/ValidationError.cs` | Created | Line + message + severity |
|
||||||
|
| `Cnc/Models/ValidationResult.cs` | Created | Success flag + error list, Ok()/Fail() |
|
||||||
|
| `Cnc/INcProgramValidator.cs` | Created | Validator interface |
|
||||||
|
| `Cnc/NcProgramValidator.cs` | Created | Full rule implementation |
|
||||||
|
| `Cnc/Fanuc/FanucMachine.cs` | Modified | Validator injected, WriteProgramAsync gated |
|
||||||
|
| `Cnc/Heidenhain/HeidenhainMachine.cs` | Modified | Same |
|
||||||
|
| `Cnc/Siemens/SiemensMachine.cs` | Modified | Same |
|
||||||
|
| `Cnc/Mitsubishi/MitsubishiMachine.cs` | Modified | Same |
|
||||||
|
| `FanucProgramManager.Tests/Unit/NcProgramValidatorTests.cs` | Created | 30+ test cases |
|
||||||
|
| `FanucProgramManager.csproj` | Modified | +5 Compile entries |
|
||||||
|
| `FanucProgramManager.Tests/FanucProgramManager.Tests.csproj` | Modified | +1 Compile entry |
|
||||||
|
|
||||||
|
## Decisions Made
|
||||||
|
|
||||||
|
| Decision | Rationale | Impact |
|
||||||
|
|----------|-----------|--------|
|
||||||
|
| `#` = Warning in Fanuc/Mitsubishi | Macro variable indicator — valid in context | Uploads proceed; operator notified |
|
||||||
|
| Internal constructor for mock injection | .NET 4.7.2 — no Moq interface without internal access | All machine tests remain isolated |
|
||||||
|
|
||||||
|
## Deviations from Plan
|
||||||
|
|
||||||
|
None — plan executed as specified.
|
||||||
|
|
||||||
|
## Issues Encountered
|
||||||
|
|
||||||
|
| Issue | Resolution |
|
||||||
|
|-------|------------|
|
||||||
|
| Build not verifiable on Linux | fwlib32 is Windows-only DLL — tests using FOCAS marked `[Ignore]` |
|
||||||
|
|
||||||
|
## Next Phase Readiness
|
||||||
|
|
||||||
|
**Ready:**
|
||||||
|
- Validator fully integrated — any new machine implementing `ICncMachine` can inject it
|
||||||
|
- Test infrastructure in place for future expansion
|
||||||
|
|
||||||
|
**Concerns:**
|
||||||
|
- Hardware testing still pending for Heidenhain and Siemens
|
||||||
|
- License system hardcoded — deferred from earlier phases
|
||||||
|
|
||||||
|
**Blockers:** None
|
||||||
|
|
||||||
|
---
|
||||||
|
*Phase: 05-nc-validator, Plan: 01*
|
||||||
|
*Completed: 2026-05-13*
|
||||||
220
.paul/phases/06-rename-cleanup/06-01-PLAN.md
Normal file
220
.paul/phases/06-rename-cleanup/06-01-PLAN.md
Normal file
|
|
@ -0,0 +1,220 @@
|
||||||
|
---
|
||||||
|
phase: 06-rename-cleanup
|
||||||
|
plan: 01
|
||||||
|
type: execute
|
||||||
|
wave: 1
|
||||||
|
depends_on: []
|
||||||
|
files_modified:
|
||||||
|
- "**/*.cs (all ~62 files — namespace string replace)"
|
||||||
|
- Properties/AssemblyInfo.cs
|
||||||
|
- FanucProgramManager.csproj → NcProgramManager.csproj
|
||||||
|
- FanucProgramManager.sln → NcProgramManager.sln
|
||||||
|
- FanucProgramManager.Tests/FanucProgramManager.Tests.csproj → NcProgramManager.Tests/NcProgramManager.Tests.csproj
|
||||||
|
- FANUCMachine.cs (delete)
|
||||||
|
autonomous: true
|
||||||
|
---
|
||||||
|
|
||||||
|
<objective>
|
||||||
|
## Goal
|
||||||
|
Rename project from FanucProgramManager to NcProgramManager: namespace, assembly, project files, test folder, and delete dead legacy file.
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
Product is no longer Fanuc-only. Name FanucProgramManager is wrong. NcProgramManager reflects multi-CN scope.
|
||||||
|
|
||||||
|
## Output
|
||||||
|
- All namespaces: `FanucProgramManager` → `NcProgramManager`
|
||||||
|
- Project/solution files renamed
|
||||||
|
- Test folder renamed
|
||||||
|
- `FANUCMachine.cs` deleted (zero references outside itself)
|
||||||
|
- Solution builds with no errors
|
||||||
|
</objective>
|
||||||
|
|
||||||
|
<context>
|
||||||
|
## Project Context
|
||||||
|
@.paul/PROJECT.md
|
||||||
|
@.paul/STATE.md
|
||||||
|
|
||||||
|
## Key Files
|
||||||
|
@FanucProgramManager.csproj
|
||||||
|
@FanucProgramManager.sln
|
||||||
|
@Properties/AssemblyInfo.cs
|
||||||
|
@FanucProgramManager.Tests/FanucProgramManager.Tests.csproj
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<acceptance_criteria>
|
||||||
|
|
||||||
|
## AC-1: Namespace renamed everywhere
|
||||||
|
```gherkin
|
||||||
|
Given any .cs file in the project
|
||||||
|
When opened
|
||||||
|
Then namespace declarations and using directives reference NcProgramManager (not FanucProgramManager)
|
||||||
|
```
|
||||||
|
|
||||||
|
## AC-2: Project and solution files updated
|
||||||
|
```gherkin
|
||||||
|
Given the renamed solution
|
||||||
|
When opened in Visual Studio or built with msbuild
|
||||||
|
Then assembly name is NcProgramManager, test assembly is NcProgramManager.Tests, project reference resolves
|
||||||
|
```
|
||||||
|
|
||||||
|
## AC-3: Dead code removed
|
||||||
|
```gherkin
|
||||||
|
Given FANUCMachine.cs
|
||||||
|
When cleanup completes
|
||||||
|
Then file does not exist (confirmed zero references before deletion)
|
||||||
|
```
|
||||||
|
|
||||||
|
</acceptance_criteria>
|
||||||
|
|
||||||
|
<tasks>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 1: Replace FanucProgramManager string in all .cs files</name>
|
||||||
|
<files>All *.cs files under project root (recursively)</files>
|
||||||
|
<action>
|
||||||
|
Run find+sed to replace all occurrences of `FanucProgramManager` with `NcProgramManager` in every .cs file:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
find /path/to/project -name "*.cs" -exec sed -i 's/FanucProgramManager/NcProgramManager/g' {} +
|
||||||
|
```
|
||||||
|
|
||||||
|
This covers:
|
||||||
|
- `namespace FanucProgramManager` → `namespace NcProgramManager`
|
||||||
|
- `namespace FanucProgramManager.Cnc` → `namespace NcProgramManager.Cnc`
|
||||||
|
- `using FanucProgramManager;` → `using NcProgramManager;`
|
||||||
|
- `using FanucProgramManager.Cnc.Fanuc;` → `using NcProgramManager.Cnc.Fanuc;`
|
||||||
|
- All sub-namespaces (.Cnc, .Cnc.Fanuc, .Cnc.Heidenhain, .Cnc.Siemens, .Cnc.Mitsubishi, .Cnc.Models)
|
||||||
|
- `InternalsVisibleTo("FanucProgramManager.Tests")` in AssemblyInfo.cs
|
||||||
|
- `AssemblyTitle`, `AssemblyProduct` in AssemblyInfo.cs
|
||||||
|
|
||||||
|
Avoid: editing binary files, NuGet package cache, obj/bin folders.
|
||||||
|
Use: `-not -path "*/obj/*" -not -path "*/bin/*" -not -path "*/.paul/*"`
|
||||||
|
</action>
|
||||||
|
<verify>
|
||||||
|
```bash
|
||||||
|
grep -r "FanucProgramManager" --include="*.cs" .
|
||||||
|
```
|
||||||
|
Must return zero results.
|
||||||
|
</verify>
|
||||||
|
<done>AC-1 satisfied: no .cs file contains FanucProgramManager</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 2: Update project and solution metadata files</name>
|
||||||
|
<files>
|
||||||
|
FanucProgramManager.csproj,
|
||||||
|
FanucProgramManager.Tests/FanucProgramManager.Tests.csproj,
|
||||||
|
FanucProgramManager.sln
|
||||||
|
</files>
|
||||||
|
<action>
|
||||||
|
In `FanucProgramManager.csproj`:
|
||||||
|
- `<RootNamespace>FanucProgramManager</RootNamespace>` → `<RootNamespace>NcProgramManager</RootNamespace>`
|
||||||
|
- `<AssemblyName>FanucProgramManager</AssemblyName>` → `<AssemblyName>NcProgramManager</AssemblyName>`
|
||||||
|
|
||||||
|
In `FanucProgramManager.Tests/FanucProgramManager.Tests.csproj`:
|
||||||
|
- `<RootNamespace>FanucProgramManager.Tests</RootNamespace>` → `<RootNamespace>NcProgramManager.Tests</RootNamespace>`
|
||||||
|
- `<AssemblyName>FanucProgramManager.Tests</AssemblyName>` → `<AssemblyName>NcProgramManager.Tests</AssemblyName>`
|
||||||
|
- `<ProjectReference Include="..\FanucProgramManager.csproj">` → `<ProjectReference Include="..\NcProgramManager.csproj">`
|
||||||
|
- `<Name>FanucProgramManager</Name>` → `<Name>NcProgramManager</Name>`
|
||||||
|
|
||||||
|
In `FanucProgramManager.sln`:
|
||||||
|
- Project line: `"FanucProgramManager", "FanucProgramManager.csproj"` → `"NcProgramManager", "NcProgramManager.csproj"`
|
||||||
|
- Project line: `"FanucProgramManager.Tests", "FanucProgramManager.Tests\FanucProgramManager.Tests.csproj"` → `"NcProgramManager.Tests", "NcProgramManager.Tests\NcProgramManager.Tests.csproj"`
|
||||||
|
</action>
|
||||||
|
<verify>
|
||||||
|
```bash
|
||||||
|
grep -n "FanucProgramManager" FanucProgramManager.csproj FanucProgramManager.Tests/FanucProgramManager.Tests.csproj FanucProgramManager.sln
|
||||||
|
```
|
||||||
|
Must return zero results.
|
||||||
|
</verify>
|
||||||
|
<done>AC-2 satisfied: all project metadata references NcProgramManager</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 3: Rename files/folder and delete dead code</name>
|
||||||
|
<files>
|
||||||
|
FANUCMachine.cs (delete),
|
||||||
|
FanucProgramManager.csproj → NcProgramManager.csproj (rename),
|
||||||
|
FanucProgramManager.sln → NcProgramManager.sln (rename),
|
||||||
|
FanucProgramManager.Tests/ → NcProgramManager.Tests/ (folder rename),
|
||||||
|
FanucProgramManager.Tests/FanucProgramManager.Tests.csproj → NcProgramManager.Tests/NcProgramManager.Tests.csproj (rename)
|
||||||
|
</files>
|
||||||
|
<action>
|
||||||
|
1. Delete `FANUCMachine.cs` — confirmed dead: no file outside itself references `FANUCMachine`. Also remove its `<Compile Include="FANUCMachine.cs" />` entry from csproj.
|
||||||
|
|
||||||
|
2. Rename project file:
|
||||||
|
```bash
|
||||||
|
mv FanucProgramManager.csproj NcProgramManager.csproj
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Rename solution file:
|
||||||
|
```bash
|
||||||
|
mv FanucProgramManager.sln NcProgramManager.sln
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Rename test folder (this moves all contents):
|
||||||
|
```bash
|
||||||
|
mv FanucProgramManager.Tests NcProgramManager.Tests
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Rename test csproj inside the now-renamed folder:
|
||||||
|
```bash
|
||||||
|
mv NcProgramManager.Tests/FanucProgramManager.Tests.csproj NcProgramManager.Tests/NcProgramManager.Tests.csproj
|
||||||
|
```
|
||||||
|
|
||||||
|
Order matters: rename folder BEFORE renaming csproj inside it.
|
||||||
|
The .sln file was already updated in Task 2 to reference new paths — verify paths match after rename.
|
||||||
|
|
||||||
|
Avoid: renaming `Cnc/Fanuc/` folder or any Fanuc-prefixed class files — `FanucMachine`, `FanucConnectionConfig` etc. are manufacturer-specific names, keep them.
|
||||||
|
</action>
|
||||||
|
<verify>
|
||||||
|
```bash
|
||||||
|
ls NcProgramManager.csproj NcProgramManager.sln NcProgramManager.Tests/NcProgramManager.Tests.csproj
|
||||||
|
ls FANUCMachine.cs 2>&1 # must say: No such file
|
||||||
|
grep "FANUCMachine" NcProgramManager.csproj # must return nothing
|
||||||
|
```
|
||||||
|
</verify>
|
||||||
|
<done>AC-2 and AC-3 satisfied: files renamed, dead code deleted, .sln paths match physical files</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
</tasks>
|
||||||
|
|
||||||
|
<boundaries>
|
||||||
|
|
||||||
|
## DO NOT CHANGE
|
||||||
|
- `Cnc/Fanuc/` folder name — Fanuc is a manufacturer name, not a project name
|
||||||
|
- `FanucMachine.cs`, `FanucConnectionConfig.cs`, `FanucCapabilities.cs` — manufacturer-specific class names, keep
|
||||||
|
- `FanucProgram.cs` — Fanuc ISO program format class, name is accurate
|
||||||
|
- `FanucProgramParsingTests.cs` — test file for FanucProgram, name is accurate
|
||||||
|
- `IFanucMachine.cs` — interface name correct (Fanuc-specific capability set)
|
||||||
|
- Any class name that describes Fanuc-specific behavior
|
||||||
|
|
||||||
|
## SCOPE LIMITS
|
||||||
|
- No Italian → English rename in this plan (deferred)
|
||||||
|
- No logic changes — pure rename/delete only
|
||||||
|
- No NuGet package changes
|
||||||
|
- No new files created
|
||||||
|
|
||||||
|
</boundaries>
|
||||||
|
|
||||||
|
<verification>
|
||||||
|
Before declaring plan complete:
|
||||||
|
- [ ] `grep -r "FanucProgramManager" --include="*.cs" .` returns zero results
|
||||||
|
- [ ] `grep -r "FanucProgramManager" --include="*.csproj" .` returns zero results
|
||||||
|
- [ ] `grep "FanucProgramManager" NcProgramManager.sln` returns zero results
|
||||||
|
- [ ] `ls FANUCMachine.cs` returns "No such file"
|
||||||
|
- [ ] `ls NcProgramManager.csproj NcProgramManager.sln NcProgramManager.Tests/` all exist
|
||||||
|
- [ ] All acceptance criteria met
|
||||||
|
</verification>
|
||||||
|
|
||||||
|
<success_criteria>
|
||||||
|
- All tasks completed
|
||||||
|
- All verification checks pass
|
||||||
|
- No FanucProgramManager references remain in .cs, .csproj, or .sln files
|
||||||
|
- FANUCMachine.cs deleted
|
||||||
|
- Project file names match NcProgramManager
|
||||||
|
</success_criteria>
|
||||||
|
|
||||||
|
<output>
|
||||||
|
After completion, create `.paul/phases/06-rename-cleanup/06-01-SUMMARY.md`
|
||||||
|
</output>
|
||||||
102
.paul/phases/06-rename-cleanup/06-01-SUMMARY.md
Normal file
102
.paul/phases/06-rename-cleanup/06-01-SUMMARY.md
Normal file
|
|
@ -0,0 +1,102 @@
|
||||||
|
---
|
||||||
|
phase: 06-rename-cleanup
|
||||||
|
plan: 01
|
||||||
|
subsystem: infra
|
||||||
|
tags: [rename, namespace, csharp, dotnet472, cleanup]
|
||||||
|
|
||||||
|
requires: []
|
||||||
|
provides:
|
||||||
|
- NcProgramManager namespace across all 62 .cs files
|
||||||
|
- NcProgramManager.csproj / NcProgramManager.sln / NcProgramManager.Tests/
|
||||||
|
- FANUCMachine.cs deleted
|
||||||
|
affects: [07-license-core, 08-license-integration, 09-license-generator]
|
||||||
|
|
||||||
|
tech-stack:
|
||||||
|
added: []
|
||||||
|
patterns: []
|
||||||
|
|
||||||
|
key-files:
|
||||||
|
created: []
|
||||||
|
modified:
|
||||||
|
- NcProgramManager.csproj (was FanucProgramManager.csproj)
|
||||||
|
- NcProgramManager.sln (was FanucProgramManager.sln)
|
||||||
|
- NcProgramManager.Tests/NcProgramManager.Tests.csproj
|
||||||
|
- All 62 .cs files (namespace string replace)
|
||||||
|
|
||||||
|
key-decisions:
|
||||||
|
- "Fanuc-prefixed class names kept: FanucMachine, FanucProgram, IFanucMachine — manufacturer names, not project names"
|
||||||
|
|
||||||
|
patterns-established: []
|
||||||
|
|
||||||
|
duration: 5min
|
||||||
|
started: 2026-05-17T00:00:00Z
|
||||||
|
completed: 2026-05-17T00:00:00Z
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 6 Plan 1: Rename Cleanup Summary
|
||||||
|
|
||||||
|
**FanucProgramManager → NcProgramManager across 62 .cs files, 3 project/solution files, test folder rename, FANUCMachine.cs deleted.**
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
| Metric | Value |
|
||||||
|
|--------|-------|
|
||||||
|
| Duration | ~5 min |
|
||||||
|
| Started | 2026-05-17 |
|
||||||
|
| Completed | 2026-05-17 |
|
||||||
|
| Tasks | 3 completed |
|
||||||
|
| Files modified | 62 .cs + 3 project files + 1 folder rename + 1 file deleted |
|
||||||
|
|
||||||
|
## Acceptance Criteria Results
|
||||||
|
|
||||||
|
| Criterion | Status | Notes |
|
||||||
|
|-----------|--------|-------|
|
||||||
|
| AC-1: Namespace renamed everywhere | Pass | grep returns zero results across all .cs files |
|
||||||
|
| AC-2: Project/solution files updated | Pass | AssemblyName, RootNamespace, ProjectReference all updated; files renamed |
|
||||||
|
| AC-3: Dead code removed | Pass | FANUCMachine.cs deleted; Compile entry removed from csproj |
|
||||||
|
|
||||||
|
## Accomplishments
|
||||||
|
|
||||||
|
- All namespaces, using directives, AssemblyTitle, AssemblyProduct, InternalsVisibleTo updated in one sed pass
|
||||||
|
- Project and test folder physically renamed to match new name
|
||||||
|
- Zero FanucProgramManager strings remain in .cs, .csproj, or .sln
|
||||||
|
|
||||||
|
## Files Created/Modified
|
||||||
|
|
||||||
|
| File | Change | Purpose |
|
||||||
|
|------|--------|---------|
|
||||||
|
| All 62 `.cs` files | Modified | `FanucProgramManager` → `NcProgramManager` namespace/usings |
|
||||||
|
| `NcProgramManager.csproj` | Renamed + modified | AssemblyName + RootNamespace updated |
|
||||||
|
| `NcProgramManager.sln` | Renamed + modified | Project references updated |
|
||||||
|
| `NcProgramManager.Tests/NcProgramManager.Tests.csproj` | Renamed + modified | AssemblyName, RootNamespace, ProjectReference updated |
|
||||||
|
| `FANUCMachine.cs` | Deleted | Dead code — zero references outside itself |
|
||||||
|
|
||||||
|
## Decisions Made
|
||||||
|
|
||||||
|
| Decision | Rationale | Impact |
|
||||||
|
|----------|-----------|--------|
|
||||||
|
| Keep `FanucMachine`, `FanucProgram`, `IFanucMachine` names | These are manufacturer-specific identifiers, not project names | Future phases reference these names unchanged |
|
||||||
|
|
||||||
|
## Deviations from Plan
|
||||||
|
|
||||||
|
None — plan executed exactly as written.
|
||||||
|
|
||||||
|
## Issues Encountered
|
||||||
|
|
||||||
|
None.
|
||||||
|
|
||||||
|
## Next Phase Readiness
|
||||||
|
|
||||||
|
**Ready:**
|
||||||
|
- All code under `NcProgramManager` namespace
|
||||||
|
- Project builds under new name (pending Windows build verification)
|
||||||
|
- Clean foundation for license system phases
|
||||||
|
|
||||||
|
**Concerns:**
|
||||||
|
- Build not verifiable on Linux (fwlib32 Windows-only DLL) — same as before
|
||||||
|
|
||||||
|
**Blockers:** None
|
||||||
|
|
||||||
|
---
|
||||||
|
*Phase: 06-rename-cleanup, Plan: 01*
|
||||||
|
*Completed: 2026-05-17*
|
||||||
441
.paul/phases/07-license-core/07-01-PLAN.md
Normal file
441
.paul/phases/07-license-core/07-01-PLAN.md
Normal file
|
|
@ -0,0 +1,441 @@
|
||||||
|
---
|
||||||
|
phase: 07-license-core
|
||||||
|
plan: 01
|
||||||
|
type: execute
|
||||||
|
wave: 1
|
||||||
|
depends_on: []
|
||||||
|
files_modified:
|
||||||
|
- Licensing/IMachineFingerprint.cs
|
||||||
|
- Licensing/ILicenseValidator.cs
|
||||||
|
- Licensing/LicenseFile.cs
|
||||||
|
- Licensing/MachineFingerprint.cs
|
||||||
|
- Licensing/LicenseValidator.cs
|
||||||
|
- NcProgramManager.Tests/Unit/LicenseValidatorTests.cs
|
||||||
|
- NcProgramManager.csproj
|
||||||
|
- NcProgramManager.Tests/NcProgramManager.Tests.csproj
|
||||||
|
autonomous: true
|
||||||
|
---
|
||||||
|
|
||||||
|
<objective>
|
||||||
|
## Goal
|
||||||
|
Create RSA-based offline license core: machine fingerprint reader, license file model, RSA signature validator — all injectable via interfaces for testability.
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
Current `checkLicense` in Program.cs uses hardcoded AES key — anyone with source or decompiler can generate licenses for any machine. RSA asymmetric crypto means only the holder of the private key (vendor) can issue valid licenses. Public key is safe to embed in binary.
|
||||||
|
|
||||||
|
## Output
|
||||||
|
- `Licensing/` folder with 5 new files
|
||||||
|
- `LicenseValidator` verifies RSA-SHA256 signature of machine fingerprint against embedded public key
|
||||||
|
- `MachineFingerprint` reads CPU ProcessorID + Motherboard SerialNumber via WMI (same data as current `checkLicense`)
|
||||||
|
- `LicenseFile` reads base64 signature from a `.lic` file on disk
|
||||||
|
- Unit tests: valid license passes, tampered/wrong-machine license fails
|
||||||
|
- 5 Compile entries added to main csproj, 1 to tests csproj
|
||||||
|
</objective>
|
||||||
|
|
||||||
|
<context>
|
||||||
|
## Project Context
|
||||||
|
@.paul/PROJECT.md
|
||||||
|
@.paul/STATE.md
|
||||||
|
|
||||||
|
## Source Files (existing license logic to extract from)
|
||||||
|
@Program.cs
|
||||||
|
@NcProgramManager.csproj
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<acceptance_criteria>
|
||||||
|
|
||||||
|
## AC-1: Machine fingerprint readable via interface
|
||||||
|
```gherkin
|
||||||
|
Given a Windows machine with WMI available
|
||||||
|
When MachineFingerprint.GetFingerprint() is called
|
||||||
|
Then it returns a non-empty string concatenating CPU ProcessorID and Motherboard SerialNumber
|
||||||
|
```
|
||||||
|
|
||||||
|
## AC-2: Valid license passes validation
|
||||||
|
```gherkin
|
||||||
|
Given a fingerprint string and a license file containing the RSA-SHA256 signature of that fingerprint
|
||||||
|
When LicenseValidator.Validate(fingerprint, licenseBase64) is called with the matching public key
|
||||||
|
Then it returns true
|
||||||
|
```
|
||||||
|
|
||||||
|
## AC-3: Invalid license rejected
|
||||||
|
```gherkin
|
||||||
|
Given a fingerprint string and a license signed for a different fingerprint (wrong machine)
|
||||||
|
When LicenseValidator.Validate(fingerprint, licenseBase64) is called
|
||||||
|
Then it returns false
|
||||||
|
```
|
||||||
|
|
||||||
|
## AC-4: Corrupted/missing license file handled
|
||||||
|
```gherkin
|
||||||
|
Given a path to a non-existent or empty .lic file
|
||||||
|
When LicenseFile.TryRead(path, out string b64) is called
|
||||||
|
Then it returns false and b64 is null (no exception thrown)
|
||||||
|
```
|
||||||
|
|
||||||
|
</acceptance_criteria>
|
||||||
|
|
||||||
|
<tasks>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 1: Create Licensing interfaces and LicenseFile</name>
|
||||||
|
<files>
|
||||||
|
Licensing/IMachineFingerprint.cs,
|
||||||
|
Licensing/ILicenseValidator.cs,
|
||||||
|
Licensing/LicenseFile.cs
|
||||||
|
</files>
|
||||||
|
<action>
|
||||||
|
Create folder `Licensing/` at project root.
|
||||||
|
|
||||||
|
**Licensing/IMachineFingerprint.cs**
|
||||||
|
```csharp
|
||||||
|
namespace NcProgramManager.Licensing
|
||||||
|
{
|
||||||
|
internal interface IMachineFingerprint
|
||||||
|
{
|
||||||
|
string GetFingerprint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Licensing/ILicenseValidator.cs**
|
||||||
|
```csharp
|
||||||
|
namespace NcProgramManager.Licensing
|
||||||
|
{
|
||||||
|
internal interface ILicenseValidator
|
||||||
|
{
|
||||||
|
bool Validate(string fingerprint, string licenseBase64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Licensing/LicenseFile.cs**
|
||||||
|
```csharp
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace NcProgramManager.Licensing
|
||||||
|
{
|
||||||
|
internal static class LicenseFile
|
||||||
|
{
|
||||||
|
internal static bool TryRead(string path, out string base64)
|
||||||
|
{
|
||||||
|
base64 = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!File.Exists(path))
|
||||||
|
return false;
|
||||||
|
string content = File.ReadAllText(path).Trim();
|
||||||
|
if (string.IsNullOrEmpty(content))
|
||||||
|
return false;
|
||||||
|
base64 = content;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Avoid: throwing exceptions from TryRead — callers expect bool pattern.
|
||||||
|
</action>
|
||||||
|
<verify>
|
||||||
|
```bash
|
||||||
|
ls Licensing/IMachineFingerprint.cs Licensing/ILicenseValidator.cs Licensing/LicenseFile.cs
|
||||||
|
grep -n "namespace NcProgramManager.Licensing" Licensing/IMachineFingerprint.cs Licensing/ILicenseValidator.cs Licensing/LicenseFile.cs
|
||||||
|
```
|
||||||
|
All three files exist with correct namespace.
|
||||||
|
</verify>
|
||||||
|
<done>AC-4 satisfied: LicenseFile.TryRead handles missing/empty file without exception</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 2: Implement MachineFingerprint and LicenseValidator</name>
|
||||||
|
<files>
|
||||||
|
Licensing/MachineFingerprint.cs,
|
||||||
|
Licensing/LicenseValidator.cs,
|
||||||
|
NcProgramManager.csproj
|
||||||
|
</files>
|
||||||
|
<action>
|
||||||
|
**Licensing/MachineFingerprint.cs**
|
||||||
|
Extract the WMI fingerprint logic from `Program.checkLicense`. Do NOT modify Program.cs yet — that is Phase 08.
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
using System.Management;
|
||||||
|
|
||||||
|
namespace NcProgramManager.Licensing
|
||||||
|
{
|
||||||
|
internal class MachineFingerprint : IMachineFingerprint
|
||||||
|
{
|
||||||
|
public string GetFingerprint()
|
||||||
|
{
|
||||||
|
string pcInfo = string.Empty;
|
||||||
|
|
||||||
|
using (var mc = new ManagementClass("win32_processor"))
|
||||||
|
using (ManagementObjectCollection moc = mc.GetInstances())
|
||||||
|
{
|
||||||
|
foreach (ManagementObject mo in moc)
|
||||||
|
{
|
||||||
|
pcInfo = mo.Properties["processorID"].Value.ToString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var searcher = new ManagementObjectSearcher(
|
||||||
|
"root\\CIMV2", "SELECT * FROM Win32_BaseBoard"))
|
||||||
|
{
|
||||||
|
foreach (ManagementObject obj in searcher.Get())
|
||||||
|
{
|
||||||
|
pcInfo += obj["SerialNumber"].ToString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pcInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Licensing/LicenseValidator.cs**
|
||||||
|
RSA-SHA256 verify. Public key is a placeholder XML constant — Phase 09 (generator) produces the real key pair; replace `PublicKeyXml` at that point.
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
using System;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace NcProgramManager.Licensing
|
||||||
|
{
|
||||||
|
internal class LicenseValidator : ILicenseValidator
|
||||||
|
{
|
||||||
|
// Placeholder — replace with real vendor public key XML after Phase 09 generates the key pair.
|
||||||
|
// Generate with: openssl genrsa 2048 | openssl rsa -pubout, then convert PEM → XML,
|
||||||
|
// or use RSACryptoServiceProvider.ToXmlString(false) from the generator tool.
|
||||||
|
private const string PublicKeyXml =
|
||||||
|
"<RSAKeyValue>" +
|
||||||
|
"<Modulus>PLACEHOLDER</Modulus>" +
|
||||||
|
"<Exponent>AQAB</Exponent>" +
|
||||||
|
"</RSAKeyValue>";
|
||||||
|
|
||||||
|
private readonly string _publicKeyXml;
|
||||||
|
|
||||||
|
// Public constructor: uses embedded vendor public key.
|
||||||
|
internal LicenseValidator() : this(PublicKeyXml) { }
|
||||||
|
|
||||||
|
// Internal constructor: accepts any public key XML — used in unit tests.
|
||||||
|
internal LicenseValidator(string publicKeyXml)
|
||||||
|
{
|
||||||
|
_publicKeyXml = publicKeyXml;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Validate(string fingerprint, string licenseBase64)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
byte[] signature = Convert.FromBase64String(licenseBase64);
|
||||||
|
byte[] data = Encoding.UTF8.GetBytes(fingerprint);
|
||||||
|
using (var rsa = new RSACryptoServiceProvider())
|
||||||
|
{
|
||||||
|
rsa.FromXmlString(_publicKeyXml);
|
||||||
|
return rsa.VerifyData(data, new SHA256CryptoServiceProvider(), signature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: `RSACryptoServiceProvider.VerifyData(byte[], object, byte[])` — the hash algorithm
|
||||||
|
argument is `new SHA256CryptoServiceProvider()`, not `HashAlgorithmName` (that overload
|
||||||
|
requires .NET 4.6+ RSA base class; `RSACryptoServiceProvider` overload uses the older
|
||||||
|
`object` signature which is available in .NET 4.7.2).
|
||||||
|
|
||||||
|
**NcProgramManager.csproj** — add 5 Compile entries after last existing `<Compile>` in the
|
||||||
|
`Licensing` group (create new ItemGroup if none exists):
|
||||||
|
```xml
|
||||||
|
<Compile Include="Licensing\IMachineFingerprint.cs" />
|
||||||
|
<Compile Include="Licensing\ILicenseValidator.cs" />
|
||||||
|
<Compile Include="Licensing\LicenseFile.cs" />
|
||||||
|
<Compile Include="Licensing\MachineFingerprint.cs" />
|
||||||
|
<Compile Include="Licensing\LicenseValidator.cs" />
|
||||||
|
```
|
||||||
|
|
||||||
|
System.Management reference already present — no new reference needed.
|
||||||
|
</action>
|
||||||
|
<verify>
|
||||||
|
```bash
|
||||||
|
ls Licensing/MachineFingerprint.cs Licensing/LicenseValidator.cs
|
||||||
|
grep "LicenseValidator\|MachineFingerprint\|LicenseFile\|IMachineFingerprint\|ILicenseValidator" NcProgramManager.csproj | grep "Compile"
|
||||||
|
```
|
||||||
|
Both files exist. Five Compile entries present in csproj.
|
||||||
|
</verify>
|
||||||
|
<done>AC-1 satisfied: MachineFingerprint implements IMachineFingerprint with WMI logic. AC-2/AC-3 groundwork: LicenseValidator implements ILicenseValidator with RSA verify.</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 3: Unit tests for LicenseValidator and LicenseFile</name>
|
||||||
|
<files>
|
||||||
|
NcProgramManager.Tests/Unit/LicenseValidatorTests.cs,
|
||||||
|
NcProgramManager.Tests/NcProgramManager.Tests.csproj
|
||||||
|
</files>
|
||||||
|
<action>
|
||||||
|
Tests use the internal `LicenseValidator(string publicKeyXml)` constructor to inject a
|
||||||
|
test-generated key pair — same pattern as NcProgramValidatorTests.
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
using System;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NcProgramManager.Licensing;
|
||||||
|
|
||||||
|
namespace NcProgramManager.Tests.Unit
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class LicenseValidatorTests
|
||||||
|
{
|
||||||
|
private string _publicKeyXml;
|
||||||
|
private string _privateKeyXml;
|
||||||
|
private const string TestFingerprint = "BFEBFBFF000906EAM80-80001234";
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void SetUp()
|
||||||
|
{
|
||||||
|
using (var rsa = new RSACryptoServiceProvider(2048))
|
||||||
|
{
|
||||||
|
_publicKeyXml = rsa.ToXmlString(false); // public only
|
||||||
|
_privateKeyXml = rsa.ToXmlString(true); // includes private
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string Sign(string fingerprint)
|
||||||
|
{
|
||||||
|
using (var rsa = new RSACryptoServiceProvider())
|
||||||
|
{
|
||||||
|
rsa.FromXmlString(_privateKeyXml);
|
||||||
|
byte[] sig = rsa.SignData(
|
||||||
|
Encoding.UTF8.GetBytes(fingerprint),
|
||||||
|
new SHA256CryptoServiceProvider());
|
||||||
|
return Convert.ToBase64String(sig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Validate_ValidLicense_ReturnsTrue()
|
||||||
|
{
|
||||||
|
string licenseB64 = Sign(TestFingerprint);
|
||||||
|
var validator = new LicenseValidator(_publicKeyXml);
|
||||||
|
Assert.IsTrue(validator.Validate(TestFingerprint, licenseB64));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Validate_WrongMachineFingerprint_ReturnsFalse()
|
||||||
|
{
|
||||||
|
string licenseB64 = Sign("DIFFERENT_MACHINE_ID");
|
||||||
|
var validator = new LicenseValidator(_publicKeyXml);
|
||||||
|
Assert.IsFalse(validator.Validate(TestFingerprint, licenseB64));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Validate_TamperedLicense_ReturnsFalse()
|
||||||
|
{
|
||||||
|
string licenseB64 = Sign(TestFingerprint);
|
||||||
|
// Flip one char
|
||||||
|
char[] chars = licenseB64.ToCharArray();
|
||||||
|
chars[10] = chars[10] == 'A' ? 'B' : 'A';
|
||||||
|
var validator = new LicenseValidator(_publicKeyXml);
|
||||||
|
Assert.IsFalse(validator.Validate(TestFingerprint, new string(chars)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Validate_EmptyLicense_ReturnsFalse()
|
||||||
|
{
|
||||||
|
var validator = new LicenseValidator(_publicKeyXml);
|
||||||
|
Assert.IsFalse(validator.Validate(TestFingerprint, ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Validate_NotBase64_ReturnsFalse()
|
||||||
|
{
|
||||||
|
var validator = new LicenseValidator(_publicKeyXml);
|
||||||
|
Assert.IsFalse(validator.Validate(TestFingerprint, "not-valid-base64!!!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void LicenseFile_TryRead_NonExistentPath_ReturnsFalse()
|
||||||
|
{
|
||||||
|
bool result = LicenseFile.TryRead(@"C:\does\not\exist.lic", out string b64);
|
||||||
|
Assert.IsFalse(result);
|
||||||
|
Assert.IsNull(b64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**NcProgramManager.Tests/NcProgramManager.Tests.csproj** — add 1 Compile entry:
|
||||||
|
```xml
|
||||||
|
<Compile Include="Unit\LicenseValidatorTests.cs" />
|
||||||
|
```
|
||||||
|
|
||||||
|
Avoid: creating real .lic files on disk in tests — use in-memory signing only.
|
||||||
|
Note: `InternalsVisibleTo("NcProgramManager.Tests")` already present in AssemblyInfo.cs
|
||||||
|
from Phase 5 — no change needed.
|
||||||
|
</action>
|
||||||
|
<verify>
|
||||||
|
```bash
|
||||||
|
ls NcProgramManager.Tests/Unit/LicenseValidatorTests.cs
|
||||||
|
grep "LicenseValidatorTests" NcProgramManager.Tests/NcProgramManager.Tests.csproj
|
||||||
|
grep "LicenseValidatorTests\|LicenseFile" NcProgramManager.Tests/Unit/LicenseValidatorTests.cs | head -5
|
||||||
|
```
|
||||||
|
File exists. Compile entry present. Class contains both LicenseValidator and LicenseFile tests.
|
||||||
|
</verify>
|
||||||
|
<done>AC-2 satisfied: valid license returns true. AC-3 satisfied: wrong machine returns false. AC-4 satisfied: missing file returns false.</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
</tasks>
|
||||||
|
|
||||||
|
<boundaries>
|
||||||
|
|
||||||
|
## DO NOT CHANGE
|
||||||
|
- `Program.cs` — checkLicense stays untouched until Phase 08
|
||||||
|
- `InputArgs.cs` — `-chiave=` field stays until Phase 08
|
||||||
|
- `AesCrypt.cs` — still used by program file encryption, not licensing
|
||||||
|
- All existing machine implementations (`Cnc/` folder)
|
||||||
|
- Existing test files
|
||||||
|
|
||||||
|
## SCOPE LIMITS
|
||||||
|
- No wiring into Program.cs (Phase 08)
|
||||||
|
- No license generator tool (Phase 09)
|
||||||
|
- No CLI changes (`-licfile=` arg is Phase 08)
|
||||||
|
- Public key stays as placeholder — real key generated in Phase 09
|
||||||
|
- `MachineFingerprint` is new class; do NOT delete WMI code from Program.cs yet
|
||||||
|
|
||||||
|
</boundaries>
|
||||||
|
|
||||||
|
<verification>
|
||||||
|
Before declaring plan complete:
|
||||||
|
- [ ] `ls Licensing/*.cs` shows 5 files
|
||||||
|
- [ ] `grep "Compile" NcProgramManager.csproj | grep Licensing` shows 5 entries
|
||||||
|
- [ ] `ls NcProgramManager.Tests/Unit/LicenseValidatorTests.cs` exists
|
||||||
|
- [ ] `grep "LicenseValidatorTests" NcProgramManager.Tests/NcProgramManager.Tests.csproj` finds entry
|
||||||
|
- [ ] `grep "NcProgramManager.Licensing" Licensing/*.cs` — all files correct namespace
|
||||||
|
- [ ] All acceptance criteria met
|
||||||
|
</verification>
|
||||||
|
|
||||||
|
<success_criteria>
|
||||||
|
- All tasks completed
|
||||||
|
- All verification checks pass
|
||||||
|
- No changes to Program.cs, InputArgs.cs, or any existing .cs file outside Licensing/
|
||||||
|
- 6 new files created, 2 csproj files updated
|
||||||
|
</success_criteria>
|
||||||
|
|
||||||
|
<output>
|
||||||
|
After completion, create `.paul/phases/07-license-core/07-01-SUMMARY.md`
|
||||||
|
</output>
|
||||||
148
.paul/phases/07-license-core/07-01-SUMMARY.md
Normal file
148
.paul/phases/07-license-core/07-01-SUMMARY.md
Normal file
|
|
@ -0,0 +1,148 @@
|
||||||
|
---
|
||||||
|
phase: 07-license-core
|
||||||
|
plan: 01
|
||||||
|
subsystem: licensing
|
||||||
|
tags: [rsa, cryptography, wmi, fingerprint, unit-tests, net472]
|
||||||
|
|
||||||
|
requires:
|
||||||
|
- phase: 06-rename-cleanup
|
||||||
|
provides: NcProgramManager namespace + renamed csproj files
|
||||||
|
|
||||||
|
provides:
|
||||||
|
- IMachineFingerprint interface + MachineFingerprint WMI implementation
|
||||||
|
- ILicenseValidator interface + LicenseValidator RSA-SHA256 verifier
|
||||||
|
- LicenseFile.TryRead helper
|
||||||
|
- 6 unit tests covering valid/invalid/tampered/missing license scenarios
|
||||||
|
|
||||||
|
affects:
|
||||||
|
- 08-license-integration (wires these into Program.cs)
|
||||||
|
- 09-license-generator (produces real key pair; PublicKeyXml PLACEHOLDER replaced here)
|
||||||
|
|
||||||
|
tech-stack:
|
||||||
|
added: []
|
||||||
|
patterns:
|
||||||
|
- Constructor injection for testability (internal ctor accepts public key XML)
|
||||||
|
- RSACryptoServiceProvider + SHA256CryptoServiceProvider for .NET 4.7.2 compat
|
||||||
|
|
||||||
|
key-files:
|
||||||
|
created:
|
||||||
|
- Licensing/IMachineFingerprint.cs
|
||||||
|
- Licensing/ILicenseValidator.cs
|
||||||
|
- Licensing/LicenseFile.cs
|
||||||
|
- Licensing/MachineFingerprint.cs
|
||||||
|
- Licensing/LicenseValidator.cs
|
||||||
|
- NcProgramManager.Tests/Unit/LicenseValidatorTests.cs
|
||||||
|
modified:
|
||||||
|
- NcProgramManager.csproj
|
||||||
|
- NcProgramManager.Tests/NcProgramManager.Tests.csproj
|
||||||
|
|
||||||
|
key-decisions:
|
||||||
|
- "RSA asymmetric: private key vendor-only, public key embedded in binary"
|
||||||
|
- "PublicKeyXml is PLACEHOLDER until Phase 09 generates real key pair"
|
||||||
|
- "Constructor injection: internal LicenseValidator(string publicKeyXml) for test isolation"
|
||||||
|
- "SHA256CryptoServiceProvider (not HashAlgorithmName) — .NET 4.7.2 RSACryptoServiceProvider overload"
|
||||||
|
|
||||||
|
patterns-established:
|
||||||
|
- "LicenseValidator(string publicKeyXml) internal ctor mirrors NcProgramValidator injection pattern"
|
||||||
|
- "TryRead out-param bool pattern: no exceptions escape from file I/O"
|
||||||
|
|
||||||
|
duration: ~2h (split across sessions)
|
||||||
|
started: 2026-05-17T00:00:00Z
|
||||||
|
completed: 2026-05-17T21:00:00Z
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 07 Plan 01: license-core Summary
|
||||||
|
|
||||||
|
**RSA offline license core shipped: IMachineFingerprint + ILicenseValidator interfaces, WMI fingerprint reader, RSA-SHA256 verifier with injectable key, LicenseFile TryRead helper — 118 tests pass (116 run, 2 Fanuc FOCAS ignored).**
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
| Metric | Value |
|
||||||
|
|--------|-------|
|
||||||
|
| Duration | ~2h |
|
||||||
|
| Started | 2026-05-17 |
|
||||||
|
| Completed | 2026-05-17 |
|
||||||
|
| Tasks | 3 completed |
|
||||||
|
| Files modified | 8 |
|
||||||
|
|
||||||
|
## Acceptance Criteria Results
|
||||||
|
|
||||||
|
| Criterion | Status | Notes |
|
||||||
|
|-----------|--------|-------|
|
||||||
|
| AC-1: Machine fingerprint readable via interface | Pass | MachineFingerprint : IMachineFingerprint — WMI logic extracted (not testable on Linux; verified via code review) |
|
||||||
|
| AC-2: Valid license passes validation | Pass | Validate_ValidLicense_ReturnsTrue — in-memory RSA sign+verify |
|
||||||
|
| AC-3: Invalid license rejected | Pass | Validate_WrongMachineFingerprint_ReturnsFalse, Validate_TamperedLicense_ReturnsFalse |
|
||||||
|
| AC-4: Corrupted/missing license file handled | Pass | LicenseFile_TryRead_NonExistentPath_ReturnsFalse |
|
||||||
|
|
||||||
|
## Accomplishments
|
||||||
|
|
||||||
|
- 5 new files in `Licensing/` — interfaces, implementations, file helper — clean DI-ready layer
|
||||||
|
- 6 LicenseValidator tests all pass in Docker (Mono 6.12 / .NET 4.7.2)
|
||||||
|
- PublicKeyXml PLACEHOLDER documented — Phase 09 replaces with real key pair
|
||||||
|
- Full test suite: 118 total, 116 pass, 2 ignored (Fanuc FOCAS, Windows-only DLL, expected)
|
||||||
|
|
||||||
|
## Files Created/Modified
|
||||||
|
|
||||||
|
| File | Change | Purpose |
|
||||||
|
|------|--------|---------|
|
||||||
|
| `Licensing/IMachineFingerprint.cs` | Created | Interface for fingerprint provider |
|
||||||
|
| `Licensing/ILicenseValidator.cs` | Created | Interface for RSA validator |
|
||||||
|
| `Licensing/LicenseFile.cs` | Created | TryRead: reads .lic base64, returns false on missing/empty |
|
||||||
|
| `Licensing/MachineFingerprint.cs` | Created | WMI: CPU ProcessorID + BaseBoard SerialNumber |
|
||||||
|
| `Licensing/LicenseValidator.cs` | Created | RSACryptoServiceProvider VerifyData with SHA256 |
|
||||||
|
| `NcProgramManager.Tests/Unit/LicenseValidatorTests.cs` | Created | 6 NUnit tests; generates ephemeral key pair in SetUp |
|
||||||
|
| `NcProgramManager.csproj` | Modified | +5 Compile entries for Licensing/*.cs |
|
||||||
|
| `NcProgramManager.Tests/NcProgramManager.Tests.csproj` | Modified | +1 Compile entry for LicenseValidatorTests.cs |
|
||||||
|
|
||||||
|
## Decisions Made
|
||||||
|
|
||||||
|
| Decision | Rationale | Impact |
|
||||||
|
|----------|-----------|--------|
|
||||||
|
| RSA asymmetric (not AES) | Private key vendor-only; embedded public key safe to decompile | Phase 09 must generate real 2048-bit key pair |
|
||||||
|
| `RSACryptoServiceProvider` + `SHA256CryptoServiceProvider` | .NET 4.7.2: `VerifyData(byte[], object, byte[])` overload — `HashAlgorithmName` variant requires RSA base class | Locked to this API; no upgrade path issue |
|
||||||
|
| PublicKeyXml = PLACEHOLDER | Real key not yet generated; prevents Phase 07 from blocking on Phase 09 | Phase 09 outputs real XML; copy-paste into LicenseValidator.cs |
|
||||||
|
| Internal constructor injection | Testable without Windows WMI DLL | Same pattern as NcProgramValidator — consistent across codebase |
|
||||||
|
|
||||||
|
## Deviations from Plan
|
||||||
|
|
||||||
|
### Summary
|
||||||
|
|
||||||
|
| Type | Count | Impact |
|
||||||
|
|------|-------|--------|
|
||||||
|
| Auto-fixed | 1 | Pre-existing bug, zero scope creep |
|
||||||
|
| Scope additions | 0 | — |
|
||||||
|
| Deferred | 0 | — |
|
||||||
|
|
||||||
|
### Auto-fixed Issues
|
||||||
|
|
||||||
|
**1. Build — Missing `using System;` in CncMachineFactoryTests.cs**
|
||||||
|
- **Found during:** Docker build (msbuild step)
|
||||||
|
- **Issue:** `InvalidOperationException` unresolved — `using System;` absent from `CncMachineFactoryTests.cs`
|
||||||
|
- **Fix:** Added `using System;` at top of file
|
||||||
|
- **Files:** `NcProgramManager.Tests/Unit/CncMachineFactoryTests.cs`
|
||||||
|
- **Verification:** Docker build passed; all 118 tests ran
|
||||||
|
|
||||||
|
**2. Dockerfile.test — Stale FanucProgramManager paths**
|
||||||
|
- **Found during:** First Docker build attempt
|
||||||
|
- **Issue:** Dockerfile.test still referenced `FanucProgramManager.*` paths from before Phase 06 rename
|
||||||
|
- **Fix:** Updated all paths to `NcProgramManager.*`
|
||||||
|
- **Files:** `Dockerfile.test`
|
||||||
|
- **Verification:** Docker build and test run succeeded
|
||||||
|
|
||||||
|
## Next Phase Readiness
|
||||||
|
|
||||||
|
**Ready:**
|
||||||
|
- `IMachineFingerprint` / `ILicenseValidator` injectable into any caller
|
||||||
|
- `LicenseValidator` verified correct with real RSA operations
|
||||||
|
- `LicenseFile.TryRead` ready for `-licfile=` arg wiring
|
||||||
|
|
||||||
|
**Concerns:**
|
||||||
|
- PublicKeyXml is PLACEHOLDER — production build will silently reject all licenses until Phase 09 provides real key and it's copied in
|
||||||
|
- `MachineFingerprint` uses WMI — only tested via code review on Linux; validate on Windows hardware
|
||||||
|
|
||||||
|
**Blockers:**
|
||||||
|
- None — Phase 08 can proceed
|
||||||
|
|
||||||
|
---
|
||||||
|
*Phase: 07-license-core, Plan: 01*
|
||||||
|
*Completed: 2026-05-17*
|
||||||
199
.paul/phases/08-license-integration/08-01-PLAN.md
Normal file
199
.paul/phases/08-license-integration/08-01-PLAN.md
Normal file
|
|
@ -0,0 +1,199 @@
|
||||||
|
---
|
||||||
|
phase: 08-license-integration
|
||||||
|
plan: 01
|
||||||
|
type: execute
|
||||||
|
wave: 1
|
||||||
|
depends_on: ["07-01"]
|
||||||
|
files_modified:
|
||||||
|
- Program.cs
|
||||||
|
autonomous: true
|
||||||
|
---
|
||||||
|
|
||||||
|
<objective>
|
||||||
|
## 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
|
||||||
|
</objective>
|
||||||
|
|
||||||
|
<context>
|
||||||
|
## 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
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<acceptance_criteria>
|
||||||
|
|
||||||
|
## 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
|
||||||
|
```
|
||||||
|
|
||||||
|
</acceptance_criteria>
|
||||||
|
|
||||||
|
<tasks>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 1: Wire RSA license check into Program.cs</name>
|
||||||
|
<files>Program.cs</files>
|
||||||
|
<action>
|
||||||
|
**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.
|
||||||
|
</action>
|
||||||
|
<verify>
|
||||||
|
```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).
|
||||||
|
</verify>
|
||||||
|
<done>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.</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
</tasks>
|
||||||
|
|
||||||
|
<boundaries>
|
||||||
|
|
||||||
|
## 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
|
||||||
|
|
||||||
|
</boundaries>
|
||||||
|
|
||||||
|
<verification>
|
||||||
|
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
|
||||||
|
</verification>
|
||||||
|
|
||||||
|
<success_criteria>
|
||||||
|
- 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
|
||||||
|
</success_criteria>
|
||||||
|
|
||||||
|
<output>
|
||||||
|
After completion, create `.paul/phases/08-license-integration/08-01-SUMMARY.md`
|
||||||
|
</output>
|
||||||
63
.paul/phases/08-license-integration/08-01-SUMMARY.md
Normal file
63
.paul/phases/08-license-integration/08-01-SUMMARY.md
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
---
|
||||||
|
phase: 08-license-integration
|
||||||
|
plan: 01
|
||||||
|
type: summary
|
||||||
|
status: complete
|
||||||
|
completed: 2026-05-17
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 08 Summary: license-integration
|
||||||
|
|
||||||
|
## What Was Built
|
||||||
|
|
||||||
|
RSA license check wired into `Program.cs`. Old AES-based `checkLicense` deleted. License now validated at startup against `license.lic` in the EXE directory.
|
||||||
|
|
||||||
|
**Files modified:**
|
||||||
|
- `Program.cs` — license check replaced, `checkLicense` deleted, `-chiave=` parsing removed, `MostraAiuto` updated
|
||||||
|
- `InputArgs.cs` — `chiave` field removed
|
||||||
|
|
||||||
|
## Acceptance Criteria Results
|
||||||
|
|
||||||
|
| AC | Result | Notes |
|
||||||
|
|----|--------|-------|
|
||||||
|
| AC-1: -chiave= arg still parsed | **SUPERSEDED** | User directed removal mid-APPLY (see Deviations) |
|
||||||
|
| AC-2: RSA license check at startup | PASS | `MachineFingerprint` + `LicenseFile.TryRead` + `LicenseValidator.Validate` wired |
|
||||||
|
| AC-3: License failure exits -100 | PASS | `Console.WriteLine("Licenza ERRATA")` + `vediErrore(-100)` + `return -1` |
|
||||||
|
| AC-4: Help text updated | PASS | `-chiave=` block replaced with `license.lic` location note |
|
||||||
|
|
||||||
|
## Deviations
|
||||||
|
|
||||||
|
**Plan AC-1 superseded by user decision.**
|
||||||
|
Plan stated: keep `-chiave=` as the CLI arg carrying the `.lic` file path.
|
||||||
|
User directed mid-APPLY: remove `-chiave=` entirely; hardcode `license.lic` next to the EXE.
|
||||||
|
|
||||||
|
Actual license path:
|
||||||
|
```csharp
|
||||||
|
string _licPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "license.lic");
|
||||||
|
```
|
||||||
|
|
||||||
|
`inputArgs.chiave` field removed from `InputArgs.cs`. All `-chiave=` parsing removed from `parseArgomenti`.
|
||||||
|
|
||||||
|
## Verification (post-apply grep)
|
||||||
|
|
||||||
|
```
|
||||||
|
grep "checkLicense|chiave|System.Management|System.Security.Cryptography" Program.cs → 0 hits
|
||||||
|
grep "MachineFingerprint|LicenseFile|LicenseValidator|NcProgramManager.Licensing" Program.cs → 5 hits
|
||||||
|
grep "chiave" InputArgs.cs → 0 hits
|
||||||
|
```
|
||||||
|
|
||||||
|
## Decisions Made
|
||||||
|
|
||||||
|
- License file always at `AppDomain.CurrentDomain.BaseDirectory + "license.lic"` — no CLI override
|
||||||
|
- `InputArgs.chiave` field deleted (not just unused) — cleaner than leaving dead field
|
||||||
|
- `AesCrypt.cs` left on disk (still in csproj, no cleanup in scope)
|
||||||
|
|
||||||
|
## Deferred Issues
|
||||||
|
|
||||||
|
- Real RSA key pair — Phase 09 generates; copy `PublicKeyXml` into `LicenseValidator.cs`
|
||||||
|
- Phase 09: separate `LicenseGenerator` console app — reads WMI fingerprint, signs, writes `.lic`
|
||||||
|
- `AesCrypt.cs` dead code — remove in future cleanup phase
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
|
||||||
|
No new tests (license core tested in Phase 07). Docker build + 116 tests pass (2 Fanuc FOCAS ignored, Windows-only DLL).
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
namespace FanucProgramManager
|
namespace NcProgramManager
|
||||||
{
|
{
|
||||||
class AesCrypt
|
class AesCrypt
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
using System;
|
using System;
|
||||||
using FanucProgramManager.Cnc.Fanuc;
|
using NcProgramManager.Cnc.Fanuc;
|
||||||
using FanucProgramManager.Cnc.Heidenhain;
|
using NcProgramManager.Cnc.Heidenhain;
|
||||||
using FanucProgramManager.Cnc.Mitsubishi;
|
using NcProgramManager.Cnc.Mitsubishi;
|
||||||
using FanucProgramManager.Cnc.Models;
|
using NcProgramManager.Cnc.Models;
|
||||||
using FanucProgramManager.Cnc.Siemens;
|
using NcProgramManager.Cnc.Siemens;
|
||||||
|
|
||||||
namespace FanucProgramManager.Cnc
|
namespace NcProgramManager.Cnc
|
||||||
{
|
{
|
||||||
internal static class CncMachineFactory
|
internal static class CncMachineFactory
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
namespace FanucProgramManager.Cnc.Fanuc
|
namespace NcProgramManager.Cnc.Fanuc
|
||||||
{
|
{
|
||||||
public sealed class FanucCapabilities
|
public sealed class FanucCapabilities
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace FanucProgramManager.Cnc.Fanuc
|
namespace NcProgramManager.Cnc.Fanuc
|
||||||
{
|
{
|
||||||
public enum FanucTransport
|
public enum FanucTransport
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
namespace FanucProgramManager.Cnc.Fanuc
|
namespace NcProgramManager.Cnc.Fanuc
|
||||||
{
|
{
|
||||||
public enum FanucDialect
|
public enum FanucDialect
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
using FanucProgramManager;
|
using NcProgramManager;
|
||||||
|
|
||||||
namespace FanucProgramManager.Cnc.Fanuc
|
namespace NcProgramManager.Cnc.Fanuc
|
||||||
{
|
{
|
||||||
internal static class FanucDialectDetector
|
internal static class FanucDialectDetector
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using FanucProgramManager;
|
using NcProgramManager;
|
||||||
using FanucProgramManager.Cnc.Models;
|
using NcProgramManager.Cnc.Models;
|
||||||
|
|
||||||
namespace FanucProgramManager.Cnc.Fanuc
|
namespace NcProgramManager.Cnc.Fanuc
|
||||||
{
|
{
|
||||||
internal static class FanucErrorTranslator
|
internal static class FanucErrorTranslator
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,11 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using FanucProgramManager;
|
using NcProgramManager;
|
||||||
using FanucProgramManager.Cnc;
|
using NcProgramManager.Cnc;
|
||||||
using FanucProgramManager.Cnc.Models;
|
using NcProgramManager.Cnc.Models;
|
||||||
|
|
||||||
namespace FanucProgramManager.Cnc.Fanuc
|
namespace NcProgramManager.Cnc.Fanuc
|
||||||
{
|
{
|
||||||
public sealed class FanucMachine : IFanucMachine
|
public sealed class FanucMachine : IFanucMachine
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace FanucProgramManager.Cnc.Fanuc
|
namespace NcProgramManager.Cnc.Fanuc
|
||||||
{
|
{
|
||||||
internal static class FocasDialectFactory
|
internal static class FocasDialectFactory
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
namespace FanucProgramManager.Cnc.Fanuc
|
namespace NcProgramManager.Cnc.Fanuc
|
||||||
{
|
{
|
||||||
internal interface IFocasDialect
|
internal interface IFocasDialect
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
namespace FanucProgramManager.Cnc.Fanuc
|
namespace NcProgramManager.Cnc.Fanuc
|
||||||
{
|
{
|
||||||
public static class IsoProgramFormatter
|
public static class IsoProgramFormatter
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
using FanucProgramManager;
|
using NcProgramManager;
|
||||||
|
|
||||||
namespace FanucProgramManager.Cnc.Fanuc
|
namespace NcProgramManager.Cnc.Fanuc
|
||||||
{
|
{
|
||||||
internal sealed class LegacyFocasDialect : IFocasDialect
|
internal sealed class LegacyFocasDialect : IFocasDialect
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using FanucProgramManager;
|
using NcProgramManager;
|
||||||
|
|
||||||
namespace FanucProgramManager.Cnc.Fanuc
|
namespace NcProgramManager.Cnc.Fanuc
|
||||||
{
|
{
|
||||||
internal sealed class ModernFocasDialect : IFocasDialect
|
internal sealed class ModernFocasDialect : IFocasDialect
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace FanucProgramManager.Cnc.Heidenhain
|
namespace NcProgramManager.Cnc.Heidenhain
|
||||||
{
|
{
|
||||||
public sealed class HeidenhainConnectionConfig
|
public sealed class HeidenhainConnectionConfig
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,10 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using FanucProgramManager.Cnc;
|
using NcProgramManager.Cnc;
|
||||||
using FanucProgramManager.Cnc.Models;
|
using NcProgramManager.Cnc.Models;
|
||||||
|
|
||||||
namespace FanucProgramManager.Cnc.Heidenhain
|
namespace NcProgramManager.Cnc.Heidenhain
|
||||||
{
|
{
|
||||||
public sealed class HeidenhainMachine : ICncMachine
|
public sealed class HeidenhainMachine : ICncMachine
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
namespace FanucProgramManager.Cnc.Heidenhain
|
namespace NcProgramManager.Cnc.Heidenhain
|
||||||
{
|
{
|
||||||
internal interface ILsv2Client
|
internal interface ILsv2Client
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ using System;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace FanucProgramManager.Cnc.Heidenhain
|
namespace NcProgramManager.Cnc.Heidenhain
|
||||||
{
|
{
|
||||||
/// <summary>LSV2 protocol client for Heidenhain TNC controls.</summary>
|
/// <summary>LSV2 protocol client for Heidenhain TNC controls.</summary>
|
||||||
internal sealed class Lsv2Client : ILsv2Client, IDisposable
|
internal sealed class Lsv2Client : ILsv2Client, IDisposable
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using FanucProgramManager.Cnc.Models;
|
using NcProgramManager.Cnc.Models;
|
||||||
|
|
||||||
namespace FanucProgramManager.Cnc
|
namespace NcProgramManager.Cnc
|
||||||
{
|
{
|
||||||
public interface ICncMachine : IDisposable
|
public interface ICncMachine : IDisposable
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using FanucProgramManager.Cnc.Models;
|
using NcProgramManager.Cnc.Models;
|
||||||
|
|
||||||
namespace FanucProgramManager.Cnc
|
namespace NcProgramManager.Cnc
|
||||||
{
|
{
|
||||||
/// <summary>Fanuc-specific extensions: tool offset and work zero offset transfer.</summary>
|
/// <summary>Fanuc-specific extensions: tool offset and work zero offset transfer.</summary>
|
||||||
public interface IFanucMachine : ICncMachine
|
public interface IFanucMachine : ICncMachine
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
using FanucProgramManager.Cnc.Models;
|
using NcProgramManager.Cnc.Models;
|
||||||
|
|
||||||
namespace FanucProgramManager.Cnc
|
namespace NcProgramManager.Cnc
|
||||||
{
|
{
|
||||||
/// <summary>Validates NC program content before upload to a CNC controller.</summary>
|
/// <summary>Validates NC program content before upload to a CNC controller.</summary>
|
||||||
public interface INcProgramValidator
|
public interface INcProgramValidator
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
namespace FanucProgramManager.Cnc.Mitsubishi
|
namespace NcProgramManager.Cnc.Mitsubishi
|
||||||
{
|
{
|
||||||
internal interface IMitsubishiFtpClient
|
internal interface IMitsubishiFtpClient
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace FanucProgramManager.Cnc.Mitsubishi
|
namespace NcProgramManager.Cnc.Mitsubishi
|
||||||
{
|
{
|
||||||
public sealed class MitsubishiConnectionConfig
|
public sealed class MitsubishiConnectionConfig
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace FanucProgramManager.Cnc.Mitsubishi
|
namespace NcProgramManager.Cnc.Mitsubishi
|
||||||
{
|
{
|
||||||
/// <summary>FTP client for Mitsubishi M-series CNC program transfer.</summary>
|
/// <summary>FTP client for Mitsubishi M-series CNC program transfer.</summary>
|
||||||
internal sealed class MitsubishiFtpClient : IMitsubishiFtpClient
|
internal sealed class MitsubishiFtpClient : IMitsubishiFtpClient
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,10 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using FanucProgramManager.Cnc;
|
using NcProgramManager.Cnc;
|
||||||
using FanucProgramManager.Cnc.Models;
|
using NcProgramManager.Cnc.Models;
|
||||||
|
|
||||||
namespace FanucProgramManager.Cnc.Mitsubishi
|
namespace NcProgramManager.Cnc.Mitsubishi
|
||||||
{
|
{
|
||||||
public sealed class MitsubishiMachine : ICncMachine
|
public sealed class MitsubishiMachine : ICncMachine
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace FanucProgramManager.Cnc.Models
|
namespace NcProgramManager.Cnc.Models
|
||||||
{
|
{
|
||||||
public sealed class CncError
|
public sealed class CncError
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
namespace FanucProgramManager.Cnc.Models
|
namespace NcProgramManager.Cnc.Models
|
||||||
{
|
{
|
||||||
public enum CncManufacturer { Fanuc, Heidenhain, Siemens, Mitsubishi }
|
public enum CncManufacturer { Fanuc, Heidenhain, Siemens, Mitsubishi }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
namespace FanucProgramManager.Cnc.Models
|
namespace NcProgramManager.Cnc.Models
|
||||||
{
|
{
|
||||||
public sealed class CncProgram
|
public sealed class CncProgram
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace FanucProgramManager.Cnc.Models
|
namespace NcProgramManager.Cnc.Models
|
||||||
{
|
{
|
||||||
/// <summary>Result wrapper for all CNC operations.</summary>
|
/// <summary>Result wrapper for all CNC operations.</summary>
|
||||||
public sealed class CncResult<T>
|
public sealed class CncResult<T>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
namespace FanucProgramManager.Cnc.Models
|
namespace NcProgramManager.Cnc.Models
|
||||||
{
|
{
|
||||||
public enum ConnectionState
|
public enum ConnectionState
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
namespace FanucProgramManager.Cnc.Models
|
namespace NcProgramManager.Cnc.Models
|
||||||
{
|
{
|
||||||
public enum MachineMode
|
public enum MachineMode
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace FanucProgramManager.Cnc.Models
|
namespace NcProgramManager.Cnc.Models
|
||||||
{
|
{
|
||||||
public sealed class MachineSnapshot
|
public sealed class MachineSnapshot
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
namespace FanucProgramManager.Cnc.Models
|
namespace NcProgramManager.Cnc.Models
|
||||||
{
|
{
|
||||||
public enum MotionState
|
public enum MotionState
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
namespace FanucProgramManager.Cnc.Models
|
namespace NcProgramManager.Cnc.Models
|
||||||
{
|
{
|
||||||
public enum RunState
|
public enum RunState
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
namespace FanucProgramManager.Cnc.Models
|
namespace NcProgramManager.Cnc.Models
|
||||||
{
|
{
|
||||||
public sealed class ValidationError
|
public sealed class ValidationError
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace FanucProgramManager.Cnc.Models
|
namespace NcProgramManager.Cnc.Models
|
||||||
{
|
{
|
||||||
public sealed class ValidationResult
|
public sealed class ValidationResult
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
namespace FanucProgramManager.Cnc.Models
|
namespace NcProgramManager.Cnc.Models
|
||||||
{
|
{
|
||||||
public enum ValidationSeverity { Error, Warning }
|
public enum ValidationSeverity { Error, Warning }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using FanucProgramManager.Cnc.Models;
|
using NcProgramManager.Cnc.Models;
|
||||||
|
|
||||||
namespace FanucProgramManager.Cnc
|
namespace NcProgramManager.Cnc
|
||||||
{
|
{
|
||||||
/// <summary>Validates NC program content per-manufacturer before upload.</summary>
|
/// <summary>Validates NC program content per-manufacturer before upload.</summary>
|
||||||
public sealed class NcProgramValidator : INcProgramValidator
|
public sealed class NcProgramValidator : INcProgramValidator
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
namespace FanucProgramManager.Cnc.Siemens
|
namespace NcProgramManager.Cnc.Siemens
|
||||||
{
|
{
|
||||||
internal interface ISiemensFtpClient
|
internal interface ISiemensFtpClient
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace FanucProgramManager.Cnc.Siemens
|
namespace NcProgramManager.Cnc.Siemens
|
||||||
{
|
{
|
||||||
public sealed class SiemensConnectionConfig
|
public sealed class SiemensConnectionConfig
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace FanucProgramManager.Cnc.Siemens
|
namespace NcProgramManager.Cnc.Siemens
|
||||||
{
|
{
|
||||||
/// <summary>FTP client for Siemens Sinumerik CNC program transfer.</summary>
|
/// <summary>FTP client for Siemens Sinumerik CNC program transfer.</summary>
|
||||||
internal sealed class SiemensFtpClient : ISiemensFtpClient
|
internal sealed class SiemensFtpClient : ISiemensFtpClient
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,10 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using FanucProgramManager.Cnc;
|
using NcProgramManager.Cnc;
|
||||||
using FanucProgramManager.Cnc.Models;
|
using NcProgramManager.Cnc.Models;
|
||||||
|
|
||||||
namespace FanucProgramManager.Cnc.Siemens
|
namespace NcProgramManager.Cnc.Siemens
|
||||||
{
|
{
|
||||||
public sealed class SiemensMachine : ICncMachine
|
public sealed class SiemensMachine : ICncMachine
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -6,16 +6,16 @@ WORKDIR /build
|
||||||
RUN cert-sync /etc/ssl/certs/ca-certificates.crt
|
RUN cert-sync /etc/ssl/certs/ca-certificates.crt
|
||||||
|
|
||||||
# Copy solution + projects first for layer caching
|
# Copy solution + projects first for layer caching
|
||||||
COPY FanucProgramManager.csproj ./
|
COPY NcProgramManager.csproj ./
|
||||||
COPY packages.config ./
|
COPY packages.config ./
|
||||||
COPY FanucProgramManager.Tests/FanucProgramManager.Tests.csproj ./FanucProgramManager.Tests/
|
COPY NcProgramManager.Tests/NcProgramManager.Tests.csproj ./NcProgramManager.Tests/
|
||||||
COPY FanucProgramManager.Tests/packages.config ./FanucProgramManager.Tests/
|
COPY NcProgramManager.Tests/packages.config ./NcProgramManager.Tests/
|
||||||
COPY FanucProgramManager.sln ./
|
COPY NcProgramManager.sln ./
|
||||||
|
|
||||||
# Restore all packages (sln now includes test project)
|
# Restore all packages (sln now includes test project)
|
||||||
RUN nuget restore FanucProgramManager.sln -NonInteractive
|
RUN nuget restore NcProgramManager.sln -NonInteractive
|
||||||
# Explicit fallback: restore test packages.config directly to same packages dir
|
# Explicit fallback: restore test packages.config directly to same packages dir
|
||||||
RUN nuget restore FanucProgramManager.Tests/packages.config \
|
RUN nuget restore NcProgramManager.Tests/packages.config \
|
||||||
-OutputDirectory packages -NonInteractive
|
-OutputDirectory packages -NonInteractive
|
||||||
# Grab NUnit console runner
|
# Grab NUnit console runner
|
||||||
RUN nuget install NUnit.ConsoleRunner -Version 3.16.3 -OutputDirectory packages -NonInteractive
|
RUN nuget install NUnit.ConsoleRunner -Version 3.16.3 -OutputDirectory packages -NonInteractive
|
||||||
|
|
@ -27,11 +27,11 @@ COPY . .
|
||||||
RUN ls Cnc/Fanuc/libs/ || true
|
RUN ls Cnc/Fanuc/libs/ || true
|
||||||
|
|
||||||
# Build test project (Debug)
|
# Build test project (Debug)
|
||||||
RUN msbuild FanucProgramManager.Tests/FanucProgramManager.Tests.csproj \
|
RUN msbuild NcProgramManager.Tests/NcProgramManager.Tests.csproj \
|
||||||
/p:Configuration=Debug /p:Platform=AnyCPU \
|
/p:Configuration=Debug /p:Platform=AnyCPU \
|
||||||
/v:minimal /nologo
|
/v:minimal /nologo
|
||||||
|
|
||||||
# Run tests — skip Fanuc FOCAS tests (marked [Ignore] — need fwlib32.dll)
|
# Run tests — skip Fanuc FOCAS tests (marked [Ignore] — need fwlib32.dll)
|
||||||
CMD mono packages/NUnit.ConsoleRunner.3.16.3/tools/nunit3-console.exe \
|
CMD mono packages/NUnit.ConsoleRunner.3.16.3/tools/nunit3-console.exe \
|
||||||
FanucProgramManager.Tests/bin/Debug/FanucProgramManager.Tests.dll \
|
NcProgramManager.Tests/bin/Debug/NcProgramManager.Tests.dll \
|
||||||
--labels=All
|
--labels=All
|
||||||
|
|
|
||||||
1094
FANUCMachine.cs
1094
FANUCMachine.cs
File diff suppressed because it is too large
Load diff
|
|
@ -1,7 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace FanucProgramManager
|
namespace NcProgramManager
|
||||||
{
|
{
|
||||||
internal class FanucProgram
|
internal class FanucProgram
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
using FanucProgramManager.Cnc.Models;
|
using NcProgramManager.Cnc.Models;
|
||||||
|
|
||||||
namespace FanucProgramManager
|
namespace NcProgramManager
|
||||||
{
|
{
|
||||||
internal class InputArgs
|
internal class InputArgs
|
||||||
{
|
{
|
||||||
|
|
@ -11,7 +11,6 @@ namespace FanucProgramManager
|
||||||
public string porta = "";
|
public string porta = "";
|
||||||
public short pathCNC = 1;
|
public short pathCNC = 1;
|
||||||
public int nodoHssb = -1;
|
public int nodoHssb = -1;
|
||||||
public string chiave = "";
|
|
||||||
public string username = "";
|
public string username = "";
|
||||||
public string password = "";
|
public string password = "";
|
||||||
public string commentoProgramma = "";
|
public string commentoProgramma = "";
|
||||||
|
|
|
||||||
7
Licensing/ILicenseValidator.cs
Normal file
7
Licensing/ILicenseValidator.cs
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
namespace NcProgramManager.Licensing
|
||||||
|
{
|
||||||
|
internal interface ILicenseValidator
|
||||||
|
{
|
||||||
|
bool Validate(string fingerprint, string licenseBase64);
|
||||||
|
}
|
||||||
|
}
|
||||||
7
Licensing/IMachineFingerprint.cs
Normal file
7
Licensing/IMachineFingerprint.cs
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
namespace NcProgramManager.Licensing
|
||||||
|
{
|
||||||
|
internal interface IMachineFingerprint
|
||||||
|
{
|
||||||
|
string GetFingerprint();
|
||||||
|
}
|
||||||
|
}
|
||||||
26
Licensing/LicenseFile.cs
Normal file
26
Licensing/LicenseFile.cs
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace NcProgramManager.Licensing
|
||||||
|
{
|
||||||
|
internal static class LicenseFile
|
||||||
|
{
|
||||||
|
internal static bool TryRead(string path, out string base64)
|
||||||
|
{
|
||||||
|
base64 = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!File.Exists(path))
|
||||||
|
return false;
|
||||||
|
string content = File.ReadAllText(path).Trim();
|
||||||
|
if (string.IsNullOrEmpty(content))
|
||||||
|
return false;
|
||||||
|
base64 = content;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
46
Licensing/LicenseValidator.cs
Normal file
46
Licensing/LicenseValidator.cs
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
using System;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace NcProgramManager.Licensing
|
||||||
|
{
|
||||||
|
internal class LicenseValidator : ILicenseValidator
|
||||||
|
{
|
||||||
|
// Placeholder — replace with real vendor public key XML after Phase 09 generates the key pair.
|
||||||
|
// Generate key pair with the LicenseGenerator tool, then copy the public XML here.
|
||||||
|
private const string PublicKeyXml =
|
||||||
|
"<RSAKeyValue>" +
|
||||||
|
"<Modulus>PLACEHOLDER</Modulus>" +
|
||||||
|
"<Exponent>AQAB</Exponent>" +
|
||||||
|
"</RSAKeyValue>";
|
||||||
|
|
||||||
|
private readonly string _publicKeyXml;
|
||||||
|
|
||||||
|
// Uses embedded vendor public key.
|
||||||
|
internal LicenseValidator() : this(PublicKeyXml) { }
|
||||||
|
|
||||||
|
// Accepts any public key XML — used in unit tests.
|
||||||
|
internal LicenseValidator(string publicKeyXml)
|
||||||
|
{
|
||||||
|
_publicKeyXml = publicKeyXml;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Validate(string fingerprint, string licenseBase64)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
byte[] signature = Convert.FromBase64String(licenseBase64);
|
||||||
|
byte[] data = Encoding.UTF8.GetBytes(fingerprint);
|
||||||
|
using (var rsa = new RSACryptoServiceProvider())
|
||||||
|
{
|
||||||
|
rsa.FromXmlString(_publicKeyXml);
|
||||||
|
return rsa.VerifyData(data, new SHA256CryptoServiceProvider(), signature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
34
Licensing/MachineFingerprint.cs
Normal file
34
Licensing/MachineFingerprint.cs
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
using System.Management;
|
||||||
|
|
||||||
|
namespace NcProgramManager.Licensing
|
||||||
|
{
|
||||||
|
internal class MachineFingerprint : IMachineFingerprint
|
||||||
|
{
|
||||||
|
public string GetFingerprint()
|
||||||
|
{
|
||||||
|
string pcInfo = string.Empty;
|
||||||
|
|
||||||
|
using (var mc = new ManagementClass("win32_processor"))
|
||||||
|
using (ManagementObjectCollection moc = mc.GetInstances())
|
||||||
|
{
|
||||||
|
foreach (ManagementObject mo in moc)
|
||||||
|
{
|
||||||
|
pcInfo = mo.Properties["processorID"].Value.ToString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var searcher = new ManagementObjectSearcher(
|
||||||
|
"root\\CIMV2", "SELECT * FROM Win32_BaseBoard"))
|
||||||
|
{
|
||||||
|
foreach (ManagementObject obj in searcher.Get())
|
||||||
|
{
|
||||||
|
pcInfo += obj["SerialNumber"].ToString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pcInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using FanucProgramManager.Cnc.Models;
|
using NcProgramManager.Cnc.Models;
|
||||||
using FanucProgramManager.Cnc.Heidenhain;
|
using NcProgramManager.Cnc.Heidenhain;
|
||||||
using FanucProgramManager.Tests.Integration.Stubs;
|
using NcProgramManager.Tests.Integration.Stubs;
|
||||||
|
|
||||||
namespace FanucProgramManager.Tests.Integration
|
namespace NcProgramManager.Tests.Integration
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
[Category("Integration")]
|
[Category("Integration")]
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using FanucProgramManager.Cnc.Models;
|
using NcProgramManager.Cnc.Models;
|
||||||
using FanucProgramManager.Cnc.Mitsubishi;
|
using NcProgramManager.Cnc.Mitsubishi;
|
||||||
using FanucProgramManager.Tests.Integration.Stubs;
|
using NcProgramManager.Tests.Integration.Stubs;
|
||||||
|
|
||||||
namespace FanucProgramManager.Tests.Integration
|
namespace NcProgramManager.Tests.Integration
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
[Category("Integration")]
|
[Category("Integration")]
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using FanucProgramManager.Cnc.Models;
|
using NcProgramManager.Cnc.Models;
|
||||||
using FanucProgramManager.Cnc.Siemens;
|
using NcProgramManager.Cnc.Siemens;
|
||||||
using FanucProgramManager.Tests.Integration.Stubs;
|
using NcProgramManager.Tests.Integration.Stubs;
|
||||||
|
|
||||||
namespace FanucProgramManager.Tests.Integration
|
namespace NcProgramManager.Tests.Integration
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
[Category("Integration")]
|
[Category("Integration")]
|
||||||
|
|
@ -6,7 +6,7 @@ using System.Net.Sockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace FanucProgramManager.Tests.Integration.Stubs
|
namespace NcProgramManager.Tests.Integration.Stubs
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Minimal in-process FTP server using passive mode.
|
/// Minimal in-process FTP server using passive mode.
|
||||||
|
|
@ -6,7 +6,7 @@ using System.Net.Sockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace FanucProgramManager.Tests.Integration.Stubs
|
namespace NcProgramManager.Tests.Integration.Stubs
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Minimal in-process LSV2 server.
|
/// Minimal in-process LSV2 server.
|
||||||
|
|
@ -7,8 +7,8 @@
|
||||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
<ProjectGuid>{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}</ProjectGuid>
|
<ProjectGuid>{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}</ProjectGuid>
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
<RootNamespace>FanucProgramManager.Tests</RootNamespace>
|
<RootNamespace>NcProgramManager.Tests</RootNamespace>
|
||||||
<AssemblyName>FanucProgramManager.Tests</AssemblyName>
|
<AssemblyName>NcProgramManager.Tests</AssemblyName>
|
||||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||||
<FileAlignment>512</FileAlignment>
|
<FileAlignment>512</FileAlignment>
|
||||||
<Deterministic>true</Deterministic>
|
<Deterministic>true</Deterministic>
|
||||||
|
|
@ -46,12 +46,13 @@
|
||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\FanucProgramManager.csproj">
|
<ProjectReference Include="..\NcProgramManager.csproj">
|
||||||
<Project>{1032188B-3321-42B2-87ED-343BF718CAF5}</Project>
|
<Project>{1032188B-3321-42B2-87ED-343BF718CAF5}</Project>
|
||||||
<Name>FanucProgramManager</Name>
|
<Name>NcProgramManager</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="Unit\LicenseValidatorTests.cs" />
|
||||||
<Compile Include="Unit\NcProgramValidatorTests.cs" />
|
<Compile Include="Unit\NcProgramValidatorTests.cs" />
|
||||||
<Compile Include="Unit\FanucProgramParsingTests.cs" />
|
<Compile Include="Unit\FanucProgramParsingTests.cs" />
|
||||||
<Compile Include="Unit\IsoProgramFormatterTests.cs" />
|
<Compile Include="Unit\IsoProgramFormatterTests.cs" />
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
|
using System;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using FanucProgramManager.Cnc;
|
using NcProgramManager.Cnc;
|
||||||
using FanucProgramManager.Cnc.Fanuc;
|
using NcProgramManager.Cnc.Fanuc;
|
||||||
using FanucProgramManager.Cnc.Heidenhain;
|
using NcProgramManager.Cnc.Heidenhain;
|
||||||
using FanucProgramManager.Cnc.Mitsubishi;
|
using NcProgramManager.Cnc.Mitsubishi;
|
||||||
using FanucProgramManager.Cnc.Models;
|
using NcProgramManager.Cnc.Models;
|
||||||
using FanucProgramManager.Cnc.Siemens;
|
using NcProgramManager.Cnc.Siemens;
|
||||||
|
|
||||||
namespace FanucProgramManager.Tests.Unit
|
namespace NcProgramManager.Tests.Unit
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class CncMachineFactoryTests
|
public class CncMachineFactoryTests
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using Moq;
|
using Moq;
|
||||||
using FanucProgramManager.Cnc.Fanuc;
|
using NcProgramManager.Cnc.Fanuc;
|
||||||
using FanucProgramManager.Cnc.Models;
|
using NcProgramManager.Cnc.Models;
|
||||||
|
|
||||||
namespace FanucProgramManager.Tests.Unit
|
namespace NcProgramManager.Tests.Unit
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// FanucMachine calls real FOCAS DLL in ConnectCore and most methods guard
|
/// FanucMachine calls real FOCAS DLL in ConnectCore and most methods guard
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using FanucProgramManager;
|
using NcProgramManager;
|
||||||
|
|
||||||
namespace FanucProgramManager.Tests.Unit
|
namespace NcProgramManager.Tests.Unit
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class FanucProgramParsingTests
|
public class FanucProgramParsingTests
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
using System;
|
using System;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using Moq;
|
using Moq;
|
||||||
using FanucProgramManager.Cnc;
|
using NcProgramManager.Cnc;
|
||||||
using FanucProgramManager.Cnc.Models;
|
using NcProgramManager.Cnc.Models;
|
||||||
using FanucProgramManager.Cnc.Heidenhain;
|
using NcProgramManager.Cnc.Heidenhain;
|
||||||
|
|
||||||
namespace FanucProgramManager.Tests.Unit
|
namespace NcProgramManager.Tests.Unit
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class HeidenhainMachineTests
|
public class HeidenhainMachineTests
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using FanucProgramManager.Cnc.Fanuc;
|
using NcProgramManager.Cnc.Fanuc;
|
||||||
|
|
||||||
namespace FanucProgramManager.Tests.Unit
|
namespace NcProgramManager.Tests.Unit
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class IsoProgramFormatterTests
|
public class IsoProgramFormatterTests
|
||||||
80
NcProgramManager.Tests/Unit/LicenseValidatorTests.cs
Normal file
80
NcProgramManager.Tests/Unit/LicenseValidatorTests.cs
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
using System;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NcProgramManager.Licensing;
|
||||||
|
|
||||||
|
namespace NcProgramManager.Tests.Unit
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
internal class LicenseValidatorTests
|
||||||
|
{
|
||||||
|
private RSACryptoServiceProvider _rsa;
|
||||||
|
private string _publicKeyXml;
|
||||||
|
private LicenseValidator _validator;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void SetUp()
|
||||||
|
{
|
||||||
|
_rsa = new RSACryptoServiceProvider(2048);
|
||||||
|
_publicKeyXml = _rsa.ToXmlString(false);
|
||||||
|
_validator = new LicenseValidator(_publicKeyXml);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TearDown]
|
||||||
|
public void TearDown()
|
||||||
|
{
|
||||||
|
_rsa.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private string Sign(string fingerprint)
|
||||||
|
{
|
||||||
|
byte[] data = Encoding.UTF8.GetBytes(fingerprint);
|
||||||
|
byte[] sig = _rsa.SignData(data, new SHA256CryptoServiceProvider());
|
||||||
|
return Convert.ToBase64String(sig);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Validate_ValidLicense_ReturnsTrue()
|
||||||
|
{
|
||||||
|
string fingerprint = "CPU123BOARD456";
|
||||||
|
string license = Sign(fingerprint);
|
||||||
|
Assert.IsTrue(_validator.Validate(fingerprint, license));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Validate_WrongMachineFingerprint_ReturnsFalse()
|
||||||
|
{
|
||||||
|
string license = Sign("CPU123BOARD456");
|
||||||
|
Assert.IsFalse(_validator.Validate("DIFFERENT_MACHINE", license));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Validate_TamperedLicense_ReturnsFalse()
|
||||||
|
{
|
||||||
|
string license = Sign("CPU123BOARD456");
|
||||||
|
string tampered = license.Substring(0, license.Length - 4) + "AAAA";
|
||||||
|
Assert.IsFalse(_validator.Validate("CPU123BOARD456", tampered));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Validate_EmptyLicense_ReturnsFalse()
|
||||||
|
{
|
||||||
|
Assert.IsFalse(_validator.Validate("CPU123BOARD456", string.Empty));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Validate_NotBase64_ReturnsFalse()
|
||||||
|
{
|
||||||
|
Assert.IsFalse(_validator.Validate("CPU123BOARD456", "not-base64!!!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void LicenseFile_TryRead_NonExistentPath_ReturnsFalse()
|
||||||
|
{
|
||||||
|
bool result = LicenseFile.TryRead(@"C:\nonexistent\path\license.lic", out string base64);
|
||||||
|
Assert.IsFalse(result);
|
||||||
|
Assert.IsNull(base64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
using System;
|
using System;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using Moq;
|
using Moq;
|
||||||
using FanucProgramManager.Cnc;
|
using NcProgramManager.Cnc;
|
||||||
using FanucProgramManager.Cnc.Models;
|
using NcProgramManager.Cnc.Models;
|
||||||
using FanucProgramManager.Cnc.Mitsubishi;
|
using NcProgramManager.Cnc.Mitsubishi;
|
||||||
|
|
||||||
namespace FanucProgramManager.Tests.Unit
|
namespace NcProgramManager.Tests.Unit
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class MitsubishiMachineTests
|
public class MitsubishiMachineTests
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using FanucProgramManager.Cnc;
|
using NcProgramManager.Cnc;
|
||||||
using FanucProgramManager.Cnc.Models;
|
using NcProgramManager.Cnc.Models;
|
||||||
|
|
||||||
namespace FanucProgramManager.Tests.Unit
|
namespace NcProgramManager.Tests.Unit
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class NcProgramValidatorTests
|
public class NcProgramValidatorTests
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
using System;
|
using System;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using Moq;
|
using Moq;
|
||||||
using FanucProgramManager.Cnc;
|
using NcProgramManager.Cnc;
|
||||||
using FanucProgramManager.Cnc.Models;
|
using NcProgramManager.Cnc.Models;
|
||||||
using FanucProgramManager.Cnc.Siemens;
|
using NcProgramManager.Cnc.Siemens;
|
||||||
|
|
||||||
namespace FanucProgramManager.Tests.Unit
|
namespace NcProgramManager.Tests.Unit
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class SiemensMachineTests
|
public class SiemensMachineTests
|
||||||
|
|
@ -6,8 +6,8 @@
|
||||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
<ProjectGuid>{1032188B-3321-42B2-87ED-343BF718CAF5}</ProjectGuid>
|
<ProjectGuid>{1032188B-3321-42B2-87ED-343BF718CAF5}</ProjectGuid>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<RootNamespace>FanucProgramManager</RootNamespace>
|
<RootNamespace>NcProgramManager</RootNamespace>
|
||||||
<AssemblyName>FanucProgramManager</AssemblyName>
|
<AssemblyName>NcProgramManager</AssemblyName>
|
||||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||||
<FileAlignment>512</FileAlignment>
|
<FileAlignment>512</FileAlignment>
|
||||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
|
|
@ -75,7 +75,6 @@
|
||||||
<Compile Include="AesCrypt.cs" />
|
<Compile Include="AesCrypt.cs" />
|
||||||
<Compile Include="FanucProgram.cs" />
|
<Compile Include="FanucProgram.cs" />
|
||||||
<Compile Include="InputArgs.cs" />
|
<Compile Include="InputArgs.cs" />
|
||||||
<Compile Include="FANUCMachine.cs" />
|
|
||||||
<Compile Include="fwlib32.cs" />
|
<Compile Include="fwlib32.cs" />
|
||||||
<Compile Include="Program.cs" />
|
<Compile Include="Program.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
|
@ -119,6 +118,11 @@
|
||||||
<Compile Include="Cnc\Mitsubishi\IMitsubishiFtpClient.cs" />
|
<Compile Include="Cnc\Mitsubishi\IMitsubishiFtpClient.cs" />
|
||||||
<Compile Include="Cnc\Mitsubishi\MitsubishiFtpClient.cs" />
|
<Compile Include="Cnc\Mitsubishi\MitsubishiFtpClient.cs" />
|
||||||
<Compile Include="Cnc\Mitsubishi\MitsubishiMachine.cs" />
|
<Compile Include="Cnc\Mitsubishi\MitsubishiMachine.cs" />
|
||||||
|
<Compile Include="Licensing\IMachineFingerprint.cs" />
|
||||||
|
<Compile Include="Licensing\ILicenseValidator.cs" />
|
||||||
|
<Compile Include="Licensing\LicenseFile.cs" />
|
||||||
|
<Compile Include="Licensing\MachineFingerprint.cs" />
|
||||||
|
<Compile Include="Licensing\LicenseValidator.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="App.config" />
|
<None Include="App.config" />
|
||||||
|
|
@ -3,9 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio Version 17
|
# Visual Studio Version 17
|
||||||
VisualStudioVersion = 17.5.33414.496
|
VisualStudioVersion = 17.5.33414.496
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FanucProgramManager", "FanucProgramManager.csproj", "{1032188B-3321-42B2-87ED-343BF718CAF5}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NcProgramManager", "NcProgramManager.csproj", "{1032188B-3321-42B2-87ED-343BF718CAF5}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FanucProgramManager.Tests", "FanucProgramManager.Tests\FanucProgramManager.Tests.csproj", "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NcProgramManager.Tests", "NcProgramManager.Tests\NcProgramManager.Tests.csproj", "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
61
Program.cs
61
Program.cs
|
|
@ -1,13 +1,12 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Management;
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using FanucProgramManager.Cnc;
|
using NcProgramManager.Cnc;
|
||||||
using FanucProgramManager.Cnc.Models;
|
using NcProgramManager.Cnc.Models;
|
||||||
|
using NcProgramManager.Licensing;
|
||||||
|
|
||||||
namespace FanucProgramManager
|
namespace NcProgramManager
|
||||||
{
|
{
|
||||||
internal class Program
|
internal class Program
|
||||||
{
|
{
|
||||||
|
|
@ -35,7 +34,11 @@ namespace FanucProgramManager
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!checkLicense(inputArgs.chiave))
|
string _licFingerprint = new MachineFingerprint().GetFingerprint();
|
||||||
|
string _licBase64;
|
||||||
|
string _licPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "license.lic");
|
||||||
|
if (!LicenseFile.TryRead(_licPath, out _licBase64)
|
||||||
|
|| !new LicenseValidator().Validate(_licFingerprint, _licBase64))
|
||||||
{
|
{
|
||||||
Console.WriteLine("Licenza ERRATA");
|
Console.WriteLine("Licenza ERRATA");
|
||||||
vediErrore(-100);
|
vediErrore(-100);
|
||||||
|
|
@ -275,47 +278,6 @@ namespace FanucProgramManager
|
||||||
Console.ReadLine();
|
Console.ReadLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
static Boolean checkLicense(string chiave)
|
|
||||||
{
|
|
||||||
string pcInfo = string.Empty;
|
|
||||||
ManagementClass mc = new ManagementClass("win32_processor");
|
|
||||||
ManagementObjectCollection moc = mc.GetInstances();
|
|
||||||
|
|
||||||
foreach (ManagementObject mo in moc)
|
|
||||||
{
|
|
||||||
//Get only the first CPU's ID
|
|
||||||
pcInfo = mo.Properties["processorID"].Value.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
ManagementObjectSearcher baseboardSearcher = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_BaseBoard");
|
|
||||||
foreach (ManagementObject queryObj in baseboardSearcher.Get())
|
|
||||||
{
|
|
||||||
//Get motherboardSerialNumber
|
|
||||||
pcInfo += queryObj["SerialNumber"].ToString();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
using (Aes myAes = Aes.Create())
|
|
||||||
{
|
|
||||||
if (chiave == "")
|
|
||||||
return false;
|
|
||||||
myAes.IV = Convert.FromBase64String("qqxNM8Li99Cwx61VX/QoWA==");
|
|
||||||
myAes.Key = Convert.FromBase64String("7/12mP3dFLGqPGjujlwBCVblURxBaBcGGQ2c2FatfP4=");
|
|
||||||
byte[] encrypted = AesCrypt.EncryptStringToBytes_Aes(pcInfo, myAes.Key, myAes.IV);
|
|
||||||
string roundtrip = AesCrypt.DecryptStringFromBytes_Aes(encrypted, myAes.Key, myAes.IV);
|
|
||||||
string decoded = "";
|
|
||||||
try
|
|
||||||
{
|
|
||||||
decoded = AesCrypt.DecryptStringFromBytes_Aes(Convert.FromBase64String(chiave), myAes.Key, myAes.IV);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine(ex.ToString());
|
|
||||||
}
|
|
||||||
return pcInfo == decoded;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void MostraAiuto()
|
static void MostraAiuto()
|
||||||
{
|
{
|
||||||
Console.WriteLine("Utilizzo del Software gestore Programmi FANUC");
|
Console.WriteLine("Utilizzo del Software gestore Programmi FANUC");
|
||||||
|
|
@ -326,8 +288,7 @@ namespace FanucProgramManager
|
||||||
Console.WriteLine();
|
Console.WriteLine();
|
||||||
Console.WriteLine("Lista dei parametri da fornire all'eseguibile\nDevono essere separati da uno spazio tra l'uno e l'altro,\nnon andare a capo e non lasciare spazi dopo l'= ");
|
Console.WriteLine("Lista dei parametri da fornire all'eseguibile\nDevono essere separati da uno spazio tra l'uno e l'altro,\nnon andare a capo e non lasciare spazi dopo l'= ");
|
||||||
Console.WriteLine();
|
Console.WriteLine();
|
||||||
Console.WriteLine("-chiave=");
|
Console.WriteLine("Il file 'license.lic' deve essere posizionato nella stessa cartella dell'eseguibile.");
|
||||||
Console.WriteLine(" la stringa chiave per eseguire il software.");
|
|
||||||
Console.WriteLine("-azione=");
|
Console.WriteLine("-azione=");
|
||||||
Console.WriteLine(" l'{AZIONE} da eseguire.");
|
Console.WriteLine(" l'{AZIONE} da eseguire.");
|
||||||
Console.WriteLine("-manufacturer=");
|
Console.WriteLine("-manufacturer=");
|
||||||
|
|
@ -385,8 +346,6 @@ namespace FanucProgramManager
|
||||||
inputArgs.mostraHelp = true;
|
inputArgs.mostraHelp = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var chiave = arguments.Find(it => new Regex("-chiave=.*", RegexOptions.IgnoreCase).IsMatch(it));
|
|
||||||
inputArgs.chiave = chiave.Substring(8);
|
|
||||||
var azione = arguments.Find(it => new Regex("-azione=.*", RegexOptions.IgnoreCase).IsMatch(it));
|
var azione = arguments.Find(it => new Regex("-azione=.*", RegexOptions.IgnoreCase).IsMatch(it));
|
||||||
inputArgs.azione = azione.Substring(8);
|
inputArgs.azione = azione.Substring(8);
|
||||||
var manufacturer = arguments.Find(it => new Regex("-manufacturer=.*", RegexOptions.IgnoreCase).IsMatch(it));
|
var manufacturer = arguments.Find(it => new Regex("-manufacturer=.*", RegexOptions.IgnoreCase).IsMatch(it));
|
||||||
|
|
|
||||||
|
|
@ -2,17 +2,17 @@
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
[assembly: InternalsVisibleTo("FanucProgramManager.Tests")]
|
[assembly: InternalsVisibleTo("NcProgramManager.Tests")]
|
||||||
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
|
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
|
||||||
|
|
||||||
// Le informazioni generali relative a un assembly sono controllate dal seguente
|
// Le informazioni generali relative a un assembly sono controllate dal seguente
|
||||||
// set di attributi. Modificare i valori di questi attributi per modificare le informazioni
|
// set di attributi. Modificare i valori di questi attributi per modificare le informazioni
|
||||||
// associate a un assembly.
|
// associate a un assembly.
|
||||||
[assembly: AssemblyTitle("FanucProgramManager")]
|
[assembly: AssemblyTitle("NcProgramManager")]
|
||||||
[assembly: AssemblyDescription("")]
|
[assembly: AssemblyDescription("")]
|
||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCompany("")]
|
[assembly: AssemblyCompany("")]
|
||||||
[assembly: AssemblyProduct("FanucProgramManager")]
|
[assembly: AssemblyProduct("NcProgramManager")]
|
||||||
[assembly: AssemblyCopyright("Copyright © 2023")]
|
[assembly: AssemblyCopyright("Copyright © 2023")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue