diff --git a/apps/electionguard-cli/ElectionGuard.CLI.sln b/apps/electionguard-cli/ElectionGuard.CLI.sln index c5f19978a..e48e9735f 100644 --- a/apps/electionguard-cli/ElectionGuard.CLI.sln +++ b/apps/electionguard-cli/ElectionGuard.CLI.sln @@ -1,105 +1,105 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.2.32519.379 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4DDF806F-023D-4917-B855-E5959DE468BD}" - ProjectSection(SolutionItems) = preProject - icon.png = icon.png - README.md = README.md - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.CLI", "ElectionGuard.CLI.csproj", "{0771316F-7C71-4795-90DF-705EC63442ED}" - ProjectSection(ProjectDependencies) = postProject - {DC80E980-829A-4AFF-BB29-AAA594A4118B} = {DC80E980-829A-4AFF-BB29-AAA594A4118B} - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.Encryption.Utils", "..\..\bindings\netstandard\ElectionGuard\ElectionGuard.Encryption.Utils\ElectionGuard.Encryption.Utils.csproj", "{9CF2608E-9B97-4E21-B5B7-C59E2435B110}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.Encryption", "..\..\bindings\netstandard\ElectionGuard\ElectionGuard.Encryption\ElectionGuard.Encryption.csproj", "{DC80E980-829A-4AFF-BB29-AAA594A4118B}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ElectionGuard.ElectionSetup", "..\..\bindings\netstandard\ElectionGuard\ElectionGuard.ElectionSetup\ElectionGuard.ElectionSetup.csproj", "{507D524F-0911-4575-8991-C36741FD5A46}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ElectionGuard.Decryption", "..\..\bindings\netstandard\ElectionGuard\ElectionGuard.Decryption\ElectionGuard.Decryption.csproj", "{7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - Debug|arm64 = Debug|arm64 - Release|arm64 = Release|arm64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {0771316F-7C71-4795-90DF-705EC63442ED}.Debug|x64.ActiveCfg = Debug|x64 - {0771316F-7C71-4795-90DF-705EC63442ED}.Debug|x64.Build.0 = Debug|x64 - {0771316F-7C71-4795-90DF-705EC63442ED}.Debug|x86.ActiveCfg = Debug|x86 - {0771316F-7C71-4795-90DF-705EC63442ED}.Debug|x86.Build.0 = Debug|x86 - {0771316F-7C71-4795-90DF-705EC63442ED}.Release|x64.ActiveCfg = Release|x64 - {0771316F-7C71-4795-90DF-705EC63442ED}.Release|x64.Build.0 = Release|x64 - {0771316F-7C71-4795-90DF-705EC63442ED}.Release|x86.ActiveCfg = Release|x86 - {0771316F-7C71-4795-90DF-705EC63442ED}.Release|x86.Build.0 = Release|x86 - {0771316F-7C71-4795-90DF-705EC63442ED}.Debug|arm64.ActiveCfg = Debug|arm64 - {0771316F-7C71-4795-90DF-705EC63442ED}.Debug|arm64.Build.0 = Debug|arm64 - {0771316F-7C71-4795-90DF-705EC63442ED}.Release|arm64.ActiveCfg = Release|arm64 - {0771316F-7C71-4795-90DF-705EC63442ED}.Release|arm64.Build.0 = Release|arm64 - {9CF2608E-9B97-4E21-B5B7-C59E2435B110}.Debug|x64.ActiveCfg = Debug|x64 - {9CF2608E-9B97-4E21-B5B7-C59E2435B110}.Debug|x64.Build.0 = Debug|x64 - {9CF2608E-9B97-4E21-B5B7-C59E2435B110}.Debug|x86.ActiveCfg = Debug|x86 - {9CF2608E-9B97-4E21-B5B7-C59E2435B110}.Debug|x86.Build.0 = Debug|x86 - {9CF2608E-9B97-4E21-B5B7-C59E2435B110}.Release|x64.ActiveCfg = Release|x64 - {9CF2608E-9B97-4E21-B5B7-C59E2435B110}.Release|x64.Build.0 = Release|x64 - {9CF2608E-9B97-4E21-B5B7-C59E2435B110}.Release|x86.ActiveCfg = Release|x86 - {9CF2608E-9B97-4E21-B5B7-C59E2435B110}.Release|x86.Build.0 = Release|x86 - {9CF2608E-9B97-4E21-B5B7-C59E2435B110}.Debug|arm64.ActiveCfg = Debug|arm64 - {9CF2608E-9B97-4E21-B5B7-C59E2435B110}.Debug|arm64.Build.0 = Debug|arm64 - {9CF2608E-9B97-4E21-B5B7-C59E2435B110}.Release|arm64.ActiveCfg = Release|arm64 - {9CF2608E-9B97-4E21-B5B7-C59E2435B110}.Release|arm64.Build.0 = Release|arm64 - {DC80E980-829A-4AFF-BB29-AAA594A4118B}.Debug|x64.ActiveCfg = Debug|x64 - {DC80E980-829A-4AFF-BB29-AAA594A4118B}.Debug|x64.Build.0 = Debug|x64 - {DC80E980-829A-4AFF-BB29-AAA594A4118B}.Debug|x86.ActiveCfg = Debug|x86 - {DC80E980-829A-4AFF-BB29-AAA594A4118B}.Debug|x86.Build.0 = Debug|x86 - {DC80E980-829A-4AFF-BB29-AAA594A4118B}.Release|x64.ActiveCfg = Release|x64 - {DC80E980-829A-4AFF-BB29-AAA594A4118B}.Release|x64.Build.0 = Release|x64 - {DC80E980-829A-4AFF-BB29-AAA594A4118B}.Release|x86.ActiveCfg = Release|x86 - {DC80E980-829A-4AFF-BB29-AAA594A4118B}.Release|x86.Build.0 = Release|x86 - {DC80E980-829A-4AFF-BB29-AAA594A4118B}.Debug|arm64.ActiveCfg = Debug|arm64 - {DC80E980-829A-4AFF-BB29-AAA594A4118B}.Debug|arm64.Build.0 = Debug|arm64 - {DC80E980-829A-4AFF-BB29-AAA594A4118B}.Release|arm64.ActiveCfg = Release|arm64 - {DC80E980-829A-4AFF-BB29-AAA594A4118B}.Release|arm64.Build.0 = Release|arm64 - {507D524F-0911-4575-8991-C36741FD5A46}.Debug|x64.ActiveCfg = Debug|x64 - {507D524F-0911-4575-8991-C36741FD5A46}.Debug|x64.Build.0 = Debug|x64 - {507D524F-0911-4575-8991-C36741FD5A46}.Debug|x86.ActiveCfg = Debug|x86 - {507D524F-0911-4575-8991-C36741FD5A46}.Debug|x86.Build.0 = Debug|x86 - {507D524F-0911-4575-8991-C36741FD5A46}.Release|x64.ActiveCfg = Release|x64 - {507D524F-0911-4575-8991-C36741FD5A46}.Release|x64.Build.0 = Release|x64 - {507D524F-0911-4575-8991-C36741FD5A46}.Release|x86.ActiveCfg = Release|x86 - {507D524F-0911-4575-8991-C36741FD5A46}.Release|x86.Build.0 = Release|x86 - {507D524F-0911-4575-8991-C36741FD5A46}.Debug|arm64.ActiveCfg = Debug|arm64 - {507D524F-0911-4575-8991-C36741FD5A46}.Debug|arm64.Build.0 = Debug|arm64 - {507D524F-0911-4575-8991-C36741FD5A46}.Release|arm64.ActiveCfg = Release|arm64 - {507D524F-0911-4575-8991-C36741FD5A46}.Release|arm64.Build.0 = Release|arm64 - {7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Debug|x64.ActiveCfg = Debug|x64 - {7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Debug|x64.Build.0 = Debug|x64 - {7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Debug|x86.ActiveCfg = Debug|x86 - {7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Debug|x86.Build.0 = Debug|x86 - {7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Release|x64.ActiveCfg = Release|x64 - {7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Release|x64.Build.0 = Release|x64 - {7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Release|x86.ActiveCfg = Release|x86 - {7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Release|x86.Build.0 = Release|x86 - {7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Debug|arm64.ActiveCfg = Debug|arm64 - {7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Debug|arm64.Build.0 = Debug|arm64 - {7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Release|arm64.ActiveCfg = Release|arm64 - {7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Release|arm64.Build.0 = Release|arm64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {44312322-DEA7-4BDE-8930-AFEAB72CA425} - EndGlobalSection - GlobalSection(MonoDevelopProperties) = preSolution - Policies = $0 - $0.TextStylePolicy = $3 - EndGlobalSection -EndGlobal +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32519.379 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4DDF806F-023D-4917-B855-E5959DE468BD}" + ProjectSection(SolutionItems) = preProject + icon.png = icon.png + README.md = README.md + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.CLI", "ElectionGuard.CLI.csproj", "{0771316F-7C71-4795-90DF-705EC63442ED}" + ProjectSection(ProjectDependencies) = postProject + {DC80E980-829A-4AFF-BB29-AAA594A4118B} = {DC80E980-829A-4AFF-BB29-AAA594A4118B} + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.Encryption.Utils", "..\..\bindings\netstandard\ElectionGuard\ElectionGuard.Encryption.Utils\ElectionGuard.Encryption.Utils.csproj", "{9CF2608E-9B97-4E21-B5B7-C59E2435B110}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.Encryption", "..\..\bindings\netstandard\ElectionGuard\ElectionGuard.Encryption\ElectionGuard.Encryption.csproj", "{DC80E980-829A-4AFF-BB29-AAA594A4118B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ElectionGuard.ElectionSetup", "..\..\bindings\netstandard\ElectionGuard\ElectionGuard.ElectionSetup\ElectionGuard.ElectionSetup.csproj", "{507D524F-0911-4575-8991-C36741FD5A46}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ElectionGuard.Decryption", "..\..\bindings\netstandard\ElectionGuard\ElectionGuard.Decryption\ElectionGuard.Decryption.csproj", "{7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + Debug|arm64 = Debug|arm64 + Release|arm64 = Release|arm64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0771316F-7C71-4795-90DF-705EC63442ED}.Debug|x64.ActiveCfg = Debug|x64 + {0771316F-7C71-4795-90DF-705EC63442ED}.Debug|x64.Build.0 = Debug|x64 + {0771316F-7C71-4795-90DF-705EC63442ED}.Debug|x86.ActiveCfg = Debug|x86 + {0771316F-7C71-4795-90DF-705EC63442ED}.Debug|x86.Build.0 = Debug|x86 + {0771316F-7C71-4795-90DF-705EC63442ED}.Release|x64.ActiveCfg = Release|x64 + {0771316F-7C71-4795-90DF-705EC63442ED}.Release|x64.Build.0 = Release|x64 + {0771316F-7C71-4795-90DF-705EC63442ED}.Release|x86.ActiveCfg = Release|x86 + {0771316F-7C71-4795-90DF-705EC63442ED}.Release|x86.Build.0 = Release|x86 + {0771316F-7C71-4795-90DF-705EC63442ED}.Debug|arm64.ActiveCfg = Debug|arm64 + {0771316F-7C71-4795-90DF-705EC63442ED}.Debug|arm64.Build.0 = Debug|arm64 + {0771316F-7C71-4795-90DF-705EC63442ED}.Release|arm64.ActiveCfg = Release|arm64 + {0771316F-7C71-4795-90DF-705EC63442ED}.Release|arm64.Build.0 = Release|arm64 + {9CF2608E-9B97-4E21-B5B7-C59E2435B110}.Debug|x64.ActiveCfg = Debug|x64 + {9CF2608E-9B97-4E21-B5B7-C59E2435B110}.Debug|x64.Build.0 = Debug|x64 + {9CF2608E-9B97-4E21-B5B7-C59E2435B110}.Debug|x86.ActiveCfg = Debug|x86 + {9CF2608E-9B97-4E21-B5B7-C59E2435B110}.Debug|x86.Build.0 = Debug|x86 + {9CF2608E-9B97-4E21-B5B7-C59E2435B110}.Release|x64.ActiveCfg = Release|x64 + {9CF2608E-9B97-4E21-B5B7-C59E2435B110}.Release|x64.Build.0 = Release|x64 + {9CF2608E-9B97-4E21-B5B7-C59E2435B110}.Release|x86.ActiveCfg = Release|x86 + {9CF2608E-9B97-4E21-B5B7-C59E2435B110}.Release|x86.Build.0 = Release|x86 + {9CF2608E-9B97-4E21-B5B7-C59E2435B110}.Debug|arm64.ActiveCfg = Debug|arm64 + {9CF2608E-9B97-4E21-B5B7-C59E2435B110}.Debug|arm64.Build.0 = Debug|arm64 + {9CF2608E-9B97-4E21-B5B7-C59E2435B110}.Release|arm64.ActiveCfg = Release|arm64 + {9CF2608E-9B97-4E21-B5B7-C59E2435B110}.Release|arm64.Build.0 = Release|arm64 + {DC80E980-829A-4AFF-BB29-AAA594A4118B}.Debug|x64.ActiveCfg = Debug|x64 + {DC80E980-829A-4AFF-BB29-AAA594A4118B}.Debug|x64.Build.0 = Debug|x64 + {DC80E980-829A-4AFF-BB29-AAA594A4118B}.Debug|x86.ActiveCfg = Debug|x86 + {DC80E980-829A-4AFF-BB29-AAA594A4118B}.Debug|x86.Build.0 = Debug|x86 + {DC80E980-829A-4AFF-BB29-AAA594A4118B}.Release|x64.ActiveCfg = Release|x64 + {DC80E980-829A-4AFF-BB29-AAA594A4118B}.Release|x64.Build.0 = Release|x64 + {DC80E980-829A-4AFF-BB29-AAA594A4118B}.Release|x86.ActiveCfg = Release|x86 + {DC80E980-829A-4AFF-BB29-AAA594A4118B}.Release|x86.Build.0 = Release|x86 + {DC80E980-829A-4AFF-BB29-AAA594A4118B}.Debug|arm64.ActiveCfg = Debug|arm64 + {DC80E980-829A-4AFF-BB29-AAA594A4118B}.Debug|arm64.Build.0 = Debug|arm64 + {DC80E980-829A-4AFF-BB29-AAA594A4118B}.Release|arm64.ActiveCfg = Release|arm64 + {DC80E980-829A-4AFF-BB29-AAA594A4118B}.Release|arm64.Build.0 = Release|arm64 + {507D524F-0911-4575-8991-C36741FD5A46}.Debug|x64.ActiveCfg = Debug|x64 + {507D524F-0911-4575-8991-C36741FD5A46}.Debug|x64.Build.0 = Debug|x64 + {507D524F-0911-4575-8991-C36741FD5A46}.Debug|x86.ActiveCfg = Debug|x86 + {507D524F-0911-4575-8991-C36741FD5A46}.Debug|x86.Build.0 = Debug|x86 + {507D524F-0911-4575-8991-C36741FD5A46}.Release|x64.ActiveCfg = Release|x64 + {507D524F-0911-4575-8991-C36741FD5A46}.Release|x64.Build.0 = Release|x64 + {507D524F-0911-4575-8991-C36741FD5A46}.Release|x86.ActiveCfg = Release|x86 + {507D524F-0911-4575-8991-C36741FD5A46}.Release|x86.Build.0 = Release|x86 + {507D524F-0911-4575-8991-C36741FD5A46}.Debug|arm64.ActiveCfg = Debug|arm64 + {507D524F-0911-4575-8991-C36741FD5A46}.Debug|arm64.Build.0 = Debug|arm64 + {507D524F-0911-4575-8991-C36741FD5A46}.Release|arm64.ActiveCfg = Release|arm64 + {507D524F-0911-4575-8991-C36741FD5A46}.Release|arm64.Build.0 = Release|arm64 + {7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Debug|x64.ActiveCfg = Debug|x64 + {7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Debug|x64.Build.0 = Debug|x64 + {7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Debug|x86.ActiveCfg = Debug|x86 + {7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Debug|x86.Build.0 = Debug|x86 + {7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Release|x64.ActiveCfg = Release|x64 + {7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Release|x64.Build.0 = Release|x64 + {7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Release|x86.ActiveCfg = Release|x86 + {7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Release|x86.Build.0 = Release|x86 + {7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Debug|arm64.ActiveCfg = Debug|arm64 + {7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Debug|arm64.Build.0 = Debug|arm64 + {7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Release|arm64.ActiveCfg = Release|arm64 + {7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Release|arm64.Build.0 = Release|arm64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {44312322-DEA7-4BDE-8930-AFEAB72CA425} + EndGlobalSection + GlobalSection(MonoDevelopProperties) = preSolution + Policies = $0 + $0.TextStylePolicy = $3 + EndGlobalSection +EndGlobal diff --git a/apps/electionguard-cli/Generate/PlainTally.cs b/apps/electionguard-cli/Generate/PlainTally.cs index c900e407c..a8ee8968b 100644 --- a/apps/electionguard-cli/Generate/PlainTally.cs +++ b/apps/electionguard-cli/Generate/PlainTally.cs @@ -1,92 +1,92 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Numerics; -using System.Text; -using System.Threading.Tasks; - -namespace ElectionGuard.CLI.Generate -{ - - - public class PlainTally - { - public List contests { get; set; } = new(); - public string object_id { get; set; } - public string style_id { get; set; } - - public void Clear() - { - foreach (Contest contest in contests) - { - contest.Clear(); - } - } - public static PlainTally operator +(PlainTally left, PlainTally right) - { +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; + +namespace ElectionGuard.CLI.Generate +{ + + + public class PlainTally + { + public List contests { get; set; } = new(); + public string object_id { get; set; } + public string style_id { get; set; } + + public void Clear() + { + foreach (Contest contest in contests) + { + contest.Clear(); + } + } + public static PlainTally operator +(PlainTally left, PlainTally right) + { foreach (var contest in right.contests) { var l = left.contests.SingleOrDefault(c => c.object_id == contest.object_id); - if (l != null) - { - l += contest; + if (l != null) + { + l += contest; } - else - { - left.contests.Add(contest); + else + { + left.contests.Add(contest); } - } - return left; - } - } - - public class Contest - { - public List ballot_selections { get; set; } = new(); - public string object_id { get; set; } - - public void Clear() - { + } + return left; + } + } + + public class Contest + { + public List ballot_selections { get; set; } = new(); + public string object_id { get; set; } + + public void Clear() + { foreach (var selection in ballot_selections) { selection.Clear(); - } - } - - public static Contest operator +(Contest left, Contest right) - { + } + } + + public static Contest operator +(Contest left, Contest right) + { foreach (var selection in right.ballot_selections) { var l = left.ballot_selections.SingleOrDefault(b => b.object_id == selection.object_id); - if (l != null) - { - l += selection; + if (l != null) + { + l += selection; } - else - { - left.ballot_selections.Add(selection); + else + { + left.ballot_selections.Add(selection); } - } - return left; - } - } - - public class Ballot_Selections - { - public bool is_placeholder_selection { get; set; } - public string object_id { get; set; } - public int vote { get; set; } - public string write_in { get; set; } - - public void Clear() - { - vote = 0; - } - - public static Ballot_Selections operator +(Ballot_Selections left, Ballot_Selections right) - { - left.vote += right.vote; - return left; - } - } -} + } + return left; + } + } + + public class Ballot_Selections + { + public bool is_placeholder_selection { get; set; } + public string object_id { get; set; } + public int vote { get; set; } + public string write_in { get; set; } + + public void Clear() + { + vote = 0; + } + + public static Ballot_Selections operator +(Ballot_Selections left, Ballot_Selections right) + { + left.vote += right.vote; + return left; + } + } +} diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.Decryption.Tests/ElectionGuard.Decryption.Tests.csproj b/bindings/netstandard/ElectionGuard/ElectionGuard.Decryption.Tests/ElectionGuard.Decryption.Tests.csproj index 9d400c0fa..a2204a451 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.Decryption.Tests/ElectionGuard.Decryption.Tests.csproj +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.Decryption.Tests/ElectionGuard.Decryption.Tests.csproj @@ -1,76 +1,76 @@ - - - - net7.0 - enable - enable - true - true - false - arm64;x64;x86 - - - - - - - - - - - - - - - - - - - - - - - - full - true - 1701;1702 - 4 - SYSLIB0004 - - - - pdbonly - 1701;1702 - 4 - SYSLIB0004 - - - - ..\..\..\..\data - ..\..\..\..\build\libs - - - - PreserveNewest - - - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - - - - - - - - - + + + + net9.0 + enable + enable + true + true + false + arm64;x64;x86 + + + + + + + + + + + + + + + + + + + + + + + + full + true + 1701;1702 + 4 + SYSLIB0004 + + + + pdbonly + 1701;1702 + 4 + SYSLIB0004 + + + + ..\..\..\..\data + ..\..\..\..\build\libs + + + + PreserveNewest + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + + + + + + + + diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.Decryption/Accumulation/AccumulateShares.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.Decryption/Accumulation/AccumulateShares.cs index e54541c70..8da078d79 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.Decryption/Accumulation/AccumulateShares.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.Decryption/Accumulation/AccumulateShares.cs @@ -74,13 +74,13 @@ public static List AccumulateShares( var ballots = new List(); foreach (var (ballotId, ballot) in self) { - var accumulation = ballot.AccumulateShares( - tallyId, - ballotShares[ballotId], - lagrangeCoefficients, - extendedBaseHash, - skipValidation); - ballots.Add(accumulation); + var accumulation = ballot.AccumulateShares( + tallyId, + ballotShares[ballotId], + lagrangeCoefficients, + extendedBaseHash, + skipValidation); + ballots.Add(accumulation); } return ballots; } diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.Decryption/DecryptionMediator.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.Decryption/DecryptionMediator.cs index d31ad9ed1..023a690b8 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.Decryption/DecryptionMediator.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.Decryption/DecryptionMediator.cs @@ -201,9 +201,9 @@ public void SubmitShares( var guardian = Guardians[ballotShares.First().GuardianId]; foreach (var ballotShare in ballotShares) { - tallyDecryption.AddBallotShare( - guardian, ballotShare, - ballots.First(i => i.ObjectId == ballotShare.BallotId)); + tallyDecryption.AddBallotShare( + guardian, ballotShare, + ballots.First(i => i.ObjectId == ballotShare.BallotId)); } } diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.Decryption/ElectionGuard.Decryption.csproj b/bindings/netstandard/ElectionGuard/ElectionGuard.Decryption/ElectionGuard.Decryption.csproj index f86cc97a9..3392ae8bb 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.Decryption/ElectionGuard.Decryption.csproj +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.Decryption/ElectionGuard.Decryption.csproj @@ -1,33 +1,65 @@ - - - - net7.0 - enable - enable - true - true - arm64;x64;x86 - - - - - - - - - - full - true - 1701;1702 - 4 - SYSLIB0004 - - - - pdbonly - 1701;1702 - 4 - SYSLIB0004 - - - + + + + net9.0 + + ElectionGuard + ElectionGuard.Decryption + 1.75.17 + 1.75.17.0 + 1.75.17.0 + true + true + x64;x86 + enable + enable + + + + + Enhanced.ElectionGuard.Decryption + Enhanced ElectionGuard Decryption + Private fork of open source implementation of ElectionGuard's ballot decryption. + Enhanced Voting + 1.75.17 + MIT + https://github.com/Enhanced-Voting/electionguard + https://github.com/Enhanced-Voting/electionguard + Enhanced;Electionguard;Decryption;Windows;Linux + README.md + icon.png + PackageReference + true + + + x64;x86 + + + + + + + + + + full + true + 1701;1702 + 4 + SYSLIB0004 + + + + pdbonly + 1701;1702 + 4 + SYSLIB0004 + true + + + + + + + + diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup.Tests/ElectionGuard.ElectionSetup.Tests.csproj b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup.Tests/ElectionGuard.ElectionSetup.Tests.csproj index 0ffe645fd..b0df9a3cc 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup.Tests/ElectionGuard.ElectionSetup.Tests.csproj +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup.Tests/ElectionGuard.ElectionSetup.Tests.csproj @@ -1,7 +1,7 @@ - net7.0 + net9.0 enable enable true @@ -27,6 +27,7 @@ + diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup.Tests/Generators/KeyCeremonyGenerator.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup.Tests/Generators/KeyCeremonyGenerator.cs index ef8b6e7dd..7e3e05a09 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup.Tests/Generators/KeyCeremonyGenerator.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup.Tests/Generators/KeyCeremonyGenerator.cs @@ -1,4 +1,4 @@ - + using ElectionGuard.UI.Lib.Models; using ElectionGuard.ElectionSetup.Tests.KeyCeremony; using ElectionGuard.ElectionSetup.Tests.Mocks; @@ -179,7 +179,7 @@ public static ElectionJointKey RunKeyCeremony( data.KeyCeremony.Id, guardian.GuardianId, b.DesignatedId!, - b) + new(b)) ).ToList()); } @@ -187,7 +187,7 @@ public static ElectionJointKey RunKeyCeremony( foreach (var guardian in data.Guardians) { var backups = data.Mediator.ShareBackups(guardian.GuardianId); - backups!.ForEach(guardian.SaveElectionPartialKeyBackup); + backups!.ForEach(g=>guardian.SaveElectionPartialKeyBackup(g.ToRecord())); } // ROUND 3: Joint Key @@ -199,7 +199,7 @@ public static ElectionJointKey RunKeyCeremony( { var verification = guardian.VerifyElectionPartialKeyBackup( owner.GuardianId, data.KeyCeremony.Id); - data.Mediator.ReceiveElectionPartialKeyVerification(verification!); + data.Mediator.ReceiveElectionPartialKeyVerification(new(verification!)); }); } Assert.That(data.Mediator.AllBackupsVerified(), data.Mediator.GetVerificationState().ToString()); diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup.Tests/KeyCeremony/TestKeyCeremony.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup.Tests/KeyCeremony/TestKeyCeremony.cs index e55fc6c62..131fb71b6 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup.Tests/KeyCeremony/TestKeyCeremony.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup.Tests/KeyCeremony/TestKeyCeremony.cs @@ -1,4 +1,4 @@ -using ElectionGuard.ElectionSetup.Tests.Generators; +using ElectionGuard.ElectionSetup.Tests.Generators; using ElectionGuard.UI.Lib.Models; namespace ElectionGuard.ElectionSetup.Tests.KeyCeremony; @@ -61,7 +61,7 @@ public void Test_KeyCeremony() keyCeremony.Id, sender.GuardianId, b.DesignatedId!, - b + new(b) )).ToList() ); } @@ -72,7 +72,7 @@ public void Test_KeyCeremony() foreach (var guardian in guardians) { var backups = mediator.ShareBackups(guardian.GuardianId); - backups!.ForEach(guardian.SaveElectionPartialKeyBackup); + backups!.ForEach(g => guardian.SaveElectionPartialKeyBackup(g.ToRecord())); } // ROUND 3: Partial Key Verification @@ -83,7 +83,7 @@ public void Test_KeyCeremony() .ForEach(owner => { var verification = guardian.VerifyElectionPartialKeyBackup(owner.GuardianId, keyCeremony.Id); - mediator.ReceiveElectionPartialKeyVerification(verification!); + mediator.ReceiveElectionPartialKeyVerification(new(verification!)); }); } diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup.Tests/Mocks/MockBaseDatabaseService.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup.Tests/Mocks/MockBaseDatabaseService.cs index 4dabdd301..79e4c0122 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup.Tests/Mocks/MockBaseDatabaseService.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup.Tests/Mocks/MockBaseDatabaseService.cs @@ -12,13 +12,13 @@ public abstract class MockBaseDatabaseServiceBase : DisposableBase, IDatabase public Task CountByFilterAsync(FilterDefinition filter, string? table = null) { throw new NotImplementedException(); - } - - public Task ExistsByFilterAsync(FilterDefinition filter, string? table = null) - { - throw new NotImplementedException(); - } - + } + + public Task ExistsByFilterAsync(FilterDefinition filter, string? table = null) + { + throw new NotImplementedException(); + } + public Task> GetAllAsync(string? table = null) { return Task.FromResult(Collection.Values.ToList()); @@ -49,8 +49,8 @@ public Task> GetAllByFilterAsync(FilterDefinition filter, string? tab throw new NotImplementedException(); } - public abstract Task SaveAsync(T data, FilterDefinition? customFilter = null, string? table = null); - + public abstract Task SaveAsync(T data, FilterDefinition? customFilter = null, string? table = null); + public Task UpdateAsync(FilterDefinition filter, UpdateDefinition update, string? table = null) { throw new NotImplementedException(); diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup.Tests/Mocks/MockGuardianBackupService.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup.Tests/Mocks/MockGuardianBackupService.cs index 2b680f122..6f7b8418f 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup.Tests/Mocks/MockGuardianBackupService.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup.Tests/Mocks/MockGuardianBackupService.cs @@ -1,8 +1,8 @@ using ElectionGuard.ElectionSetup.Concurrency; using ElectionGuard.UI.Lib.Models; using ElectionGuard.UI.Lib.Services; -using MongoDB.Driver; - +using MongoDB.Driver; + namespace ElectionGuard.ElectionSetup.Tests.Mocks; public class MockGuardianBackupService : MockBaseDatabaseServiceBase, IGuardianBackupService diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup.Tests/Mocks/MockGuardianPublicKeyService.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup.Tests/Mocks/MockGuardianPublicKeyService.cs index 72e4b3f5e..0b040265a 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup.Tests/Mocks/MockGuardianPublicKeyService.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup.Tests/Mocks/MockGuardianPublicKeyService.cs @@ -2,8 +2,8 @@ using ElectionGuard.Guardians; using ElectionGuard.UI.Lib.Models; using ElectionGuard.UI.Lib.Services; -using MongoDB.Driver; - +using MongoDB.Driver; + namespace ElectionGuard.ElectionSetup.Tests.Mocks; public class MockGuardianPublicKeyService : MockBaseDatabaseServiceBase, IGuardianPublicKeyService diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup.Tests/Mocks/MockKeyCeremonyService.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup.Tests/Mocks/MockKeyCeremonyService.cs index 69da3babe..9697f253a 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup.Tests/Mocks/MockKeyCeremonyService.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup.Tests/Mocks/MockKeyCeremonyService.cs @@ -1,8 +1,8 @@ using ElectionGuard.ElectionSetup.Concurrency; using ElectionGuard.UI.Lib.Models; using ElectionGuard.UI.Lib.Services; -using MongoDB.Driver; - +using MongoDB.Driver; + namespace ElectionGuard.ElectionSetup.Tests.Mocks; public class MockKeyCeremonyService : MockBaseDatabaseServiceBase, IKeyCeremonyService @@ -46,8 +46,8 @@ public async Task UpdateStateAsync(string keyCeremonyId, KeyCeremonyState state) Collection[keyCeremonyId] = record; } } - public override async Task SaveAsync(KeyCeremonyRecord data, FilterDefinition? customFilter = null, string? table = null) - { + public override async Task SaveAsync(KeyCeremonyRecord data, FilterDefinition? customFilter = null, string? table = null) + { using (await _lock.LockAsync()) { data.Id ??= Guid.NewGuid().ToString(); diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup.Tests/Mocks/MockVerificationService.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup.Tests/Mocks/MockVerificationService.cs index 7b8269e18..8ec280daf 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup.Tests/Mocks/MockVerificationService.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup.Tests/Mocks/MockVerificationService.cs @@ -1,7 +1,7 @@ using ElectionGuard.UI.Lib.Models; using ElectionGuard.UI.Lib.Services; -using MongoDB.Driver; - +using MongoDB.Driver; + namespace ElectionGuard.ElectionSetup.Tests.Mocks; public class MockVerificationService : MockBaseDatabaseServiceBase, IVerificationService @@ -22,8 +22,8 @@ public Task CountAsync(string keyCeremonyId) { var records = Collection.Values.Where(x => x.KeyCeremonyId == keyCeremonyId).ToList(); return Task.FromResult(records ?? null); - } - + } + public override Task SaveAsync(ElectionPartialKeyVerification data, FilterDefinition? customFilter = null, string? table = null) { data.Id ??= Guid.NewGuid().ToString(); diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/BackupVerificationState.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/BackupVerificationState.cs index 6f896e576..9d01ef68b 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/BackupVerificationState.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/BackupVerificationState.cs @@ -1,7 +1,9 @@ -namespace ElectionGuard.ElectionSetup; - -/// -/// The state of the verifications of all guardian election partial key backups -/// -public record BackupVerificationState(bool AllSent = false, bool AllVerified = false, List? FailedVerification = null); - +using ElectionGuard.ElectionSetup.Records; + +namespace ElectionGuard.ElectionSetup; + +/// +/// The state of the verifications of all guardian election partial key backups +/// +public record BackupVerificationState(bool AllSent = false, bool AllVerified = false, List? FailedVerification = null); + diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/ElectionBuilder.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/ElectionBuilder.cs index c903357e9..e75113d1d 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/ElectionBuilder.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/ElectionBuilder.cs @@ -1,8 +1,8 @@ -namespace ElectionGuard.ElectionSetup; - -/// -/// Class to create and export the encryption package for the election -/// -public class ElectionBuilder -{ -} +namespace ElectionGuard.ElectionSetup; + +/// +/// Class to create and export the encryption package for the election +/// +public class ElectionBuilder +{ +} diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/ElectionGuard.ElectionSetup.csproj b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/ElectionGuard.ElectionSetup.csproj index 876d62f2a..fdd6d1f7b 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/ElectionGuard.ElectionSetup.csproj +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/ElectionGuard.ElectionSetup.csproj @@ -1,17 +1,39 @@ - net7.0 + net9.0 + 1.75.17 + 1.75.17.0 + 1.75.17.0 enable enable true true - arm64;x64;x86 + x64;x86 Debug;Release + + + Enhanced.ElectionGuard.ElectionSetup + Enhanced ElectionGuard Election Setup + Private fork of open source implementation of ElectionGuard's election setup. + Enhanced Voting + 1.75.17 + MIT + https://github.com/Enhanced-Voting/electionguard + https://github.com/Enhanced-Voting/electionguard + Enhanced;Electionguard;Election;Setup;Windows;Linux + README.md + icon.png + PackageReference + true + + + x64;x86 + + - @@ -30,4 +52,9 @@ SYSLIB0004 + + + + + diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/ElectionPartialKeyBackupAttribute.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/ElectionPartialKeyBackupAttribute.cs index 237540f25..ffbe3b8de 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/ElectionPartialKeyBackupAttribute.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/ElectionPartialKeyBackupAttribute.cs @@ -25,10 +25,10 @@ public class ElectionPartialKeyBackupAttribute : DisposableBase /// public HashedElGamalCiphertext? EncryptedCoordinate { get; init; } - protected override void DisposeUnmanaged() - { - base.DisposeUnmanaged(); - EncryptedCoordinate?.Dispose(); + protected override void DisposeUnmanaged() + { + base.DisposeUnmanaged(); + EncryptedCoordinate?.Dispose(); } } } \ No newline at end of file diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/ElectionPartialKeyChallenge.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/ElectionPartialKeyChallenge.cs index 1195ac2c2..832b50381 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/ElectionPartialKeyChallenge.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/ElectionPartialKeyChallenge.cs @@ -1,24 +1,24 @@ -using ElectionGuard.ElectionSetup.Extensions; -using ElectionGuard.Proofs; -using ElectionGuard.Extensions; - -namespace ElectionGuard.ElectionSetup; -public class ElectionPartialKeyChallenge : DisposableBase -{ - public string? OwnerId { get; init; } - public string? DesignatedId { get; init; } - public ulong DesignatedSequenceOrder { get; init; } - public ElementModQ? Value { get; init; } - public List? CoefficientCommitments { get; init; } - public List? CoefficientProofs { get; init; } - - protected override void DisposeUnmanaged() - { - base.DisposeUnmanaged(); - - Value?.Dispose(); - - CoefficientCommitments?.Dispose(); - CoefficientProofs?.Dispose(); - } -} +using ElectionGuard.ElectionSetup.Extensions; +using ElectionGuard.Proofs; +using ElectionGuard.Extensions; + +namespace ElectionGuard.ElectionSetup; +public class ElectionPartialKeyChallenge : DisposableBase +{ + public string? OwnerId { get; init; } + public string? DesignatedId { get; init; } + public ulong DesignatedSequenceOrder { get; init; } + public ElementModQ? Value { get; init; } + public List? CoefficientCommitments { get; init; } + public List? CoefficientProofs { get; init; } + + protected override void DisposeUnmanaged() + { + base.DisposeUnmanaged(); + + Value?.Dispose(); + + CoefficientCommitments?.Dispose(); + CoefficientProofs?.Dispose(); + } +} diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Extensions/DictionaryExtensions.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Extensions/DictionaryExtensions.cs index f3a0788e0..bc40d5193 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Extensions/DictionaryExtensions.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Extensions/DictionaryExtensions.cs @@ -1,30 +1,32 @@ -namespace ElectionGuard.ElectionSetup.Extensions; - -public static class DictionaryExtensions -{ - public static void Dispose(this Dictionary source) where T : IDisposable - { - if (source is null) - { - return; - } - foreach (var item in source.Values) - { - item.Dispose(); - } - source.Clear(); - } - - public static void Dispose(this Dictionary source) where T : IDisposable - { - if (source is null) - { - return; - } - foreach (var item in source.Values) - { - item.Dispose(); - } - source.Clear(); - } -} +using ElectionGuard.ElectionSetup.Records; + +namespace ElectionGuard.ElectionSetup.Extensions; + +public static class DictionaryExtensions +{ + public static void Dispose(this Dictionary source) where T : IDisposable + { + if (source is null) + { + return; + } + foreach (var item in source.Values) + { + item.Dispose(); + } + source.Clear(); + } + + public static void Dispose(this Dictionary source) where T : IDisposable + { + if (source is null) + { + return; + } + foreach (var item in source.Values) + { + item.Dispose(); + } + source.Clear(); + } +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Extensions/ObservableCollectionExtension.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Extensions/ObservableCollectionExtension.cs similarity index 87% rename from src/electionguard-ui/ElectionGuard.UI.Lib/Extensions/ObservableCollectionExtension.cs rename to bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Extensions/ObservableCollectionExtension.cs index d0bb89ac3..389a05aca 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Extensions/ObservableCollectionExtension.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Extensions/ObservableCollectionExtension.cs @@ -1,6 +1,6 @@ using System.Collections.ObjectModel; -namespace ElectionGuard.UI.Lib.Extensions +namespace ElectionGuard.ElectionSetup.Extensions { public static class ObservableCollectionExtension { diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Guardian/Guardian.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Guardian/Guardian.cs index d19f16240..c1eb74b7f 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Guardian/Guardian.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Guardian/Guardian.cs @@ -1,8 +1,8 @@ -using System.Diagnostics; +using System.Diagnostics; using ElectionGuard.ElectionSetup.Extensions; using ElectionGuard.Extensions; -using ElectionGuard.UI.Lib.Models; using ElectionGuard.Guardians; +using ElectionGuard.ElectionSetup.Records; namespace ElectionGuard.ElectionSetup; @@ -28,8 +28,8 @@ public partial class Guardian : DisposableBase, IElectionGuardian private readonly ElementModQ _commitmentSeed; private ElementModQ? _myPartialSecretKey; private readonly Dictionary _publicKeys = new(); - private readonly Dictionary _partialKeyBackups = new(); - private readonly Dictionary _partialVerifications = new(); + private readonly Dictionary _partialKeyBackups = new(); + private readonly Dictionary _partialVerifications = new(); public string ObjectId => GuardianId; @@ -51,7 +51,7 @@ public partial class Guardian : DisposableBase, IElectionGuardian /// /// Encrypted segments of the guardian's private key that are shared with other guardians. /// - public Dictionary BackupsToShare { get; set; } = new(); + public Dictionary BackupsToShare { get; set; } = new(); private ElementModP? _commitmentOffset; @@ -204,9 +204,9 @@ public Guardian( ElementModQ commitmentSeed, CeremonyDetails ceremonyDetails, Dictionary? otherKeys = null, - Dictionary? otherBackups = null, - Dictionary? backupsToShare = null, - Dictionary? otherVerifications = null + Dictionary? otherBackups = null, + Dictionary? backupsToShare = null, + Dictionary? otherVerifications = null ) { _myElectionKeys = new(keyPair); @@ -311,25 +311,25 @@ public bool GenerateElectionPartialKeyBackups() SequenceOrder, _myElectionKeys.Polynomial, guardianKey); - BackupsToShare[guardianKey.GuardianId] = new(backup); + BackupsToShare[guardianKey.GuardianId] = new(backup.OwnerId, backup.OwnerSequenceOrder, backup.DesignatedId, backup.DesignatedSequenceOrder, backup.EncryptedCoordinate); } return true; } // share_election_partial_key_backups - public List ShareElectionPartialKeyBackups() + public List ShareElectionPartialKeyBackups() { return BackupsToShare.Values.ToList(); } // save_election_partial_key_backup public void SaveElectionPartialKeyBackup( - ElectionPartialKeyBackup backup) + ElectionPartialKeyBackupRecord backup) { - _partialKeyBackups[backup.OwnerId!] = new(backup); + _partialKeyBackups[backup.OwnerId!] = new(backup.OwnerId, backup.OwnerSequenceOrder, backup.DesignatedId, backup.DesignatedSequenceOrder, backup.EncryptedCoordinate); } - private static ElectionPartialKeyBackup GenerateElectionPartialKeyBackup( + private static ElectionPartialKeyBackupRecord GenerateElectionPartialKeyBackup( string myGuardianId, ulong mySequenceOrder, ElectionPolynomial myPolynomial, diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Guardian/GuardianBackupChallengeMethods.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Guardian/GuardianBackupChallengeMethods.cs index 073c2740c..805eaf848 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Guardian/GuardianBackupChallengeMethods.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Guardian/GuardianBackupChallengeMethods.cs @@ -1,4 +1,4 @@ -using ElectionGuard.UI.Lib.Models; +using ElectionGuard.ElectionSetup.Records; namespace ElectionGuard.ElectionSetup; @@ -19,14 +19,14 @@ public partial class Guardian } // verify_election_partial_key_challenge - public ElectionPartialKeyVerification VerifyElectionPartialKeyChallenge( + public ElectionPartialKeyVerificationRecord VerifyElectionPartialKeyChallenge( ElectionPartialKeyChallenge challenge) { return VerifyElectionPartialKeyChallenge(GuardianId, challenge); } private static ElectionPartialKeyChallenge GenerateElectionPartialKeyChallenge( - ElectionPartialKeyBackup backup, ElectionPolynomial polynomial) + ElectionPartialKeyBackupRecord backup, ElectionPolynomial polynomial) { return new() { @@ -39,18 +39,13 @@ private static ElectionPartialKeyChallenge GenerateElectionPartialKeyChallenge( }; } - private static ElectionPartialKeyVerification VerifyElectionPartialKeyChallenge( + private static ElectionPartialKeyVerificationRecord VerifyElectionPartialKeyChallenge( string verifierId, ElectionPartialKeyChallenge challenge) { - return new ElectionPartialKeyVerification() - { - OwnerId = challenge.OwnerId, - DesignatedId = challenge.DesignatedId, - VerifierId = verifierId, - Verified = ElectionPolynomial.VerifyCoordinate( + return new ElectionPartialKeyVerificationRecord(null, challenge.OwnerId, challenge.DesignatedId, verifierId, ElectionPolynomial.VerifyCoordinate( challenge.DesignatedSequenceOrder, challenge.Value!, - challenge.CoefficientCommitments!) - }; + challenge.CoefficientCommitments!)); + } } diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Guardian/GuardianBackupVerifyMethods.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Guardian/GuardianBackupVerifyMethods.cs index bfbde282d..2d8d2c1df 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Guardian/GuardianBackupVerifyMethods.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Guardian/GuardianBackupVerifyMethods.cs @@ -1,6 +1,6 @@ -using System.Diagnostics; +using System.Diagnostics; using ElectionGuard.Guardians; -using ElectionGuard.UI.Lib.Models; +using ElectionGuard.ElectionSetup.Records; namespace ElectionGuard.ElectionSetup; @@ -34,13 +34,13 @@ public bool AllElectionPartialKeyBackupsVerified } // save_election_partial_key_verification - public void SaveElectionPartialKeyVerification(ElectionPartialKeyVerification verification) + public void SaveElectionPartialKeyVerification(ElectionPartialKeyVerificationRecord verification) { _partialVerifications[verification.DesignatedId!] = verification; } // verify_election_partial_key_backup - public ElectionPartialKeyVerification? VerifyElectionPartialKeyBackup( + public ElectionPartialKeyVerificationRecord? VerifyElectionPartialKeyBackup( string guardianId, string keyCeremonyId) { var backup = _partialKeyBackups[guardianId]; @@ -59,9 +59,9 @@ public void SaveElectionPartialKeyVerification(ElectionPartialKeyVerification ve backup?.DesignatedId!, backup!, publicKey, _myElectionKeys, keyCeremonyId); } - private static ElectionPartialKeyVerification VerifyElectionPartialKeyBackup( + private static ElectionPartialKeyVerificationRecord VerifyElectionPartialKeyBackup( string receiverGuardianId, - ElectionPartialKeyBackup senderGuardianBackup, + ElectionPartialKeyBackupRecord senderGuardianBackup, ElectionPublicKey senderGuardianPublicKey, ElectionKeyPair myKeyPair, string keyCeremonyId) { @@ -69,14 +69,7 @@ private static ElectionPartialKeyVerification VerifyElectionPartialKeyBackup( if (coordinateData is null) { Debug.WriteLine($"VerifyElectionPartialKeyBackup: {receiverGuardianId} -> {senderGuardianBackup.OwnerId} {senderGuardianBackup.DesignatedSequenceOrder} failed to decrypt"); - return new() - { - KeyCeremonyId = keyCeremonyId, - OwnerId = senderGuardianBackup.OwnerId, - DesignatedId = senderGuardianBackup.DesignatedId, - VerifierId = receiverGuardianId, - Verified = false - }; + return new(keyCeremonyId, senderGuardianBackup.OwnerId, senderGuardianBackup.DesignatedId, receiverGuardianId, false); } var verified = ElectionPolynomial.VerifyCoordinate( @@ -85,13 +78,6 @@ private static ElectionPartialKeyVerification VerifyElectionPartialKeyBackup( senderGuardianPublicKey.CoefficientCommitments ); Debug.WriteLine($"VerifyElectionPartialKeyBackup: {receiverGuardianId} -> {senderGuardianBackup.OwnerId} {senderGuardianBackup.DesignatedSequenceOrder} {verified}"); - return new() - { - KeyCeremonyId = keyCeremonyId, - OwnerId = senderGuardianBackup.OwnerId, - DesignatedId = senderGuardianBackup.DesignatedId, - VerifierId = receiverGuardianId, - Verified = verified - }; + return new(keyCeremonyId, senderGuardianBackup.OwnerId, senderGuardianBackup.DesignatedId, receiverGuardianId, verified); } } diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Guardian/GuardianDecryptMethods.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Guardian/GuardianDecryptMethods.cs index 5223b674f..dad8c387e 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Guardian/GuardianDecryptMethods.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Guardian/GuardianDecryptMethods.cs @@ -1,4 +1,4 @@ -using ElectionGuard.UI.Lib.Models; +using ElectionGuard.ElectionSetup.Records; namespace ElectionGuard.ElectionSetup; @@ -66,7 +66,7 @@ private ElementModQ CombinePrivateKeyShares() /// /// Missing guardian's backup /// coordinatedata of the decryption and its proof - private ElementModQ? DecryptBackup(ElectionPartialKeyBackup backup) + private ElementModQ? DecryptBackup(ElectionPartialKeyBackupRecord backup) { return DecryptBackup(backup, _myElectionKeys); } @@ -78,7 +78,7 @@ private ElementModQ CombinePrivateKeyShares() /// The present guardian's key pair that will be used to decrypt the backup /// coordinatedata of the decryption and its proof private static ElementModQ? DecryptBackup( - ElectionPartialKeyBackup guardianBackup, ElectionKeyPair myKeyPair) + ElectionPartialKeyBackupRecord guardianBackup, ElectionKeyPair myKeyPair) { var encryptionSeed = GetBackupSeed( myKeyPair.SequenceOrder, diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/CeremonyDetails.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Records/CeremonyDetails.cs similarity index 74% rename from src/electionguard-ui/ElectionGuard.UI.Lib/Models/CeremonyDetails.cs rename to bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Records/CeremonyDetails.cs index cda277875..a41161fe0 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/CeremonyDetails.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Records/CeremonyDetails.cs @@ -1,4 +1,4 @@ -namespace ElectionGuard.UI.Lib.Models; +namespace ElectionGuard.ElectionSetup.Records; /// /// Details of key ceremony diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Records/ElectionPartialKeyBackup.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Records/ElectionPartialKeyBackup.cs new file mode 100644 index 000000000..c8e58a8a3 --- /dev/null +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Records/ElectionPartialKeyBackup.cs @@ -0,0 +1,46 @@ +namespace ElectionGuard.ElectionSetup.Records; + +/// +/// Election partial key backup used for key sharing +/// +public record ElectionPartialKeyBackupRecord : DisposableRecordBase +{ + // TODO: implement IElectionGuardian + + /// + /// The guardian id of the owner who created this backup + /// + public string OwnerId { get; set; } + + public ulong OwnerSequenceOrder { get; set; } + + /// + /// The guardian id of the designated guardian who should receive this backup + /// + public string DesignatedId { get; set; } + + public ulong DesignatedSequenceOrder { get; set; } + + public HashedElGamalCiphertext EncryptedCoordinate { get; set; } + + public ElectionPartialKeyBackupRecord( + string ownerId, + ulong ownerSequenceOrder, + string designatedId, + ulong designatedSequenceOrder, + HashedElGamalCiphertext encryptedCoordinate) + { + OwnerId = ownerId; + OwnerSequenceOrder = ownerSequenceOrder; + DesignatedId = designatedId; + DesignatedSequenceOrder = designatedSequenceOrder; + EncryptedCoordinate = new(encryptedCoordinate); + } + + + protected override void DisposeUnmanaged() + { + base.DisposeUnmanaged(); + EncryptedCoordinate?.Dispose(); + } +} diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Records/ElectionPartialKeyVerification.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Records/ElectionPartialKeyVerification.cs new file mode 100644 index 000000000..69eea1ed3 --- /dev/null +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Records/ElectionPartialKeyVerification.cs @@ -0,0 +1,6 @@ +namespace ElectionGuard.ElectionSetup.Records; +/// +/// Verification of election partial key used in key sharing +/// +public record ElectionPartialKeyVerificationRecord(string? KeyCeremonyId, string? OwnerId, string? DesignatedId, string? VerifierId, bool Verified); + diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Records/GuardianBackups.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Records/GuardianBackups.cs new file mode 100644 index 000000000..f285053bb --- /dev/null +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Records/GuardianBackups.cs @@ -0,0 +1,30 @@ +namespace ElectionGuard.ElectionSetup.Records; + +public record GuardianBackupsRecord : DisposableRecordBase +{ + public string? KeyCeremonyId { get; set; } + + public string? GuardianId { get; set; } + + public string? DesignatedId { get; set; } + + public ElectionPartialKeyBackupRecord? Backup { get; set; } + + public GuardianBackupsRecord( + string keyCeremonyId, + string guardianId, + string designatedId, + ElectionPartialKeyBackupRecord backup) + { + KeyCeremonyId = keyCeremonyId; + GuardianId = guardianId; + DesignatedId = designatedId; + Backup = new(backup.OwnerId, backup.OwnerSequenceOrder, backup.DesignatedId, backup.DesignatedSequenceOrder, backup.EncryptedCoordinate); + } + protected override void DisposeUnmanaged() + { + base.DisposeUnmanaged(); + Backup?.Dispose(); + } + +} diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Guardian/GuardianPair.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Records/GuardianPair.cs similarity index 57% rename from bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Guardian/GuardianPair.cs rename to bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Records/GuardianPair.cs index 8933066e8..a4faec515 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Guardian/GuardianPair.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Records/GuardianPair.cs @@ -1,4 +1,4 @@ -namespace ElectionGuard.ElectionSetup; - -public record GuardianPair(string OwnerId, string DesignatedId); - +namespace ElectionGuard.ElectionSetup.Records; + +public record GuardianPair(string OwnerId, string DesignatedId); + diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Guardian/GuardianPrivateRecord.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Records/GuardianPrivateRecord.cs similarity index 94% rename from bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Guardian/GuardianPrivateRecord.cs rename to bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Records/GuardianPrivateRecord.cs index ada8f84ab..1a7e7e392 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Guardian/GuardianPrivateRecord.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Records/GuardianPrivateRecord.cs @@ -1,4 +1,4 @@ -namespace ElectionGuard.ElectionSetup; +namespace ElectionGuard.ElectionSetup.Records; /// /// A guardian is a person or entity that is responsible for decrypting a share of the election record. diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/StateMachineStep.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/StateMachineStep.cs index 3611a0487..aa6dfa86d 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/StateMachineStep.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/StateMachineStep.cs @@ -1,6 +1,4 @@ -using ElectionGuard.UI.Lib.Models; - -namespace ElectionGuard.ElectionSetup; +namespace ElectionGuard.ElectionSetup; /// /// Data structure for keeping track of the steps needed for admin/guardians diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption.Tests/ElectionGuard.Encryption.Tests.csproj b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption.Tests/ElectionGuard.Encryption.Tests.csproj index 2e341deb9..b84c48df2 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption.Tests/ElectionGuard.Encryption.Tests.csproj +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption.Tests/ElectionGuard.Encryption.Tests.csproj @@ -1,67 +1,67 @@ - - - - netstandard2.0;net7.0 - false - true - true - arm64;x64;x86 - - - - - - - NU1701 - - - - - - - - - - full - true - 1701;1702 - 4 - SYSLIB0004 - - - - pdbonly - 1701;1702 - 4 - SYSLIB0004 - - - - - ..\..\..\..\data - ..\..\..\..\build\libs - - - - PreserveNewest - - - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - - - - - - - - + + + + netstandard2.0;net7.0 + false + true + true + arm64;x64;x86 + + + + + + + NU1701 + + + + + + + + + + full + true + 1701;1702 + 4 + SYSLIB0004 + + + + pdbonly + 1701;1702 + 4 + SYSLIB0004 + + + + + ..\..\..\..\data + ..\..\..\..\build\libs + + + + PreserveNewest + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + + + + + + + diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption.Tests/TestPrecompute.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption.Tests/TestPrecompute.cs index ba35dcc43..eb121388a 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption.Tests/TestPrecompute.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption.Tests/TestPrecompute.cs @@ -1,91 +1,91 @@ -using System; -using System.Diagnostics; -using System.Threading; -using System.Threading.Tasks; -using NUnit.Framework; - -namespace ElectionGuard.Encryption.Tests -{ - [NonParallelizable] - [TestFixture] - public class TestPrecompute - { - private const int MaxCompleteDelay = 30000; - private const int TestBufferSize = 500; - private const int TestRunLengthInS = 10; - - private PrecomputeBufferContext _precompute; - private AutoResetEvent _waitHandle; - - [OneTimeSetUp] - public void OneTimeSetup() - { - _waitHandle = new AutoResetEvent(false); - - var keyPair = ElGamalKeyPair.FromSecret(Constants.TWO_MOD_Q); - _precompute = new PrecomputeBufferContext(keyPair.PublicKey, TestBufferSize); - _precompute.CompletedEvent += status => - { - _ = _waitHandle.Set(); - }; - } - - [Test, Order(1)] - public void Test_Precompute_Buffer_Size() - { - var status = _precompute.GetStatus(); - Assert.AreEqual(TestBufferSize, status.MaxQueueSize); - } - - [Test, Order(2)] - public void Test_Precompute_Status_NoStarted() - { - var status = _precompute.GetStatus(); - Assert.AreEqual(PrecomputeState.NotStarted, status.CurrentState); - } - - [Test, Order(3)] - public async Task Test_Precompute_Status_Running() - { - _precompute.StartPrecomputeAsync(); - var runningStatus = _precompute.GetStatus(); - - await TestHelpers.RunForAsync(TimeSpan.FromSeconds(1)); - - _precompute.StopPrecompute(); - - var status = _precompute.GetStatus(); - - Console.WriteLine($"Running: {status.CurrentQueueSize}"); - - Assert.That(status.CurrentQueueSize, Is.GreaterThan(0)); - Assert.AreEqual(PrecomputeState.Running, runningStatus.CurrentState); - } - - [Test, Order(4)] - public async Task Test_Precompute_Status_Complete() - { - _precompute.StartPrecomputeAsync(); - - await TestHelpers.RunForAsync(TimeSpan.FromSeconds(TestRunLengthInS)); - - var waitReturn = _waitHandle.WaitOne(); - - var status = _precompute.GetStatus(); - - Assert.That(status.CurrentQueueSize, Is.GreaterThanOrEqualTo(TestBufferSize)); - Assert.That(status.Progress, Is.GreaterThanOrEqualTo(1.0)); - Assert.AreEqual(PrecomputeState.Completed, status.CurrentState); - Assert.AreEqual(true, waitReturn); - } - - [Test, Order(5)] - public void Test_Precompute_Using_Old_Interface() - { - var compute = new Precompute(); - compute.StartPrecomputeAsync(_precompute.PublicKey, TestBufferSize); - TestHelpers.RunFor(TimeSpan.FromSeconds(TestRunLengthInS)); - compute.StopPrecompute(); - } - } -} +using System; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using NUnit.Framework; + +namespace ElectionGuard.Encryption.Tests +{ + [NonParallelizable] + [TestFixture] + public class TestPrecompute + { + private const int MaxCompleteDelay = 30000; + private const int TestBufferSize = 500; + private const int TestRunLengthInS = 10; + + private PrecomputeBufferContext _precompute; + private AutoResetEvent _waitHandle; + + [OneTimeSetUp] + public void OneTimeSetup() + { + _waitHandle = new AutoResetEvent(false); + + var keyPair = ElGamalKeyPair.FromSecret(Constants.TWO_MOD_Q); + _precompute = new PrecomputeBufferContext(keyPair.PublicKey, TestBufferSize); + _precompute.CompletedEvent += status => + { + _ = _waitHandle.Set(); + }; + } + + [Test, Order(1)] + public void Test_Precompute_Buffer_Size() + { + var status = _precompute.GetStatus(); + Assert.AreEqual(TestBufferSize, status.MaxQueueSize); + } + + [Test, Order(2)] + public void Test_Precompute_Status_NoStarted() + { + var status = _precompute.GetStatus(); + Assert.AreEqual(PrecomputeState.NotStarted, status.CurrentState); + } + + [Test, Order(3)] + public async Task Test_Precompute_Status_Running() + { + _precompute.StartPrecomputeAsync(); + var runningStatus = _precompute.GetStatus(); + + await TestHelpers.RunForAsync(TimeSpan.FromSeconds(1)); + + _precompute.StopPrecompute(); + + var status = _precompute.GetStatus(); + + Console.WriteLine($"Running: {status.CurrentQueueSize}"); + + Assert.That(status.CurrentQueueSize, Is.GreaterThan(0)); + Assert.AreEqual(PrecomputeState.Running, runningStatus.CurrentState); + } + + [Test, Order(4)] + public async Task Test_Precompute_Status_Complete() + { + _precompute.StartPrecomputeAsync(); + + await TestHelpers.RunForAsync(TimeSpan.FromSeconds(TestRunLengthInS)); + + var waitReturn = _waitHandle.WaitOne(); + + var status = _precompute.GetStatus(); + + Assert.That(status.CurrentQueueSize, Is.GreaterThanOrEqualTo(TestBufferSize)); + Assert.That(status.Progress, Is.GreaterThanOrEqualTo(1.0)); + Assert.AreEqual(PrecomputeState.Completed, status.CurrentState); + Assert.AreEqual(true, waitReturn); + } + + [Test, Order(5)] + public void Test_Precompute_Using_Old_Interface() + { + var compute = new Precompute(); + compute.StartPrecomputeAsync(_precompute.PublicKey, TestBufferSize); + TestHelpers.RunFor(TimeSpan.FromSeconds(TestRunLengthInS)); + compute.StopPrecompute(); + } + } +} diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Base/IntPtr.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Base/IntPtr.cs index 82db36c31..0947e7fdc 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Base/IntPtr.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Base/IntPtr.cs @@ -1,52 +1,52 @@ -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; - -namespace ElectionGuard -{ - /// - /// Extension class to add functionality to the IntPtr class in .NET - /// - public static class IntPtrExtension - { - /// - /// Creates a new IntPtr that is offset from the original - /// - /// original IntPtr - /// Amount to shift by - /// New IntPtr to the new address - public static IntPtr Offset(this IntPtr ptr, long that) - { - return new IntPtr(ptr.ToInt64() + that); - } - - /// - /// Converts the data at the IntPtr to a c# string class - /// - /// IntPtr to convert - /// string found at the IntPtr - public static string PtrToStringUTF8(this IntPtr rawPtr) - { - if (rawPtr == IntPtr.Zero) - { - return null; - } - - var bytes = new List(); - while (true) - { - var b = Marshal.ReadByte(rawPtr); - if (b == 0) - { - break; - } - - bytes.Add(b); - rawPtr = rawPtr.Offset(1); - } - - return System.Text.Encoding.UTF8.GetString(bytes.ToArray()); - } - - } -} +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace ElectionGuard +{ + /// + /// Extension class to add functionality to the IntPtr class in .NET + /// + public static class IntPtrExtension + { + /// + /// Creates a new IntPtr that is offset from the original + /// + /// original IntPtr + /// Amount to shift by + /// New IntPtr to the new address + public static IntPtr Offset(this IntPtr ptr, long that) + { + return new IntPtr(ptr.ToInt64() + that); + } + + /// + /// Converts the data at the IntPtr to a c# string class + /// + /// IntPtr to convert + /// string found at the IntPtr + public static string PtrToStringUTF8(this IntPtr rawPtr) + { + if (rawPtr == IntPtr.Zero) + { + return null; + } + + var bytes = new List(); + while (true) + { + var b = Marshal.ReadByte(rawPtr); + if (b == 0) + { + break; + } + + bytes.Add(b); + rawPtr = rawPtr.Offset(1); + } + + return System.Text.Encoding.UTF8.GetString(bytes.ToArray()); + } + + } +} diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/ContestDescriptionWithPlaceholders.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/ContestDescriptionWithPlaceholders.cs index 782463bb3..b548c02fe 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/ContestDescriptionWithPlaceholders.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/ContestDescriptionWithPlaceholders.cs @@ -2,9 +2,9 @@ using System.Collections.Generic; using System.Runtime.InteropServices; using ElectionGuard.Ballot; -using ElectionGuard.Extensions; -using Newtonsoft.Json; - +using ElectionGuard.Extensions; +using Newtonsoft.Json; + namespace ElectionGuard { /// @@ -270,14 +270,14 @@ public ContestDescriptionWithPlaceholders( Dictionary selections, Dictionary placeholders) { var selectionPointers = new IntPtr[selections.Values.Count]; - foreach (var (selection, index) in selections.Values.WithIndex()) - { + foreach (var (selection, index) in selections.Values.WithIndex()) + { selectionPointers[index] = selection.Handle.Ptr; selection.Dispose(); } var placeholderPointers = new IntPtr[placeholders.Values.Count]; - foreach (var (placeholder, index) in placeholders.Values.WithIndex()) + foreach (var (placeholder, index) in placeholders.Values.WithIndex()) { placeholderPointers[index] = placeholder.Handle.Ptr; placeholder.Dispose(); diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/ElectionGuard.Encryption.csproj b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/ElectionGuard.Encryption.csproj index c0f57634f..4e8f56d73 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/ElectionGuard.Encryption.csproj +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/ElectionGuard.Encryption.csproj @@ -1,173 +1,173 @@ - - - - netstandard2.0;net7.0 - - ElectionGuard - ElectionGuard.Encryption - 1.75.17 - 1.75.17.0 - 1.75.17.0 - true - true - arm64;x64;x86 - - - - ElectionGuard.Encryption - ElectionGuard Encryption - Open source implementation of ElectionGuard's ballot encryption. - Microsoft - 1.75.17 - MIT - https://github.com/microsoft/electionguard-core2 - https://github.com/microsoft/electionguard-core2 - Microsoft;Electionguard;Encryption;Windows;MacOS;Linux - README.md - icon.png - PackageReference - true - - - arm64;x64;x86 - - - ElectionGuard - true - - - full - true - 1701;1702 - 4 - SYSLIB0004 - - - pdbonly - true - - 1701;1702 - 4 - SYSLIB0004 - - - ..\..\..\..\build\libs - - - - true - true - runtimes\win-arm64\native - - - true - true - runtimes\win-arm64\native - - - true - true - runtimes\win-x86\native - - - true - true - runtimes\win-x86\native - - - true - true - runtimes\win-x86\native - - - true - true - runtimes\win-x86\native - - - true - true - runtimes\win-x64\native - - - true - true - runtimes\win-x64\native - - - true - true - runtimes\osx-arm64\native - - - true - true - runtimes\osx-arm64\native - - - true - true - runtimes\osx-x64\native - - - true - true - runtimes\osx-x64\native - - - true - true - runtimes\maccatalyst-arm64\native - - - true - true - runtimes\maccatalyst-arm64\native - - - true - true - runtimes\maccatalyst-x64\native - - - true - true - runtimes\maccatalyst-x64\native - - - true - true - runtimes\linux-arm64\native - - - true - true - runtimes\linux-arm64\native - - - true - true - runtimes\linux-x64\native - - - true - true - runtimes\linux-x64\native - - - build\ - true - - - - - - - - - - - - - + + + + netstandard2.0;net9.0 + + ElectionGuard + ElectionGuard.Encryption + 1.75.17 + 1.75.17.0 + 1.75.17.0 + true + true + x64;x86 + + + + Enhanced.ElectionGuard.Encryption + Enhanced ElectionGuard Encryption + Private fork of open source implementation of ElectionGuard's ballot encryption. + Enhanced Voting + 1.75.17 + MIT + https://github.com/Enhanced-Voting/electionguard + https://github.com/Enhanced-Voting/electionguard + Enhanced;Electionguard;Encryption;Windows;Linux + README.md + icon.png + PackageReference + true + + + x64;x86 + + + ElectionGuard + true + + + full + true + 1701;1702 + 4 + SYSLIB0004 + + + pdbonly + true + + 1701;1702 + 4 + SYSLIB0004 + + + ..\..\..\..\build\libs + + + + true + true + runtimes\win-arm64\native + + + true + true + runtimes\win-arm64\native + + + true + true + runtimes\win-x86\native + + + true + true + runtimes\win-x86\native + + + true + true + runtimes\win-x86\native + + + true + true + runtimes\win-x86\native + + + true + true + runtimes\win-x64\native + + + true + true + runtimes\win-x64\native + + + true + true + runtimes\osx-arm64\native + + + true + true + runtimes\osx-arm64\native + + + true + true + runtimes\osx-x64\native + + + true + true + runtimes\osx-x64\native + + + true + true + runtimes\maccatalyst-arm64\native + + + true + true + runtimes\maccatalyst-arm64\native + + + true + true + runtimes\maccatalyst-x64\native + + + true + true + runtimes\maccatalyst-x64\native + + + true + true + runtimes\linux-arm64\native + + + true + true + runtimes\linux-arm64\native + + + true + true + runtimes\linux-x64\native + + + true + true + runtimes\linux-x64\native + + + build\ + true + + + + + + + + + + + + + \ No newline at end of file diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/ElectionGuardException.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/ElectionGuardException.cs index d3d77f7f7..5a4e01dd7 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/ElectionGuardException.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/ElectionGuardException.cs @@ -1,7 +1,7 @@ using System; -using System.Diagnostics.CodeAnalysis; -// ReSharper disable UnusedAutoPropertyAccessor.Global - +using System.Diagnostics.CodeAnalysis; +// ReSharper disable UnusedAutoPropertyAccessor.Global + namespace ElectionGuard { /// @@ -43,22 +43,22 @@ public ElectionGuardException(string message, Status code) : base(message) /// message to be used in the exception handling /// exception to wrap inside the ElectionGuardException /// New ElectionGuardException object - public ElectionGuardException(string message, Exception inner) : base(message, inner) { } - - - /// - /// Throws an if is null containing - /// -#if NETSTANDARD2_0 + public ElectionGuardException(string message, Exception inner) : base(message, inner) { } + + + /// + /// Throws an if is null containing + /// +#if NETSTANDARD2_0 public static void ThrowIfNull(object argument, string message = null) -#else - public static void ThrowIfNull([NotNull] object argument, string message = null) +#else + public static void ThrowIfNull([NotNull] object argument, string message = null) #endif - { - if (argument == null) - { - throw new ElectionGuardException(message ?? "Data is null"); - } + { + if (argument == null) + { + throw new ElectionGuardException(message ?? "Data is null"); + } } } diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/ElectionJointKey.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/ElectionJointKey.cs index 39ca04cf1..5681ed560 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/ElectionJointKey.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/ElectionJointKey.cs @@ -1,47 +1,47 @@ -namespace ElectionGuard -{ - /// - /// The Election joint key - /// - public class ElectionJointKey : DisposableBase - { - /// - /// The product of the guardian public keys - /// K = ∏ ni=1 Ki mod p. - /// - public ElementModP JointPublicKey { get; set; } - - /// - /// The hash of the commitments that the guardians make to each other - /// H = H(K 1,0 , K 2,0 ... , K n,0 ) - /// - public ElementModQ CommitmentHash { get; set; } - - - public ElectionJointKey() - { - - } - - public ElectionJointKey( - ElementModP jointPublicKey, ElementModQ commitmentHash) - { - JointPublicKey = new ElementModP(jointPublicKey); - CommitmentHash = new ElementModQ(commitmentHash); - } - - public ElectionJointKey(ElectionJointKey other) - { - JointPublicKey = new ElementModP(other.JointPublicKey); - CommitmentHash = new ElementModQ(other.CommitmentHash); - } - - protected override void DisposeUnmanaged() - { - base.DisposeUnmanaged(); - - JointPublicKey?.Dispose(); - CommitmentHash?.Dispose(); - } - } -} +namespace ElectionGuard +{ + /// + /// The Election joint key + /// + public class ElectionJointKey : DisposableBase + { + /// + /// The product of the guardian public keys + /// K = ∏ ni=1 Ki mod p. + /// + public ElementModP JointPublicKey { get; set; } + + /// + /// The hash of the commitments that the guardians make to each other + /// H = H(K 1,0 , K 2,0 ... , K n,0 ) + /// + public ElementModQ CommitmentHash { get; set; } + + + public ElectionJointKey() + { + + } + + public ElectionJointKey( + ElementModP jointPublicKey, ElementModQ commitmentHash) + { + JointPublicKey = new ElementModP(jointPublicKey); + CommitmentHash = new ElementModQ(commitmentHash); + } + + public ElectionJointKey(ElectionJointKey other) + { + JointPublicKey = new ElementModP(other.JointPublicKey); + CommitmentHash = new ElementModQ(other.CommitmentHash); + } + + protected override void DisposeUnmanaged() + { + base.DisposeUnmanaged(); + + JointPublicKey?.Dispose(); + CommitmentHash?.Dispose(); + } + } +} diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Encrypt.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Encrypt.cs index c8b980305..7610d31f1 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Encrypt.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Encrypt.cs @@ -1,206 +1,206 @@ -namespace ElectionGuard -{ - /// - /// Metadata for encryption - /// - /// The encrypt object is used for encrypting ballots. - /// - /// - public class Encrypt - { - /// - /// Encrypt a specific `BallotSelection` in the context of a specific `BallotContest` - /// - /// the selection in the valid input form - /// the `SelectionDescription` from the `ContestDescription` - /// which defines this selection's structure - /// the public key (K) used to encrypt the ballot - /// the extended base hash of the election - /// an `ElementModQ` used as a header to seed the `Nonce` generated - /// for this selection. this value can be (or derived from) the - /// Contest nonce, but no relationship is required - /// specify if precomputed values should be used - /// specify if the proofs should be verified using precomputed values (default False) - /// A `CiphertextBallotSelection` - public static CiphertextBallotSelection Selection( - PlaintextBallotSelection plaintext, - SelectionDescription description, - ElementModP elgamalPublicKey, - ElementModQ cryptoExtendedBaseHash, - ElementModQ nonceSeed, - bool shouldVerifyProofs = true, - bool usePrecomputedValues = false - ) - { - var status = NativeInterface.Encrypt.Selection( - plaintext.Handle, description.Handle, elgamalPublicKey.Handle, - cryptoExtendedBaseHash.Handle, nonceSeed.Handle, shouldVerifyProofs, - usePrecomputedValues, - out var ciphertext); - status.ThrowIfError(); - return ciphertext.IsInvalid ? null : new CiphertextBallotSelection(ciphertext); - } - - /// - /// Encrypt a specific `BallotContest` in the context of a specific `Ballot` - /// - /// This method accepts a contest representation that only includes `True` selections. - /// It will fill missing selections for a contest with `False` values, and generate `placeholder` - /// selections to represent the number of seats available for a given contest. By adding `placeholder` - /// votes - /// - /// the selection in the valid input form - /// the `ContestDescriptionWithPlaceholders` from the `ContestDescription` - /// which defines this contest's structure - /// the public key (K) used to encrypt the ballot - /// the extended base hash of the election - /// an `ElementModQ` used as a header to seed the `Nonce` generated - /// for this contest. this value can be (or derived from) the - /// Ballot nonce, but no relationship is required - /// specify if the proofs should be verified prior to returning (default True) - /// specify if the precompute values should be used - /// A `CiphertextBallotContest` - public static CiphertextBallotContest Contest( - PlaintextBallotContest plaintext, - ContestDescription description, - ElementModP elgamalPublicKey, - ElementModQ cryptoExtendedBaseHash, - ElementModQ nonceSeed, - bool shouldVerifyProofs = true, - bool usePrecomputedValues = false - ) - { - var status = NativeInterface.Encrypt.Contest( - plaintext.Handle, - description.Handle, - elgamalPublicKey.Handle, - cryptoExtendedBaseHash.Handle, - nonceSeed.Handle, - shouldVerifyProofs, - usePrecomputedValues, - out var ciphertext); - - status.ThrowIfError(); - return ciphertext.IsInvalid ? null : new CiphertextBallotContest(ciphertext); - } - - /// - /// Encrypt a specific `Ballot` in the context of a specific `CiphertextElectionContext` - /// - /// This method accepts a ballot representation that only includes `True` selections. - /// It will fill missing selections for a contest with `False` values, and generate `placeholder` - /// selections to represent the number of seats available for a given contest. By adding `placeholder` - /// votes - /// - /// This method also allows for ballots to exclude passing contests for which the voter made no selections. - /// It will fill missing contests with `False` selections and generate `placeholder` selections that are marked `True`. - /// This function can also take advantage of PrecomputeBuffers to speed up the encryption process. - /// when using precomputed values, the application looks in the `PrecomputeBufferContext` for values - /// and uses them for the encryptions. You must preload the `PrecomputeBufferContext` prior to calling this function - /// with `shouldUsePrecomputedValues` set to `true`, otherwise the function will fall back to realtime generation. - /// - /// Because PrecomputeBuffers require a random nonce, calling this function with `shouldUsePrecomputedValues` - /// set to `true` while also providing a nonce will result in an error. - /// - /// the selection in the valid input form - /// the `InternalManifest` which defines this ballot's structure - /// all the cryptographic context for the election - /// Hash from previous ballot or hash from device - /// an optional value used to seed the `Nonce` generated for this ballot - /// if this value is not provided, the secret generating mechanism of the OS provides its own - /// timestamp to use - /// specify if the proofs should be verified prior to returning (default True) - /// specify if precomputed values should be used (default True) - /// A `CiphertextBallot` - public static CiphertextBallot Ballot( - PlaintextBallot ballot, - InternalManifest internalManifest, - CiphertextElectionContext context, - ElementModQ ballotCodeSeed, - ElementModQ nonce = null, - ulong timestamp = 0, - bool shouldVerifyProofs = true, - bool usePrecomputedValues = false) - { - if (nonce == null) - { - var status = NativeInterface.Encrypt.Ballot( - ballot.Handle, - internalManifest.Handle, - context.Handle, - ballotCodeSeed.Handle, - shouldVerifyProofs, - usePrecomputedValues, - out var ciphertext); - status.ThrowIfError(); - return ciphertext.IsInvalid ? null : new CiphertextBallot(ciphertext); - } - else - { - var status = NativeInterface.Encrypt.Ballot( - ballot.Handle, - internalManifest.Handle, - context.Handle, - ballotCodeSeed.Handle, - nonce.Handle, - timestamp, - shouldVerifyProofs, - out var ciphertext); - status.ThrowIfError(); - return ciphertext.IsInvalid ? null : new CiphertextBallot(ciphertext); - } - } - - /// - /// Encrypt a specific `Ballot` in the context of a specific `CiphertextElectionContext` - /// - /// This method accepts a ballot representation that only includes `True` selections. - /// It will fill missing selections for a contest with `False` values, and generate `placeholder` - /// selections to represent the number of seats available for a given contest. By adding `placeholder` - /// votes - /// - /// This method also allows for ballots to exclude passing contests for which the voter made no selections. - /// It will fill missing contests with `False` selections and generate `placeholder` selections that are marked `True`. - /// - /// This version of the encrypt method returns a `compact` version of the ballot that includes a minimal representation - /// of the plaintext ballot along with the crypto parameters that are required to expand the ballot - /// - /// the selection in the valid input form - /// the `InternalManifest` which defines this ballot's structure - /// all the cryptographic context for the election - /// Hash from previous ballot or hash from device - /// an optional value used to seed the `Nonce` generated for this ballot - /// if this value is not provided, the secret generating mechanism of the OS provides its own - /// timestamp to use - /// specify if the proofs should be verified prior to returning (default True) - /// A `CiphertextBallot` - public static CompactCiphertextBallot CompactBallot( - PlaintextBallot ballot, - InternalManifest internalManifest, - CiphertextElectionContext context, - ElementModQ ballotCodeSeed, - ElementModQ nonce = null, - ulong timestamp = 0, - bool shouldVerifyProofs = true) - { - if (nonce == null) - { - var status = NativeInterface.Encrypt.CompactBallot( - ballot.Handle, internalManifest.Handle, context.Handle, - ballotCodeSeed.Handle, shouldVerifyProofs, - out var ciphertext); - status.ThrowIfError(); - return ciphertext.IsInvalid ? null : new CompactCiphertextBallot(ciphertext); - } - else - { - var status = NativeInterface.Encrypt.CompactBallot( - ballot.Handle, internalManifest.Handle, context.Handle, - ballotCodeSeed.Handle, nonce.Handle, timestamp, shouldVerifyProofs, - out var ciphertext); - status.ThrowIfError(); - return ciphertext.IsInvalid ? null : new CompactCiphertextBallot(ciphertext); - } - } - } -} +namespace ElectionGuard +{ + /// + /// Metadata for encryption + /// + /// The encrypt object is used for encrypting ballots. + /// + /// + public class Encrypt + { + /// + /// Encrypt a specific `BallotSelection` in the context of a specific `BallotContest` + /// + /// the selection in the valid input form + /// the `SelectionDescription` from the `ContestDescription` + /// which defines this selection's structure + /// the public key (K) used to encrypt the ballot + /// the extended base hash of the election + /// an `ElementModQ` used as a header to seed the `Nonce` generated + /// for this selection. this value can be (or derived from) the + /// Contest nonce, but no relationship is required + /// specify if precomputed values should be used + /// specify if the proofs should be verified using precomputed values (default False) + /// A `CiphertextBallotSelection` + public static CiphertextBallotSelection Selection( + PlaintextBallotSelection plaintext, + SelectionDescription description, + ElementModP elgamalPublicKey, + ElementModQ cryptoExtendedBaseHash, + ElementModQ nonceSeed, + bool shouldVerifyProofs = true, + bool usePrecomputedValues = false + ) + { + var status = NativeInterface.Encrypt.Selection( + plaintext.Handle, description.Handle, elgamalPublicKey.Handle, + cryptoExtendedBaseHash.Handle, nonceSeed.Handle, shouldVerifyProofs, + usePrecomputedValues, + out var ciphertext); + status.ThrowIfError(); + return ciphertext.IsInvalid ? null : new CiphertextBallotSelection(ciphertext); + } + + /// + /// Encrypt a specific `BallotContest` in the context of a specific `Ballot` + /// + /// This method accepts a contest representation that only includes `True` selections. + /// It will fill missing selections for a contest with `False` values, and generate `placeholder` + /// selections to represent the number of seats available for a given contest. By adding `placeholder` + /// votes + /// + /// the selection in the valid input form + /// the `ContestDescriptionWithPlaceholders` from the `ContestDescription` + /// which defines this contest's structure + /// the public key (K) used to encrypt the ballot + /// the extended base hash of the election + /// an `ElementModQ` used as a header to seed the `Nonce` generated + /// for this contest. this value can be (or derived from) the + /// Ballot nonce, but no relationship is required + /// specify if the proofs should be verified prior to returning (default True) + /// specify if the precompute values should be used + /// A `CiphertextBallotContest` + public static CiphertextBallotContest Contest( + PlaintextBallotContest plaintext, + ContestDescription description, + ElementModP elgamalPublicKey, + ElementModQ cryptoExtendedBaseHash, + ElementModQ nonceSeed, + bool shouldVerifyProofs = true, + bool usePrecomputedValues = false + ) + { + var status = NativeInterface.Encrypt.Contest( + plaintext.Handle, + description.Handle, + elgamalPublicKey.Handle, + cryptoExtendedBaseHash.Handle, + nonceSeed.Handle, + shouldVerifyProofs, + usePrecomputedValues, + out var ciphertext); + + status.ThrowIfError(); + return ciphertext.IsInvalid ? null : new CiphertextBallotContest(ciphertext); + } + + /// + /// Encrypt a specific `Ballot` in the context of a specific `CiphertextElectionContext` + /// + /// This method accepts a ballot representation that only includes `True` selections. + /// It will fill missing selections for a contest with `False` values, and generate `placeholder` + /// selections to represent the number of seats available for a given contest. By adding `placeholder` + /// votes + /// + /// This method also allows for ballots to exclude passing contests for which the voter made no selections. + /// It will fill missing contests with `False` selections and generate `placeholder` selections that are marked `True`. + /// This function can also take advantage of PrecomputeBuffers to speed up the encryption process. + /// when using precomputed values, the application looks in the `PrecomputeBufferContext` for values + /// and uses them for the encryptions. You must preload the `PrecomputeBufferContext` prior to calling this function + /// with `shouldUsePrecomputedValues` set to `true`, otherwise the function will fall back to realtime generation. + /// + /// Because PrecomputeBuffers require a random nonce, calling this function with `shouldUsePrecomputedValues` + /// set to `true` while also providing a nonce will result in an error. + /// + /// the selection in the valid input form + /// the `InternalManifest` which defines this ballot's structure + /// all the cryptographic context for the election + /// Hash from previous ballot or hash from device + /// an optional value used to seed the `Nonce` generated for this ballot + /// if this value is not provided, the secret generating mechanism of the OS provides its own + /// timestamp to use + /// specify if the proofs should be verified prior to returning (default True) + /// specify if precomputed values should be used (default True) + /// A `CiphertextBallot` + public static CiphertextBallot Ballot( + PlaintextBallot ballot, + InternalManifest internalManifest, + CiphertextElectionContext context, + ElementModQ ballotCodeSeed, + ElementModQ nonce = null, + ulong timestamp = 0, + bool shouldVerifyProofs = true, + bool usePrecomputedValues = false) + { + if (nonce == null) + { + var status = NativeInterface.Encrypt.Ballot( + ballot.Handle, + internalManifest.Handle, + context.Handle, + ballotCodeSeed.Handle, + shouldVerifyProofs, + usePrecomputedValues, + out var ciphertext); + status.ThrowIfError(); + return ciphertext.IsInvalid ? null : new CiphertextBallot(ciphertext); + } + else + { + var status = NativeInterface.Encrypt.Ballot( + ballot.Handle, + internalManifest.Handle, + context.Handle, + ballotCodeSeed.Handle, + nonce.Handle, + timestamp, + shouldVerifyProofs, + out var ciphertext); + status.ThrowIfError(); + return ciphertext.IsInvalid ? null : new CiphertextBallot(ciphertext); + } + } + + /// + /// Encrypt a specific `Ballot` in the context of a specific `CiphertextElectionContext` + /// + /// This method accepts a ballot representation that only includes `True` selections. + /// It will fill missing selections for a contest with `False` values, and generate `placeholder` + /// selections to represent the number of seats available for a given contest. By adding `placeholder` + /// votes + /// + /// This method also allows for ballots to exclude passing contests for which the voter made no selections. + /// It will fill missing contests with `False` selections and generate `placeholder` selections that are marked `True`. + /// + /// This version of the encrypt method returns a `compact` version of the ballot that includes a minimal representation + /// of the plaintext ballot along with the crypto parameters that are required to expand the ballot + /// + /// the selection in the valid input form + /// the `InternalManifest` which defines this ballot's structure + /// all the cryptographic context for the election + /// Hash from previous ballot or hash from device + /// an optional value used to seed the `Nonce` generated for this ballot + /// if this value is not provided, the secret generating mechanism of the OS provides its own + /// timestamp to use + /// specify if the proofs should be verified prior to returning (default True) + /// A `CiphertextBallot` + public static CompactCiphertextBallot CompactBallot( + PlaintextBallot ballot, + InternalManifest internalManifest, + CiphertextElectionContext context, + ElementModQ ballotCodeSeed, + ElementModQ nonce = null, + ulong timestamp = 0, + bool shouldVerifyProofs = true) + { + if (nonce == null) + { + var status = NativeInterface.Encrypt.CompactBallot( + ballot.Handle, internalManifest.Handle, context.Handle, + ballotCodeSeed.Handle, shouldVerifyProofs, + out var ciphertext); + status.ThrowIfError(); + return ciphertext.IsInvalid ? null : new CompactCiphertextBallot(ciphertext); + } + else + { + var status = NativeInterface.Encrypt.CompactBallot( + ballot.Handle, internalManifest.Handle, context.Handle, + ballotCodeSeed.Handle, nonce.Handle, timestamp, shouldVerifyProofs, + out var ciphertext); + status.ThrowIfError(); + return ciphertext.IsInvalid ? null : new CompactCiphertextBallot(ciphertext); + } + } + } +} diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/ExceptionHandler.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/ExceptionHandler.cs index daf414bf2..b2b7cf760 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/ExceptionHandler.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/ExceptionHandler.cs @@ -1,16 +1,16 @@ -namespace ElectionGuard -{ - public static class ExceptionHandler - { - public static void GetData(out string function, out string message, out ulong code) - { - var status = NativeInterface.ExceptionHandler.GetData(out var functionData, out var messageData, out var codeData); - function = functionData.PtrToStringUTF8(); - message = messageData.PtrToStringUTF8(); - code = codeData; - _ = NativeInterface.Memory.FreeIntPtr(functionData); - _ = NativeInterface.Memory.FreeIntPtr(messageData); - } - - } -} +namespace ElectionGuard +{ + public static class ExceptionHandler + { + public static void GetData(out string function, out string message, out ulong code) + { + var status = NativeInterface.ExceptionHandler.GetData(out var functionData, out var messageData, out var codeData); + function = functionData.PtrToStringUTF8(); + message = messageData.PtrToStringUTF8(); + code = codeData; + _ = NativeInterface.Memory.FreeIntPtr(functionData); + _ = NativeInterface.Memory.FreeIntPtr(messageData); + } + + } +} diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Hash.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Hash.cs index a34a9e6fb..613c0815a 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Hash.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Hash.cs @@ -1,687 +1,687 @@ -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; -using ElectionGuard.Base; - -namespace ElectionGuard -{ - - /// - /// Class for wrapping hashing methods - /// - public static class Hash - { - /// - /// HP = H(HV ;00,p,q,g). Parameter Hash 3.1.2 - /// - public static string Prefix_ParameterHash - { - get - { - var ptr = External.GetPrefix_ParameterHash(); - return Marshal.PtrToStringAnsi(ptr); - } - } - - /// - /// HM = H(HP;01,manifest). Manifest Hash 3.1.4 - /// - public static string Prefix_ManifestHash - { - get - { - var ptr = External.GetPrefix_ManifestHash(); - return Marshal.PtrToStringAnsi(ptr); - } - } - - /// - /// HB = (HP;02,n,k,date,info,HM). Election Base Hash 3.1.5 - /// - public static string Prefix_BaseHash - { - get - { - var ptr = External.GetPrefix_BaseHash(); - return Marshal.PtrToStringAnsi(ptr); - } - } - - /// - /// H = (HP ; 10, i, j, Ki,j , hi,j ). Guardin Share proof challenge 3.2.2 - /// - public static string Prefix_GuardianShareChallenge - { - get - { - var ptr = External.GetPrefix_GuardianShareChallenge(); - return Marshal.PtrToStringAnsi(ptr); - } - } - - /// - /// ki,l = H(HP;11,i,l,Kl,αi,l,βi,l). (14) Guardain Share Encryption Secret Key 3.2.2 - /// - public static string Prefix_GuardianShareSecret - { - get - { - var ptr = External.GetPrefix_GuardianShareSecret(); - return Marshal.PtrToStringAnsi(ptr); - } - } - - /// - /// HE = H(HB;12,K,K1,0,K1,1,...,K1,k−1,K2,0,...,Kn,k−2,Kn,k−1). Extended Base Hash 3.2.3 - /// - public static string Prefix_ExtendedHash - { - get - { - var ptr = External.GetPrefix_ExtendedHash(); - return Marshal.PtrToStringAnsi(ptr); - } - } - - /// - /// ξi,j = H(HE;20,ξB,Λi,λj). encryption nonce 3.3.2 - /// - public static string Prefix_SelectionNonce - { - get - { - var ptr = External.GetPrefix_SelectionNonce(); - return Marshal.PtrToStringAnsi(ptr); - } - } - - /// - /// c = H(HE;21,K,α,β,a0,b0,a1,b1,...,aL,bL). Ballot Selection Encryption Proof (ranged) 3.3.5 - /// c = H(HE;21,K,α,β,a0,b0,a1,b1). Ballot Selection Encryption Proof (unselected) 3.3.5 - /// c = H(HE;21,K,α,β,a0,b0,a1,b1). Ballot Selection Encryption Proof (selected) 3.3.5 - /// - public static string Prefix_SelectionProof - { - get - { - var ptr = External.GetPrefix_SelectionProof(); - return Marshal.PtrToStringAnsi(ptr); - } - } - - /// - /// ξ = H (HE ; 20, ξB , Λ, ”contest data”). Ballot Contest Data Nonce 3.3.6 - /// - public static string Prefix_ContestDataNonce - { - get - { - var ptr = External.GetPrefix_ContestDataNonce(); - return Marshal.PtrToStringAnsi(ptr); - } - } - - /// - /// k = H(HE;22,K,α,β). Ballot ContestData Secret Key 3.3.6 - /// - public static string Prefix_ContestDataSecret - { - get - { - var ptr = External.GetPrefix_ContestDataSecret(); - return Marshal.PtrToStringAnsi(ptr); - } - } - - /// - /// c = H(HE;21,K,α ̄,β ̄,a0,b0,a1,b1,...,aL,bL). Ballot Contest Limit Encryption Proof 3.3.8 - /// - public static string Prefix_ContestProof - { - get - { - var ptr = External.GetPrefix_ContestProof(); - return Marshal.PtrToStringAnsi(ptr); - } - } - - /// - /// χl = H(HE;23,Λl,K,α1,β1,α2,β2 ...,αm,βm). Contest Hash 3.4.1 - /// - public static string Prefix_ContestHash - { - get - { - var ptr = External.GetPrefix_ContestHash(); - return Marshal.PtrToStringAnsi(ptr); - } - } - - /// - /// H(B) = H(HE;24,χ1,χ2,...,χmB ,Baux). Confirmation Code 3.4.2 - /// - public static string Prefix_BallotCode - { - get - { - var ptr = External.GetPrefix_BallotCode(); - return Marshal.PtrToStringAnsi(ptr); - } - } - - /// - /// H0 = H(HE;24,Baux,0), Ballot Chaining for Fixed Device 3.4.3 - /// H = H(HE;24,Baux), Ballot chaining closure - /// - public static string Prefix_BallotChain - { - get - { - var ptr = External.GetPrefix_BallotChain(); - return Marshal.PtrToStringAnsi(ptr); - } - } - - /// - /// c = H(HE;30,K,A,B,a,b,M). Ballot Selection Decryption Proof 3.6.3 - /// c = H(HE;30,K,α,β,a,b,M). Challenge Ballot Selection Decryption Proof 3.6.5 - /// - public static string Prefix_DecryptSelectionProof - { - get - { - var ptr = External.GetPrefix_DecryptSelectionProof(); - return Marshal.PtrToStringAnsi(ptr); - } - } - - /// - /// c = H(HE;31,K,C0,C1,C2,a,b,β). Ballot Contest Decryption of Contest Data 3.6.4 - /// - public static string Prefix_DescryptContestData - { - get - { - var ptr = External.GetPrefix_DescryptContestData(); - return Marshal.PtrToStringAnsi(ptr); - } - } - - /// - /// Hash together the values - /// - /// first value for the hash - public static ElementModQ HashElems(string first) - { - var status = External.HashElems(first, - out var value); - status.ThrowIfError(); - return value.IsInvalid ? null : new ElementModQ(value); - } - - /// - /// Hash together the values - /// - /// first value for the hash - public static ElementModQ HashElems(ulong first) - { - var status = External.HashElems(first, - out var value); - status.ThrowIfError(); - return value.IsInvalid ? null : new ElementModQ(value); - } - - /// - /// Hash together the values - /// - /// first value for the hash - /// second value for the hash - public static ElementModQ HashElems(string first, ulong second) - { - var status = External.HashElems(first, second, - out var value); - status.ThrowIfError(); - return value.IsInvalid ? null : new ElementModQ(value); - } - - /// - /// Hash together the values - /// - /// first value for the hash - /// second value for the hash - public static ElementModQ HashElems(ulong first, ulong second) - { - var status = External.HashElems(first, second, - out var value); - status.ThrowIfError(); - return value.IsInvalid ? null : new ElementModQ(value); - } - - /// - /// Hash together the ElementModP values - /// - /// first value for the hash - /// second value for the hash - /// third value for the hash - public static ElementModQ HashElems(string first, ulong second, ElementModP third) - { - var status = External.HashElems(first, second, third.Handle, - out var value); - status.ThrowIfError(); - return value.IsInvalid ? null : new ElementModQ(value); - } - - /// - /// Hash together the ElementModP values - /// - /// first value for the hash - /// second value for the hash - /// third value for the hash - public static ElementModQ HashElems(string first, ulong second, ElementModQ third) - { - var status = External.HashElems(first, second, third.Handle, - out var value); - status.ThrowIfError(); - return value.IsInvalid ? null : new ElementModQ(value); - } - - /// - /// Hash together the ElementModP values - /// - /// first value for the hash - /// second value for the hash - public static ElementModQ HashElems(ElementModP first, ElementModP second) - { - var status = External.HashElems(first.Handle, second.Handle, - out var value); - status.ThrowIfError(); - return value.IsInvalid ? null : new ElementModQ(value); - } - - /// - /// Hash together the ElementModP values - /// - /// first value for the hash - /// second value for the hash - public static ElementModQ HashElems(ElementModP first, ElementModQ second) - { - var status = External.HashElems(first.Handle, second.Handle, - out var value); - status.ThrowIfError(); - return value.IsInvalid ? null : new ElementModQ(value); - } - - /// - /// Hash together the ElementModP values - /// - /// first value for the hash - /// second value for the hash - public static ElementModQ HashElems(ElementModQ first, ElementModQ second) - { - var status = External.HashElems(first.Handle, second.Handle, - out var value); - status.ThrowIfError(); - return value.IsInvalid ? null : new ElementModQ(value); - } - - /// - /// Hash together the ElementModP values - /// - /// first value for the hash - /// second value for the hash - public static ElementModQ HashElems(ElementModQ first, ElementModP second) - { - var status = External.HashElems(first.Handle, second.Handle, - out var value); - status.ThrowIfError(); - return value.IsInvalid ? null : new ElementModQ(value); - } - - /// - /// Hash together the values - /// - /// first value for the hash - /// second value for the hash - public static ElementModQ HashElems(ElementModQ first, ulong second) - { - var status = External.HashElems(first.Handle, second, - out var value); - status.ThrowIfError(); - return value.IsInvalid ? null : new ElementModQ(value); - } - - /// - /// Hash together the ElementModP values - /// - /// List of ElementModP to hash together - public static ElementModQ HashElems(List data) - { - var dataPointers = new IntPtr[data.Count]; - for (var i = 0; i < data.Count; i++) - { - dataPointers[i] = data[i].Handle.Ptr; - // TODO: Do we really want to dispose here? - data[i].Dispose(); - } - - var status = External.HashElems(dataPointers, (ulong)data.Count, - out var value); - status.ThrowIfError(); - return value.IsInvalid ? null : new ElementModQ(value); - } - - /// - /// Hash together the ICryptoHashableType values - /// - public static ElementModQ HashElems( - ElementModQ seed, params ICryptoHashableType[] data) - { - // TODO: ISSUE #239 we should define a clear method for - // passing hashable elements back and forth - // between C# and C++ so we don't have to do this - foreach (var item in data) - { - if (item is CryptoHashableBase) - { - if (item is ElementModP p) - { - using (var combined = HashElems(seed, p)) - { - seed.Reassign(combined); - } - - } - else if (item is ElementModQ q) - { - - using (var combined = HashElems(seed, q)) - { - seed.Reassign(combined); - } - } - } - else - { - throw new ArgumentException("data must be of type CryptoHashableBase"); - } - } - return seed; - } - - /// - /// Hash together the ICryptoHashableType values - /// - public static ElementModQ HashElems( - string prefix, params ICryptoHashableType[] data) - { - var hashed = HashElems(prefix); - return HashElems(hashed, data); - } - - public static ElementModQ HashElems( - ElementModQ header, string prefix, params ICryptoHashableType[] data) - { - var hashedPrefix = HashElems(prefix); - var hashed = HashElems(header, hashedPrefix); - return HashElems(hashed, data); - } - - internal static class External - { - [DllImport( - NativeInterface.DllName, - EntryPoint = "eg_hash_get_prefix_parameter_hash", - CallingConvention = CallingConvention.Cdecl, - SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr GetPrefix_ParameterHash(); - - [DllImport( - NativeInterface.DllName, - EntryPoint = "eg_hash_get_prefix_manifest_hash", - CallingConvention = CallingConvention.Cdecl, - SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr GetPrefix_ManifestHash(); - - [DllImport( - NativeInterface.DllName, - EntryPoint = "eg_hash_get_prefix_base_hash", - CallingConvention = CallingConvention.Cdecl, - SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr GetPrefix_BaseHash(); - - [DllImport( - NativeInterface.DllName, - EntryPoint = "eg_hash_get_prefix_guardian_share_challenge", - CallingConvention = CallingConvention.Cdecl, - SetLastError = true, CharSet = CharSet.Unicode)] - - public static extern IntPtr GetPrefix_GuardianShareChallenge(); - - [DllImport( - NativeInterface.DllName, - EntryPoint = "eg_hash_get_prefix_guardian_share_secret", - CallingConvention = CallingConvention.Cdecl, - SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr GetPrefix_GuardianShareSecret(); - - [DllImport( - NativeInterface.DllName, - EntryPoint = "eg_hash_get_prefix_extended_hash", - CallingConvention = CallingConvention.Cdecl, - SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr GetPrefix_ExtendedHash(); - - [DllImport( - NativeInterface.DllName, - EntryPoint = "eg_hash_get_prefix_selection_nonce", - CallingConvention = CallingConvention.Cdecl, - SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr GetPrefix_SelectionNonce(); - - [DllImport( - NativeInterface.DllName, - EntryPoint = "eg_hash_get_prefix_selection_proof", - CallingConvention = CallingConvention.Cdecl, - SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr GetPrefix_SelectionProof(); - - [DllImport( - NativeInterface.DllName, - EntryPoint = "eg_hash_get_prefix_contest_data_nonce", - CallingConvention = CallingConvention.Cdecl, - SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr GetPrefix_ContestDataNonce(); - - [DllImport( - NativeInterface.DllName, - EntryPoint = "eg_hash_get_prefix_contest_data_secret", - CallingConvention = CallingConvention.Cdecl, - SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr GetPrefix_ContestDataSecret(); - - [DllImport( - NativeInterface.DllName, - EntryPoint = "eg_hash_get_prefix_contest_proof", - CallingConvention = CallingConvention.Cdecl, - SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr GetPrefix_ContestProof(); - - [DllImport( - NativeInterface.DllName, - EntryPoint = "eg_hash_get_prefix_contest_hash", - CallingConvention = CallingConvention.Cdecl, - SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr GetPrefix_ContestHash(); - - [DllImport( - NativeInterface.DllName, - EntryPoint = "eg_hash_get_prefix_ballot_code", - CallingConvention = CallingConvention.Cdecl, - SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr GetPrefix_BallotCode(); - - [DllImport( - NativeInterface.DllName, - EntryPoint = "eg_hash_get_prefix_ballot_chain", - CallingConvention = CallingConvention.Cdecl, - SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr GetPrefix_BallotChain(); - - [DllImport( - NativeInterface.DllName, - EntryPoint = "eg_hash_get_prefix_decrypt_selection_proof", - CallingConvention = CallingConvention.Cdecl, - SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr GetPrefix_DecryptSelectionProof(); - - [DllImport( - NativeInterface.DllName, - EntryPoint = "eg_hash_get_prefix_decrypt_contest_data", - CallingConvention = CallingConvention.Cdecl, - SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr GetPrefix_DescryptContestData(); - - [DllImport( - NativeInterface.DllName, - EntryPoint = "eg_hash_elems_string", - CallingConvention = CallingConvention.Cdecl, - SetLastError = true)] - internal static extern Status HashElems( - [MarshalAs(UnmanagedType.LPStr)] string a, - out NativeInterface.ElementModQ.ElementModQHandle handle - ); - - [DllImport( - NativeInterface.DllName, - EntryPoint = "eg_hash_elems_strings", - CallingConvention = CallingConvention.Cdecl, - SetLastError = true)] - internal static extern Status HashElems( - [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr)] string[] a, - ulong length, - out NativeInterface.ElementModQ.ElementModQHandle handle - ); - - [DllImport( - NativeInterface.DllName, - EntryPoint = "eg_hash_elems_int", - CallingConvention = CallingConvention.Cdecl, - SetLastError = true)] - internal static extern Status HashElems( - ulong a, - out NativeInterface.ElementModQ.ElementModQHandle handle - ); - - [DllImport( - NativeInterface.DllName, - EntryPoint = "eg_hash_elems_string_int", - CallingConvention = CallingConvention.Cdecl, - SetLastError = true)] - internal static extern Status HashElems( - [MarshalAs(UnmanagedType.LPStr)] string a, - ulong b, - out NativeInterface.ElementModQ.ElementModQHandle handle - ); - - [DllImport( - NativeInterface.DllName, - EntryPoint = "eg_hash_elems_int_int", - CallingConvention = CallingConvention.Cdecl, - SetLastError = true)] - internal static extern Status HashElems( - ulong a, - ulong b, - out NativeInterface.ElementModQ.ElementModQHandle handle - ); - - [DllImport( - NativeInterface.DllName, - EntryPoint = "eg_hash_elems_string_int_modp", - CallingConvention = CallingConvention.Cdecl, - SetLastError = true)] - internal static extern Status HashElems( - [MarshalAs(UnmanagedType.LPStr)] string a, - ulong b, NativeInterface.ElementModP.ElementModPHandle c, - out NativeInterface.ElementModQ.ElementModQHandle handle - ); - - [DllImport( - NativeInterface.DllName, - EntryPoint = "eg_hash_elems_string_int_modq", - CallingConvention = CallingConvention.Cdecl, - SetLastError = true)] - internal static extern Status HashElems( - [MarshalAs(UnmanagedType.LPStr)] string a, - ulong b, NativeInterface.ElementModQ.ElementModQHandle c, - out NativeInterface.ElementModQ.ElementModQHandle handle - ); - - [DllImport( - NativeInterface.DllName, - EntryPoint = "eg_hash_elems_modp_modp", - CallingConvention = CallingConvention.Cdecl, - SetLastError = true)] - internal static extern Status HashElems( - NativeInterface.ElementModP.ElementModPHandle a, - NativeInterface.ElementModP.ElementModPHandle b, - out NativeInterface.ElementModQ.ElementModQHandle handle - ); - - [DllImport( - NativeInterface.DllName, - EntryPoint = "eg_hash_elems_modp_modq", - CallingConvention = CallingConvention.Cdecl, - SetLastError = true)] - internal static extern Status HashElems( - NativeInterface.ElementModP.ElementModPHandle a, - NativeInterface.ElementModQ.ElementModQHandle b, - out NativeInterface.ElementModQ.ElementModQHandle handle - ); - - [DllImport( - NativeInterface.DllName, - EntryPoint = "eg_hash_elems_modq_modq", - CallingConvention = CallingConvention.Cdecl, - SetLastError = true)] - internal static extern Status HashElems( - NativeInterface.ElementModQ.ElementModQHandle a, - NativeInterface.ElementModQ.ElementModQHandle b, - out NativeInterface.ElementModQ.ElementModQHandle handle - ); - - [DllImport( - NativeInterface.DllName, - EntryPoint = "eg_hash_elems_modq_int", - CallingConvention = CallingConvention.Cdecl, - SetLastError = true)] - internal static extern Status HashElems( - NativeInterface.ElementModQ.ElementModQHandle a, - ulong b, - out NativeInterface.ElementModQ.ElementModQHandle handle - ); - - [DllImport( - NativeInterface.DllName, - EntryPoint = "eg_hash_elems_modq_modp", - CallingConvention = CallingConvention.Cdecl, - SetLastError = true)] - internal static extern Status HashElems( - NativeInterface.ElementModQ.ElementModQHandle a, - NativeInterface.ElementModP.ElementModPHandle b, - out NativeInterface.ElementModQ.ElementModQHandle handle - ); - - [DllImport( - NativeInterface.DllName, - EntryPoint = "eg_hash_elems_array", - CallingConvention = CallingConvention.Cdecl, - SetLastError = true)] - internal static extern Status HashElems( - // TODO: type safety - [MarshalAs(UnmanagedType.LPArray)] IntPtr[] inData, - ulong inDataSize, - out NativeInterface.ElementModQ.ElementModQHandle handle - ); - } - } -} +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using ElectionGuard.Base; + +namespace ElectionGuard +{ + + /// + /// Class for wrapping hashing methods + /// + public static class Hash + { + /// + /// HP = H(HV ;00,p,q,g). Parameter Hash 3.1.2 + /// + public static string Prefix_ParameterHash + { + get + { + var ptr = External.GetPrefix_ParameterHash(); + return Marshal.PtrToStringAnsi(ptr); + } + } + + /// + /// HM = H(HP;01,manifest). Manifest Hash 3.1.4 + /// + public static string Prefix_ManifestHash + { + get + { + var ptr = External.GetPrefix_ManifestHash(); + return Marshal.PtrToStringAnsi(ptr); + } + } + + /// + /// HB = (HP;02,n,k,date,info,HM). Election Base Hash 3.1.5 + /// + public static string Prefix_BaseHash + { + get + { + var ptr = External.GetPrefix_BaseHash(); + return Marshal.PtrToStringAnsi(ptr); + } + } + + /// + /// H = (HP ; 10, i, j, Ki,j , hi,j ). Guardin Share proof challenge 3.2.2 + /// + public static string Prefix_GuardianShareChallenge + { + get + { + var ptr = External.GetPrefix_GuardianShareChallenge(); + return Marshal.PtrToStringAnsi(ptr); + } + } + + /// + /// ki,l = H(HP;11,i,l,Kl,αi,l,βi,l). (14) Guardain Share Encryption Secret Key 3.2.2 + /// + public static string Prefix_GuardianShareSecret + { + get + { + var ptr = External.GetPrefix_GuardianShareSecret(); + return Marshal.PtrToStringAnsi(ptr); + } + } + + /// + /// HE = H(HB;12,K,K1,0,K1,1,...,K1,k−1,K2,0,...,Kn,k−2,Kn,k−1). Extended Base Hash 3.2.3 + /// + public static string Prefix_ExtendedHash + { + get + { + var ptr = External.GetPrefix_ExtendedHash(); + return Marshal.PtrToStringAnsi(ptr); + } + } + + /// + /// ξi,j = H(HE;20,ξB,Λi,λj). encryption nonce 3.3.2 + /// + public static string Prefix_SelectionNonce + { + get + { + var ptr = External.GetPrefix_SelectionNonce(); + return Marshal.PtrToStringAnsi(ptr); + } + } + + /// + /// c = H(HE;21,K,α,β,a0,b0,a1,b1,...,aL,bL). Ballot Selection Encryption Proof (ranged) 3.3.5 + /// c = H(HE;21,K,α,β,a0,b0,a1,b1). Ballot Selection Encryption Proof (unselected) 3.3.5 + /// c = H(HE;21,K,α,β,a0,b0,a1,b1). Ballot Selection Encryption Proof (selected) 3.3.5 + /// + public static string Prefix_SelectionProof + { + get + { + var ptr = External.GetPrefix_SelectionProof(); + return Marshal.PtrToStringAnsi(ptr); + } + } + + /// + /// ξ = H (HE ; 20, ξB , Λ, ”contest data”). Ballot Contest Data Nonce 3.3.6 + /// + public static string Prefix_ContestDataNonce + { + get + { + var ptr = External.GetPrefix_ContestDataNonce(); + return Marshal.PtrToStringAnsi(ptr); + } + } + + /// + /// k = H(HE;22,K,α,β). Ballot ContestData Secret Key 3.3.6 + /// + public static string Prefix_ContestDataSecret + { + get + { + var ptr = External.GetPrefix_ContestDataSecret(); + return Marshal.PtrToStringAnsi(ptr); + } + } + + /// + /// c = H(HE;21,K,α ̄,β ̄,a0,b0,a1,b1,...,aL,bL). Ballot Contest Limit Encryption Proof 3.3.8 + /// + public static string Prefix_ContestProof + { + get + { + var ptr = External.GetPrefix_ContestProof(); + return Marshal.PtrToStringAnsi(ptr); + } + } + + /// + /// χl = H(HE;23,Λl,K,α1,β1,α2,β2 ...,αm,βm). Contest Hash 3.4.1 + /// + public static string Prefix_ContestHash + { + get + { + var ptr = External.GetPrefix_ContestHash(); + return Marshal.PtrToStringAnsi(ptr); + } + } + + /// + /// H(B) = H(HE;24,χ1,χ2,...,χmB ,Baux). Confirmation Code 3.4.2 + /// + public static string Prefix_BallotCode + { + get + { + var ptr = External.GetPrefix_BallotCode(); + return Marshal.PtrToStringAnsi(ptr); + } + } + + /// + /// H0 = H(HE;24,Baux,0), Ballot Chaining for Fixed Device 3.4.3 + /// H = H(HE;24,Baux), Ballot chaining closure + /// + public static string Prefix_BallotChain + { + get + { + var ptr = External.GetPrefix_BallotChain(); + return Marshal.PtrToStringAnsi(ptr); + } + } + + /// + /// c = H(HE;30,K,A,B,a,b,M). Ballot Selection Decryption Proof 3.6.3 + /// c = H(HE;30,K,α,β,a,b,M). Challenge Ballot Selection Decryption Proof 3.6.5 + /// + public static string Prefix_DecryptSelectionProof + { + get + { + var ptr = External.GetPrefix_DecryptSelectionProof(); + return Marshal.PtrToStringAnsi(ptr); + } + } + + /// + /// c = H(HE;31,K,C0,C1,C2,a,b,β). Ballot Contest Decryption of Contest Data 3.6.4 + /// + public static string Prefix_DescryptContestData + { + get + { + var ptr = External.GetPrefix_DescryptContestData(); + return Marshal.PtrToStringAnsi(ptr); + } + } + + /// + /// Hash together the values + /// + /// first value for the hash + public static ElementModQ HashElems(string first) + { + var status = External.HashElems(first, + out var value); + status.ThrowIfError(); + return value.IsInvalid ? null : new ElementModQ(value); + } + + /// + /// Hash together the values + /// + /// first value for the hash + public static ElementModQ HashElems(ulong first) + { + var status = External.HashElems(first, + out var value); + status.ThrowIfError(); + return value.IsInvalid ? null : new ElementModQ(value); + } + + /// + /// Hash together the values + /// + /// first value for the hash + /// second value for the hash + public static ElementModQ HashElems(string first, ulong second) + { + var status = External.HashElems(first, second, + out var value); + status.ThrowIfError(); + return value.IsInvalid ? null : new ElementModQ(value); + } + + /// + /// Hash together the values + /// + /// first value for the hash + /// second value for the hash + public static ElementModQ HashElems(ulong first, ulong second) + { + var status = External.HashElems(first, second, + out var value); + status.ThrowIfError(); + return value.IsInvalid ? null : new ElementModQ(value); + } + + /// + /// Hash together the ElementModP values + /// + /// first value for the hash + /// second value for the hash + /// third value for the hash + public static ElementModQ HashElems(string first, ulong second, ElementModP third) + { + var status = External.HashElems(first, second, third.Handle, + out var value); + status.ThrowIfError(); + return value.IsInvalid ? null : new ElementModQ(value); + } + + /// + /// Hash together the ElementModP values + /// + /// first value for the hash + /// second value for the hash + /// third value for the hash + public static ElementModQ HashElems(string first, ulong second, ElementModQ third) + { + var status = External.HashElems(first, second, third.Handle, + out var value); + status.ThrowIfError(); + return value.IsInvalid ? null : new ElementModQ(value); + } + + /// + /// Hash together the ElementModP values + /// + /// first value for the hash + /// second value for the hash + public static ElementModQ HashElems(ElementModP first, ElementModP second) + { + var status = External.HashElems(first.Handle, second.Handle, + out var value); + status.ThrowIfError(); + return value.IsInvalid ? null : new ElementModQ(value); + } + + /// + /// Hash together the ElementModP values + /// + /// first value for the hash + /// second value for the hash + public static ElementModQ HashElems(ElementModP first, ElementModQ second) + { + var status = External.HashElems(first.Handle, second.Handle, + out var value); + status.ThrowIfError(); + return value.IsInvalid ? null : new ElementModQ(value); + } + + /// + /// Hash together the ElementModP values + /// + /// first value for the hash + /// second value for the hash + public static ElementModQ HashElems(ElementModQ first, ElementModQ second) + { + var status = External.HashElems(first.Handle, second.Handle, + out var value); + status.ThrowIfError(); + return value.IsInvalid ? null : new ElementModQ(value); + } + + /// + /// Hash together the ElementModP values + /// + /// first value for the hash + /// second value for the hash + public static ElementModQ HashElems(ElementModQ first, ElementModP second) + { + var status = External.HashElems(first.Handle, second.Handle, + out var value); + status.ThrowIfError(); + return value.IsInvalid ? null : new ElementModQ(value); + } + + /// + /// Hash together the values + /// + /// first value for the hash + /// second value for the hash + public static ElementModQ HashElems(ElementModQ first, ulong second) + { + var status = External.HashElems(first.Handle, second, + out var value); + status.ThrowIfError(); + return value.IsInvalid ? null : new ElementModQ(value); + } + + /// + /// Hash together the ElementModP values + /// + /// List of ElementModP to hash together + public static ElementModQ HashElems(List data) + { + var dataPointers = new IntPtr[data.Count]; + for (var i = 0; i < data.Count; i++) + { + dataPointers[i] = data[i].Handle.Ptr; + // TODO: Do we really want to dispose here? + data[i].Dispose(); + } + + var status = External.HashElems(dataPointers, (ulong)data.Count, + out var value); + status.ThrowIfError(); + return value.IsInvalid ? null : new ElementModQ(value); + } + + /// + /// Hash together the ICryptoHashableType values + /// + public static ElementModQ HashElems( + ElementModQ seed, params ICryptoHashableType[] data) + { + // TODO: ISSUE #239 we should define a clear method for + // passing hashable elements back and forth + // between C# and C++ so we don't have to do this + foreach (var item in data) + { + if (item is CryptoHashableBase) + { + if (item is ElementModP p) + { + using (var combined = HashElems(seed, p)) + { + seed.Reassign(combined); + } + + } + else if (item is ElementModQ q) + { + + using (var combined = HashElems(seed, q)) + { + seed.Reassign(combined); + } + } + } + else + { + throw new ArgumentException("data must be of type CryptoHashableBase"); + } + } + return seed; + } + + /// + /// Hash together the ICryptoHashableType values + /// + public static ElementModQ HashElems( + string prefix, params ICryptoHashableType[] data) + { + var hashed = HashElems(prefix); + return HashElems(hashed, data); + } + + public static ElementModQ HashElems( + ElementModQ header, string prefix, params ICryptoHashableType[] data) + { + var hashedPrefix = HashElems(prefix); + var hashed = HashElems(header, hashedPrefix); + return HashElems(hashed, data); + } + + internal static class External + { + [DllImport( + NativeInterface.DllName, + EntryPoint = "eg_hash_get_prefix_parameter_hash", + CallingConvention = CallingConvention.Cdecl, + SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr GetPrefix_ParameterHash(); + + [DllImport( + NativeInterface.DllName, + EntryPoint = "eg_hash_get_prefix_manifest_hash", + CallingConvention = CallingConvention.Cdecl, + SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr GetPrefix_ManifestHash(); + + [DllImport( + NativeInterface.DllName, + EntryPoint = "eg_hash_get_prefix_base_hash", + CallingConvention = CallingConvention.Cdecl, + SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr GetPrefix_BaseHash(); + + [DllImport( + NativeInterface.DllName, + EntryPoint = "eg_hash_get_prefix_guardian_share_challenge", + CallingConvention = CallingConvention.Cdecl, + SetLastError = true, CharSet = CharSet.Unicode)] + + public static extern IntPtr GetPrefix_GuardianShareChallenge(); + + [DllImport( + NativeInterface.DllName, + EntryPoint = "eg_hash_get_prefix_guardian_share_secret", + CallingConvention = CallingConvention.Cdecl, + SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr GetPrefix_GuardianShareSecret(); + + [DllImport( + NativeInterface.DllName, + EntryPoint = "eg_hash_get_prefix_extended_hash", + CallingConvention = CallingConvention.Cdecl, + SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr GetPrefix_ExtendedHash(); + + [DllImport( + NativeInterface.DllName, + EntryPoint = "eg_hash_get_prefix_selection_nonce", + CallingConvention = CallingConvention.Cdecl, + SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr GetPrefix_SelectionNonce(); + + [DllImport( + NativeInterface.DllName, + EntryPoint = "eg_hash_get_prefix_selection_proof", + CallingConvention = CallingConvention.Cdecl, + SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr GetPrefix_SelectionProof(); + + [DllImport( + NativeInterface.DllName, + EntryPoint = "eg_hash_get_prefix_contest_data_nonce", + CallingConvention = CallingConvention.Cdecl, + SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr GetPrefix_ContestDataNonce(); + + [DllImport( + NativeInterface.DllName, + EntryPoint = "eg_hash_get_prefix_contest_data_secret", + CallingConvention = CallingConvention.Cdecl, + SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr GetPrefix_ContestDataSecret(); + + [DllImport( + NativeInterface.DllName, + EntryPoint = "eg_hash_get_prefix_contest_proof", + CallingConvention = CallingConvention.Cdecl, + SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr GetPrefix_ContestProof(); + + [DllImport( + NativeInterface.DllName, + EntryPoint = "eg_hash_get_prefix_contest_hash", + CallingConvention = CallingConvention.Cdecl, + SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr GetPrefix_ContestHash(); + + [DllImport( + NativeInterface.DllName, + EntryPoint = "eg_hash_get_prefix_ballot_code", + CallingConvention = CallingConvention.Cdecl, + SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr GetPrefix_BallotCode(); + + [DllImport( + NativeInterface.DllName, + EntryPoint = "eg_hash_get_prefix_ballot_chain", + CallingConvention = CallingConvention.Cdecl, + SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr GetPrefix_BallotChain(); + + [DllImport( + NativeInterface.DllName, + EntryPoint = "eg_hash_get_prefix_decrypt_selection_proof", + CallingConvention = CallingConvention.Cdecl, + SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr GetPrefix_DecryptSelectionProof(); + + [DllImport( + NativeInterface.DllName, + EntryPoint = "eg_hash_get_prefix_decrypt_contest_data", + CallingConvention = CallingConvention.Cdecl, + SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr GetPrefix_DescryptContestData(); + + [DllImport( + NativeInterface.DllName, + EntryPoint = "eg_hash_elems_string", + CallingConvention = CallingConvention.Cdecl, + SetLastError = true)] + internal static extern Status HashElems( + [MarshalAs(UnmanagedType.LPStr)] string a, + out NativeInterface.ElementModQ.ElementModQHandle handle + ); + + [DllImport( + NativeInterface.DllName, + EntryPoint = "eg_hash_elems_strings", + CallingConvention = CallingConvention.Cdecl, + SetLastError = true)] + internal static extern Status HashElems( + [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr)] string[] a, + ulong length, + out NativeInterface.ElementModQ.ElementModQHandle handle + ); + + [DllImport( + NativeInterface.DllName, + EntryPoint = "eg_hash_elems_int", + CallingConvention = CallingConvention.Cdecl, + SetLastError = true)] + internal static extern Status HashElems( + ulong a, + out NativeInterface.ElementModQ.ElementModQHandle handle + ); + + [DllImport( + NativeInterface.DllName, + EntryPoint = "eg_hash_elems_string_int", + CallingConvention = CallingConvention.Cdecl, + SetLastError = true)] + internal static extern Status HashElems( + [MarshalAs(UnmanagedType.LPStr)] string a, + ulong b, + out NativeInterface.ElementModQ.ElementModQHandle handle + ); + + [DllImport( + NativeInterface.DllName, + EntryPoint = "eg_hash_elems_int_int", + CallingConvention = CallingConvention.Cdecl, + SetLastError = true)] + internal static extern Status HashElems( + ulong a, + ulong b, + out NativeInterface.ElementModQ.ElementModQHandle handle + ); + + [DllImport( + NativeInterface.DllName, + EntryPoint = "eg_hash_elems_string_int_modp", + CallingConvention = CallingConvention.Cdecl, + SetLastError = true)] + internal static extern Status HashElems( + [MarshalAs(UnmanagedType.LPStr)] string a, + ulong b, NativeInterface.ElementModP.ElementModPHandle c, + out NativeInterface.ElementModQ.ElementModQHandle handle + ); + + [DllImport( + NativeInterface.DllName, + EntryPoint = "eg_hash_elems_string_int_modq", + CallingConvention = CallingConvention.Cdecl, + SetLastError = true)] + internal static extern Status HashElems( + [MarshalAs(UnmanagedType.LPStr)] string a, + ulong b, NativeInterface.ElementModQ.ElementModQHandle c, + out NativeInterface.ElementModQ.ElementModQHandle handle + ); + + [DllImport( + NativeInterface.DllName, + EntryPoint = "eg_hash_elems_modp_modp", + CallingConvention = CallingConvention.Cdecl, + SetLastError = true)] + internal static extern Status HashElems( + NativeInterface.ElementModP.ElementModPHandle a, + NativeInterface.ElementModP.ElementModPHandle b, + out NativeInterface.ElementModQ.ElementModQHandle handle + ); + + [DllImport( + NativeInterface.DllName, + EntryPoint = "eg_hash_elems_modp_modq", + CallingConvention = CallingConvention.Cdecl, + SetLastError = true)] + internal static extern Status HashElems( + NativeInterface.ElementModP.ElementModPHandle a, + NativeInterface.ElementModQ.ElementModQHandle b, + out NativeInterface.ElementModQ.ElementModQHandle handle + ); + + [DllImport( + NativeInterface.DllName, + EntryPoint = "eg_hash_elems_modq_modq", + CallingConvention = CallingConvention.Cdecl, + SetLastError = true)] + internal static extern Status HashElems( + NativeInterface.ElementModQ.ElementModQHandle a, + NativeInterface.ElementModQ.ElementModQHandle b, + out NativeInterface.ElementModQ.ElementModQHandle handle + ); + + [DllImport( + NativeInterface.DllName, + EntryPoint = "eg_hash_elems_modq_int", + CallingConvention = CallingConvention.Cdecl, + SetLastError = true)] + internal static extern Status HashElems( + NativeInterface.ElementModQ.ElementModQHandle a, + ulong b, + out NativeInterface.ElementModQ.ElementModQHandle handle + ); + + [DllImport( + NativeInterface.DllName, + EntryPoint = "eg_hash_elems_modq_modp", + CallingConvention = CallingConvention.Cdecl, + SetLastError = true)] + internal static extern Status HashElems( + NativeInterface.ElementModQ.ElementModQHandle a, + NativeInterface.ElementModP.ElementModPHandle b, + out NativeInterface.ElementModQ.ElementModQHandle handle + ); + + [DllImport( + NativeInterface.DllName, + EntryPoint = "eg_hash_elems_array", + CallingConvention = CallingConvention.Cdecl, + SetLastError = true)] + internal static extern Status HashElems( + // TODO: type safety + [MarshalAs(UnmanagedType.LPArray)] IntPtr[] inData, + ulong inDataSize, + out NativeInterface.ElementModQ.ElementModQHandle handle + ); + } + } +} diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Language.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Language.cs index 4863a0f7a..b2d85c0cb 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Language.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Language.cs @@ -10,7 +10,7 @@ namespace ElectionGuard /// see: https://developers.google.com/civics-data/reference/internationalized-text#language-string /// public class Language : DisposableBase - { + { /// /// The value /// diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Manifest.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Manifest.cs index 4ff2171d4..c14d9dcd2 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Manifest.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Manifest.cs @@ -1,429 +1,429 @@ -using System; -using System.Runtime.InteropServices; - -namespace ElectionGuard -{ - using NativeGeopoliticalUnit = NativeInterface.GeopoliticalUnit.GeopoliticalUnitHandle; - using NativeBallotStyle = NativeInterface.BallotStyle.BallotStyleHandle; - using NativeParty = NativeInterface.Party.PartyHandle; - using NativeCandidate = NativeInterface.Candidate.CandidateHandle; - using NativeContestDescription = NativeInterface.ContestDescription.ContestDescriptionHandle; - using NativeElementModQ = NativeInterface.ElementModQ.ElementModQHandle; - - #region AnnotatedString - - #endregion - - #region Language - - #endregion - - #region InternationalizedText - - #endregion - - #region ContactInformation - - #endregion - - #region GeopoliticalUnit - - #endregion - - #region BallotStyle - - #endregion - - #region Party - - #endregion - - #region Candidate - - #endregion - - #region SelectionDescription - - #endregion - - #region ContestDescription - - #endregion - - #region ContestDescriptionWithPlaceholders - - #endregion - - /// - /// Use this entity for defining the structure of the election and associated - /// information such as candidates, contests, and vote counts. This class is - /// based on the NIST Election Common Standard Data Specification. Some deviations - /// from the standard exist. - /// - /// This structure is considered an immutable input object and should not be changed - /// through the course of an election, as it's hash representation is the basis for all - /// other hash representations within an ElectionGuard election context. - /// - /// The ElectionGuard Documentation - /// The Civics Common Standard Data Specification - /// - public partial class Manifest : DisposableBase - { - /// - /// Creates a Manifest object from a [RFC-8259] UTF-8 encoded JSON string - /// - /// A UTF-8 Encoded JSON data string - public Manifest(string json) - { - var data = Language.EncodeNonAsciiCharacters(json); - var status = NativeInterface.Manifest.FromJson(data, out Handle); - if (status != Status.ELECTIONGUARD_STATUS_SUCCESS) - { - ExceptionHandler.GetData(out var function, out var message, out var _); - throw new ElectionGuardException($"Manifest Error Status: {status} function: {function} message: {message}"); - } - } - - /// - /// Creates a `Manifest` object - /// - /// byte array of data describing the manifest - /// binary encoding for the data - public unsafe Manifest(byte[] data, BinarySerializationEncoding encoding) - { - fixed (byte* pointer = data) - { - var status = encoding == BinarySerializationEncoding.BSON - ? NativeInterface.Manifest.FromBson(pointer, (ulong)data.Length, out Handle) - : NativeInterface.Manifest.FromMsgPack(pointer, (ulong)data.Length, out Handle); - if (status != Status.ELECTIONGUARD_STATUS_SUCCESS) - { - ExceptionHandler.GetData(out var function, out var message, out var _); - throw new ElectionGuardException($"Manifest Error Binary Ctor: {status} function: {function} message: {message}"); - } - } - } - - /// - /// Creates a `Manifest` object - /// - /// - /// election type - /// election type - /// start date for election - /// end data for the election - /// array of the `GeopoliticalUnit` for election - /// array of the `Party` for election - /// array of the `Candidate` for election - /// array of the `ContestDescription` for election - /// array of the `BallotStyle` for election - public Manifest( - string electionScopeId, string specVersion, ElectionType electionType, - DateTime startDate, DateTime endDate, - GeopoliticalUnit[] gpUnits, Party[] parties, - Candidate[] candidates, ContestDescription[] contests, - BallotStyle[] ballotStyles) - { - var gpUnitPointers = new IntPtr[gpUnits.Length]; - for (var i = 0; i < gpUnits.Length; i++) - { - gpUnitPointers[i] = gpUnits[i].Handle.Ptr; - gpUnits[i].Dispose(); - } - - var partyPointers = new IntPtr[parties.Length]; - for (var i = 0; i < parties.Length; i++) - { - partyPointers[i] = parties[i].Handle.Ptr; - parties[i].Dispose(); - } - - var candidatePointers = new IntPtr[candidates.Length]; - for (var i = 0; i < candidates.Length; i++) - { - candidatePointers[i] = candidates[i].Handle.Ptr; - candidates[i].Dispose(); - } - - var contestPointers = new IntPtr[contests.Length]; - for (var i = 0; i < contests.Length; i++) - { - contestPointers[i] = contests[i].Handle.Ptr; - contests[i].Dispose(); - } - - var ballotStylePointers = new IntPtr[ballotStyles.Length]; - for (var i = 0; i < ballotStyles.Length; i++) - { - ballotStylePointers[i] = ballotStyles[i].Handle.Ptr; - ballotStyles[i].Dispose(); - } - - var status = NativeInterface.Manifest.New( - electionScopeId, specVersion, electionType, - (ulong)new DateTimeOffset(startDate).ToUnixTimeMilliseconds(), - (ulong)new DateTimeOffset(endDate).ToUnixTimeMilliseconds(), - gpUnitPointers, (ulong)gpUnitPointers.LongLength, - partyPointers, (ulong)partyPointers.LongLength, - candidatePointers, (ulong)candidatePointers.LongLength, - contestPointers, (ulong)contestPointers.LongLength, - ballotStylePointers, (ulong)ballotStylePointers.LongLength, - out Handle); - if (status != Status.ELECTIONGUARD_STATUS_SUCCESS) - { - ExceptionHandler.GetData(out var function, out var message, out var _); - throw new ElectionGuardException($"Manifest Error Status: {status} function: {function} message: {message}"); - } - } - - /// - /// Creates a `Manifest` object - /// - /// - /// election type - /// start date for election - /// end data for the election - /// array of the `GeopoliticalUnit` for election - /// array of the `Party` for election - /// array of the `Candidate` for election - /// array of the `ContestDescription` for election - /// array of the `BallotStyle` for election - /// name of the election - /// contact information for the election - public Manifest( - string electionScopeId, ElectionType electionType, - DateTime startDate, DateTime endDate, - GeopoliticalUnit[] gpUnits, Party[] parties, - Candidate[] candidates, ContestDescription[] contests, - BallotStyle[] ballotStyles, InternationalizedText name, ContactInformation contact) : this(electionScopeId, "1.9", electionType, - startDate, endDate, gpUnits, parties, candidates, contests, ballotStyles, name, contact) - { - } - - /// - /// Creates a `Manifest` object - /// - /// - /// election type - /// election type - /// start date for election - /// end data for the election - /// array of the `GeopoliticalUnit` for election - /// array of the `Party` for election - /// array of the `Candidate` for election - /// array of the `ContestDescription` for election - /// array of the `BallotStyle` for election - /// name of the election - /// contact information for the election - public Manifest( - string electionScopeId, string specVersion, ElectionType electionType, - DateTime startDate, DateTime endDate, - GeopoliticalUnit[] gpUnits, Party[] parties, - Candidate[] candidates, ContestDescription[] contests, - BallotStyle[] ballotStyles, InternationalizedText name, ContactInformation contact) - { - var gpUnitPointers = new IntPtr[gpUnits.Length]; - for (var i = 0; i < gpUnits.Length; i++) - { - gpUnitPointers[i] = gpUnits[i].Handle.Ptr; - gpUnits[i].Dispose(); - } - - var partyPointers = new IntPtr[parties.Length]; - for (var i = 0; i < parties.Length; i++) - { - partyPointers[i] = parties[i].Handle.Ptr; - parties[i].Dispose(); - } - - var candidatePointers = new IntPtr[candidates.Length]; - for (var i = 0; i < candidates.Length; i++) - { - candidatePointers[i] = candidates[i].Handle.Ptr; - candidates[i].Dispose(); - } - - var contestPointers = new IntPtr[contests.Length]; - for (var i = 0; i < contests.Length; i++) - { - contestPointers[i] = contests[i].Handle.Ptr; - contests[i].Dispose(); - } - - var ballotStylePointers = new IntPtr[ballotStyles.Length]; - for (var i = 0; i < ballotStyles.Length; i++) - { - ballotStylePointers[i] = ballotStyles[i].Handle.Ptr; - ballotStyles[i].Dispose(); - } - - var status = NativeInterface.Manifest.New( - electionScopeId, specVersion, electionType, - (ulong)new DateTimeOffset(startDate).ToUnixTimeMilliseconds(), - (ulong)new DateTimeOffset(endDate).ToUnixTimeMilliseconds(), - gpUnitPointers, (ulong)gpUnitPointers.LongLength, - partyPointers, (ulong)partyPointers.LongLength, - candidatePointers, (ulong)candidatePointers.LongLength, - contestPointers, (ulong)contestPointers.LongLength, - ballotStylePointers, (ulong)ballotStylePointers.LongLength, - name.Handle, - contact.Handle, - out Handle); - if (status != Status.ELECTIONGUARD_STATUS_SUCCESS) - { - ExceptionHandler.GetData(out var function, out var message, out var _); - throw new ElectionGuardException($"Manifest Error Status: {status} function: {function} message: {message}"); - } - } - - /// - /// Collection of geopolitical units for this election. - /// - public GeopoliticalUnit GetGeopoliticalUnitAtIndex(ulong index) - { - var status = NativeInterface.Manifest.GetGeopoliticalUnitAtIndex( - Handle, index, out var value); - return status != Status.ELECTIONGUARD_STATUS_SUCCESS - ? throw new ElectionGuardException($"Manifest Error GetGeopoliticalUnitAtIndex: {status}") - : new GeopoliticalUnit(value); - } - - /// - /// Collection of parties for this election. - /// - public Party GetPartyAtIndex(ulong index) - { - var status = NativeInterface.Manifest.GetPartyAtIndex( - Handle, index, out var value); - return status != Status.ELECTIONGUARD_STATUS_SUCCESS - ? throw new ElectionGuardException($"Manifest Error GetPartyAtIndex: {status}") - : new Party(value); - } - - /// - /// Collection of candidates for this election. - /// - public Candidate GetCandidateAtIndex(ulong index) - { - var status = NativeInterface.Manifest.GetCandidateAtIndex( - Handle, index, out var value); - return status != Status.ELECTIONGUARD_STATUS_SUCCESS - ? throw new ElectionGuardException($"Manifest Error GetCandidateAtIndex: {status}") - : new Candidate(value); - } - - /// - /// Collection of contests for this election. - /// - public ContestDescription GetContestAtIndex(ulong index) - { - var status = NativeInterface.Manifest.GetContestAtIndex( - Handle, index, out var value); - return status != Status.ELECTIONGUARD_STATUS_SUCCESS - ? throw new ElectionGuardException($"Manifest Error GetContestAtIndex: {status}") - : new ContestDescription(value); - } - - /// - /// Collection of ballot styles for this election. - /// - public BallotStyle GetBallotStyleAtIndex(ulong index) - { - var status = NativeInterface.Manifest.GetBallotStyleAtIndex( - Handle, index, out var value); - return status != Status.ELECTIONGUARD_STATUS_SUCCESS - ? throw new ElectionGuardException($"Manifest Error GetContestAtIndex: {status}") - : new BallotStyle(value); - } - - /// - /// A hash representation of the object - /// - public ElementModQ CryptoHash() - { - var status = NativeInterface.Manifest.CryptoHash( - Handle, out var value); - return status != Status.ELECTIONGUARD_STATUS_SUCCESS - ? throw new ElectionGuardException($"CryptoHash Error Status: {status}") - : new ElementModQ(value); - } - - /// - /// Check whether the election manifest is valid and well-formed. - /// - public bool IsValid() - { - var value = NativeInterface.Manifest.IsValid(Handle); - return value; - } - - /// - /// Export the ballot representation as JSON - /// - public string ToJson() - { - var status = NativeInterface.Manifest.ToJson( - Handle, out var pointer, out _); - if (status != Status.ELECTIONGUARD_STATUS_SUCCESS) - { - ExceptionHandler.GetData(out var function, out var message, out var _); - throw new ElectionGuardException($"ToJson Error Status: {status} function: {function} message: {message}"); - } - var json = pointer.PtrToStringUTF8(); - _ = NativeInterface.Memory.FreeIntPtr(pointer); - return json; - } - - /// - /// Export the ballot representation as ToBson - /// - public byte[] ToBson() - { - - var status = NativeInterface.Manifest.ToBson( - Handle, out var data, out var size); - - if (status != Status.ELECTIONGUARD_STATUS_SUCCESS) - { - ExceptionHandler.GetData(out var function, out var message, out var _); - throw new ElectionGuardException($"Manifest Error ToBson: {status} function: {function} message: {message}"); - } - - if (size > int.MaxValue) - { - throw new ElectionGuardException($"Manifest Error ToBson: size is too big. Expected <= {int.MaxValue}, Actual: {size}."); - } - - var byteArray = new byte[(int)size]; - Marshal.Copy(data, byteArray, 0, (int)size); - _ = NativeInterface.Memory.DeleteIntPtr(data); - return byteArray; - } - - /// - /// Export the ballot representation as MsgPack - /// - public byte[] ToMsgPack() - { - - var status = NativeInterface.Manifest.ToMsgPack( - Handle, out var data, out var size); - - if (status != Status.ELECTIONGUARD_STATUS_SUCCESS) - { - ExceptionHandler.GetData(out var function, out var message, out var _); - throw new ElectionGuardException($"Manifest Error ToMsgPack: {status} function: {function} message: {message}"); - } - - if (size > int.MaxValue) - { - throw new ElectionGuardException($"Manifest Error ToMsgPack: size is too big. Expected <= {int.MaxValue}, actual: {size}."); - } - - var byteArray = new byte[(int)size]; - Marshal.Copy(data, byteArray, 0, (int)size); - _ = NativeInterface.Memory.DeleteIntPtr(data); - return byteArray; - } - } -} +using System; +using System.Runtime.InteropServices; + +namespace ElectionGuard +{ + using NativeGeopoliticalUnit = NativeInterface.GeopoliticalUnit.GeopoliticalUnitHandle; + using NativeBallotStyle = NativeInterface.BallotStyle.BallotStyleHandle; + using NativeParty = NativeInterface.Party.PartyHandle; + using NativeCandidate = NativeInterface.Candidate.CandidateHandle; + using NativeContestDescription = NativeInterface.ContestDescription.ContestDescriptionHandle; + using NativeElementModQ = NativeInterface.ElementModQ.ElementModQHandle; + + #region AnnotatedString + + #endregion + + #region Language + + #endregion + + #region InternationalizedText + + #endregion + + #region ContactInformation + + #endregion + + #region GeopoliticalUnit + + #endregion + + #region BallotStyle + + #endregion + + #region Party + + #endregion + + #region Candidate + + #endregion + + #region SelectionDescription + + #endregion + + #region ContestDescription + + #endregion + + #region ContestDescriptionWithPlaceholders + + #endregion + + /// + /// Use this entity for defining the structure of the election and associated + /// information such as candidates, contests, and vote counts. This class is + /// based on the NIST Election Common Standard Data Specification. Some deviations + /// from the standard exist. + /// + /// This structure is considered an immutable input object and should not be changed + /// through the course of an election, as it's hash representation is the basis for all + /// other hash representations within an ElectionGuard election context. + /// + /// The ElectionGuard Documentation + /// The Civics Common Standard Data Specification + /// + public partial class Manifest : DisposableBase + { + /// + /// Creates a Manifest object from a [RFC-8259] UTF-8 encoded JSON string + /// + /// A UTF-8 Encoded JSON data string + public Manifest(string json) + { + var data = Language.EncodeNonAsciiCharacters(json); + var status = NativeInterface.Manifest.FromJson(data, out Handle); + if (status != Status.ELECTIONGUARD_STATUS_SUCCESS) + { + ExceptionHandler.GetData(out var function, out var message, out var _); + throw new ElectionGuardException($"Manifest Error Status: {status} function: {function} message: {message}"); + } + } + + /// + /// Creates a `Manifest` object + /// + /// byte array of data describing the manifest + /// binary encoding for the data + public unsafe Manifest(byte[] data, BinarySerializationEncoding encoding) + { + fixed (byte* pointer = data) + { + var status = encoding == BinarySerializationEncoding.BSON + ? NativeInterface.Manifest.FromBson(pointer, (ulong)data.Length, out Handle) + : NativeInterface.Manifest.FromMsgPack(pointer, (ulong)data.Length, out Handle); + if (status != Status.ELECTIONGUARD_STATUS_SUCCESS) + { + ExceptionHandler.GetData(out var function, out var message, out var _); + throw new ElectionGuardException($"Manifest Error Binary Ctor: {status} function: {function} message: {message}"); + } + } + } + + /// + /// Creates a `Manifest` object + /// + /// + /// election type + /// election type + /// start date for election + /// end data for the election + /// array of the `GeopoliticalUnit` for election + /// array of the `Party` for election + /// array of the `Candidate` for election + /// array of the `ContestDescription` for election + /// array of the `BallotStyle` for election + public Manifest( + string electionScopeId, string specVersion, ElectionType electionType, + DateTime startDate, DateTime endDate, + GeopoliticalUnit[] gpUnits, Party[] parties, + Candidate[] candidates, ContestDescription[] contests, + BallotStyle[] ballotStyles) + { + var gpUnitPointers = new IntPtr[gpUnits.Length]; + for (var i = 0; i < gpUnits.Length; i++) + { + gpUnitPointers[i] = gpUnits[i].Handle.Ptr; + gpUnits[i].Dispose(); + } + + var partyPointers = new IntPtr[parties.Length]; + for (var i = 0; i < parties.Length; i++) + { + partyPointers[i] = parties[i].Handle.Ptr; + parties[i].Dispose(); + } + + var candidatePointers = new IntPtr[candidates.Length]; + for (var i = 0; i < candidates.Length; i++) + { + candidatePointers[i] = candidates[i].Handle.Ptr; + candidates[i].Dispose(); + } + + var contestPointers = new IntPtr[contests.Length]; + for (var i = 0; i < contests.Length; i++) + { + contestPointers[i] = contests[i].Handle.Ptr; + contests[i].Dispose(); + } + + var ballotStylePointers = new IntPtr[ballotStyles.Length]; + for (var i = 0; i < ballotStyles.Length; i++) + { + ballotStylePointers[i] = ballotStyles[i].Handle.Ptr; + ballotStyles[i].Dispose(); + } + + var status = NativeInterface.Manifest.New( + electionScopeId, specVersion, electionType, + (ulong)new DateTimeOffset(startDate).ToUnixTimeMilliseconds(), + (ulong)new DateTimeOffset(endDate).ToUnixTimeMilliseconds(), + gpUnitPointers, (ulong)gpUnitPointers.LongLength, + partyPointers, (ulong)partyPointers.LongLength, + candidatePointers, (ulong)candidatePointers.LongLength, + contestPointers, (ulong)contestPointers.LongLength, + ballotStylePointers, (ulong)ballotStylePointers.LongLength, + out Handle); + if (status != Status.ELECTIONGUARD_STATUS_SUCCESS) + { + ExceptionHandler.GetData(out var function, out var message, out var _); + throw new ElectionGuardException($"Manifest Error Status: {status} function: {function} message: {message}"); + } + } + + /// + /// Creates a `Manifest` object + /// + /// + /// election type + /// start date for election + /// end data for the election + /// array of the `GeopoliticalUnit` for election + /// array of the `Party` for election + /// array of the `Candidate` for election + /// array of the `ContestDescription` for election + /// array of the `BallotStyle` for election + /// name of the election + /// contact information for the election + public Manifest( + string electionScopeId, ElectionType electionType, + DateTime startDate, DateTime endDate, + GeopoliticalUnit[] gpUnits, Party[] parties, + Candidate[] candidates, ContestDescription[] contests, + BallotStyle[] ballotStyles, InternationalizedText name, ContactInformation contact) : this(electionScopeId, "1.9", electionType, + startDate, endDate, gpUnits, parties, candidates, contests, ballotStyles, name, contact) + { + } + + /// + /// Creates a `Manifest` object + /// + /// + /// election type + /// election type + /// start date for election + /// end data for the election + /// array of the `GeopoliticalUnit` for election + /// array of the `Party` for election + /// array of the `Candidate` for election + /// array of the `ContestDescription` for election + /// array of the `BallotStyle` for election + /// name of the election + /// contact information for the election + public Manifest( + string electionScopeId, string specVersion, ElectionType electionType, + DateTime startDate, DateTime endDate, + GeopoliticalUnit[] gpUnits, Party[] parties, + Candidate[] candidates, ContestDescription[] contests, + BallotStyle[] ballotStyles, InternationalizedText name, ContactInformation contact) + { + var gpUnitPointers = new IntPtr[gpUnits.Length]; + for (var i = 0; i < gpUnits.Length; i++) + { + gpUnitPointers[i] = gpUnits[i].Handle.Ptr; + gpUnits[i].Dispose(); + } + + var partyPointers = new IntPtr[parties.Length]; + for (var i = 0; i < parties.Length; i++) + { + partyPointers[i] = parties[i].Handle.Ptr; + parties[i].Dispose(); + } + + var candidatePointers = new IntPtr[candidates.Length]; + for (var i = 0; i < candidates.Length; i++) + { + candidatePointers[i] = candidates[i].Handle.Ptr; + candidates[i].Dispose(); + } + + var contestPointers = new IntPtr[contests.Length]; + for (var i = 0; i < contests.Length; i++) + { + contestPointers[i] = contests[i].Handle.Ptr; + contests[i].Dispose(); + } + + var ballotStylePointers = new IntPtr[ballotStyles.Length]; + for (var i = 0; i < ballotStyles.Length; i++) + { + ballotStylePointers[i] = ballotStyles[i].Handle.Ptr; + ballotStyles[i].Dispose(); + } + + var status = NativeInterface.Manifest.New( + electionScopeId, specVersion, electionType, + (ulong)new DateTimeOffset(startDate).ToUnixTimeMilliseconds(), + (ulong)new DateTimeOffset(endDate).ToUnixTimeMilliseconds(), + gpUnitPointers, (ulong)gpUnitPointers.LongLength, + partyPointers, (ulong)partyPointers.LongLength, + candidatePointers, (ulong)candidatePointers.LongLength, + contestPointers, (ulong)contestPointers.LongLength, + ballotStylePointers, (ulong)ballotStylePointers.LongLength, + name.Handle, + contact.Handle, + out Handle); + if (status != Status.ELECTIONGUARD_STATUS_SUCCESS) + { + ExceptionHandler.GetData(out var function, out var message, out var _); + throw new ElectionGuardException($"Manifest Error Status: {status} function: {function} message: {message}"); + } + } + + /// + /// Collection of geopolitical units for this election. + /// + public GeopoliticalUnit GetGeopoliticalUnitAtIndex(ulong index) + { + var status = NativeInterface.Manifest.GetGeopoliticalUnitAtIndex( + Handle, index, out var value); + return status != Status.ELECTIONGUARD_STATUS_SUCCESS + ? throw new ElectionGuardException($"Manifest Error GetGeopoliticalUnitAtIndex: {status}") + : new GeopoliticalUnit(value); + } + + /// + /// Collection of parties for this election. + /// + public Party GetPartyAtIndex(ulong index) + { + var status = NativeInterface.Manifest.GetPartyAtIndex( + Handle, index, out var value); + return status != Status.ELECTIONGUARD_STATUS_SUCCESS + ? throw new ElectionGuardException($"Manifest Error GetPartyAtIndex: {status}") + : new Party(value); + } + + /// + /// Collection of candidates for this election. + /// + public Candidate GetCandidateAtIndex(ulong index) + { + var status = NativeInterface.Manifest.GetCandidateAtIndex( + Handle, index, out var value); + return status != Status.ELECTIONGUARD_STATUS_SUCCESS + ? throw new ElectionGuardException($"Manifest Error GetCandidateAtIndex: {status}") + : new Candidate(value); + } + + /// + /// Collection of contests for this election. + /// + public ContestDescription GetContestAtIndex(ulong index) + { + var status = NativeInterface.Manifest.GetContestAtIndex( + Handle, index, out var value); + return status != Status.ELECTIONGUARD_STATUS_SUCCESS + ? throw new ElectionGuardException($"Manifest Error GetContestAtIndex: {status}") + : new ContestDescription(value); + } + + /// + /// Collection of ballot styles for this election. + /// + public BallotStyle GetBallotStyleAtIndex(ulong index) + { + var status = NativeInterface.Manifest.GetBallotStyleAtIndex( + Handle, index, out var value); + return status != Status.ELECTIONGUARD_STATUS_SUCCESS + ? throw new ElectionGuardException($"Manifest Error GetContestAtIndex: {status}") + : new BallotStyle(value); + } + + /// + /// A hash representation of the object + /// + public ElementModQ CryptoHash() + { + var status = NativeInterface.Manifest.CryptoHash( + Handle, out var value); + return status != Status.ELECTIONGUARD_STATUS_SUCCESS + ? throw new ElectionGuardException($"CryptoHash Error Status: {status}") + : new ElementModQ(value); + } + + /// + /// Check whether the election manifest is valid and well-formed. + /// + public bool IsValid() + { + var value = NativeInterface.Manifest.IsValid(Handle); + return value; + } + + /// + /// Export the ballot representation as JSON + /// + public string ToJson() + { + var status = NativeInterface.Manifest.ToJson( + Handle, out var pointer, out _); + if (status != Status.ELECTIONGUARD_STATUS_SUCCESS) + { + ExceptionHandler.GetData(out var function, out var message, out var _); + throw new ElectionGuardException($"ToJson Error Status: {status} function: {function} message: {message}"); + } + var json = pointer.PtrToStringUTF8(); + _ = NativeInterface.Memory.FreeIntPtr(pointer); + return json; + } + + /// + /// Export the ballot representation as ToBson + /// + public byte[] ToBson() + { + + var status = NativeInterface.Manifest.ToBson( + Handle, out var data, out var size); + + if (status != Status.ELECTIONGUARD_STATUS_SUCCESS) + { + ExceptionHandler.GetData(out var function, out var message, out var _); + throw new ElectionGuardException($"Manifest Error ToBson: {status} function: {function} message: {message}"); + } + + if (size > int.MaxValue) + { + throw new ElectionGuardException($"Manifest Error ToBson: size is too big. Expected <= {int.MaxValue}, Actual: {size}."); + } + + var byteArray = new byte[(int)size]; + Marshal.Copy(data, byteArray, 0, (int)size); + _ = NativeInterface.Memory.DeleteIntPtr(data); + return byteArray; + } + + /// + /// Export the ballot representation as MsgPack + /// + public byte[] ToMsgPack() + { + + var status = NativeInterface.Manifest.ToMsgPack( + Handle, out var data, out var size); + + if (status != Status.ELECTIONGUARD_STATUS_SUCCESS) + { + ExceptionHandler.GetData(out var function, out var message, out var _); + throw new ElectionGuardException($"Manifest Error ToMsgPack: {status} function: {function} message: {message}"); + } + + if (size > int.MaxValue) + { + throw new ElectionGuardException($"Manifest Error ToMsgPack: size is too big. Expected <= {int.MaxValue}, actual: {size}."); + } + + var byteArray = new byte[(int)size]; + Marshal.Copy(data, byteArray, 0, (int)size); + _ = NativeInterface.Memory.DeleteIntPtr(data); + return byteArray; + } + } +} diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Proofs/SchnorrProof.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Proofs/SchnorrProof.cs index 21d67fedb..bacfd81fa 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Proofs/SchnorrProof.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Proofs/SchnorrProof.cs @@ -1,166 +1,166 @@ -using Newtonsoft.Json; - -namespace ElectionGuard.Proofs -{ - - /// - /// Representation of a Schnorr proof - /// - public class SchnorrProof : DisposableBase - { - /// - /// k in the spec - /// - public ElementModP PublicKey { get; private set; } - - /// - /// h in the spec - /// - public ElementModP Commitment { get; private set; } - - /// - /// c in the spec - /// - public ElementModQ Challenge { get; private set; } - - /// - /// u in the spec - /// - public ElementModQ Response { get; private set; } - - public ProofUsage Usage = ProofUsage.SecretValue; - - [JsonConstructor] - public SchnorrProof( - ElementModP publicKey, - ElementModP commitment, - ElementModQ challenge, - ElementModQ response) - { - PublicKey = new ElementModP(publicKey); - Commitment = new ElementModP(commitment); - Challenge = new ElementModQ(challenge); - Response = new ElementModQ(response); - } - - /// - /// Create a new instance of a Schnorr proof using the provided secret and a random seed. - /// - public SchnorrProof(ElementModQ secretKey) - { - using (var keyPair = ElGamalKeyPair.FromSecret(secretKey)) - using (var seed = BigMath.RandQ()) - { - PublicKey = new ElementModP(keyPair.PublicKey); - Commitment = BigMath.GPowP(seed); - Challenge = Hash.HashElems(PublicKey, Commitment); - Response = BigMath.APlusBMulCModQ(seed, keyPair.SecretKey, Challenge); - } - } - - /// - /// Create a new instance of a Schnorr proof using the provided key pair and a random seed. - /// - public SchnorrProof(ElGamalKeyPair keyPair) - { - using (var seed = BigMath.RandQ()) - { - PublicKey = new ElementModP(keyPair.PublicKey); - Commitment = BigMath.GPowP(seed); - Challenge = Hash.HashElems(PublicKey, Commitment); - Response = BigMath.APlusBMulCModQ(seed, keyPair.SecretKey, Challenge); - } - } - - /// - /// Create a new instance of a Schnorr proof using the provided secret and seed. - /// - public SchnorrProof(ElementModQ secretKey, ElementModQ seed) - { - using (var keyPair = ElGamalKeyPair.FromSecret(secretKey)) - { - - PublicKey = new ElementModP(keyPair.PublicKey); - Commitment = BigMath.GPowP(seed); - Challenge = Hash.HashElems(PublicKey, Commitment); - Response = BigMath.APlusBMulCModQ(seed, keyPair.SecretKey, Challenge); - } - } - - /// - /// Create a new instance of a Schnorr proof using the provided key pair and seed. - /// - public SchnorrProof(ElGamalKeyPair keyPair, ElementModQ seed) - { - PublicKey = new ElementModP(keyPair.PublicKey); - Commitment = BigMath.GPowP(seed); - Challenge = Hash.HashElems(PublicKey, Commitment); - Response = BigMath.APlusBMulCModQ(seed, keyPair.SecretKey, Challenge); - } - - public SchnorrProof(SchnorrProof other) - { - PublicKey = new ElementModP(other.PublicKey); - Commitment = new ElementModP(other.Commitment); - Challenge = new ElementModQ(other.Challenge); - Response = new ElementModQ(other.Response); - } - - /// - /// Check validity of the `proof` for proving possession of the secret key corresponding to the public key - /// - public bool IsValid() - { - var k = PublicKey; - var h = Commitment; - var u = Response; - var validPublicKey = k.IsValidResidue(); - var inBoundsH = h.IsInBounds(); - var inBoundsU = u.IsInBounds(); - -#pragma warning disable IDE0063 // Use simple 'using' statement. Need to support Net Standard 2.0, which doesn't have this. - using (var c = Hash.HashElems(k, h)) - using (var gp = BigMath.GPowP(u)) - using (var pp = BigMath.PowModP(k, c)) - using (var mp = BigMath.MultModP(h, pp)) -#pragma warning restore IDE0063 - { - - var validChallenge = c.Equals(Challenge); - var validProof = gp.Equals(mp); - - var success = validPublicKey && inBoundsH && inBoundsU && validChallenge && validProof; - if (success is false) - { - #region commented Code - // TODO: result - //log_warning( - // "found an invalid Schnorr proof: %s", - // str( - // { - // "in_bounds_h": in_bounds_h, - // "in_bounds_u": in_bounds_u, - // "valid_public_key": valid_public_key, - // "valid_challenge": valid_challenge, - // "valid_proof": valid_proof, - // "proof": self, - // } - // ), - // ) - #endregion - } - return success; - } - } - - protected override void DisposeUnmanaged() - { - base.DisposeUnmanaged(); - - PublicKey.Dispose(); - Commitment.Dispose(); - Challenge.Dispose(); - Response.Dispose(); - } - } -} +using Newtonsoft.Json; + +namespace ElectionGuard.Proofs +{ + + /// + /// Representation of a Schnorr proof + /// + public class SchnorrProof : DisposableBase + { + /// + /// k in the spec + /// + public ElementModP PublicKey { get; private set; } + + /// + /// h in the spec + /// + public ElementModP Commitment { get; private set; } + + /// + /// c in the spec + /// + public ElementModQ Challenge { get; private set; } + + /// + /// u in the spec + /// + public ElementModQ Response { get; private set; } + + public ProofUsage Usage = ProofUsage.SecretValue; + + [JsonConstructor] + public SchnorrProof( + ElementModP publicKey, + ElementModP commitment, + ElementModQ challenge, + ElementModQ response) + { + PublicKey = new ElementModP(publicKey); + Commitment = new ElementModP(commitment); + Challenge = new ElementModQ(challenge); + Response = new ElementModQ(response); + } + + /// + /// Create a new instance of a Schnorr proof using the provided secret and a random seed. + /// + public SchnorrProof(ElementModQ secretKey) + { + using (var keyPair = ElGamalKeyPair.FromSecret(secretKey)) + using (var seed = BigMath.RandQ()) + { + PublicKey = new ElementModP(keyPair.PublicKey); + Commitment = BigMath.GPowP(seed); + Challenge = Hash.HashElems(PublicKey, Commitment); + Response = BigMath.APlusBMulCModQ(seed, keyPair.SecretKey, Challenge); + } + } + + /// + /// Create a new instance of a Schnorr proof using the provided key pair and a random seed. + /// + public SchnorrProof(ElGamalKeyPair keyPair) + { + using (var seed = BigMath.RandQ()) + { + PublicKey = new ElementModP(keyPair.PublicKey); + Commitment = BigMath.GPowP(seed); + Challenge = Hash.HashElems(PublicKey, Commitment); + Response = BigMath.APlusBMulCModQ(seed, keyPair.SecretKey, Challenge); + } + } + + /// + /// Create a new instance of a Schnorr proof using the provided secret and seed. + /// + public SchnorrProof(ElementModQ secretKey, ElementModQ seed) + { + using (var keyPair = ElGamalKeyPair.FromSecret(secretKey)) + { + + PublicKey = new ElementModP(keyPair.PublicKey); + Commitment = BigMath.GPowP(seed); + Challenge = Hash.HashElems(PublicKey, Commitment); + Response = BigMath.APlusBMulCModQ(seed, keyPair.SecretKey, Challenge); + } + } + + /// + /// Create a new instance of a Schnorr proof using the provided key pair and seed. + /// + public SchnorrProof(ElGamalKeyPair keyPair, ElementModQ seed) + { + PublicKey = new ElementModP(keyPair.PublicKey); + Commitment = BigMath.GPowP(seed); + Challenge = Hash.HashElems(PublicKey, Commitment); + Response = BigMath.APlusBMulCModQ(seed, keyPair.SecretKey, Challenge); + } + + public SchnorrProof(SchnorrProof other) + { + PublicKey = new ElementModP(other.PublicKey); + Commitment = new ElementModP(other.Commitment); + Challenge = new ElementModQ(other.Challenge); + Response = new ElementModQ(other.Response); + } + + /// + /// Check validity of the `proof` for proving possession of the secret key corresponding to the public key + /// + public bool IsValid() + { + var k = PublicKey; + var h = Commitment; + var u = Response; + var validPublicKey = k.IsValidResidue(); + var inBoundsH = h.IsInBounds(); + var inBoundsU = u.IsInBounds(); + +#pragma warning disable IDE0063 // Use simple 'using' statement. Need to support Net Standard 2.0, which doesn't have this. + using (var c = Hash.HashElems(k, h)) + using (var gp = BigMath.GPowP(u)) + using (var pp = BigMath.PowModP(k, c)) + using (var mp = BigMath.MultModP(h, pp)) +#pragma warning restore IDE0063 + { + + var validChallenge = c.Equals(Challenge); + var validProof = gp.Equals(mp); + + var success = validPublicKey && inBoundsH && inBoundsU && validChallenge && validProof; + if (success is false) + { + #region commented Code + // TODO: result + //log_warning( + // "found an invalid Schnorr proof: %s", + // str( + // { + // "in_bounds_h": in_bounds_h, + // "in_bounds_u": in_bounds_u, + // "valid_public_key": valid_public_key, + // "valid_challenge": valid_challenge, + // "valid_proof": valid_proof, + // "proof": self, + // } + // ), + // ) + #endregion + } + return success; + } + } + + protected override void DisposeUnmanaged() + { + base.DisposeUnmanaged(); + + PublicKey.Dispose(); + Commitment.Dispose(); + Challenge.Dispose(); + Response.Dispose(); + } + } +} diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Random.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Random.cs index 1fd54bd03..49bac681e 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Random.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Random.cs @@ -1,40 +1,40 @@ -using System; - -namespace ElectionGuard -{ - public static class RandomExtensions - { - /// - /// Generates a random ElementModP - /// - public static ElementModP NextElementModP(this Random random) - { - var array = random.NextInBoundsArray(ElementModP.MaxSize); - return new ElementModP(array); - } - - /// - /// Generates a random ElementModQ - /// - public static ElementModQ NextElementModQ(this Random random) - { - var array = random.NextInBoundsArray(ElementModQ.MaxSize); - return new ElementModQ(array); - } - - /// - /// Generates a random array of ulong values that are within the bounds of the specified size - /// - public static ulong[] NextInBoundsArray(this Random random, ulong size) - { - var array = new ulong[size]; - for (var i = 0; i < array.Length; i++) - { - // Generate a random ulong value using the Random class - var value = ((uint)random.Next() << 32) | (uint)random.Next(); - array[i] = value; - } - return array; - } - } -} +using System; + +namespace ElectionGuard +{ + public static class RandomExtensions + { + /// + /// Generates a random ElementModP + /// + public static ElementModP NextElementModP(this Random random) + { + var array = random.NextInBoundsArray(ElementModP.MaxSize); + return new ElementModP(array); + } + + /// + /// Generates a random ElementModQ + /// + public static ElementModQ NextElementModQ(this Random random) + { + var array = random.NextInBoundsArray(ElementModQ.MaxSize); + return new ElementModQ(array); + } + + /// + /// Generates a random array of ulong values that are within the bounds of the specified size + /// + public static ulong[] NextInBoundsArray(this Random random, ulong size) + { + var array = new ulong[size]; + for (var i = 0; i < array.Length; i++) + { + // Generate a random ulong value using the Random class + var value = ((uint)random.Next() << 32) | (uint)random.Next(); + array[i] = value; + } + return array; + } + } +} diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/SelectionDescription.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/SelectionDescription.cs index da377ef3e..189a2fea9 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/SelectionDescription.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/SelectionDescription.cs @@ -1,7 +1,7 @@ using System.Runtime.InteropServices; using ElectionGuard.Ballot; -using Newtonsoft.Json; - +using Newtonsoft.Json; + namespace ElectionGuard { /// diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.sln b/bindings/netstandard/ElectionGuard/ElectionGuard.sln index 1be8f2642..22102f49c 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.sln +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.sln @@ -1,153 +1,205 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.2.32519.379 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.Encryption", "ElectionGuard.Encryption\ElectionGuard.Encryption.csproj", "{A4437B27-1101-4C91-AEBE-F97606990E2B}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.Encryption.Tests", "ElectionGuard.Encryption.Tests\ElectionGuard.Encryption.Tests.csproj", "{111BE643-7978-4CDB-9FDC-0A198139A488}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4DDF806F-023D-4917-B855-E5959DE468BD}" - ProjectSection(SolutionItems) = preProject - icon.png = icon.png - README.md = README.md - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.Encryption.Bench", "ElectionGuard.Encryption.Bench\ElectionGuard.Encryption.Bench.csproj", "{06B6E480-D964-4351-8FF3-E62F652B8D4C}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.Encryption.Utils", "ElectionGuard.Encryption.Utils\ElectionGuard.Encryption.Utils.csproj", "{6AC780D0-1862-4680-8B47-AD6CCF97B66C}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.ElectionSetup", "ElectionGuard.ElectionSetup\ElectionGuard.ElectionSetup.csproj", "{E6E5DC4A-F899-48D9-8586-408A39C0324B}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.ElectionSetup.Tests", "ElectionGuard.ElectionSetup.Tests\ElectionGuard.ElectionSetup.Tests.csproj", "{334BEA82-395E-4012-8BA6-77161EE7AED6}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.Decryption", "ElectionGuard.Decryption\ElectionGuard.Decryption.csproj", "{A94C923B-A34B-4FE4-A8E0-B1CB74976B11}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.Decryption.Tests", "ElectionGuard.Decryption.Tests\ElectionGuard.Decryption.Tests.csproj", "{728D53B2-FE17-44A2-A534-9DFDDF2D46EA}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|arm64 = Debug|arm64 - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|arm64 = Release|arm64 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A4437B27-1101-4C91-AEBE-F97606990E2B}.Debug|arm64.ActiveCfg = Debug|arm64 - {A4437B27-1101-4C91-AEBE-F97606990E2B}.Debug|arm64.Build.0 = Debug|arm64 - {A4437B27-1101-4C91-AEBE-F97606990E2B}.Debug|x64.ActiveCfg = Debug|x64 - {A4437B27-1101-4C91-AEBE-F97606990E2B}.Debug|x64.Build.0 = Debug|x64 - {A4437B27-1101-4C91-AEBE-F97606990E2B}.Debug|x86.ActiveCfg = Debug|x86 - {A4437B27-1101-4C91-AEBE-F97606990E2B}.Debug|x86.Build.0 = Debug|x86 - {A4437B27-1101-4C91-AEBE-F97606990E2B}.Release|arm64.ActiveCfg = Release|arm64 - {A4437B27-1101-4C91-AEBE-F97606990E2B}.Release|arm64.Build.0 = Release|arm64 - {A4437B27-1101-4C91-AEBE-F97606990E2B}.Release|x64.ActiveCfg = Release|x64 - {A4437B27-1101-4C91-AEBE-F97606990E2B}.Release|x64.Build.0 = Release|x64 - {A4437B27-1101-4C91-AEBE-F97606990E2B}.Release|x86.ActiveCfg = Release|x86 - {A4437B27-1101-4C91-AEBE-F97606990E2B}.Release|x86.Build.0 = Release|x86 - {111BE643-7978-4CDB-9FDC-0A198139A488}.Debug|arm64.ActiveCfg = Debug|arm64 - {111BE643-7978-4CDB-9FDC-0A198139A488}.Debug|arm64.Build.0 = Debug|arm64 - {111BE643-7978-4CDB-9FDC-0A198139A488}.Debug|x64.ActiveCfg = Debug|x64 - {111BE643-7978-4CDB-9FDC-0A198139A488}.Debug|x64.Build.0 = Debug|x64 - {111BE643-7978-4CDB-9FDC-0A198139A488}.Debug|x86.ActiveCfg = Debug|x86 - {111BE643-7978-4CDB-9FDC-0A198139A488}.Debug|x86.Build.0 = Debug|x86 - {111BE643-7978-4CDB-9FDC-0A198139A488}.Release|arm64.ActiveCfg = Release|arm64 - {111BE643-7978-4CDB-9FDC-0A198139A488}.Release|arm64.Build.0 = Release|arm64 - {111BE643-7978-4CDB-9FDC-0A198139A488}.Release|x64.ActiveCfg = Release|x64 - {111BE643-7978-4CDB-9FDC-0A198139A488}.Release|x64.Build.0 = Release|x64 - {111BE643-7978-4CDB-9FDC-0A198139A488}.Release|x86.ActiveCfg = Release|x86 - {111BE643-7978-4CDB-9FDC-0A198139A488}.Release|x86.Build.0 = Release|x86 - {06B6E480-D964-4351-8FF3-E62F652B8D4C}.Debug|arm64.ActiveCfg = Debug|arm64 - {06B6E480-D964-4351-8FF3-E62F652B8D4C}.Debug|arm64.Build.0 = Debug|arm64 - {06B6E480-D964-4351-8FF3-E62F652B8D4C}.Debug|x64.ActiveCfg = Debug|x64 - {06B6E480-D964-4351-8FF3-E62F652B8D4C}.Debug|x64.Build.0 = Debug|x64 - {06B6E480-D964-4351-8FF3-E62F652B8D4C}.Debug|x86.ActiveCfg = Debug|x86 - {06B6E480-D964-4351-8FF3-E62F652B8D4C}.Debug|x86.Build.0 = Debug|x86 - {06B6E480-D964-4351-8FF3-E62F652B8D4C}.Release|arm64.ActiveCfg = Release|arm64 - {06B6E480-D964-4351-8FF3-E62F652B8D4C}.Release|arm64.Build.0 = Release|arm64 - {06B6E480-D964-4351-8FF3-E62F652B8D4C}.Release|x64.ActiveCfg = Release|x64 - {06B6E480-D964-4351-8FF3-E62F652B8D4C}.Release|x64.Build.0 = Release|x64 - {06B6E480-D964-4351-8FF3-E62F652B8D4C}.Release|x86.ActiveCfg = Release|x86 - {06B6E480-D964-4351-8FF3-E62F652B8D4C}.Release|x86.Build.0 = Release|x86 - {6AC780D0-1862-4680-8B47-AD6CCF97B66C}.Debug|arm64.ActiveCfg = Debug|arm64 - {6AC780D0-1862-4680-8B47-AD6CCF97B66C}.Debug|arm64.Build.0 = Debug|arm64 - {6AC780D0-1862-4680-8B47-AD6CCF97B66C}.Debug|x64.ActiveCfg = Debug|x64 - {6AC780D0-1862-4680-8B47-AD6CCF97B66C}.Debug|x64.Build.0 = Debug|x64 - {6AC780D0-1862-4680-8B47-AD6CCF97B66C}.Debug|x86.ActiveCfg = Debug|x86 - {6AC780D0-1862-4680-8B47-AD6CCF97B66C}.Debug|x86.Build.0 = Debug|x86 - {6AC780D0-1862-4680-8B47-AD6CCF97B66C}.Release|arm64.ActiveCfg = Release|arm64 - {6AC780D0-1862-4680-8B47-AD6CCF97B66C}.Release|arm64.Build.0 = Release|arm64 - {6AC780D0-1862-4680-8B47-AD6CCF97B66C}.Release|x64.ActiveCfg = Release|x64 - {6AC780D0-1862-4680-8B47-AD6CCF97B66C}.Release|x64.Build.0 = Release|x64 - {6AC780D0-1862-4680-8B47-AD6CCF97B66C}.Release|x86.ActiveCfg = Release|x86 - {6AC780D0-1862-4680-8B47-AD6CCF97B66C}.Release|x86.Build.0 = Release|x86 - {E6E5DC4A-F899-48D9-8586-408A39C0324B}.Debug|arm64.ActiveCfg = Debug|arm64 - {E6E5DC4A-F899-48D9-8586-408A39C0324B}.Debug|arm64.Build.0 = Debug|arm64 - {E6E5DC4A-F899-48D9-8586-408A39C0324B}.Debug|x64.ActiveCfg = Debug|x64 - {E6E5DC4A-F899-48D9-8586-408A39C0324B}.Debug|x64.Build.0 = Debug|x64 - {E6E5DC4A-F899-48D9-8586-408A39C0324B}.Debug|x86.ActiveCfg = Debug|x86 - {E6E5DC4A-F899-48D9-8586-408A39C0324B}.Debug|x86.Build.0 = Debug|x86 - {E6E5DC4A-F899-48D9-8586-408A39C0324B}.Release|arm64.ActiveCfg = Release|arm64 - {E6E5DC4A-F899-48D9-8586-408A39C0324B}.Release|arm64.Build.0 = Release|arm64 - {E6E5DC4A-F899-48D9-8586-408A39C0324B}.Release|x64.ActiveCfg = Release|x64 - {E6E5DC4A-F899-48D9-8586-408A39C0324B}.Release|x64.Build.0 = Release|x64 - {E6E5DC4A-F899-48D9-8586-408A39C0324B}.Release|x86.ActiveCfg = Release|x86 - {E6E5DC4A-F899-48D9-8586-408A39C0324B}.Release|x86.Build.0 = Release|x86 - {334BEA82-395E-4012-8BA6-77161EE7AED6}.Debug|arm64.ActiveCfg = Debug|arm64 - {334BEA82-395E-4012-8BA6-77161EE7AED6}.Debug|arm64.Build.0 = Debug|arm64 - {334BEA82-395E-4012-8BA6-77161EE7AED6}.Debug|x64.ActiveCfg = Debug|x64 - {334BEA82-395E-4012-8BA6-77161EE7AED6}.Debug|x64.Build.0 = Debug|x64 - {334BEA82-395E-4012-8BA6-77161EE7AED6}.Debug|x86.ActiveCfg = Debug|x86 - {334BEA82-395E-4012-8BA6-77161EE7AED6}.Debug|x86.Build.0 = Debug|x86 - {334BEA82-395E-4012-8BA6-77161EE7AED6}.Release|arm64.ActiveCfg = Release|arm64 - {334BEA82-395E-4012-8BA6-77161EE7AED6}.Release|arm64.Build.0 = Release|arm64 - {334BEA82-395E-4012-8BA6-77161EE7AED6}.Release|x64.ActiveCfg = Release|x64 - {334BEA82-395E-4012-8BA6-77161EE7AED6}.Release|x64.Build.0 = Release|x64 - {334BEA82-395E-4012-8BA6-77161EE7AED6}.Release|x86.ActiveCfg = Release|x86 - {334BEA82-395E-4012-8BA6-77161EE7AED6}.Release|x86.Build.0 = Release|x86 - {A94C923B-A34B-4FE4-A8E0-B1CB74976B11}.Debug|arm64.ActiveCfg = Debug|arm64 - {A94C923B-A34B-4FE4-A8E0-B1CB74976B11}.Debug|arm64.Build.0 = Debug|arm64 - {A94C923B-A34B-4FE4-A8E0-B1CB74976B11}.Debug|x64.ActiveCfg = Debug|x64 - {A94C923B-A34B-4FE4-A8E0-B1CB74976B11}.Debug|x64.Build.0 = Debug|x64 - {A94C923B-A34B-4FE4-A8E0-B1CB74976B11}.Debug|x86.ActiveCfg = Debug|x86 - {A94C923B-A34B-4FE4-A8E0-B1CB74976B11}.Debug|x86.Build.0 = Debug|x86 - {A94C923B-A34B-4FE4-A8E0-B1CB74976B11}.Release|arm64.ActiveCfg = Release|arm64 - {A94C923B-A34B-4FE4-A8E0-B1CB74976B11}.Release|arm64.Build.0 = Release|arm64 - {A94C923B-A34B-4FE4-A8E0-B1CB74976B11}.Release|x64.ActiveCfg = Release|x64 - {A94C923B-A34B-4FE4-A8E0-B1CB74976B11}.Release|x64.Build.0 = Release|x64 - {A94C923B-A34B-4FE4-A8E0-B1CB74976B11}.Release|x86.ActiveCfg = Release|x86 - {A94C923B-A34B-4FE4-A8E0-B1CB74976B11}.Release|x86.Build.0 = Release|x86 - {728D53B2-FE17-44A2-A534-9DFDDF2D46EA}.Debug|arm64.ActiveCfg = Debug|arm64 - {728D53B2-FE17-44A2-A534-9DFDDF2D46EA}.Debug|arm64.Build.0 = Debug|arm64 - {728D53B2-FE17-44A2-A534-9DFDDF2D46EA}.Debug|x64.ActiveCfg = Debug|x64 - {728D53B2-FE17-44A2-A534-9DFDDF2D46EA}.Debug|x64.Build.0 = Debug|x64 - {728D53B2-FE17-44A2-A534-9DFDDF2D46EA}.Debug|x86.ActiveCfg = Debug|x86 - {728D53B2-FE17-44A2-A534-9DFDDF2D46EA}.Debug|x86.Build.0 = Debug|x86 - {728D53B2-FE17-44A2-A534-9DFDDF2D46EA}.Release|arm64.ActiveCfg = Release|arm64 - {728D53B2-FE17-44A2-A534-9DFDDF2D46EA}.Release|arm64.Build.0 = Release|arm64 - {728D53B2-FE17-44A2-A534-9DFDDF2D46EA}.Release|x64.ActiveCfg = Release|x64 - {728D53B2-FE17-44A2-A534-9DFDDF2D46EA}.Release|x64.Build.0 = Release|x64 - {728D53B2-FE17-44A2-A534-9DFDDF2D46EA}.Release|x86.ActiveCfg = Release|x86 - {728D53B2-FE17-44A2-A534-9DFDDF2D46EA}.Release|x86.Build.0 = Release|x86 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {44312322-DEA7-4BDE-8930-AFEAB72CA425} - EndGlobalSection - GlobalSection(MonoDevelopProperties) = preSolution - Policies = $0 - $0.TextStylePolicy = $3 - $1.inheritsSet = null - $1.scope = application/x-msbuild - $0.XmlFormattingPolicy = $4 - $2.inheritsSet = null - $2.scope = application/x-msbuild - $3.inheritsSet = null - $3.scope = application/xml - $4.scope = application/xml - $0.StandardHeader = $5 - EndGlobalSection -EndGlobal +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32519.379 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.Encryption", "ElectionGuard.Encryption\ElectionGuard.Encryption.csproj", "{A4437B27-1101-4C91-AEBE-F97606990E2B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.Encryption.Tests", "ElectionGuard.Encryption.Tests\ElectionGuard.Encryption.Tests.csproj", "{111BE643-7978-4CDB-9FDC-0A198139A488}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4DDF806F-023D-4917-B855-E5959DE468BD}" + ProjectSection(SolutionItems) = preProject + icon.png = icon.png + README.md = README.md + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.Encryption.Bench", "ElectionGuard.Encryption.Bench\ElectionGuard.Encryption.Bench.csproj", "{06B6E480-D964-4351-8FF3-E62F652B8D4C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.Encryption.Utils", "ElectionGuard.Encryption.Utils\ElectionGuard.Encryption.Utils.csproj", "{6AC780D0-1862-4680-8B47-AD6CCF97B66C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.ElectionSetup", "ElectionGuard.ElectionSetup\ElectionGuard.ElectionSetup.csproj", "{E6E5DC4A-F899-48D9-8586-408A39C0324B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.ElectionSetup.Tests", "ElectionGuard.ElectionSetup.Tests\ElectionGuard.ElectionSetup.Tests.csproj", "{334BEA82-395E-4012-8BA6-77161EE7AED6}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.Decryption", "ElectionGuard.Decryption\ElectionGuard.Decryption.csproj", "{A94C923B-A34B-4FE4-A8E0-B1CB74976B11}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.Decryption.Tests", "ElectionGuard.Decryption.Tests\ElectionGuard.Decryption.Tests.csproj", "{728D53B2-FE17-44A2-A534-9DFDDF2D46EA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ElectionGuard.UI.Lib", "..\..\..\src\electionguard-ui\ElectionGuard.UI.Lib\ElectionGuard.UI.Lib.csproj", "{D9D6EDD9-C919-D3FC-DAE3-1908A1A96318}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|arm64 = Debug|arm64 + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|arm64 = Release|arm64 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A4437B27-1101-4C91-AEBE-F97606990E2B}.Debug|Any CPU.ActiveCfg = Debug|x64 + {A4437B27-1101-4C91-AEBE-F97606990E2B}.Debug|Any CPU.Build.0 = Debug|x64 + {A4437B27-1101-4C91-AEBE-F97606990E2B}.Debug|arm64.ActiveCfg = Debug|arm64 + {A4437B27-1101-4C91-AEBE-F97606990E2B}.Debug|arm64.Build.0 = Debug|arm64 + {A4437B27-1101-4C91-AEBE-F97606990E2B}.Debug|x64.ActiveCfg = Debug|x64 + {A4437B27-1101-4C91-AEBE-F97606990E2B}.Debug|x64.Build.0 = Debug|x64 + {A4437B27-1101-4C91-AEBE-F97606990E2B}.Debug|x86.ActiveCfg = Debug|x86 + {A4437B27-1101-4C91-AEBE-F97606990E2B}.Debug|x86.Build.0 = Debug|x86 + {A4437B27-1101-4C91-AEBE-F97606990E2B}.Release|Any CPU.ActiveCfg = Release|x64 + {A4437B27-1101-4C91-AEBE-F97606990E2B}.Release|Any CPU.Build.0 = Release|x64 + {A4437B27-1101-4C91-AEBE-F97606990E2B}.Release|arm64.ActiveCfg = Release|arm64 + {A4437B27-1101-4C91-AEBE-F97606990E2B}.Release|arm64.Build.0 = Release|arm64 + {A4437B27-1101-4C91-AEBE-F97606990E2B}.Release|x64.ActiveCfg = Release|x64 + {A4437B27-1101-4C91-AEBE-F97606990E2B}.Release|x64.Build.0 = Release|x64 + {A4437B27-1101-4C91-AEBE-F97606990E2B}.Release|x86.ActiveCfg = Release|x86 + {A4437B27-1101-4C91-AEBE-F97606990E2B}.Release|x86.Build.0 = Release|x86 + {111BE643-7978-4CDB-9FDC-0A198139A488}.Debug|Any CPU.ActiveCfg = Debug|x64 + {111BE643-7978-4CDB-9FDC-0A198139A488}.Debug|Any CPU.Build.0 = Debug|x64 + {111BE643-7978-4CDB-9FDC-0A198139A488}.Debug|arm64.ActiveCfg = Debug|arm64 + {111BE643-7978-4CDB-9FDC-0A198139A488}.Debug|arm64.Build.0 = Debug|arm64 + {111BE643-7978-4CDB-9FDC-0A198139A488}.Debug|x64.ActiveCfg = Debug|x64 + {111BE643-7978-4CDB-9FDC-0A198139A488}.Debug|x64.Build.0 = Debug|x64 + {111BE643-7978-4CDB-9FDC-0A198139A488}.Debug|x86.ActiveCfg = Debug|x86 + {111BE643-7978-4CDB-9FDC-0A198139A488}.Debug|x86.Build.0 = Debug|x86 + {111BE643-7978-4CDB-9FDC-0A198139A488}.Release|Any CPU.ActiveCfg = Release|x64 + {111BE643-7978-4CDB-9FDC-0A198139A488}.Release|Any CPU.Build.0 = Release|x64 + {111BE643-7978-4CDB-9FDC-0A198139A488}.Release|arm64.ActiveCfg = Release|arm64 + {111BE643-7978-4CDB-9FDC-0A198139A488}.Release|arm64.Build.0 = Release|arm64 + {111BE643-7978-4CDB-9FDC-0A198139A488}.Release|x64.ActiveCfg = Release|x64 + {111BE643-7978-4CDB-9FDC-0A198139A488}.Release|x64.Build.0 = Release|x64 + {111BE643-7978-4CDB-9FDC-0A198139A488}.Release|x86.ActiveCfg = Release|x86 + {111BE643-7978-4CDB-9FDC-0A198139A488}.Release|x86.Build.0 = Release|x86 + {06B6E480-D964-4351-8FF3-E62F652B8D4C}.Debug|Any CPU.ActiveCfg = Debug|x64 + {06B6E480-D964-4351-8FF3-E62F652B8D4C}.Debug|Any CPU.Build.0 = Debug|x64 + {06B6E480-D964-4351-8FF3-E62F652B8D4C}.Debug|arm64.ActiveCfg = Debug|arm64 + {06B6E480-D964-4351-8FF3-E62F652B8D4C}.Debug|arm64.Build.0 = Debug|arm64 + {06B6E480-D964-4351-8FF3-E62F652B8D4C}.Debug|x64.ActiveCfg = Debug|x64 + {06B6E480-D964-4351-8FF3-E62F652B8D4C}.Debug|x64.Build.0 = Debug|x64 + {06B6E480-D964-4351-8FF3-E62F652B8D4C}.Debug|x86.ActiveCfg = Debug|x86 + {06B6E480-D964-4351-8FF3-E62F652B8D4C}.Debug|x86.Build.0 = Debug|x86 + {06B6E480-D964-4351-8FF3-E62F652B8D4C}.Release|Any CPU.ActiveCfg = Release|x64 + {06B6E480-D964-4351-8FF3-E62F652B8D4C}.Release|Any CPU.Build.0 = Release|x64 + {06B6E480-D964-4351-8FF3-E62F652B8D4C}.Release|arm64.ActiveCfg = Release|arm64 + {06B6E480-D964-4351-8FF3-E62F652B8D4C}.Release|arm64.Build.0 = Release|arm64 + {06B6E480-D964-4351-8FF3-E62F652B8D4C}.Release|x64.ActiveCfg = Release|x64 + {06B6E480-D964-4351-8FF3-E62F652B8D4C}.Release|x64.Build.0 = Release|x64 + {06B6E480-D964-4351-8FF3-E62F652B8D4C}.Release|x86.ActiveCfg = Release|x86 + {06B6E480-D964-4351-8FF3-E62F652B8D4C}.Release|x86.Build.0 = Release|x86 + {6AC780D0-1862-4680-8B47-AD6CCF97B66C}.Debug|Any CPU.ActiveCfg = Debug|x64 + {6AC780D0-1862-4680-8B47-AD6CCF97B66C}.Debug|Any CPU.Build.0 = Debug|x64 + {6AC780D0-1862-4680-8B47-AD6CCF97B66C}.Debug|arm64.ActiveCfg = Debug|arm64 + {6AC780D0-1862-4680-8B47-AD6CCF97B66C}.Debug|arm64.Build.0 = Debug|arm64 + {6AC780D0-1862-4680-8B47-AD6CCF97B66C}.Debug|x64.ActiveCfg = Debug|x64 + {6AC780D0-1862-4680-8B47-AD6CCF97B66C}.Debug|x64.Build.0 = Debug|x64 + {6AC780D0-1862-4680-8B47-AD6CCF97B66C}.Debug|x86.ActiveCfg = Debug|x86 + {6AC780D0-1862-4680-8B47-AD6CCF97B66C}.Debug|x86.Build.0 = Debug|x86 + {6AC780D0-1862-4680-8B47-AD6CCF97B66C}.Release|Any CPU.ActiveCfg = Release|x64 + {6AC780D0-1862-4680-8B47-AD6CCF97B66C}.Release|Any CPU.Build.0 = Release|x64 + {6AC780D0-1862-4680-8B47-AD6CCF97B66C}.Release|arm64.ActiveCfg = Release|arm64 + {6AC780D0-1862-4680-8B47-AD6CCF97B66C}.Release|arm64.Build.0 = Release|arm64 + {6AC780D0-1862-4680-8B47-AD6CCF97B66C}.Release|x64.ActiveCfg = Release|x64 + {6AC780D0-1862-4680-8B47-AD6CCF97B66C}.Release|x64.Build.0 = Release|x64 + {6AC780D0-1862-4680-8B47-AD6CCF97B66C}.Release|x86.ActiveCfg = Release|x86 + {6AC780D0-1862-4680-8B47-AD6CCF97B66C}.Release|x86.Build.0 = Release|x86 + {E6E5DC4A-F899-48D9-8586-408A39C0324B}.Debug|Any CPU.ActiveCfg = Debug|x64 + {E6E5DC4A-F899-48D9-8586-408A39C0324B}.Debug|Any CPU.Build.0 = Debug|x64 + {E6E5DC4A-F899-48D9-8586-408A39C0324B}.Debug|arm64.ActiveCfg = Debug|arm64 + {E6E5DC4A-F899-48D9-8586-408A39C0324B}.Debug|arm64.Build.0 = Debug|arm64 + {E6E5DC4A-F899-48D9-8586-408A39C0324B}.Debug|x64.ActiveCfg = Debug|x64 + {E6E5DC4A-F899-48D9-8586-408A39C0324B}.Debug|x64.Build.0 = Debug|x64 + {E6E5DC4A-F899-48D9-8586-408A39C0324B}.Debug|x86.ActiveCfg = Debug|x86 + {E6E5DC4A-F899-48D9-8586-408A39C0324B}.Debug|x86.Build.0 = Debug|x86 + {E6E5DC4A-F899-48D9-8586-408A39C0324B}.Release|Any CPU.ActiveCfg = Release|x64 + {E6E5DC4A-F899-48D9-8586-408A39C0324B}.Release|Any CPU.Build.0 = Release|x64 + {E6E5DC4A-F899-48D9-8586-408A39C0324B}.Release|arm64.ActiveCfg = Release|arm64 + {E6E5DC4A-F899-48D9-8586-408A39C0324B}.Release|arm64.Build.0 = Release|arm64 + {E6E5DC4A-F899-48D9-8586-408A39C0324B}.Release|x64.ActiveCfg = Release|x64 + {E6E5DC4A-F899-48D9-8586-408A39C0324B}.Release|x64.Build.0 = Release|x64 + {E6E5DC4A-F899-48D9-8586-408A39C0324B}.Release|x86.ActiveCfg = Release|x86 + {E6E5DC4A-F899-48D9-8586-408A39C0324B}.Release|x86.Build.0 = Release|x86 + {334BEA82-395E-4012-8BA6-77161EE7AED6}.Debug|Any CPU.ActiveCfg = Debug|x64 + {334BEA82-395E-4012-8BA6-77161EE7AED6}.Debug|Any CPU.Build.0 = Debug|x64 + {334BEA82-395E-4012-8BA6-77161EE7AED6}.Debug|arm64.ActiveCfg = Debug|arm64 + {334BEA82-395E-4012-8BA6-77161EE7AED6}.Debug|arm64.Build.0 = Debug|arm64 + {334BEA82-395E-4012-8BA6-77161EE7AED6}.Debug|x64.ActiveCfg = Debug|x64 + {334BEA82-395E-4012-8BA6-77161EE7AED6}.Debug|x64.Build.0 = Debug|x64 + {334BEA82-395E-4012-8BA6-77161EE7AED6}.Debug|x86.ActiveCfg = Debug|x86 + {334BEA82-395E-4012-8BA6-77161EE7AED6}.Debug|x86.Build.0 = Debug|x86 + {334BEA82-395E-4012-8BA6-77161EE7AED6}.Release|Any CPU.ActiveCfg = Release|x64 + {334BEA82-395E-4012-8BA6-77161EE7AED6}.Release|Any CPU.Build.0 = Release|x64 + {334BEA82-395E-4012-8BA6-77161EE7AED6}.Release|arm64.ActiveCfg = Release|arm64 + {334BEA82-395E-4012-8BA6-77161EE7AED6}.Release|arm64.Build.0 = Release|arm64 + {334BEA82-395E-4012-8BA6-77161EE7AED6}.Release|x64.ActiveCfg = Release|x64 + {334BEA82-395E-4012-8BA6-77161EE7AED6}.Release|x64.Build.0 = Release|x64 + {334BEA82-395E-4012-8BA6-77161EE7AED6}.Release|x86.ActiveCfg = Release|x86 + {334BEA82-395E-4012-8BA6-77161EE7AED6}.Release|x86.Build.0 = Release|x86 + {A94C923B-A34B-4FE4-A8E0-B1CB74976B11}.Debug|Any CPU.ActiveCfg = Debug|x64 + {A94C923B-A34B-4FE4-A8E0-B1CB74976B11}.Debug|Any CPU.Build.0 = Debug|x64 + {A94C923B-A34B-4FE4-A8E0-B1CB74976B11}.Debug|arm64.ActiveCfg = Debug|arm64 + {A94C923B-A34B-4FE4-A8E0-B1CB74976B11}.Debug|arm64.Build.0 = Debug|arm64 + {A94C923B-A34B-4FE4-A8E0-B1CB74976B11}.Debug|x64.ActiveCfg = Debug|x64 + {A94C923B-A34B-4FE4-A8E0-B1CB74976B11}.Debug|x64.Build.0 = Debug|x64 + {A94C923B-A34B-4FE4-A8E0-B1CB74976B11}.Debug|x86.ActiveCfg = Debug|x86 + {A94C923B-A34B-4FE4-A8E0-B1CB74976B11}.Debug|x86.Build.0 = Debug|x86 + {A94C923B-A34B-4FE4-A8E0-B1CB74976B11}.Release|Any CPU.ActiveCfg = Release|x64 + {A94C923B-A34B-4FE4-A8E0-B1CB74976B11}.Release|Any CPU.Build.0 = Release|x64 + {A94C923B-A34B-4FE4-A8E0-B1CB74976B11}.Release|arm64.ActiveCfg = Release|arm64 + {A94C923B-A34B-4FE4-A8E0-B1CB74976B11}.Release|arm64.Build.0 = Release|arm64 + {A94C923B-A34B-4FE4-A8E0-B1CB74976B11}.Release|x64.ActiveCfg = Release|x64 + {A94C923B-A34B-4FE4-A8E0-B1CB74976B11}.Release|x64.Build.0 = Release|x64 + {A94C923B-A34B-4FE4-A8E0-B1CB74976B11}.Release|x86.ActiveCfg = Release|x86 + {A94C923B-A34B-4FE4-A8E0-B1CB74976B11}.Release|x86.Build.0 = Release|x86 + {728D53B2-FE17-44A2-A534-9DFDDF2D46EA}.Debug|Any CPU.ActiveCfg = Debug|x64 + {728D53B2-FE17-44A2-A534-9DFDDF2D46EA}.Debug|Any CPU.Build.0 = Debug|x64 + {728D53B2-FE17-44A2-A534-9DFDDF2D46EA}.Debug|arm64.ActiveCfg = Debug|arm64 + {728D53B2-FE17-44A2-A534-9DFDDF2D46EA}.Debug|arm64.Build.0 = Debug|arm64 + {728D53B2-FE17-44A2-A534-9DFDDF2D46EA}.Debug|x64.ActiveCfg = Debug|x64 + {728D53B2-FE17-44A2-A534-9DFDDF2D46EA}.Debug|x64.Build.0 = Debug|x64 + {728D53B2-FE17-44A2-A534-9DFDDF2D46EA}.Debug|x86.ActiveCfg = Debug|x86 + {728D53B2-FE17-44A2-A534-9DFDDF2D46EA}.Debug|x86.Build.0 = Debug|x86 + {728D53B2-FE17-44A2-A534-9DFDDF2D46EA}.Release|Any CPU.ActiveCfg = Release|x64 + {728D53B2-FE17-44A2-A534-9DFDDF2D46EA}.Release|Any CPU.Build.0 = Release|x64 + {728D53B2-FE17-44A2-A534-9DFDDF2D46EA}.Release|arm64.ActiveCfg = Release|arm64 + {728D53B2-FE17-44A2-A534-9DFDDF2D46EA}.Release|arm64.Build.0 = Release|arm64 + {728D53B2-FE17-44A2-A534-9DFDDF2D46EA}.Release|x64.ActiveCfg = Release|x64 + {728D53B2-FE17-44A2-A534-9DFDDF2D46EA}.Release|x64.Build.0 = Release|x64 + {728D53B2-FE17-44A2-A534-9DFDDF2D46EA}.Release|x86.ActiveCfg = Release|x86 + {728D53B2-FE17-44A2-A534-9DFDDF2D46EA}.Release|x86.Build.0 = Release|x86 + {D9D6EDD9-C919-D3FC-DAE3-1908A1A96318}.Debug|Any CPU.ActiveCfg = Debug|x64 + {D9D6EDD9-C919-D3FC-DAE3-1908A1A96318}.Debug|Any CPU.Build.0 = Debug|x64 + {D9D6EDD9-C919-D3FC-DAE3-1908A1A96318}.Debug|arm64.ActiveCfg = Debug|arm64 + {D9D6EDD9-C919-D3FC-DAE3-1908A1A96318}.Debug|arm64.Build.0 = Debug|arm64 + {D9D6EDD9-C919-D3FC-DAE3-1908A1A96318}.Debug|x64.ActiveCfg = Debug|x64 + {D9D6EDD9-C919-D3FC-DAE3-1908A1A96318}.Debug|x64.Build.0 = Debug|x64 + {D9D6EDD9-C919-D3FC-DAE3-1908A1A96318}.Debug|x86.ActiveCfg = Debug|x86 + {D9D6EDD9-C919-D3FC-DAE3-1908A1A96318}.Debug|x86.Build.0 = Debug|x86 + {D9D6EDD9-C919-D3FC-DAE3-1908A1A96318}.Release|Any CPU.ActiveCfg = Release|x64 + {D9D6EDD9-C919-D3FC-DAE3-1908A1A96318}.Release|Any CPU.Build.0 = Release|x64 + {D9D6EDD9-C919-D3FC-DAE3-1908A1A96318}.Release|arm64.ActiveCfg = Release|arm64 + {D9D6EDD9-C919-D3FC-DAE3-1908A1A96318}.Release|arm64.Build.0 = Release|arm64 + {D9D6EDD9-C919-D3FC-DAE3-1908A1A96318}.Release|x64.ActiveCfg = Release|x64 + {D9D6EDD9-C919-D3FC-DAE3-1908A1A96318}.Release|x64.Build.0 = Release|x64 + {D9D6EDD9-C919-D3FC-DAE3-1908A1A96318}.Release|x86.ActiveCfg = Release|x86 + {D9D6EDD9-C919-D3FC-DAE3-1908A1A96318}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {44312322-DEA7-4BDE-8930-AFEAB72CA425} + EndGlobalSection + GlobalSection(MonoDevelopProperties) = preSolution + Policies = $0 + $0.TextStylePolicy = $3 + $1.inheritsSet = null + $1.scope = application/x-msbuild + $0.XmlFormattingPolicy = $4 + $2.inheritsSet = null + $2.scope = application/x-msbuild + $3.inheritsSet = null + $3.scope = application/xml + $4.scope = application/xml + $0.StandardHeader = $5 + EndGlobalSection +EndGlobal diff --git a/bindings/netstandard/ElectionGuard/README.md b/bindings/netstandard/ElectionGuard/README.md index e3fbcf8ce..52a197392 100644 --- a/bindings/netstandard/ElectionGuard/README.md +++ b/bindings/netstandard/ElectionGuard/README.md @@ -1,5 +1,5 @@ -# ElectionGuard - -ElectionGuard is an open source software development kit (SDK) that makes voting more secure, transparent and accessible. The ElectionGuard SDK leverages homomorphic encryption to ensure that votes recorded by electronic systems of any type remain encrypted, secure, and secret. Meanwhile, ElectionGuard also allows verifiable and accurate tallying of ballots by any 3rd party organization without compromising secrecy or security. - -Learn More in the [ElectionGuard Repository](https://github.com/microsoft/electionguard) +# ElectionGuard + +ElectionGuard is an open source software development kit (SDK) that makes voting more secure, transparent and accessible. The ElectionGuard SDK leverages homomorphic encryption to ensure that votes recorded by electronic systems of any type remain encrypted, secure, and secret. Meanwhile, ElectionGuard also allows verifiable and accurate tallying of ballots by any 3rd party organization without compromising secrecy or security. + +Learn More in the [ElectionGuard Repository](https://github.com/microsoft/electionguard) diff --git a/cmake/tools.cmake b/cmake/tools.cmake index 27ef28ef6..81543159d 100644 --- a/cmake/tools.cmake +++ b/cmake/tools.cmake @@ -5,7 +5,7 @@ option(CODE_COVERAGE "Enable code coverage" OFF) option(USE_STATIC_ANALYSIS "use static analysis tools" OFF) option(USE_DYNAMIC_ANALYSIS "use dynamic analysis tools" OFF) -option(USE_FORMATTING "use formatting tools" ON) +option(USE_FORMATTING "use formatting tools" OFF) function(use_valgrind TARGET_NAME) set(VALGRIND_LOG ${PROJECT_BINARY_DIR}/valgrind.log) @@ -20,7 +20,7 @@ function(use_valgrind TARGET_NAME) endfunction() # ---- Dependencies ---- -include(cmake/CPM.cmake) +include(cmake/CPM_0.31.0.cmake) CPMAddPackage( NAME StableCoder-cmake-scripts @@ -111,7 +111,7 @@ if(USE_DYNAMIC_ANALYSIS) endif() endif() -if(USE_FORMATTING) - message("++ Running with formatting") - include(${StableCoder-cmake-scripts_SOURCE_DIR}/formatting.cmake) -endif() +#if(USE_FORMATTING) +# message("++ Running with formatting") +# include(${StableCoder-cmake-scripts_SOURCE_DIR}/formatting.cmake) +#endif() diff --git a/libs/hacl/CMakeLists.txt b/libs/hacl/CMakeLists.txt index 1090c734d..aa3515b8a 100644 --- a/libs/hacl/CMakeLists.txt +++ b/libs/hacl/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.14...3.16 FATAL_ERROR) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../cmake") # ---- Dependencies ---- -include(../../cmake/CPM.cmake) +include(../../cmake/CPM_0.31.0.cmake) if(MSVC) set(HACL_CUSTOM_CONFIG_FILE_PATH ${PROJECT_SOURCE_DIR}/libs/hacl/config.msvc.cmake) diff --git a/scripts/build.cake b/scripts/build.cake index f77fdc9e3..d0d407258 100644 --- a/scripts/build.cake +++ b/scripts/build.cake @@ -1,43 +1,48 @@ using System.Xml.Linq; -var target = HasArgument("target") ? Argument("target", "Build") : Argument("t", "Build"); +var target = HasArgument("target") ? Argument("target", "Build") : Argument("t", "Build"); var configuration = Argument("configuration", "Release"); var encryptionProj = "../bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/ElectionGuard.Encryption.csproj"; +var decryptionProj = "../bindings/netstandard/ElectionGuard/ElectionGuard.Decryption/ElectionGuard.Decryption.csproj"; +var setupProj = "../bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/ElectionGuard.ElectionSetup.csproj"; + +var projects = new[] { encryptionProj, decryptionProj, setupProj }; Task("AssignVersion") .Does(() => { - var csprojFile = Argument("csproj", encryptionProj); var newVersion = Argument("newVersion", ""); - if (string.IsNullOrEmpty(newVersion)) { throw new InvalidOperationException("Both csproj and newVersion arguments must be provided."); } - var xdoc = XDocument.Load(csprojFile); - var ns = xdoc.Root.GetDefaultNamespace(); - var versionElement = xdoc.Descendants(ns + "Version").FirstOrDefault(); - var packageVersionElement = xdoc.Descendants(ns + "PackageVersion").FirstOrDefault(); - - if (versionElement == null) + foreach (var csprojFile in projects) { - throw new InvalidOperationException($"No 'Version' element found in the '{csprojFile}'."); + var xdoc = XDocument.Load(csprojFile); + var ns = xdoc.Root.GetDefaultNamespace(); + var versionElement = xdoc.Descendants(ns + "Version").FirstOrDefault(); + var packageVersionElement = xdoc.Descendants(ns + "PackageVersion").FirstOrDefault(); + + if (versionElement == null) + { + throw new InvalidOperationException($"No 'Version' element found in '{csprojFile}'."); + } + + if (packageVersionElement == null) + { + throw new InvalidOperationException($"No 'PackageVersion' element found in '{csprojFile}'."); + } + + versionElement.Value = newVersion; + packageVersionElement.Value = newVersion; + xdoc.Save(csprojFile); } - - if (packageVersionElement == null) - { - throw new InvalidOperationException($"No 'PackageVersion' element found in the '{csprojFile}'."); - } - - versionElement.Value = newVersion; - packageVersionElement.Value = newVersion; - xdoc.Save(csprojFile); }); ////////////////////////////////////////////////////////////////////// // EXECUTION ////////////////////////////////////////////////////////////////////// -RunTarget(target); \ No newline at end of file +RunTarget(target); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9c78ba23b..f257921c2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.14...3.16 FATAL_ERROR) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../cmake") # ---- Dependencies ---- -include(../cmake/CPM.cmake) +include(../cmake/CPM_0.31.0.cmake) CPMAddPackage( NAME date @@ -266,7 +266,7 @@ if(CODE_COVERAGE) target_code_coverage(${META_PROJECT_TARGET} AUTO) endif() -if(USE_FORMATTING) - message("++ Building with formatting") - clang_format(format ${PROJECT_SOURCE_FILES}) -endif() +#if(USE_FORMATTING) +# message("++ Building with formatting") +# clang_format(format ${PROJECT_SOURCE_FILES}) +#endif() diff --git a/src/electionguard-ui/Directory.Packages.props b/src/electionguard-ui/Directory.Packages.props index 3db6fdda5..e641f943a 100644 --- a/src/electionguard-ui/Directory.Packages.props +++ b/src/electionguard-ui/Directory.Packages.props @@ -8,6 +8,8 @@ + + diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/ElectionGuard.UI.Lib.csproj b/src/electionguard-ui/ElectionGuard.UI.Lib/ElectionGuard.UI.Lib.csproj index 3ab8fb863..faf507f7e 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/ElectionGuard.UI.Lib.csproj +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/ElectionGuard.UI.Lib.csproj @@ -1,6 +1,6 @@  - net7.0 + net9.0 true enable enable @@ -14,6 +14,7 @@ + diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Exceptions/KeyCeremonyException.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Exceptions/KeyCeremonyException.cs similarity index 88% rename from bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Exceptions/KeyCeremonyException.cs rename to src/electionguard-ui/ElectionGuard.UI.Lib/Exceptions/KeyCeremonyException.cs index f2e516d32..d02485eae 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Exceptions/KeyCeremonyException.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Exceptions/KeyCeremonyException.cs @@ -1,23 +1,23 @@ -using ElectionGuard.UI.Lib.Models; - -namespace ElectionGuard.ElectionSetup.Exceptions -{ - internal class KeyCeremonyException : Exception - { - public KeyCeremonyState State { get; set; } - public string GuardianId { get; set; } - - public string KeyCeremonyId { get; set; } - - public KeyCeremonyException( - KeyCeremonyState state, - string keyCeremonyId, - string guardian, - string? message = null) : base(message) - { - State = state; - KeyCeremonyId = keyCeremonyId; - GuardianId = guardian; - } - } -} +using ElectionGuard.UI.Lib.Models; + +namespace ElectionGuard.UI.Lib.Exceptions +{ + internal class KeyCeremonyException : Exception + { + public KeyCeremonyState State { get; set; } + public string GuardianId { get; set; } + + public string KeyCeremonyId { get; set; } + + public KeyCeremonyException( + KeyCeremonyState state, + string keyCeremonyId, + string guardian, + string? message = null) : base(message) + { + State = state; + KeyCeremonyId = keyCeremonyId; + GuardianId = guardian; + } + } +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/BallotRecord.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/BallotRecord.cs index ec4df3be4..fba219768 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/BallotRecord.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/BallotRecord.cs @@ -1,32 +1,32 @@ -namespace ElectionGuard.UI.Lib.Models; - -public partial class BallotRecord : DatabaseRecord -{ - [ObservableProperty] - private string? _electionId; - - [ObservableProperty] - private string? _uploadId; - - [ObservableProperty] - private string? _fileName; - - [ObservableProperty] - private string? _ballotCode; - - [ObservableProperty] - private BallotBoxState _ballotState; - - [ObservableProperty] - private DateTime _timeStamp; - - [ObservableProperty] - private string? _ballotData; - - public BallotRecord() : base(nameof(BallotRecord)) - { - } - - public override string ToString() => BallotData ?? string.Empty; - public static implicit operator string(BallotRecord? record) => record?.ToString() ?? string.Empty; -} +namespace ElectionGuard.UI.Lib.Models; + +public partial class BallotRecord : DatabaseRecord +{ + [ObservableProperty] + private string? _electionId; + + [ObservableProperty] + private string? _uploadId; + + [ObservableProperty] + private string? _fileName; + + [ObservableProperty] + private string? _ballotCode; + + [ObservableProperty] + private BallotBoxState _ballotState; + + [ObservableProperty] + private DateTime _timeStamp; + + [ObservableProperty] + private string? _ballotData; + + public BallotRecord() : base(nameof(BallotRecord)) + { + } + + public override string ToString() => BallotData ?? string.Empty; + public static implicit operator string(BallotRecord? record) => record?.ToString() ?? string.Empty; +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/BallotUpload.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/BallotUpload.cs index 7fc095e08..964815afc 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/BallotUpload.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/BallotUpload.cs @@ -1,67 +1,67 @@ -namespace ElectionGuard.UI.Lib.Models; - -public partial class BallotUpload : DatabaseRecord -{ - [ObservableProperty] - private string? _electionId; - - [ObservableProperty] - private string? _uploadId; - - [ObservableProperty] - private string? _deviceFileName; - - [ObservableProperty] - private string? _deviceFileContents; - - [ObservableProperty] - private string? _location; - - [ObservableProperty] - private long _launchCode; - - [ObservableProperty] - private long _deviceId; - - [ObservableProperty] - private long _sessionId; - - [ObservableProperty] - private long _ballotCount; - - [ObservableProperty] - private long _ballotImported; - - [ObservableProperty] - private long _ballotChallenged; - - [ObservableProperty] - private long _ballotSpoiled; - - [ObservableProperty] - private long _ballotDuplicated; - - [ObservableProperty] - private long _ballotRejected; - - [ObservableProperty] - private long _serialNumber; - - [ObservableProperty] - private string? _createdBy; - - [ObservableProperty] - private DateTime _createdAt; - - [ObservableProperty] - private DateTime _ballotsStart; - - [ObservableProperty] - private DateTime _ballotsEnd; - - public BallotUpload() : base(nameof(BallotUpload)) - { - UploadId = Guid.NewGuid().ToString(); - CreatedAt = DateTime.UtcNow; - } -} +namespace ElectionGuard.UI.Lib.Models; + +public partial class BallotUpload : DatabaseRecord +{ + [ObservableProperty] + private string? _electionId; + + [ObservableProperty] + private string? _uploadId; + + [ObservableProperty] + private string? _deviceFileName; + + [ObservableProperty] + private string? _deviceFileContents; + + [ObservableProperty] + private string? _location; + + [ObservableProperty] + private long _launchCode; + + [ObservableProperty] + private long _deviceId; + + [ObservableProperty] + private long _sessionId; + + [ObservableProperty] + private long _ballotCount; + + [ObservableProperty] + private long _ballotImported; + + [ObservableProperty] + private long _ballotChallenged; + + [ObservableProperty] + private long _ballotSpoiled; + + [ObservableProperty] + private long _ballotDuplicated; + + [ObservableProperty] + private long _ballotRejected; + + [ObservableProperty] + private long _serialNumber; + + [ObservableProperty] + private string? _createdBy; + + [ObservableProperty] + private DateTime _createdAt; + + [ObservableProperty] + private DateTime _ballotsStart; + + [ObservableProperty] + private DateTime _ballotsEnd; + + public BallotUpload() : base(nameof(BallotUpload)) + { + UploadId = Guid.NewGuid().ToString(); + CreatedAt = DateTime.UtcNow; + } +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/ChallengedBallotRecord.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/ChallengedBallotRecord.cs index c7a0b8835..2653cf800 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/ChallengedBallotRecord.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/ChallengedBallotRecord.cs @@ -1,23 +1,23 @@ -namespace ElectionGuard.UI.Lib.Models; - -public partial class ChallengedBallotRecord : DatabaseRecord -{ - [ObservableProperty] - private string _electionId = string.Empty; - - [ObservableProperty] - private string _tallyId = string.Empty; - - [ObservableProperty] - private string _ballotCode = string.Empty; - - [ObservableProperty] - private string _ballotData = string.Empty; - - public ChallengedBallotRecord() : base(nameof(ChallengedBallotRecord)) - { - } - - public override string ToString() => BallotData ?? string.Empty; - public static implicit operator string(ChallengedBallotRecord? record) => record?.ToString() ?? string.Empty; -} +namespace ElectionGuard.UI.Lib.Models; + +public partial class ChallengedBallotRecord : DatabaseRecord +{ + [ObservableProperty] + private string _electionId = string.Empty; + + [ObservableProperty] + private string _tallyId = string.Empty; + + [ObservableProperty] + private string _ballotCode = string.Empty; + + [ObservableProperty] + private string _ballotData = string.Empty; + + public ChallengedBallotRecord() : base(nameof(ChallengedBallotRecord)) + { + } + + public override string ToString() => BallotData ?? string.Empty; + public static implicit operator string(ChallengedBallotRecord? record) => record?.ToString() ?? string.Empty; +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/CiphertextTallyRecord.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/CiphertextTallyRecord.cs index 837dcf69d..c6e2bfab4 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/CiphertextTallyRecord.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/CiphertextTallyRecord.cs @@ -1,27 +1,27 @@ -namespace ElectionGuard.UI.Lib.Models; - -public partial class CiphertextTallyRecord : DatabaseRecord -{ - [ObservableProperty] - private string _tallyId = string.Empty; - - [ObservableProperty] - private string _electionId = string.Empty; - - [ObservableProperty] - private string _uploadId = string.Empty; - - [ObservableProperty] - private bool _isExportable = false; - - [ObservableProperty] - private string _ciphertextTallyData = string.Empty; - - public CiphertextTallyRecord() : base(nameof(CiphertextTallyRecord)) - { - } - - public override string ToString() => CiphertextTallyData ?? string.Empty; - public static implicit operator string(CiphertextTallyRecord? record) => record?.ToString() ?? string.Empty; - -} +namespace ElectionGuard.UI.Lib.Models; + +public partial class CiphertextTallyRecord : DatabaseRecord +{ + [ObservableProperty] + private string _tallyId = string.Empty; + + [ObservableProperty] + private string _electionId = string.Empty; + + [ObservableProperty] + private string _uploadId = string.Empty; + + [ObservableProperty] + private bool _isExportable = false; + + [ObservableProperty] + private string _ciphertextTallyData = string.Empty; + + public CiphertextTallyRecord() : base(nameof(CiphertextTallyRecord)) + { + } + + public override string ToString() => CiphertextTallyData ?? string.Empty; + public static implicit operator string(CiphertextTallyRecord? record) => record?.ToString() ?? string.Empty; + +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/ConstantsRecord.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/ConstantsRecord.cs index af1b42b02..b1ff3a0fd 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/ConstantsRecord.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/ConstantsRecord.cs @@ -1,23 +1,23 @@ -namespace ElectionGuard.UI.Lib.Models; - -public partial class ConstantsRecord : DatabaseRecord -{ - [ObservableProperty] - private string? _electionId; - - [ObservableProperty] - private string? _constantsData; - - public ConstantsRecord(string electionId, string constantsData) : base(nameof(ConstantsRecord)) - { - ElectionId = electionId; - ConstantsData = constantsData; - } - - public ConstantsRecord() : base(nameof(ConstantsRecord)) - { - } - - public override string ToString() => ConstantsData ?? string.Empty; - public static implicit operator string(ConstantsRecord? record) => record?.ToString() ?? string.Empty; -} +namespace ElectionGuard.UI.Lib.Models; + +public partial class ConstantsRecord : DatabaseRecord +{ + [ObservableProperty] + private string? _electionId; + + [ObservableProperty] + private string? _constantsData; + + public ConstantsRecord(string electionId, string constantsData) : base(nameof(ConstantsRecord)) + { + ElectionId = electionId; + ConstantsData = constantsData; + } + + public ConstantsRecord() : base(nameof(ConstantsRecord)) + { + } + + public override string ToString() => ConstantsData ?? string.Empty; + public static implicit operator string(ConstantsRecord? record) => record?.ToString() ?? string.Empty; +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/ContestItem.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/ContestItem.cs index 51526fede..2912cdef4 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/ContestItem.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/ContestItem.cs @@ -1,15 +1,15 @@ -using System.Collections.ObjectModel; - -namespace ElectionGuard.UI.Lib.Models; - -public partial class ContestItem : ObservableObject -{ - [ObservableProperty] - private string _name = string.Empty; - - [ObservableProperty] - private ObservableCollection _selections = new(); - - [ObservableProperty] - private ulong _totalVotes = 0; -} +using System.Collections.ObjectModel; + +namespace ElectionGuard.UI.Lib.Models; + +public partial class ContestItem : ObservableObject +{ + [ObservableProperty] + private string _name = string.Empty; + + [ObservableProperty] + private ObservableCollection _selections = new(); + + [ObservableProperty] + private ulong _totalVotes = 0; +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/ContextRecord.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/ContextRecord.cs index 8465b3085..7b66fd17d 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/ContextRecord.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/ContextRecord.cs @@ -1,17 +1,17 @@ -namespace ElectionGuard.UI.Lib.Models; - -public partial class ContextRecord : DatabaseRecord -{ - [ObservableProperty] - private string? _electionId; - - [ObservableProperty] - private string? _contextData; - - public ContextRecord() : base(nameof(ContextRecord)) - { - } - - public override string ToString() => ContextData ?? string.Empty; - public static implicit operator string(ContextRecord? record) => record?.ToString() ?? string.Empty; -} +namespace ElectionGuard.UI.Lib.Models; + +public partial class ContextRecord : DatabaseRecord +{ + [ObservableProperty] + private string? _electionId; + + [ObservableProperty] + private string? _contextData; + + public ContextRecord() : base(nameof(ContextRecord)) + { + } + + public override string ToString() => ContextData ?? string.Empty; + public static implicit operator string(ContextRecord? record) => record?.ToString() ?? string.Empty; +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/DatabaseRecord.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/DatabaseRecord.cs index 16ee42b2a..b3be73744 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/DatabaseRecord.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/DatabaseRecord.cs @@ -1,22 +1,22 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; - - -namespace ElectionGuard.UI.Lib.Models; - -public class DatabaseRecord : ObservableObject -{ - [BsonRepresentation(BsonType.ObjectId)] - public string Id { get; set; } - - public string DataType { get; set; } - - public bool SoftDeleted { get; set; } - - public DatabaseRecord(string dataType) - { - Id = MongoDB.Bson.ObjectId.GenerateNewId().ToString(); - DataType = dataType; - SoftDeleted = false; - } -} +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; + + +namespace ElectionGuard.UI.Lib.Models; + +public class DatabaseRecord : ObservableObject +{ + [BsonRepresentation(BsonType.ObjectId)] + public string Id { get; set; } + + public string DataType { get; set; } + + public bool SoftDeleted { get; set; } + + public DatabaseRecord(string dataType) + { + Id = MongoDB.Bson.ObjectId.GenerateNewId().ToString(); + DataType = dataType; + SoftDeleted = false; + } +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/Election.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/Election.cs index 998d84a4b..97b242a89 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/Election.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/Election.cs @@ -1,32 +1,32 @@ -namespace ElectionGuard.UI.Lib.Models; - -public partial class Election : DatabaseRecord -{ - [ObservableProperty] - private string? _electionId; - - [ObservableProperty] - private string? _name; - - [ObservableProperty] - private string? _electionUrl; - - [ObservableProperty] - private string? _keyCeremonyId; - - [ObservableProperty] - private DateTime? _exportEncryptionDateTime; - - [ObservableProperty] - private string? _createdBy; - - [ObservableProperty] - private DateTime _createdAt; - - public Election() : base(nameof(Election)) - { - ElectionId = Guid.NewGuid().ToString(); - CreatedAt = DateTime.UtcNow; - } - -} +namespace ElectionGuard.UI.Lib.Models; + +public partial class Election : DatabaseRecord +{ + [ObservableProperty] + private string? _electionId; + + [ObservableProperty] + private string? _name; + + [ObservableProperty] + private string? _electionUrl; + + [ObservableProperty] + private string? _keyCeremonyId; + + [ObservableProperty] + private DateTime? _exportEncryptionDateTime; + + [ObservableProperty] + private string? _createdBy; + + [ObservableProperty] + private DateTime _createdAt; + + public Election() : base(nameof(Election)) + { + ElectionId = Guid.NewGuid().ToString(); + CreatedAt = DateTime.UtcNow; + } + +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/ElectionItem.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/ElectionItem.cs index 3c05ce953..c5f371cdb 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/ElectionItem.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/ElectionItem.cs @@ -1,33 +1,33 @@ -using System.Collections.ObjectModel; - -namespace ElectionGuard.UI.Lib.Models; - -public partial class ElectionItem : ObservableObject -{ - [ObservableProperty] - private Election? _election; - - [ObservableProperty] - private string _tallyId = string.Empty; - - [ObservableProperty] - private ObservableCollection _ballotUploads = new(); - - [ObservableProperty] - private long _ballotAddedTotal; - - [ObservableProperty] - private long _ballotChallengedTotal; - - [ObservableProperty] - private long _ballotSpoiledTotal; - - [ObservableProperty] - private long _ballotDuplicateTotal; - - [ObservableProperty] - private long _ballotRejectedTotal; - - [ObservableProperty] - private long _ballotCountTotal; -} +using System.Collections.ObjectModel; + +namespace ElectionGuard.UI.Lib.Models; + +public partial class ElectionItem : ObservableObject +{ + [ObservableProperty] + private Election? _election; + + [ObservableProperty] + private string _tallyId = string.Empty; + + [ObservableProperty] + private ObservableCollection _ballotUploads = new(); + + [ObservableProperty] + private long _ballotAddedTotal; + + [ObservableProperty] + private long _ballotChallengedTotal; + + [ObservableProperty] + private long _ballotSpoiledTotal; + + [ObservableProperty] + private long _ballotDuplicateTotal; + + [ObservableProperty] + private long _ballotRejectedTotal; + + [ObservableProperty] + private long _ballotCountTotal; +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/ElectionPartialKeyBackup.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/ElectionPartialKeyBackup.cs index 92eea7e74..40b442532 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/ElectionPartialKeyBackup.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/ElectionPartialKeyBackup.cs @@ -1,4 +1,6 @@ -namespace ElectionGuard.UI.Lib.Models; +using ElectionGuard.ElectionSetup.Records; + +namespace ElectionGuard.UI.Lib.Models; /// /// Election partial key backup used for key sharing @@ -23,6 +25,7 @@ public class ElectionPartialKeyBackup : DisposableBase public HashedElGamalCiphertext EncryptedCoordinate { get; set; } + public ElectionPartialKeyBackup( string ownerId, ulong ownerSequenceOrder, @@ -45,6 +48,19 @@ public ElectionPartialKeyBackup(ElectionPartialKeyBackup other) DesignatedSequenceOrder = other.DesignatedSequenceOrder; EncryptedCoordinate = new(other.EncryptedCoordinate); } + public ElectionPartialKeyBackup(ElectionPartialKeyBackupRecord contract) + { + OwnerId = contract.OwnerId; + OwnerSequenceOrder = contract.OwnerSequenceOrder; + DesignatedId = contract.DesignatedId; + DesignatedSequenceOrder = contract.DesignatedSequenceOrder; + EncryptedCoordinate = contract.EncryptedCoordinate; + } + + public ElectionPartialKeyBackupRecord ToRecord() + { + return new(OwnerId, OwnerSequenceOrder, DesignatedId, DesignatedSequenceOrder, EncryptedCoordinate); + } protected override void DisposeUnmanaged() { diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/ElectionPartialKeyVerification.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/ElectionPartialKeyVerification.cs index 37dab5879..a55498665 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/ElectionPartialKeyVerification.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/ElectionPartialKeyVerification.cs @@ -1,27 +1,40 @@ -namespace ElectionGuard.UI.Lib.Models; - -/// -/// Verification of election partial key used in key sharing -/// -public class ElectionPartialKeyVerification : DatabaseRecord -{ - public string? KeyCeremonyId { get; set; } - public string? OwnerId { get; init; } - public string? DesignatedId { get; init; } - public string? VerifierId { get; init; } - public bool Verified { get; init; } - - public ElectionPartialKeyVerification() : base(nameof(ElectionPartialKeyVerification)) - { - - } - - public ElectionPartialKeyVerification(ElectionPartialKeyVerification other) : base(nameof(ElectionPartialKeyVerification)) - { - KeyCeremonyId = other.KeyCeremonyId; - OwnerId = other.OwnerId; - DesignatedId = other.DesignatedId; - VerifierId = other.VerifierId; - Verified = other.Verified; - } -} +using ElectionGuard.ElectionSetup.Records; + +namespace ElectionGuard.UI.Lib.Models; + +/// +/// Verification of election partial key used in key sharing +/// +public class ElectionPartialKeyVerification : DatabaseRecord +{ + public string? KeyCeremonyId { get; set; } + public string? OwnerId { get; init; } + public string? DesignatedId { get; init; } + public string? VerifierId { get; init; } + public bool Verified { get; init; } + + + public ElectionPartialKeyVerification() : base(nameof(ElectionPartialKeyVerification)) + { + + } + + public ElectionPartialKeyVerification(ElectionPartialKeyVerification other) : base(nameof(ElectionPartialKeyVerification)) + { + KeyCeremonyId = other.KeyCeremonyId; + OwnerId = other.OwnerId; + DesignatedId = other.DesignatedId; + VerifierId = other.VerifierId; + Verified = other.Verified; + } + public ElectionPartialKeyVerification(ElectionPartialKeyVerificationRecord record) : base(nameof(ElectionPartialKeyVerification)) + { + KeyCeremonyId = record.KeyCeremonyId; + OwnerId = record.OwnerId; + DesignatedId = record.DesignatedId; + VerifierId = record.VerifierId; + Verified = record.Verified; + } + + +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/FileContent.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/FileContent.cs index 2f4dc1a1e..f5d9a71ae 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/FileContent.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/FileContent.cs @@ -1,6 +1,6 @@ -namespace ElectionGuard.UI.Lib.Models; - -/// -/// structure to hold data for files to write to zip file -/// -public record FileContents(string FileName, string Contents); +namespace ElectionGuard.UI.Lib.Models; + +/// +/// structure to hold data for files to write to zip file +/// +public record FileContents(string FileName, string Contents); diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/GuardianBackups.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/GuardianBackups.cs index 837ffb0d3..5d1ea97c9 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/GuardianBackups.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/GuardianBackups.cs @@ -1,41 +1,51 @@ -namespace ElectionGuard.UI.Lib.Models; - -public class GuardianBackups : DatabaseRecord, IDisposable -{ - public string? KeyCeremonyId { get; set; } - - public string? GuardianId { get; set; } - - public string? DesignatedId { get; set; } - - public ElectionPartialKeyBackup? Backup { get; set; } - - public GuardianBackups() : base(nameof(GuardianBackups)) - { - } - - public GuardianBackups( - string keyCeremonyId, - string guardianId, - string designatedId, - ElectionPartialKeyBackup backup) : base(nameof(GuardianBackups)) - { - KeyCeremonyId = keyCeremonyId; - GuardianId = guardianId; - DesignatedId = designatedId; - Backup = new(backup); - } - - public GuardianBackups(GuardianBackups other) : base(nameof(GuardianBackups)) - { - KeyCeremonyId = other.KeyCeremonyId; - GuardianId = other.GuardianId; - DesignatedId = other.DesignatedId; - Backup = other.Backup != null ? new(other.Backup) : null; - } - - public void Dispose() - { - Backup?.Dispose(); - } -} +using ElectionGuard.ElectionSetup.Records; + +namespace ElectionGuard.UI.Lib.Models; + +public class GuardianBackups : DatabaseRecord, IDisposable +{ + public string? KeyCeremonyId { get; set; } + + public string? GuardianId { get; set; } + + public string? DesignatedId { get; set; } + + public ElectionPartialKeyBackup? Backup { get; set; } + + public GuardianBackups(GuardianBackups guardianBackups) : base(nameof(GuardianBackups)) + { + KeyCeremonyId = guardianBackups.KeyCeremonyId; + GuardianId = guardianBackups.GuardianId; + DesignatedId = guardianBackups.DesignatedId; + Backup = guardianBackups.Backup != null ? new ElectionPartialKeyBackup(guardianBackups.Backup) : null; + } + + public GuardianBackups() : base(nameof(GuardianBackups)) + { + } + + public GuardianBackups( + string keyCeremonyId, + string guardianId, + string designatedId, + ElectionPartialKeyBackup backup) : base(nameof(GuardianBackups)) + { + KeyCeremonyId = keyCeremonyId; + GuardianId = guardianId; + DesignatedId = designatedId; + Backup = new(backup); + } + + public GuardianBackups(GuardianBackupsRecord other) : base(nameof(GuardianBackups)) + { + KeyCeremonyId = other.KeyCeremonyId; + GuardianId = other.GuardianId; + DesignatedId = other.DesignatedId; + Backup = other.Backup != null ? new(other.Backup) : null; + } + + public void Dispose() + { + Backup?.Dispose(); + } +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/GuardianPublicKey.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/GuardianPublicKey.cs index ba16f2577..e4da48267 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/GuardianPublicKey.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/GuardianPublicKey.cs @@ -1,31 +1,31 @@ -using ElectionGuard.Guardians; - -namespace ElectionGuard.UI.Lib.Models; - - -public class GuardianPublicKey : DatabaseRecord, IDisposable -{ - // TODO: implement IElectionGuardian by including the sequence order - - public string? KeyCeremonyId { get; set; } - - public string? GuardianId { get; set; } - - public ElectionPublicKey? PublicKey { get; set; } - - public GuardianPublicKey() : base(nameof(GuardianPublicKey)) - { - } - - public GuardianPublicKey(GuardianPublicKey other) : base(nameof(GuardianPublicKey)) - { - KeyCeremonyId = other.KeyCeremonyId; - GuardianId = other.GuardianId; - PublicKey = other.PublicKey != null ? new(other.PublicKey) : null; - } - - public void Dispose() - { - PublicKey?.Dispose(); - } -} +using ElectionGuard.Guardians; + +namespace ElectionGuard.UI.Lib.Models; + + +public class GuardianPublicKey : DatabaseRecord, IDisposable +{ + // TODO: implement IElectionGuardian by including the sequence order + + public string? KeyCeremonyId { get; set; } + + public string? GuardianId { get; set; } + + public ElectionPublicKey? PublicKey { get; set; } + + public GuardianPublicKey() : base(nameof(GuardianPublicKey)) + { + } + + public GuardianPublicKey(GuardianPublicKey other) : base(nameof(GuardianPublicKey)) + { + KeyCeremonyId = other.KeyCeremonyId; + GuardianId = other.GuardianId; + PublicKey = other.PublicKey != null ? new(other.PublicKey) : null; + } + + public void Dispose() + { + PublicKey?.Dispose(); + } +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/KeyCeremonyRecord.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/KeyCeremonyRecord.cs index 4b69624de..ecc6da39d 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/KeyCeremonyRecord.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/KeyCeremonyRecord.cs @@ -1,73 +1,75 @@ -namespace ElectionGuard.UI.Lib.Models; - -/// -/// Data for the key ceremony that is saved to the database -/// -public partial class KeyCeremonyRecord : DatabaseRecord, IDisposable -{ - public KeyCeremonyRecord(string name, int numberOfGuardians, int quorum, string admin) : base(nameof(KeyCeremonyRecord)) - { - Name = name; - NumberOfGuardians = numberOfGuardians; - Quorum = quorum; - KeyCeremonyId = Guid.NewGuid().ToString(); - CreatedAt = DateTime.UtcNow; - CompletedAt = null; - State = KeyCeremonyState.PendingGuardiansJoin; - CreatedBy = admin; - } - - public KeyCeremonyRecord(KeyCeremonyRecord other) : base(nameof(KeyCeremonyRecord)) - { - KeyCeremonyId = other.KeyCeremonyId; - Name = other.Name; - Quorum = other.Quorum; - NumberOfGuardians = other.NumberOfGuardians; - JointKey = other.JointKey != null ? new(other.JointKey) : null; - CreatedBy = other.CreatedBy; - CreatedAt = other.CreatedAt; - CompletedAt = other.CompletedAt; - UpdatedAt = other.UpdatedAt; - State = other.State; - } - - [ObservableProperty] - private string? _keyCeremonyId; - - [ObservableProperty] - private string? _name; - - [ObservableProperty] - private int _quorum; - - [ObservableProperty] - private int _numberOfGuardians; - - [ObservableProperty] - private ElectionJointKey? _jointKey; - - [ObservableProperty] - private string? _createdBy; - - [ObservableProperty] - private DateTime _createdAt; - - [ObservableProperty] - private DateTime? _completedAt; - - [ObservableProperty] - private DateTime? _updatedAt; - - [ObservableProperty] - private KeyCeremonyState _state; - - public static implicit operator CeremonyDetails(KeyCeremonyRecord data) - { - return new(data.KeyCeremonyId!, data.NumberOfGuardians, data.Quorum); - } - - public void Dispose() - { - JointKey?.Dispose(); - } -} +using ElectionGuard.ElectionSetup.Records; + +namespace ElectionGuard.UI.Lib.Models; + +/// +/// Data for the key ceremony that is saved to the database +/// +public partial class KeyCeremonyRecord : DatabaseRecord, IDisposable +{ + public KeyCeremonyRecord(string name, int numberOfGuardians, int quorum, string admin) : base(nameof(KeyCeremonyRecord)) + { + Name = name; + NumberOfGuardians = numberOfGuardians; + Quorum = quorum; + KeyCeremonyId = Guid.NewGuid().ToString(); + CreatedAt = DateTime.UtcNow; + CompletedAt = null; + State = KeyCeremonyState.PendingGuardiansJoin; + CreatedBy = admin; + } + + public KeyCeremonyRecord(KeyCeremonyRecord other) : base(nameof(KeyCeremonyRecord)) + { + KeyCeremonyId = other.KeyCeremonyId; + Name = other.Name; + Quorum = other.Quorum; + NumberOfGuardians = other.NumberOfGuardians; + JointKey = other.JointKey != null ? new(other.JointKey) : null; + CreatedBy = other.CreatedBy; + CreatedAt = other.CreatedAt; + CompletedAt = other.CompletedAt; + UpdatedAt = other.UpdatedAt; + State = other.State; + } + + [ObservableProperty] + private string? _keyCeremonyId; + + [ObservableProperty] + private string? _name; + + [ObservableProperty] + private int _quorum; + + [ObservableProperty] + private int _numberOfGuardians; + + [ObservableProperty] + private ElectionJointKey? _jointKey; + + [ObservableProperty] + private string? _createdBy; + + [ObservableProperty] + private DateTime _createdAt; + + [ObservableProperty] + private DateTime? _completedAt; + + [ObservableProperty] + private DateTime? _updatedAt; + + [ObservableProperty] + private KeyCeremonyState _state; + + public static implicit operator CeremonyDetails(KeyCeremonyRecord data) + { + return new(data.KeyCeremonyId!, data.NumberOfGuardians, data.Quorum); + } + + public void Dispose() + { + JointKey?.Dispose(); + } +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/KeyCeremonyStatesEnum.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/KeyCeremonyStatesEnum.cs index 04c18a011..d7cdd9f6c 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/KeyCeremonyStatesEnum.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/KeyCeremonyStatesEnum.cs @@ -1,16 +1,16 @@ -namespace ElectionGuard.UI.Lib.Models; - -/// -/// A list of states for the key ceremony. -/// -public enum KeyCeremonyState -{ - DoesNotExist = 0, - PendingGuardiansJoin = 1, - PendingAdminAnnounce = 2, - PendingGuardianBackups = 3, - PendingAdminToShareBackups = 4, - PendingGuardiansVerifyBackups = 5, - PendingAdminToPublishJointKey = 6, - Complete = 7 -} +namespace ElectionGuard.UI.Lib.Models; + +/// +/// A list of states for the key ceremony. +/// +public enum KeyCeremonyState +{ + DoesNotExist = 0, + PendingGuardiansJoin = 1, + PendingAdminAnnounce = 2, + PendingGuardianBackups = 3, + PendingAdminToShareBackups = 4, + PendingGuardiansVerifyBackups = 5, + PendingAdminToPublishJointKey = 6, + Complete = 7 +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/LagrangeCoefficientsRecord.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/LagrangeCoefficientsRecord.cs index 55a1c6c0d..d60149581 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/LagrangeCoefficientsRecord.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/LagrangeCoefficientsRecord.cs @@ -1,17 +1,17 @@ -namespace ElectionGuard.UI.Lib.Models; - -public partial class LagrangeCoefficientsRecord : DatabaseRecord -{ - [ObservableProperty] - private string _tallyId = string.Empty; - - [ObservableProperty] - private string? _lagrangeCoefficientsData; - - public LagrangeCoefficientsRecord() : base(nameof(LagrangeCoefficientsRecord)) - { - } - - public override string ToString() => LagrangeCoefficientsData ?? string.Empty; - public static implicit operator string(LagrangeCoefficientsRecord? record) => record?.ToString() ?? string.Empty; -} +namespace ElectionGuard.UI.Lib.Models; + +public partial class LagrangeCoefficientsRecord : DatabaseRecord +{ + [ObservableProperty] + private string _tallyId = string.Empty; + + [ObservableProperty] + private string? _lagrangeCoefficientsData; + + public LagrangeCoefficientsRecord() : base(nameof(LagrangeCoefficientsRecord)) + { + } + + public override string ToString() => LagrangeCoefficientsData ?? string.Empty; + public static implicit operator string(LagrangeCoefficientsRecord? record) => record?.ToString() ?? string.Empty; +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/ManifestRecord.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/ManifestRecord.cs index 5f9e43f6e..844070c20 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/ManifestRecord.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/ManifestRecord.cs @@ -1,22 +1,22 @@ -namespace ElectionGuard.UI.Lib.Models; - -public partial class ManifestRecord : DatabaseRecord -{ - [ObservableProperty] - private string? _electionId; - - [ObservableProperty] - private string? _manifestData; - - public ManifestRecord(string electionId, string manifestData) : base(nameof(ManifestRecord)) - { - ElectionId = electionId; - ManifestData = manifestData; - } - public ManifestRecord() : base(nameof(ManifestRecord)) - { - } - - public override string ToString() => ManifestData ?? string.Empty; - public static implicit operator string(ManifestRecord? record) => record?.ToString() ?? string.Empty; -} +namespace ElectionGuard.UI.Lib.Models; + +public partial class ManifestRecord : DatabaseRecord +{ + [ObservableProperty] + private string? _electionId; + + [ObservableProperty] + private string? _manifestData; + + public ManifestRecord(string electionId, string manifestData) : base(nameof(ManifestRecord)) + { + ElectionId = electionId; + ManifestData = manifestData; + } + public ManifestRecord() : base(nameof(ManifestRecord)) + { + } + + public override string ToString() => ManifestData ?? string.Empty; + public static implicit operator string(ManifestRecord? record) => record?.ToString() ?? string.Empty; +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/MultiTallyRecord.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/MultiTallyRecord.cs index 811c700d8..e899efa35 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/MultiTallyRecord.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/MultiTallyRecord.cs @@ -1,25 +1,25 @@ -namespace ElectionGuard.UI.Lib.Models; - -public partial class MultiTallyRecord : DatabaseRecord -{ - [ObservableProperty] - private string? _name; - - [ObservableProperty] - private string? _multiTallyId; - - [ObservableProperty] - private string? _keyCeremonyId; - - [ObservableProperty] - private string _resultsPath = string.Empty; - - [ObservableProperty] - private List<(string TallyId, string ElectionId, string TallyName)> _tallyIds = new(); - - public MultiTallyRecord() : base(nameof(MultiTallyRecord)) - { - MultiTallyId = Guid.NewGuid().ToString(); - } -} - +namespace ElectionGuard.UI.Lib.Models; + +public partial class MultiTallyRecord : DatabaseRecord +{ + [ObservableProperty] + private string? _name; + + [ObservableProperty] + private string? _multiTallyId; + + [ObservableProperty] + private string? _keyCeremonyId; + + [ObservableProperty] + private string _resultsPath = string.Empty; + + [ObservableProperty] + private List<(string TallyId, string ElectionId, string TallyName)> _tallyIds = new(); + + public MultiTallyRecord() : base(nameof(MultiTallyRecord)) + { + MultiTallyId = Guid.NewGuid().ToString(); + } +} + diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/PlaintextTallyRecord.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/PlaintextTallyRecord.cs index bccbfb320..e6d0c766a 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/PlaintextTallyRecord.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/PlaintextTallyRecord.cs @@ -1,18 +1,18 @@ -namespace ElectionGuard.UI.Lib.Models; - -public partial class PlaintextTallyRecord : DatabaseRecord -{ - [ObservableProperty] - private string _tallyId = string.Empty; - - [ObservableProperty] - private string? _plaintextTallyData; - - public PlaintextTallyRecord() : base(nameof(PlaintextTallyRecord)) - { - } - - public override string ToString() => PlaintextTallyData ?? string.Empty; - public static implicit operator string(PlaintextTallyRecord? record) => record?.ToString() ?? string.Empty; - -} +namespace ElectionGuard.UI.Lib.Models; + +public partial class PlaintextTallyRecord : DatabaseRecord +{ + [ObservableProperty] + private string _tallyId = string.Empty; + + [ObservableProperty] + private string? _plaintextTallyData; + + public PlaintextTallyRecord() : base(nameof(PlaintextTallyRecord)) + { + } + + public override string ToString() => PlaintextTallyData ?? string.Empty; + public static implicit operator string(PlaintextTallyRecord? record) => record?.ToString() ?? string.Empty; + +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/TallyItem.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/TallyItem.cs index e632b907d..f5c711eec 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/TallyItem.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/TallyItem.cs @@ -1,17 +1,17 @@ -namespace ElectionGuard.UI.Lib.Models; - -public partial class TallyItem : ObservableObject -{ - [ObservableProperty] - private string _name = string.Empty; - - [ObservableProperty] - private string _party = string.Empty; - - [ObservableProperty] - private ulong _votes; - - [ObservableProperty] - private float _percent; - -} +namespace ElectionGuard.UI.Lib.Models; + +public partial class TallyItem : ObservableObject +{ + [ObservableProperty] + private string _name = string.Empty; + + [ObservableProperty] + private string _party = string.Empty; + + [ObservableProperty] + private ulong _votes; + + [ObservableProperty] + private float _percent; + +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/TallyRecord.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/TallyRecord.cs index 4d4f38acc..f6be0c36a 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/TallyRecord.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/TallyRecord.cs @@ -1,59 +1,59 @@ -namespace ElectionGuard.UI.Lib.Models; - -public partial class TallyRecord : DatabaseRecord -{ - [ObservableProperty] - private string? _name; - - [ObservableProperty] - private string? _electionId; - - [ObservableProperty] - private string? _keyCeremonyId; - - [ObservableProperty] - private string _tallyId = string.Empty; - - [ObservableProperty] - private int _quorum; - - [ObservableProperty] - private int _numberOfGuardians; - - [ObservableProperty] - private long _castBallotCount; - - [ObservableProperty] - private long _challengedBallotCount; - - [ObservableProperty] - private long _spoiledBallotCount; - - [ObservableProperty] - private TallyState _state; - - [ObservableProperty] - private bool _multiTally; - - [ObservableProperty] - private bool _viewed; - - [ObservableProperty] - private DateTime? _lastExport = null; - - [ObservableProperty] - private List _deviceIds = new(); - - [ObservableProperty] - private List _dates = new(); - - [ObservableProperty] - private DateTime _createdAt; - - public TallyRecord() : base(nameof(TallyRecord)) - { - TallyId = Guid.NewGuid().ToString(); - CreatedAt = DateTime.UtcNow; - } -} - +namespace ElectionGuard.UI.Lib.Models; + +public partial class TallyRecord : DatabaseRecord +{ + [ObservableProperty] + private string? _name; + + [ObservableProperty] + private string? _electionId; + + [ObservableProperty] + private string? _keyCeremonyId; + + [ObservableProperty] + private string _tallyId = string.Empty; + + [ObservableProperty] + private int _quorum; + + [ObservableProperty] + private int _numberOfGuardians; + + [ObservableProperty] + private long _castBallotCount; + + [ObservableProperty] + private long _challengedBallotCount; + + [ObservableProperty] + private long _spoiledBallotCount; + + [ObservableProperty] + private TallyState _state; + + [ObservableProperty] + private bool _multiTally; + + [ObservableProperty] + private bool _viewed; + + [ObservableProperty] + private DateTime? _lastExport = null; + + [ObservableProperty] + private List _deviceIds = new(); + + [ObservableProperty] + private List _dates = new(); + + [ObservableProperty] + private DateTime _createdAt; + + public TallyRecord() : base(nameof(TallyRecord)) + { + TallyId = Guid.NewGuid().ToString(); + CreatedAt = DateTime.UtcNow; + } +} + diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/TallyStatesEnum.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/TallyStatesEnum.cs index afcbf3aad..88696ff23 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/TallyStatesEnum.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/TallyStatesEnum.cs @@ -1,18 +1,18 @@ -namespace ElectionGuard.UI.Lib.Models; - -/// -/// A list of states for the key ceremony. -/// -public enum TallyState -{ - DoesNotExist, - PendingGuardiansJoin, - TallyStarted, - AdminAccumulateTally, - PendingGuardianDecryptShares, - AdminGenerateChallenge, - PendingGuardianRespondChallenge, - AdminVerifyChallenge, - Complete, - Abandoned -} +namespace ElectionGuard.UI.Lib.Models; + +/// +/// A list of states for the key ceremony. +/// +public enum TallyState +{ + DoesNotExist, + PendingGuardiansJoin, + TallyStarted, + AdminAccumulateTally, + PendingGuardianDecryptShares, + AdminGenerateChallenge, + PendingGuardianRespondChallenge, + AdminVerifyChallenge, + Complete, + Abandoned +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/User.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/User.cs index e9211da74..b8ee9d32d 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Models/User.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Models/User.cs @@ -1,15 +1,15 @@ -namespace ElectionGuard.UI.Lib.Models; - -public partial class User : DatabaseRecord -{ - [ObservableProperty] - private string? _name; - - [ObservableProperty] - private bool _isAdmin = false; - - public User() : base(nameof(User)) - { - - } -} +namespace ElectionGuard.UI.Lib.Models; + +public partial class User : DatabaseRecord +{ + [ObservableProperty] + private string? _name; + + [ObservableProperty] + private bool _isAdmin = false; + + public User() : base(nameof(User)) + { + + } +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/BallotService.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/BallotService.cs index ad42e5a4b..45b9b3282 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/BallotService.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/BallotService.cs @@ -1,130 +1,130 @@ -using ElectionGuard.UI.Lib.Models; -using MongoDB.Driver; - -namespace ElectionGuard.UI.Lib.Services; - -/// -/// Data Service for Elections -/// -public class BallotService : BaseDatabaseService -{ - /// - /// The collection name to use to get/save data into - /// - private readonly static string _collection = Constants.TableBallots; - - /// - /// Default constructor that sets the collection name - /// - public BallotService() : base(_collection, nameof(BallotRecord)) { } - - /// - /// Gets ballots for an election - /// - /// election id to search for - public async Task GetByOjectIdAsync(string electionId) - { - return await GetByFieldAsync(Constants.ObjectId, electionId); - } - - /// - /// Gets ballots for an election - /// - /// election id to search for - public async Task> GetByElectionIdAsync(string electionId) - { - return await GetAllByFieldAsync(Constants.ElectionId, electionId); - } - - /// - /// Gets ballots for an election - /// - /// election id to search for - public async Task> GetCursorByElectionIdAsync(string electionId) - { - var filter = FilterBuilder.And( - FilterBuilder.Eq(Constants.ElectionId, electionId), - FilterBuilder.Ne(Constants.BallotState, BallotBoxState.Spoiled)); - return await GetCursorByFilterAsync(filter); - } - - /// - /// Gets ballots for an election - /// - /// election id to search for - /// State to filter the ballots - public async Task> GetCursorBallotsByElectionIdStateAsync(string electionId, BallotBoxState state) - { - var filter = FilterBuilder.And( - FilterBuilder.Eq(Constants.ElectionId, electionId), - FilterBuilder.Eq(Constants.BallotState, state)); - return await GetCursorByFilterAsync(filter); - } - - public async Task GetCountBallotsByElectionIdStateAsync(string electionId, BallotBoxState state) - { - var filter = FilterBuilder.And( - FilterBuilder.Eq(Constants.ElectionId, electionId), - FilterBuilder.Eq(Constants.BallotState, state)); - return await CountByFilterAsync(filter); - } - - /// - /// Gets ballots from a single upload - /// - /// upload id to search for - public async Task> GetByUploadIdAsync(string uploadId) - { - return await GetAllByFieldAsync(Constants.UploadId, uploadId); - } - - /// - /// Check to see if the ballot has already been included - /// - /// ballotcode to find - public async Task BallotExistsAsync(string ballotCode) - { - var filter = FilterBuilder.Eq(Constants.BallotCode, ballotCode); - - var ballotCount = await CountByFilterAsync(filter); - return ballotCount > 0; - } - - /// - /// Get a ballot based on its ballot code - /// - /// ballotcode to find - public async Task GetByBallotCodeAsync(string ballotCode) - { - return await GetByFieldAsync(Constants.BallotCode, ballotCode); - } - - /// - /// Check to see if the ballot has already been included - /// - /// ballotcode to find - public async Task DeleteByBallotCodeAsync(string ballotCode) - { - var filter = FilterBuilder.Eq(Constants.BallotCode, ballotCode); - - await MarkAsDeletedAsync(filter); - } - - /// - /// Move a ballot into a spoiled state - /// - /// ballot code for the ballot to convert - public async Task ConvertToSpoiledByBallotCodeAsync(string ballotCode) - { - var filter = FilterBuilder.And( - FilterBuilder.Eq(Constants.BallotCode, ballotCode), - FilterBuilder.Ne(Constants.BallotState, BallotBoxState.Cast)); - var update = Builders.Update.Set(Constants.BallotState, BallotBoxState.Spoiled); - - await UpdateAsync(filter, update); - } - - - - -} +using ElectionGuard.UI.Lib.Models; +using MongoDB.Driver; + +namespace ElectionGuard.UI.Lib.Services; + +/// +/// Data Service for Elections +/// +public class BallotService : BaseDatabaseService +{ + /// + /// The collection name to use to get/save data into + /// + private readonly static string _collection = DbConstants.TableBallots; + + /// + /// Default constructor that sets the collection name + /// + public BallotService() : base(_collection, nameof(BallotRecord)) { } + + /// + /// Gets ballots for an election + /// + /// election id to search for + public async Task GetByOjectIdAsync(string electionId) + { + return await GetByFieldAsync(DbConstants.ObjectId, electionId); + } + + /// + /// Gets ballots for an election + /// + /// election id to search for + public async Task> GetByElectionIdAsync(string electionId) + { + return await GetAllByFieldAsync(DbConstants.ElectionId, electionId); + } + + /// + /// Gets ballots for an election + /// + /// election id to search for + public async Task> GetCursorByElectionIdAsync(string electionId) + { + var filter = FilterBuilder.And( + FilterBuilder.Eq(DbConstants.ElectionId, electionId), + FilterBuilder.Ne(DbConstants.BallotState, BallotBoxState.Spoiled)); + return await GetCursorByFilterAsync(filter); + } + + /// + /// Gets ballots for an election + /// + /// election id to search for + /// State to filter the ballots + public async Task> GetCursorBallotsByElectionIdStateAsync(string electionId, BallotBoxState state) + { + var filter = FilterBuilder.And( + FilterBuilder.Eq(DbConstants.ElectionId, electionId), + FilterBuilder.Eq(DbConstants.BallotState, state)); + return await GetCursorByFilterAsync(filter); + } + + public async Task GetCountBallotsByElectionIdStateAsync(string electionId, BallotBoxState state) + { + var filter = FilterBuilder.And( + FilterBuilder.Eq(DbConstants.ElectionId, electionId), + FilterBuilder.Eq(DbConstants.BallotState, state)); + return await CountByFilterAsync(filter); + } + + /// + /// Gets ballots from a single upload + /// + /// upload id to search for + public async Task> GetByUploadIdAsync(string uploadId) + { + return await GetAllByFieldAsync(DbConstants.UploadId, uploadId); + } + + /// + /// Check to see if the ballot has already been included + /// + /// ballotcode to find + public async Task BallotExistsAsync(string ballotCode) + { + var filter = FilterBuilder.Eq(DbConstants.BallotCode, ballotCode); + + var ballotCount = await CountByFilterAsync(filter); + return ballotCount > 0; + } + + /// + /// Get a ballot based on its ballot code + /// + /// ballotcode to find + public async Task GetByBallotCodeAsync(string ballotCode) + { + return await GetByFieldAsync(DbConstants.BallotCode, ballotCode); + } + + /// + /// Check to see if the ballot has already been included + /// + /// ballotcode to find + public async Task DeleteByBallotCodeAsync(string ballotCode) + { + var filter = FilterBuilder.Eq(DbConstants.BallotCode, ballotCode); + + await MarkAsDeletedAsync(filter); + } + + /// + /// Move a ballot into a spoiled state + /// + /// ballot code for the ballot to convert + public async Task ConvertToSpoiledByBallotCodeAsync(string ballotCode) + { + var filter = FilterBuilder.And( + FilterBuilder.Eq(DbConstants.BallotCode, ballotCode), + FilterBuilder.Ne(DbConstants.BallotState, BallotBoxState.Cast)); + var update = Builders.Update.Set(DbConstants.BallotState, BallotBoxState.Spoiled); + + await UpdateAsync(filter, update); + } + + + + +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/BallotUploadService.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/BallotUploadService.cs index ed6cd2cad..aefaefed9 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/BallotUploadService.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/BallotUploadService.cs @@ -1,49 +1,49 @@ -using ElectionGuard.UI.Lib.Models; -using MongoDB.Driver; - -namespace ElectionGuard.UI.Lib.Services; - -/// -/// Data Service for Elections -/// -public class BallotUploadService : BaseDatabaseService -{ - /// - /// The collection name to use to get/save data into - /// - private readonly static string _collection = Constants.TableBallots; - - /// - /// Default constructor that sets the collection name - /// - public BallotUploadService() : base(_collection, nameof(BallotUpload)) { } - - /// - /// Gets an election - /// - /// election id to search for - public async Task> GetByElectionIdAsync(string electionId) - { - return await GetAllByFieldAsync(Constants.ElectionId, electionId); - } - - public async Task DriveUsed(long serialNumber, string electionId) - { - var filterBuilder = Builders.Filter; - var filter = filterBuilder.And(filterBuilder.Eq(Constants.SerialNumber, serialNumber), filterBuilder.Eq(Constants.ElectionId, electionId)); - - var uploadCount = await CountByFilterAsync(filter); - return uploadCount > 0; - } - - public async Task DecrementBallotsChallenged(string uploadId) - { - var filter = FilterBuilder.And(FilterBuilder.Eq(Constants.UploadId, uploadId)); - var upload = await GetByFieldAsync(Constants.UploadId, uploadId); - var update = Builders.Update - .Set(Constants.BallotChallenged, upload!.BallotChallenged - 1) - .Set(Constants.BallotSpoiled, upload!.BallotSpoiled + 1); - - await UpdateAsync(filter, update); - } -} +using ElectionGuard.UI.Lib.Models; +using MongoDB.Driver; + +namespace ElectionGuard.UI.Lib.Services; + +/// +/// Data Service for Elections +/// +public class BallotUploadService : BaseDatabaseService +{ + /// + /// The collection name to use to get/save data into + /// + private readonly static string _collection = DbConstants.TableBallots; + + /// + /// Default constructor that sets the collection name + /// + public BallotUploadService() : base(_collection, nameof(BallotUpload)) { } + + /// + /// Gets an election + /// + /// election id to search for + public async Task> GetByElectionIdAsync(string electionId) + { + return await GetAllByFieldAsync(DbConstants.ElectionId, electionId); + } + + public async Task DriveUsed(long serialNumber, string electionId) + { + var filterBuilder = Builders.Filter; + var filter = filterBuilder.And(filterBuilder.Eq(DbConstants.SerialNumber, serialNumber), filterBuilder.Eq(DbConstants.ElectionId, electionId)); + + var uploadCount = await CountByFilterAsync(filter); + return uploadCount > 0; + } + + public async Task DecrementBallotsChallenged(string uploadId) + { + var filter = FilterBuilder.And(FilterBuilder.Eq(DbConstants.UploadId, uploadId)); + var upload = await GetByFieldAsync(DbConstants.UploadId, uploadId); + var update = Builders.Update + .Set(DbConstants.BallotChallenged, upload!.BallotChallenged - 1) + .Set(DbConstants.BallotSpoiled, upload!.BallotSpoiled + 1); + + await UpdateAsync(filter, update); + } +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/BaseDatabaseService.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/BaseDatabaseService.cs index 337a1ecc6..f048a8fc1 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/BaseDatabaseService.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/BaseDatabaseService.cs @@ -1,289 +1,289 @@ -using ElectionGuard.UI.Lib.Models; -using MongoDB.Bson; -using MongoDB.Driver; - -namespace ElectionGuard.UI.Lib.Services; - -/// -/// Base class used to make services for each data type being saved into the db. -/// This base class will have all of the common calls that will be used on all -/// data types and collections. When a specific call to get data that is unique -/// to a data type, those calls will go into the specific class that was created -/// with this base class. -/// -/// The datatype being saved -public class BaseDatabaseService : IDatabaseService where T : DatabaseRecord -{ - /// - /// The collection name to use to get/save data into - /// - private readonly string? _collection = null; - - private readonly string? _type = null; - - /// - /// Constructor to set the collection name that will be used for this data type - /// - /// Name of the collection to use for this data type - public BaseDatabaseService(string collection, string? type = null) - { - _collection = collection; - _type = type; - } - - /// - /// Save the data into the collection - /// - /// data to be saved - /// Optional parameter to allow data type to use a different collection - /// - public virtual async Task> SaveManyAsync(IEnumerable data, string? table = null) - { - try - { - var collection = DbService.GetCollection(table ?? _collection); - await collection.InsertManyAsync(data); - return data; - } - catch (Exception ex) - { - DbService.OnDatabaseDisconnect(new DbEventArgs { Message = "SaveManyAsync call failed" }); - throw new ElectionGuardException("SaveManyAsync call failed", ex); - } - } - - /// - /// Save the data into the collection - /// - /// data to be saved - /// Optional parameter to allow data type to use a different collection - /// - public virtual async Task SaveAsync(T data, FilterDefinition? customFilter = null, string? table = null) - { - try - { - var collection = DbService.GetCollection(table ?? _collection); - var filter = FilterBuilder.Eq(Constants.Id, data.Id); - _ = await collection.ReplaceOneAsync(UpdateFilter(customFilter ?? filter), data, new ReplaceOptions { IsUpsert = true }); - return data; - } - catch (Exception ex) - { - DbService.OnDatabaseDisconnect(new DbEventArgs { Message = "SaveAsync call failed" }); - throw new ElectionGuardException("SaveAsync call failed", ex); - } - } - - /// - /// Update the data into the collection - /// - /// data to be updated - /// Optional parameter to allow data type to use a different collection - /// - public virtual async Task UpdateAsync(FilterDefinition filter, UpdateDefinition update, string? table = null) - { - try - { - var collection = DbService.GetCollection(table ?? _collection); - _ = await collection.UpdateOneAsync(UpdateFilter(filter), update); - } - catch (Exception ex) - { - DbService.OnDatabaseDisconnect(new DbEventArgs { Message = "Error updating a record" }); - throw new ElectionGuardException("Error updating a record", ex); - } - } - - /// - /// Get all of a data type from a given collection - /// - /// Optional parameter to allow data type to use a different collection - /// List of the documents found in the given collection - public async Task> GetAllAsync(string? table = null) - { - return await GetAllByFilterAsync(Builders.Filter.Empty); - } - - /// - /// Get the document from the database with the provided value for a field - /// - /// Field name to search for - /// Value to search for - /// Optional parameter to allow data type to use a different collection - /// List of the documents found in the given collection that matches the given field - public async Task> GetAllByFieldAsync(string fieldName, object fieldValue, string? table = null) - { - var filter = FilterBuilder.Eq(fieldName, fieldValue); - return await GetAllByFilterAsync(filter, table); - } - - /// - /// Get the document from the database with the provided value for a field - /// - /// Field name to search for - /// List of values to match for search - /// Optional parameter to allow data type to use a different collection - /// List of the documents found in the given collection that matches the given field - public async Task> GetAllByFieldInListAsync(string fieldName, BsonArray fieldValues, string? table = null) - { - var filter = FilterBuilder.In(fieldName, fieldValues); - return await GetAllByFilterAsync(filter, table); - } - - - - public FilterDefinitionBuilder FilterBuilder => Builders.Filter; - - /// - /// Get all of a data type from a given collection using a filter - /// - /// Optional parameter to allow data type to use a different collection - /// List of the documents found in the given collection - public async Task> GetAllByFilterAsync(FilterDefinition filter, string? table = null) - { - try - { - var collection = DbService.GetCollection(table ?? _collection); - var item = await collection.FindAsync(UpdateFilter(filter)); - return item?.ToList() ?? new(); - } - catch (Exception ex) - { - DbService.OnDatabaseDisconnect(new DbEventArgs { Message = "Error updating a record" }); - - throw new ElectionGuardException("Error getting all by filter", ex); - //return new(); - } - } - - /// - /// Get all of a data type from a given collection using a filter - /// - /// Optional parameter to allow data type to use a different collection - /// List of the documents found in the given collection - public async Task> GetCursorByFilterAsync(FilterDefinition filter, string? table = null) - { - try - { - var collection = DbService.GetCollection(table ?? _collection); - return await collection.FindAsync(UpdateFilter(filter)); - } - catch (Exception ex) - { - DbService.OnDatabaseDisconnect(new DbEventArgs { Message = "Error getting all by filter" }); - throw new ElectionGuardException("Error getting all by filter", ex); - } - } - - - /// - /// Get the document from the database with the provided id - /// - /// Id to search for - /// Optional parameter to allow data type to use a different collection - /// Document that matches the given id - public async Task GetByIdAsync(string id, string? table = null) - { - return await GetByFieldAsync(Constants.Id, id, table); - } - - /// - /// Get the document from the database with the provided name - /// - /// Name to search for - /// Optional parameter to allow data type to use a different collection - /// Document that matches the given name - public virtual async Task GetByNameAsync(string name, string? table = null) - { - return await GetByFieldAsync(Constants.Name, name, table); - } - - /// - /// Get the document from the database with the provided value for a field - /// - /// Field name to search for - /// Value to search for - /// Optional parameter to allow data type to use a different collection - /// Document that matches the given field - public async Task GetByFieldAsync(string fieldName, object fieldValue, string? table = null) - { - var list = await GetAllByFieldAsync(fieldName, fieldValue, table); - return list.FirstOrDefault(); - } - - /// - /// Updates the filter to only get non-deleted items - /// - /// filter to base from - /// New filter adding soft delete as false - public FilterDefinition UpdateFilter(FilterDefinition filter, bool getDeleted = false) - { - var builder = Builders.Filter; - return builder.And(filter, - builder.Eq(Constants.SoftDeleted, getDeleted), - builder.Eq(Constants.DataType, _type)); - } - - /// - /// Get count of the number of documents that match the filter - /// - /// filter used to search - /// collection to use - public async Task CountByFilterAsync(FilterDefinition filter, string? table = null) - { - try - { - var collection = DbService.GetCollection(table ?? _collection); - return await collection.CountDocumentsAsync(UpdateFilter(filter)); - } - catch (Exception ex) - { - DbService.OnDatabaseDisconnect(new DbEventArgs { Message = "Error CountByFilterAsync" }); - throw new ElectionGuardException("Error CountByFilterAsync", ex); - } - } - - /// - /// Get existance of documents that match the filter - /// - /// filter used to search - /// collection to use - public async Task ExistsByFilterAsync(FilterDefinition filter, string? table = null) - { - try - { - var collection = DbService.GetCollection(table ?? _collection); - return await collection.CountDocumentsAsync(UpdateFilter(filter)) != 0; - } - catch (Exception ex) - { - DbService.OnDatabaseDisconnect(new DbEventArgs { Message = "Error ExistsByFilterAsync" }); - throw new ElectionGuardException("Error ExistsByFilterAsync", ex); - } - } - - /// - /// - /// - /// filter to use to find the item to delete - /// Set the SoftDeleted field value - /// collection to use - public async Task MarkAsDeletedAsync(FilterDefinition filter, bool deleted = true, string? table = null) - { - try - { - var collection = DbService.GetCollection(table ?? _collection); - - var updateBuilder = Builders.Update; - var update = updateBuilder.Set(Constants.SoftDeleted, deleted); - - _ = await collection.UpdateOneAsync(UpdateFilter(filter), update); - } - catch (Exception ex) - { - DbService.OnDatabaseDisconnect(new DbEventArgs { Message = "Error MarkAsDeletedAsync" }); - throw new ElectionGuardException("Error MarkAsDeletedAsync", ex); - } - } - -} +using ElectionGuard.UI.Lib.Models; +using MongoDB.Bson; +using MongoDB.Driver; + +namespace ElectionGuard.UI.Lib.Services; + +/// +/// Base class used to make services for each data type being saved into the db. +/// This base class will have all of the common calls that will be used on all +/// data types and collections. When a specific call to get data that is unique +/// to a data type, those calls will go into the specific class that was created +/// with this base class. +/// +/// The datatype being saved +public class BaseDatabaseService : IDatabaseService where T : DatabaseRecord +{ + /// + /// The collection name to use to get/save data into + /// + private readonly string? _collection = null; + + private readonly string? _type = null; + + /// + /// Constructor to set the collection name that will be used for this data type + /// + /// Name of the collection to use for this data type + public BaseDatabaseService(string collection, string? type = null) + { + _collection = collection; + _type = type; + } + + /// + /// Save the data into the collection + /// + /// data to be saved + /// Optional parameter to allow data type to use a different collection + /// + public virtual async Task> SaveManyAsync(IEnumerable data, string? table = null) + { + try + { + var collection = DbService.GetCollection(table ?? _collection); + await collection.InsertManyAsync(data); + return data; + } + catch (Exception ex) + { + DbService.OnDatabaseDisconnect(new DbEventArgs { Message = "SaveManyAsync call failed" }); + throw new ElectionGuardException("SaveManyAsync call failed", ex); + } + } + + /// + /// Save the data into the collection + /// + /// data to be saved + /// Optional parameter to allow data type to use a different collection + /// + public virtual async Task SaveAsync(T data, FilterDefinition? customFilter = null, string? table = null) + { + try + { + var collection = DbService.GetCollection(table ?? _collection); + var filter = FilterBuilder.Eq(DbConstants.Id, data.Id); + _ = await collection.ReplaceOneAsync(UpdateFilter(customFilter ?? filter), data, new ReplaceOptions { IsUpsert = true }); + return data; + } + catch (Exception ex) + { + DbService.OnDatabaseDisconnect(new DbEventArgs { Message = "SaveAsync call failed" }); + throw new ElectionGuardException("SaveAsync call failed", ex); + } + } + + /// + /// Update the data into the collection + /// + /// data to be updated + /// Optional parameter to allow data type to use a different collection + /// + public virtual async Task UpdateAsync(FilterDefinition filter, UpdateDefinition update, string? table = null) + { + try + { + var collection = DbService.GetCollection(table ?? _collection); + _ = await collection.UpdateOneAsync(UpdateFilter(filter), update); + } + catch (Exception ex) + { + DbService.OnDatabaseDisconnect(new DbEventArgs { Message = "Error updating a record" }); + throw new ElectionGuardException("Error updating a record", ex); + } + } + + /// + /// Get all of a data type from a given collection + /// + /// Optional parameter to allow data type to use a different collection + /// List of the documents found in the given collection + public async Task> GetAllAsync(string? table = null) + { + return await GetAllByFilterAsync(Builders.Filter.Empty); + } + + /// + /// Get the document from the database with the provided value for a field + /// + /// Field name to search for + /// Value to search for + /// Optional parameter to allow data type to use a different collection + /// List of the documents found in the given collection that matches the given field + public async Task> GetAllByFieldAsync(string fieldName, object fieldValue, string? table = null) + { + var filter = FilterBuilder.Eq(fieldName, fieldValue); + return await GetAllByFilterAsync(filter, table); + } + + /// + /// Get the document from the database with the provided value for a field + /// + /// Field name to search for + /// List of values to match for search + /// Optional parameter to allow data type to use a different collection + /// List of the documents found in the given collection that matches the given field + public async Task> GetAllByFieldInListAsync(string fieldName, BsonArray fieldValues, string? table = null) + { + var filter = FilterBuilder.In(fieldName, fieldValues); + return await GetAllByFilterAsync(filter, table); + } + + + + public FilterDefinitionBuilder FilterBuilder => Builders.Filter; + + /// + /// Get all of a data type from a given collection using a filter + /// + /// Optional parameter to allow data type to use a different collection + /// List of the documents found in the given collection + public async Task> GetAllByFilterAsync(FilterDefinition filter, string? table = null) + { + try + { + var collection = DbService.GetCollection(table ?? _collection); + var item = await collection.FindAsync(UpdateFilter(filter)); + return item?.ToList() ?? new(); + } + catch (Exception ex) + { + DbService.OnDatabaseDisconnect(new DbEventArgs { Message = "Error updating a record" }); + + throw new ElectionGuardException("Error getting all by filter", ex); + //return new(); + } + } + + /// + /// Get all of a data type from a given collection using a filter + /// + /// Optional parameter to allow data type to use a different collection + /// List of the documents found in the given collection + public async Task> GetCursorByFilterAsync(FilterDefinition filter, string? table = null) + { + try + { + var collection = DbService.GetCollection(table ?? _collection); + return await collection.FindAsync(UpdateFilter(filter)); + } + catch (Exception ex) + { + DbService.OnDatabaseDisconnect(new DbEventArgs { Message = "Error getting all by filter" }); + throw new ElectionGuardException("Error getting all by filter", ex); + } + } + + + /// + /// Get the document from the database with the provided id + /// + /// Id to search for + /// Optional parameter to allow data type to use a different collection + /// Document that matches the given id + public async Task GetByIdAsync(string id, string? table = null) + { + return await GetByFieldAsync(DbConstants.Id, id, table); + } + + /// + /// Get the document from the database with the provided name + /// + /// Name to search for + /// Optional parameter to allow data type to use a different collection + /// Document that matches the given name + public virtual async Task GetByNameAsync(string name, string? table = null) + { + return await GetByFieldAsync(DbConstants.Name, name, table); + } + + /// + /// Get the document from the database with the provided value for a field + /// + /// Field name to search for + /// Value to search for + /// Optional parameter to allow data type to use a different collection + /// Document that matches the given field + public async Task GetByFieldAsync(string fieldName, object fieldValue, string? table = null) + { + var list = await GetAllByFieldAsync(fieldName, fieldValue, table); + return list.FirstOrDefault(); + } + + /// + /// Updates the filter to only get non-deleted items + /// + /// filter to base from + /// New filter adding soft delete as false + public FilterDefinition UpdateFilter(FilterDefinition filter, bool getDeleted = false) + { + var builder = Builders.Filter; + return builder.And(filter, + builder.Eq(DbConstants.SoftDeleted, getDeleted), + builder.Eq(DbConstants.DataType, _type)); + } + + /// + /// Get count of the number of documents that match the filter + /// + /// filter used to search + /// collection to use + public async Task CountByFilterAsync(FilterDefinition filter, string? table = null) + { + try + { + var collection = DbService.GetCollection(table ?? _collection); + return await collection.CountDocumentsAsync(UpdateFilter(filter)); + } + catch (Exception ex) + { + DbService.OnDatabaseDisconnect(new DbEventArgs { Message = "Error CountByFilterAsync" }); + throw new ElectionGuardException("Error CountByFilterAsync", ex); + } + } + + /// + /// Get existance of documents that match the filter + /// + /// filter used to search + /// collection to use + public async Task ExistsByFilterAsync(FilterDefinition filter, string? table = null) + { + try + { + var collection = DbService.GetCollection(table ?? _collection); + return await collection.CountDocumentsAsync(UpdateFilter(filter)) != 0; + } + catch (Exception ex) + { + DbService.OnDatabaseDisconnect(new DbEventArgs { Message = "Error ExistsByFilterAsync" }); + throw new ElectionGuardException("Error ExistsByFilterAsync", ex); + } + } + + /// + /// + /// + /// filter to use to find the item to delete + /// Set the SoftDeleted field value + /// collection to use + public async Task MarkAsDeletedAsync(FilterDefinition filter, bool deleted = true, string? table = null) + { + try + { + var collection = DbService.GetCollection(table ?? _collection); + + var updateBuilder = Builders.Update; + var update = updateBuilder.Set(DbConstants.SoftDeleted, deleted); + + _ = await collection.UpdateOneAsync(UpdateFilter(filter), update); + } + catch (Exception ex) + { + DbService.OnDatabaseDisconnect(new DbEventArgs { Message = "Error MarkAsDeletedAsync" }); + throw new ElectionGuardException("Error MarkAsDeletedAsync", ex); + } + } + +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/ChallengeResponseService.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/ChallengeResponseService.cs index db6526ed0..ff34a0ee3 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/ChallengeResponseService.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/ChallengeResponseService.cs @@ -10,7 +10,7 @@ public class ChallengeResponseService : BaseDatabaseService /// The collection name to use to get/save data into /// - private readonly static string _collection = Constants.TableTallies; + private readonly static string _collection = DbConstants.TableTallies; /// /// Default constructor that sets the collection name @@ -23,14 +23,14 @@ public ChallengeResponseService() : base(_collection, nameof(ChallengeResponseRe /// election id to search for public async Task> GetAllByTallyIdAsync(string tallyId) { - return await GetAllByFieldAsync(Constants.TallyId, tallyId); + return await GetAllByFieldAsync(DbConstants.TallyId, tallyId); } public async Task GetByGuardianIdAsync(string tallyId, string guardianId) { var filter = FilterBuilder.And( - FilterBuilder.Eq(Constants.TallyId, tallyId), - FilterBuilder.Eq(Constants.GuardianId, guardianId) + FilterBuilder.Eq(DbConstants.TallyId, tallyId), + FilterBuilder.Eq(DbConstants.GuardianId, guardianId) ); return (await GetAllByFilterAsync(filter)).FirstOrDefault(); @@ -38,15 +38,15 @@ public async Task> GetAllByTallyIdAsync(string tal public async Task GetCountByTallyAsync(string tallyId) { - var filter = FilterBuilder.Eq(Constants.TallyId, tallyId); + var filter = FilterBuilder.Eq(DbConstants.TallyId, tallyId); return await CountByFilterAsync(filter); - } - + } + public async Task GetExistsByTallyAsync(string tallyId, string guardianId) { var filter = FilterBuilder.And( - FilterBuilder.Eq(Constants.TallyId, tallyId), - FilterBuilder.Eq(Constants.GuardianId, guardianId) + FilterBuilder.Eq(DbConstants.TallyId, tallyId), + FilterBuilder.Eq(DbConstants.GuardianId, guardianId) ); return await ExistsByFilterAsync(filter); } diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/ChallengeService.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/ChallengeService.cs index 6f0e7b5c4..33a4b7c5e 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/ChallengeService.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/ChallengeService.cs @@ -10,7 +10,7 @@ public class ChallengeService : BaseDatabaseService /// /// The collection name to use to get/save data into /// - private readonly static string _collection = Constants.TableTallies; + private readonly static string _collection = DbConstants.TableTallies; /// /// Default constructor that sets the collection name @@ -23,14 +23,14 @@ public ChallengeService() : base(_collection, nameof(ChallengeRecord)) { } /// election id to search for public async Task> GetAllByTallyIdAsync(string tallyId) { - return await GetAllByFieldAsync(Constants.TallyId, tallyId); + return await GetAllByFieldAsync(DbConstants.TallyId, tallyId); } public async Task GetByGuardianIdAsync(string tallyId, string guardianId) { var filter = FilterBuilder.And( - FilterBuilder.Eq(Constants.TallyId, tallyId), - FilterBuilder.Eq(Constants.GuardianId, guardianId) + FilterBuilder.Eq(DbConstants.TallyId, tallyId), + FilterBuilder.Eq(DbConstants.GuardianId, guardianId) ); return (await GetAllByFilterAsync(filter)).FirstOrDefault(); diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/ChallengedBallotService.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/ChallengedBallotService.cs index 379636535..b1c07ee12 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/ChallengedBallotService.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/ChallengedBallotService.cs @@ -1,86 +1,86 @@ -using ElectionGuard.UI.Lib.Models; -using MongoDB.Driver; - -namespace ElectionGuard.UI.Lib.Services; - -/// -/// Data Service for Elections -/// -public class ChallengedBallotService : BaseDatabaseService -{ - /// - /// The collection name to use to get/save data into - /// - private readonly static string _collection = Constants.TableBallots; - - /// - /// Default constructor that sets the collection name - /// - public ChallengedBallotService() : base(_collection, nameof(ChallengedBallotRecord)) { } - - public Task SaveAsync(ChallengedBallotRecord data) - { - var filter = FilterBuilder.And(FilterBuilder.Eq(Constants.BallotCode, data.BallotCode), FilterBuilder.Eq(Constants.TallyId, data.TallyId)); - return SaveAsync(data, filter); - } - - /// - /// Gets ballots for an election - /// - /// election id to search for - public async Task> GetByElectionIdAsync(string electionId) - { - return await GetAllByFieldAsync(Constants.ElectionId, electionId); - } - - /// - /// Gets ballots for an election - /// - /// election id to search for - public async Task> GetCursorByElectionIdAsync(string electionId) - { - var filter = FilterBuilder.Eq(Constants.ElectionId, electionId); - return await GetCursorByFilterAsync(filter); - } - - /// - /// Gets ballots from a single upload - /// - /// upload id to search for - public async Task> GetByUploadIdAsync(string uploadId) - { - return await GetAllByFieldAsync(Constants.UploadId, uploadId); - } - - /// - /// Check to see if the ballot has already been included - /// - /// ballotcode to find - public async Task BallotExistsAsync(string ballotCode) - { - var filter = FilterBuilder.And(FilterBuilder.Eq(Constants.BallotCode, ballotCode)); - - var ballotCount = await CountByFilterAsync(filter); - return ballotCount > 0; - } - - /// - /// Get a ballot based on its ballot code - /// - /// ballotcode to find - public async Task GetByBallotCodeAsync(string ballotCode) - { - return await GetByFieldAsync(Constants.BallotCode, ballotCode); - } - - /// - /// Check to see if the ballot has already been included - /// - /// ballotcode to find - public async Task DeleteByBallotCodeAsync(string ballotCode) - { - var filter = FilterBuilder.And(FilterBuilder.Eq(Constants.BallotCode, ballotCode)); - - await MarkAsDeletedAsync(filter); - } -} +using ElectionGuard.UI.Lib.Models; +using MongoDB.Driver; + +namespace ElectionGuard.UI.Lib.Services; + +/// +/// Data Service for Elections +/// +public class ChallengedBallotService : BaseDatabaseService +{ + /// + /// The collection name to use to get/save data into + /// + private readonly static string _collection = DbConstants.TableBallots; + + /// + /// Default constructor that sets the collection name + /// + public ChallengedBallotService() : base(_collection, nameof(ChallengedBallotRecord)) { } + + public Task SaveAsync(ChallengedBallotRecord data) + { + var filter = FilterBuilder.And(FilterBuilder.Eq(DbConstants.BallotCode, data.BallotCode), FilterBuilder.Eq(DbConstants.TallyId, data.TallyId)); + return SaveAsync(data, filter); + } + + /// + /// Gets ballots for an election + /// + /// election id to search for + public async Task> GetByElectionIdAsync(string electionId) + { + return await GetAllByFieldAsync(DbConstants.ElectionId, electionId); + } + + /// + /// Gets ballots for an election + /// + /// election id to search for + public async Task> GetCursorByElectionIdAsync(string electionId) + { + var filter = FilterBuilder.Eq(DbConstants.ElectionId, electionId); + return await GetCursorByFilterAsync(filter); + } + + /// + /// Gets ballots from a single upload + /// + /// upload id to search for + public async Task> GetByUploadIdAsync(string uploadId) + { + return await GetAllByFieldAsync(DbConstants.UploadId, uploadId); + } + + /// + /// Check to see if the ballot has already been included + /// + /// ballotcode to find + public async Task BallotExistsAsync(string ballotCode) + { + var filter = FilterBuilder.And(FilterBuilder.Eq(DbConstants.BallotCode, ballotCode)); + + var ballotCount = await CountByFilterAsync(filter); + return ballotCount > 0; + } + + /// + /// Get a ballot based on its ballot code + /// + /// ballotcode to find + public async Task GetByBallotCodeAsync(string ballotCode) + { + return await GetByFieldAsync(DbConstants.BallotCode, ballotCode); + } + + /// + /// Check to see if the ballot has already been included + /// + /// ballotcode to find + public async Task DeleteByBallotCodeAsync(string ballotCode) + { + var filter = FilterBuilder.And(FilterBuilder.Eq(DbConstants.BallotCode, ballotCode)); + + await MarkAsDeletedAsync(filter); + } +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/CiphertextTallyService.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/CiphertextTallyService.cs index 6c8f38848..d94a8ea20 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/CiphertextTallyService.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/CiphertextTallyService.cs @@ -1,54 +1,54 @@ -using ElectionGuard.UI.Lib.Models; - -namespace ElectionGuard.UI.Lib.Services; - -/// -/// Data Service for CiphertextTallyRecord -/// -public class CiphertextTallyService : BaseDatabaseService -{ - /// - /// The collection name to use to get/save data into - /// - private readonly static string _collection = Constants.TableTallies; - - /// - /// Default constructor that sets the collection name - /// - public CiphertextTallyService() : base(_collection, nameof(CiphertextTallyRecord)) { } - - /// - /// Gets ciphertext tally for an election - /// - /// tally id to search for - public async Task GetByTallyIdAsync(string tallyId) - { - var filter = FilterBuilder.And( - FilterBuilder.Eq(Constants.TallyId, tallyId), - FilterBuilder.Eq(Constants.IsExportable, true)); - return (await GetAllByFilterAsync(filter)).LastOrDefault(); - } - - /// - /// Gets a list of all ciphertext tally records for an election - /// - /// election id to search for - public async Task> GetAllByElectionIdAsync(string electionId) - { - var filter = FilterBuilder.And( - FilterBuilder.Eq(Constants.ElectionId, electionId), - FilterBuilder.Eq(Constants.IsExportable, false), - FilterBuilder.Eq(Constants.TallyId, string.Empty)); - return await GetAllByFilterAsync(filter); - } - - /// - /// Gets ciphertext tally for a ballot upload - /// - /// upload id to search for - public async Task GetByUploadIdIdAsync(string uploadId) - { - return await GetByFieldAsync(Constants.UploadId, uploadId); - } - -} +using ElectionGuard.UI.Lib.Models; + +namespace ElectionGuard.UI.Lib.Services; + +/// +/// Data Service for CiphertextTallyRecord +/// +public class CiphertextTallyService : BaseDatabaseService +{ + /// + /// The collection name to use to get/save data into + /// + private readonly static string _collection = DbConstants.TableTallies; + + /// + /// Default constructor that sets the collection name + /// + public CiphertextTallyService() : base(_collection, nameof(CiphertextTallyRecord)) { } + + /// + /// Gets ciphertext tally for an election + /// + /// tally id to search for + public async Task GetByTallyIdAsync(string tallyId) + { + var filter = FilterBuilder.And( + FilterBuilder.Eq(DbConstants.TallyId, tallyId), + FilterBuilder.Eq(DbConstants.IsExportable, true)); + return (await GetAllByFilterAsync(filter)).LastOrDefault(); + } + + /// + /// Gets a list of all ciphertext tally records for an election + /// + /// election id to search for + public async Task> GetAllByElectionIdAsync(string electionId) + { + var filter = FilterBuilder.And( + FilterBuilder.Eq(DbConstants.ElectionId, electionId), + FilterBuilder.Eq(DbConstants.IsExportable, false), + FilterBuilder.Eq(DbConstants.TallyId, string.Empty)); + return await GetAllByFilterAsync(filter); + } + + /// + /// Gets ciphertext tally for a ballot upload + /// + /// upload id to search for + public async Task GetByUploadIdIdAsync(string uploadId) + { + return await GetByFieldAsync(DbConstants.UploadId, uploadId); + } + +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/ConstantsService.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/ConstantsService.cs index e0b018843..77756b4bc 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/ConstantsService.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/ConstantsService.cs @@ -1,28 +1,28 @@ -using ElectionGuard.UI.Lib.Models; - -namespace ElectionGuard.UI.Lib.Services; - -/// -/// Data Service for Elections -/// -public class ConstantsService : BaseDatabaseService -{ - /// - /// The collection name to use to get/save data into - /// - private readonly static string _collection = Constants.TableElections; - - /// - /// Default constructor that sets the collection name - /// - public ConstantsService() : base(_collection, nameof(ConstantsRecord)) { } - - /// - /// Gets a constants record - /// - /// election id to search for - public async Task GetByElectionIdAsync(string electionId) - { - return await GetByFieldAsync(Constants.ElectionId, electionId); - } -} +using ElectionGuard.UI.Lib.Models; + +namespace ElectionGuard.UI.Lib.Services; + +/// +/// Data Service for Elections +/// +public class ConstantsService : BaseDatabaseService +{ + /// + /// The collection name to use to get/save data into + /// + private readonly static string _collection = DbConstants.TableElections; + + /// + /// Default constructor that sets the collection name + /// + public ConstantsService() : base(_collection, nameof(ConstantsRecord)) { } + + /// + /// Gets a constants record + /// + /// election id to search for + public async Task GetByElectionIdAsync(string electionId) + { + return await GetByFieldAsync(DbConstants.ElectionId, electionId); + } +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/ContextService.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/ContextService.cs index 1c8bebf9d..1bba367c1 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/ContextService.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/ContextService.cs @@ -1,28 +1,28 @@ -using ElectionGuard.UI.Lib.Models; - -namespace ElectionGuard.UI.Lib.Services; - -/// -/// Data Service for Context records -/// -public class ContextService : BaseDatabaseService -{ - /// - /// The collection name to use to get/save data into - /// - private readonly static string _collection = Constants.TableElections; - - /// - /// Default constructor that sets the collection name - /// - public ContextService() : base(_collection, nameof(ContextRecord)) { } - - /// - /// Gets a context - /// - /// election id to search for - public async Task GetByElectionIdAsync(string electionId) - { - return await GetByFieldAsync(Constants.ElectionId, electionId); - } -} +using ElectionGuard.UI.Lib.Models; + +namespace ElectionGuard.UI.Lib.Services; + +/// +/// Data Service for Context records +/// +public class ContextService : BaseDatabaseService +{ + /// + /// The collection name to use to get/save data into + /// + private readonly static string _collection = DbConstants.TableElections; + + /// + /// Default constructor that sets the collection name + /// + public ContextService() : base(_collection, nameof(ContextRecord)) { } + + /// + /// Gets a context + /// + /// election id to search for + public async Task GetByElectionIdAsync(string electionId) + { + return await GetByFieldAsync(DbConstants.ElectionId, electionId); + } +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/DbService.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/DbService.cs index 0fa835d23..56db21ae9 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/DbService.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/DbService.cs @@ -1,193 +1,193 @@ -using System.Runtime.CompilerServices; -using System.Text.Json; -using MongoDB.Bson; -using MongoDB.Bson.Serialization; -using MongoDB.Bson.Serialization.Serializers; -using MongoDB.Driver; -using MongoDB.Driver.Core.Servers; - -namespace ElectionGuard.UI.Lib.Services; - - -[Obsolete("use newtonsoft")] -public class ComplexTypeSerializer : SerializerBase -{ - public override object Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) - { - var serializer = BsonSerializer.LookupSerializer(typeof(BsonDocument)); - var document = serializer.Deserialize(context, args); - - var bsonDocument = document.ToBsonDocument(); - - var result = BsonExtensionMethods.ToJson(bsonDocument); - return JsonSerializer.Deserialize(result)!; - } - - public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value) - { - var jsonDocument = JsonSerializer.Serialize(value); - var bsonDocument = BsonSerializer.Deserialize(jsonDocument); - - var serializer = BsonSerializer.LookupSerializer(typeof(BsonDocument)); - serializer.Serialize(context, bsonDocument.AsBsonValue); - } -} - - -public class DbEventArgs : EventArgs -{ - public string Message { get; set; } = String.Empty; -} - -/// -/// Database service class to access the mongo database -/// -public static class DbService -{ - private static readonly int DefaultPort = 27017; - private static readonly string DefaultDatabase = "ElectionGuardDb"; - private static readonly string DefaultUsername = "root"; - - private static string DbHost = string.Empty; - private static string DbPassword = string.Empty; - private static string DbConnection = string.Empty; - private static MongoClient client = new(); - - public static event EventHandler DatabaseDisconnected; - - public static void OnDatabaseDisconnect(DbEventArgs e) - { - EventHandler handler = DatabaseDisconnected; - if (handler != null) - { - handler(null, e); - } - } - - /// - /// Initializes the connection to the database server - /// This will need to be called if the address or the password needs to be changed. - /// - /// The IP address of the database - /// Password used for the database - public static void Init(string host, string password) - { - DbHost = host; - DbPassword = password; - Reconnect(); - } - - /// - /// Initializes the connection to the database server - /// This will need to be called if the address or the password needs to be changed. - /// - /// The connection string to use to address of the database - public static void Init(string connection) - { - DbConnection = connection; - Reconnect(); - } - - /// - /// Reconnects to the mongodb - /// - public static void Reconnect() - { - string connection; - if (!string.IsNullOrEmpty(DbConnection)) - { - connection = DbConnection; - } - else - { - connection = $"mongodb://{DefaultUsername}:{DbPassword}@{DbHost}:{DefaultPort}/{DefaultDatabase}?authSource=admin&keepAlive=true&poolSize=30&autoReconnect=true&socketTimeoutMS=360000&connectTimeoutMS=360000"; - } - client = new MongoClient(connection); - } - - - - /// - /// Gets an interface to the database - /// - /// Gets the connection to the database - public static IMongoDatabase GetDb() - { - return client.GetDatabase(DefaultDatabase); - } - - /// - /// Gets a collection from the database - /// - /// Data type to use for the collection - /// Name of the collection - /// The found collection - public static IMongoCollection GetCollection(string? collectionName) - { - try - { - var db = GetDb(); - return db.GetCollection(collectionName); - } - catch(Exception ex) - { - OnDatabaseDisconnect(new DbEventArgs { Message = "GetCollection call failed" }); - throw new ElectionGuardException("GetCollection call failed", ex); - } - } - - /// - /// Method to verify that the connection to the database is working - /// - /// True/false if the client is connected to the server - public static bool Verify() - { - try - { - var db = GetDb(); - return db.ListCollectionNames().ToList().Count > 0; - } - catch(Exception ex) - { - OnDatabaseDisconnect(new DbEventArgs { Message = "Verify call failed" }); - throw new ElectionGuardException("Verify call failed", ex); - } - } - - /// - /// Method to check the status of the data store connection - /// - /// true if connected, otherwise false - public static bool Ping() - { - // nothing to ping until we have a client. - if (client is null) - { - return false; - } - - try - { - var db = GetDb(); - // One of the interesting things about MongoDb driver is we don't get state - // information about the connection until we actually try to use it. - // to try to ping the server to do the smallest possible query. - var r = db.RunCommandAsync((Command)/*lang=json*/ "{ping: 1}").Wait(1000); - } - catch (Exception) - { - OnDatabaseDisconnect(new DbEventArgs { Message = "Ping call failed" }); - return false; - } - - var server = client.Cluster.Description.Servers.FirstOrDefault(); - var ret = server is not null && - server.HeartbeatException is null && - server.State == ServerState.Connected; - if(!ret) - { - OnDatabaseDisconnect(new DbEventArgs { Message = "Ping call failed" }); - } - return ret; - } -} +using System.Runtime.CompilerServices; +using System.Text.Json; +using MongoDB.Bson; +using MongoDB.Bson.Serialization; +using MongoDB.Bson.Serialization.Serializers; +using MongoDB.Driver; +using MongoDB.Driver.Core.Servers; + +namespace ElectionGuard.UI.Lib.Services; + + +[Obsolete("use newtonsoft")] +public class ComplexTypeSerializer : SerializerBase +{ + public override object Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) + { + var serializer = BsonSerializer.LookupSerializer(typeof(BsonDocument)); + var document = serializer.Deserialize(context, args); + + var bsonDocument = document.ToBsonDocument(); + + var result = BsonExtensionMethods.ToJson(bsonDocument); + return JsonSerializer.Deserialize(result)!; + } + + public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value) + { + var jsonDocument = JsonSerializer.Serialize(value); + var bsonDocument = BsonSerializer.Deserialize(jsonDocument); + + var serializer = BsonSerializer.LookupSerializer(typeof(BsonDocument)); + serializer.Serialize(context, bsonDocument.AsBsonValue); + } +} + + +public class DbEventArgs : EventArgs +{ + public string Message { get; set; } = String.Empty; +} + +/// +/// Database service class to access the mongo database +/// +public static class DbService +{ + private static readonly int DefaultPort = 27017; + private static readonly string DefaultDatabase = "ElectionGuardDb"; + private static readonly string DefaultUsername = "root"; + + private static string DbHost = string.Empty; + private static string DbPassword = string.Empty; + private static string DbConnection = string.Empty; + private static MongoClient client = new(); + + public static event EventHandler DatabaseDisconnected; + + public static void OnDatabaseDisconnect(DbEventArgs e) + { + EventHandler handler = DatabaseDisconnected; + if (handler != null) + { + handler(null, e); + } + } + + /// + /// Initializes the connection to the database server + /// This will need to be called if the address or the password needs to be changed. + /// + /// The IP address of the database + /// Password used for the database + public static void Init(string host, string password) + { + DbHost = host; + DbPassword = password; + Reconnect(); + } + + /// + /// Initializes the connection to the database server + /// This will need to be called if the address or the password needs to be changed. + /// + /// The connection string to use to address of the database + public static void Init(string connection) + { + DbConnection = connection; + Reconnect(); + } + + /// + /// Reconnects to the mongodb + /// + public static void Reconnect() + { + string connection; + if (!string.IsNullOrEmpty(DbConnection)) + { + connection = DbConnection; + } + else + { + connection = $"mongodb://{DefaultUsername}:{DbPassword}@{DbHost}:{DefaultPort}/{DefaultDatabase}?authSource=admin&keepAlive=true&poolSize=30&autoReconnect=true&socketTimeoutMS=360000&connectTimeoutMS=360000"; + } + client = new MongoClient(connection); + } + + + + /// + /// Gets an interface to the database + /// + /// Gets the connection to the database + public static IMongoDatabase GetDb() + { + return client.GetDatabase(DefaultDatabase); + } + + /// + /// Gets a collection from the database + /// + /// Data type to use for the collection + /// Name of the collection + /// The found collection + public static IMongoCollection GetCollection(string? collectionName) + { + try + { + var db = GetDb(); + return db.GetCollection(collectionName); + } + catch(Exception ex) + { + OnDatabaseDisconnect(new DbEventArgs { Message = "GetCollection call failed" }); + throw new ElectionGuardException("GetCollection call failed", ex); + } + } + + /// + /// Method to verify that the connection to the database is working + /// + /// True/false if the client is connected to the server + public static bool Verify() + { + try + { + var db = GetDb(); + return db.ListCollectionNames().ToList().Count > 0; + } + catch(Exception ex) + { + OnDatabaseDisconnect(new DbEventArgs { Message = "Verify call failed" }); + throw new ElectionGuardException("Verify call failed", ex); + } + } + + /// + /// Method to check the status of the data store connection + /// + /// true if connected, otherwise false + public static bool Ping() + { + // nothing to ping until we have a client. + if (client is null) + { + return false; + } + + try + { + var db = GetDb(); + // One of the interesting things about MongoDb driver is we don't get state + // information about the connection until we actually try to use it. + // to try to ping the server to do the smallest possible query. + var r = db.RunCommandAsync((Command)/*lang=json*/ "{ping: 1}").Wait(1000); + } + catch (Exception) + { + OnDatabaseDisconnect(new DbEventArgs { Message = "Ping call failed" }); + return false; + } + + var server = client.Cluster.Description.Servers.FirstOrDefault(); + var ret = server is not null && + server.HeartbeatException is null && + server.State == ServerState.Connected; + if(!ret) + { + OnDatabaseDisconnect(new DbEventArgs { Message = "Ping call failed" }); + } + return ret; + } +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/DecryptionShareService.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/DecryptionShareService.cs index 939859a9b..680f0e070 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/DecryptionShareService.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/DecryptionShareService.cs @@ -10,7 +10,7 @@ public class DecryptionShareService : BaseDatabaseService /// /// The collection name to use to get/save data into /// - private readonly static string _collection = Constants.TableTallies; + private readonly static string _collection = DbConstants.TableTallies; /// /// Default constructor that sets the collection name @@ -23,14 +23,14 @@ public DecryptionShareService() : base(_collection, nameof(DecryptionShareRecord /// election id to search for public async Task> GetAllByTallyIdAsync(string tallyId) { - return await GetAllByFieldAsync(Constants.TallyId, tallyId); + return await GetAllByFieldAsync(DbConstants.TallyId, tallyId); } public async Task GetByGuardianIdAsync(string tallyId, string guardianId) { var filter = FilterBuilder.And( - FilterBuilder.Eq(Constants.TallyId, tallyId), - FilterBuilder.Eq(Constants.GuardianId, guardianId) + FilterBuilder.Eq(DbConstants.TallyId, tallyId), + FilterBuilder.Eq(DbConstants.GuardianId, guardianId) ); return (await GetAllByFilterAsync(filter)).FirstOrDefault(); @@ -38,15 +38,15 @@ public async Task> GetAllByTallyIdAsync(string tally public async Task GetCountByTallyAsync(string tallyId) { - var filter = FilterBuilder.Eq(Constants.TallyId, tallyId); + var filter = FilterBuilder.Eq(DbConstants.TallyId, tallyId); return await CountByFilterAsync(filter); } public async Task GetExistsByTallyAsync(string tallyId, string guardianId) { var filter = FilterBuilder.And( - FilterBuilder.Eq(Constants.TallyId, tallyId), - FilterBuilder.Eq(Constants.GuardianId, guardianId) + FilterBuilder.Eq(DbConstants.TallyId, tallyId), + FilterBuilder.Eq(DbConstants.GuardianId, guardianId) ); return await ExistsByFilterAsync(filter); } diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/ElectionService.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/ElectionService.cs index fc929e3b9..614043787 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/ElectionService.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/ElectionService.cs @@ -1,78 +1,78 @@ -using ElectionGuard.UI.Lib.Models; -using MongoDB.Driver; - -namespace ElectionGuard.UI.Lib.Services; - -/// -/// Data Service for Elections -/// -public class ElectionService : BaseDatabaseService -{ - /// - /// The collection name to use to get/save data into - /// - private readonly static string _collection = Constants.TableElections; - - /// - /// Default constructor that sets the collection name - /// - public ElectionService() : base(_collection, nameof(Election)) { } - - /// - /// Gets an election - /// - /// election id to search for - public async Task GetByElectionIdAsync(string electionId) - { - return await GetByFieldAsync(Constants.ElectionId, electionId); - } - - /// - /// Check if an election exists - /// - /// name of the election to search for - public async Task ElectionNameExists(string electionName) - { - var election = await GetByNameAsync(electionName); - return election != null; - } - - /// - /// Updated the current date of the latest export - /// - /// election id to use - /// date to save - virtual public async Task UpdateEncryptionExportDateAsync(string electionId, DateTime date) - { - var filterBuilder = Builders.Filter; - var filter = filterBuilder.And(filterBuilder.Eq(Constants.ElectionId, electionId)); - - var updateBuilder = Builders.Update; - var update = updateBuilder.Set(Constants.ExportEncryptionDateTime, date); - - await UpdateAsync(filter, update); - } - - /// - /// Gets count of elections that use a key ceremony - /// - /// key ceremony id to search for - public async Task CountByKeyCeremonyIdAsync(string keyCeremonyId) - { - var filterBuilder = Builders.Filter; - var filter = filterBuilder.Eq(Constants.KeyCeremonyId, keyCeremonyId); - return await CountByFilterAsync(filter); - } - - /// - /// Gets all elections that use a key ceremony - /// - /// key ceremony id to search for - public async Task> GetAllByKeyCeremonyIdAsync(string keyCeremonyId) - { - var filterBuilder = Builders.Filter; - var filter = filterBuilder.Eq(Constants.KeyCeremonyId, keyCeremonyId); - return await GetAllByFilterAsync(filter); - } - -} +using ElectionGuard.UI.Lib.Models; +using MongoDB.Driver; + +namespace ElectionGuard.UI.Lib.Services; + +/// +/// Data Service for Elections +/// +public class ElectionService : BaseDatabaseService +{ + /// + /// The collection name to use to get/save data into + /// + private readonly static string _collection = DbConstants.TableElections; + + /// + /// Default constructor that sets the collection name + /// + public ElectionService() : base(_collection, nameof(Election)) { } + + /// + /// Gets an election + /// + /// election id to search for + public async Task GetByElectionIdAsync(string electionId) + { + return await GetByFieldAsync(DbConstants.ElectionId, electionId); + } + + /// + /// Check if an election exists + /// + /// name of the election to search for + public async Task ElectionNameExists(string electionName) + { + var election = await GetByNameAsync(electionName); + return election != null; + } + + /// + /// Updated the current date of the latest export + /// + /// election id to use + /// date to save + virtual public async Task UpdateEncryptionExportDateAsync(string electionId, DateTime date) + { + var filterBuilder = Builders.Filter; + var filter = filterBuilder.And(filterBuilder.Eq(DbConstants.ElectionId, electionId)); + + var updateBuilder = Builders.Update; + var update = updateBuilder.Set(DbConstants.ExportEncryptionDateTime, date); + + await UpdateAsync(filter, update); + } + + /// + /// Gets count of elections that use a key ceremony + /// + /// key ceremony id to search for + public async Task CountByKeyCeremonyIdAsync(string keyCeremonyId) + { + var filterBuilder = Builders.Filter; + var filter = filterBuilder.Eq(DbConstants.KeyCeremonyId, keyCeremonyId); + return await CountByFilterAsync(filter); + } + + /// + /// Gets all elections that use a key ceremony + /// + /// key ceremony id to search for + public async Task> GetAllByKeyCeremonyIdAsync(string keyCeremonyId) + { + var filterBuilder = Builders.Filter; + var filter = filterBuilder.Eq(DbConstants.KeyCeremonyId, keyCeremonyId); + return await GetAllByFilterAsync(filter); + } + +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/GuardianBackupService.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/GuardianBackupService.cs index 0307ab667..423903323 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/GuardianBackupService.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/GuardianBackupService.cs @@ -1,69 +1,70 @@ -using MongoDB.Driver; -using ElectionGuard.UI.Lib.Models; - -namespace ElectionGuard.UI.Lib.Services; - -public interface IGuardianBackupService : IDatabaseService -{ - Task CountAsync(string keyCeremonyId); - Task CountAsync(string keyCeremonyId, string guardianId); - Task?> GetByGuardianIdAsync(string keyCeremonyId, string DesignatedId); - Task?> GetByKeyCeremonyIdAsync(string keyCeremonyId); -} - -/// -/// Data Service for Key Ceremonies -/// -public class GuardianBackupService : BaseDatabaseService, IGuardianBackupService -{ - /// - /// The collection name to use to get/save data into - /// - private readonly static string _collection = Constants.TableKeyCeremonies; - - /// - /// Default constructor that sets the collection name - /// - public GuardianBackupService() : base(_collection, nameof(GuardianBackups)) { } - - /// - /// Get all of the backups for all guardians for a key ceremony - /// - /// key ceremony id to search for - public async Task?> GetByKeyCeremonyIdAsync(string keyCeremonyId) - { - return await GetAllByFieldAsync(Constants.KeyCeremonyId, keyCeremonyId); - } - - /// - /// Get all of the backups for a single guardian for a key ceremony - /// - /// key ceremony id to search for - /// guardian id to match - /// - public async Task?> GetByGuardianIdAsync(string keyCeremonyId, string DesignatedId) - { - var filterBuilder = Builders.Filter; - var filter = filterBuilder.And(filterBuilder.Eq(Constants.KeyCeremonyId, keyCeremonyId), - filterBuilder.Eq(Constants.DesignatedId, DesignatedId)); - - return await GetAllByFilterAsync(filter); - } - - public async Task CountAsync(string keyCeremonyId) - { - var filterBuilder = Builders.Filter; - var filter = filterBuilder.And(filterBuilder.Eq(Constants.KeyCeremonyId, keyCeremonyId)); - - return await CountByFilterAsync(filter); - } - - public async Task CountAsync(string keyCeremonyId, string guardianId) - { - var filterBuilder = Builders.Filter; - var filter = filterBuilder.And(filterBuilder.Eq(Constants.KeyCeremonyId, keyCeremonyId), - filterBuilder.Eq(Constants.GuardianId, guardianId)); - - return await CountByFilterAsync(filter); - } -} +using MongoDB.Driver; +using ElectionGuard.UI.Lib.Models; +using ElectionGuard.ElectionSetup.Records; + +namespace ElectionGuard.UI.Lib.Services; + +public interface IGuardianBackupService : IDatabaseService +{ + Task CountAsync(string keyCeremonyId); + Task CountAsync(string keyCeremonyId, string guardianId); + Task?> GetByGuardianIdAsync(string keyCeremonyId, string DesignatedId); + Task?> GetByKeyCeremonyIdAsync(string keyCeremonyId); +} + +/// +/// Data Service for Key Ceremonies +/// +public class GuardianBackupService : BaseDatabaseService, IGuardianBackupService +{ + /// + /// The collection name to use to get/save data into + /// + private readonly static string _collection = DbConstants.TableKeyCeremonies; + + /// + /// Default constructor that sets the collection name + /// + public GuardianBackupService() : base(_collection, nameof(GuardianBackups)) { } + + /// + /// Get all of the backups for all guardians for a key ceremony + /// + /// key ceremony id to search for + public async Task?> GetByKeyCeremonyIdAsync(string keyCeremonyId) + { + return await GetAllByFieldAsync(DbConstants.KeyCeremonyId, keyCeremonyId); + } + + /// + /// Get all of the backups for a single guardian for a key ceremony + /// + /// key ceremony id to search for + /// guardian id to match + /// + public async Task?> GetByGuardianIdAsync(string keyCeremonyId, string DesignatedId) + { + var filterBuilder = Builders.Filter; + var filter = filterBuilder.And(filterBuilder.Eq(DbConstants.KeyCeremonyId, keyCeremonyId), + filterBuilder.Eq(DbConstants.DesignatedId, DesignatedId)); + + return await GetAllByFilterAsync(filter); + } + + public async Task CountAsync(string keyCeremonyId) + { + var filterBuilder = Builders.Filter; + var filter = filterBuilder.And(filterBuilder.Eq(DbConstants.KeyCeremonyId, keyCeremonyId)); + + return await CountByFilterAsync(filter); + } + + public async Task CountAsync(string keyCeremonyId, string guardianId) + { + var filterBuilder = Builders.Filter; + var filter = filterBuilder.And(filterBuilder.Eq(DbConstants.KeyCeremonyId, keyCeremonyId), + filterBuilder.Eq(DbConstants.GuardianId, guardianId)); + + return await CountByFilterAsync(filter); + } +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/GuardianPublicKeyService.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/GuardianPublicKeyService.cs index 5363bd47d..e0a40a48c 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/GuardianPublicKeyService.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/GuardianPublicKeyService.cs @@ -1,82 +1,82 @@ -using MongoDB.Driver; -using ElectionGuard.UI.Lib.Models; -using ElectionGuard.Guardians; - -namespace ElectionGuard.UI.Lib.Services; - -public interface IGuardianPublicKeyService : IDatabaseService -{ - Task CountAsync(string keyCeremonyId); - Task> GetAllByKeyCeremonyIdAsync(string keyCeremonyId); - Task GetByIdsAsync(string keyCeremonyId, string guardianId); - Task UpdatePublicKeyAsync(string keyCeremonyId, string guardianId, ElectionPublicKey? key); -} - -/// -/// Data Service for Key Ceremonies -/// -public class GuardianPublicKeyService : BaseDatabaseService, IGuardianPublicKeyService -{ - /// - /// The collection name to use to get/save data into - /// - private static readonly string _collection = Constants.TableKeyCeremonies; - - /// - /// Default constructor that sets the collection name - /// - public GuardianPublicKeyService() : base(_collection, nameof(GuardianPublicKey)) { } - - /// - /// Get all of the Public keys for a key ceremony - /// - /// key ceremony id to use - /// - public async Task> GetAllByKeyCeremonyIdAsync(string keyCeremonyId) - { - return await GetAllByFieldAsync(Constants.KeyCeremonyId, keyCeremonyId); - } - - /// - /// Update the data into the collection - /// - /// key ceremony id to search for - /// guardian id to search for - /// key to set for the guardian - public virtual async Task UpdatePublicKeyAsync( - string keyCeremonyId, string guardianId, ElectionPublicKey? key) - { - var filterBuilder = Builders.Filter; - var filter = filterBuilder.And(filterBuilder.Eq(Constants.KeyCeremonyId, keyCeremonyId), - filterBuilder.Eq(Constants.GuardianId, guardianId)); - - var update = Builders.Update.Set(Constants.PublicKey, key!); - - await UpdateAsync(filter, update); - } - - public async Task CountAsync(string keyCeremonyId) - { - var filterBuilder = Builders.Filter; - var filter = filterBuilder.And(filterBuilder.Eq(Constants.KeyCeremonyId, keyCeremonyId)); - - return await CountByFilterAsync(filter); - } - - public async Task GetByIdsAsync(string keyCeremonyId, string guardianId) - { - var filterBuilder = Builders.Filter; - var filter = filterBuilder.And(filterBuilder.Eq(Constants.KeyCeremonyId, keyCeremonyId), - filterBuilder.Eq(Constants.GuardianId, guardianId)); - - var list = await GetAllByFilterAsync(filter); - return list.FirstOrDefault(); - } - - public async Task> GetKeyCeremonyIdsAsync(string guardianId) - { - var list = await GetAllByFieldAsync(Constants.GuardianId, guardianId); - return list.Select(g => g.KeyCeremonyId!).ToList(); - } - -} +using MongoDB.Driver; +using ElectionGuard.UI.Lib.Models; +using ElectionGuard.Guardians; + +namespace ElectionGuard.UI.Lib.Services; + +public interface IGuardianPublicKeyService : IDatabaseService +{ + Task CountAsync(string keyCeremonyId); + Task> GetAllByKeyCeremonyIdAsync(string keyCeremonyId); + Task GetByIdsAsync(string keyCeremonyId, string guardianId); + Task UpdatePublicKeyAsync(string keyCeremonyId, string guardianId, ElectionPublicKey? key); +} + +/// +/// Data Service for Key Ceremonies +/// +public class GuardianPublicKeyService : BaseDatabaseService, IGuardianPublicKeyService +{ + /// + /// The collection name to use to get/save data into + /// + private static readonly string _collection = DbConstants.TableKeyCeremonies; + + /// + /// Default constructor that sets the collection name + /// + public GuardianPublicKeyService() : base(_collection, nameof(GuardianPublicKey)) { } + + /// + /// Get all of the Public keys for a key ceremony + /// + /// key ceremony id to use + /// + public async Task> GetAllByKeyCeremonyIdAsync(string keyCeremonyId) + { + return await GetAllByFieldAsync(DbConstants.KeyCeremonyId, keyCeremonyId); + } + + /// + /// Update the data into the collection + /// + /// key ceremony id to search for + /// guardian id to search for + /// key to set for the guardian + public virtual async Task UpdatePublicKeyAsync( + string keyCeremonyId, string guardianId, ElectionPublicKey? key) + { + var filterBuilder = Builders.Filter; + var filter = filterBuilder.And(filterBuilder.Eq(DbConstants.KeyCeremonyId, keyCeremonyId), + filterBuilder.Eq(DbConstants.GuardianId, guardianId)); + + var update = Builders.Update.Set(DbConstants.PublicKey, key!); + + await UpdateAsync(filter, update); + } + + public async Task CountAsync(string keyCeremonyId) + { + var filterBuilder = Builders.Filter; + var filter = filterBuilder.And(filterBuilder.Eq(DbConstants.KeyCeremonyId, keyCeremonyId)); + + return await CountByFilterAsync(filter); + } + + public async Task GetByIdsAsync(string keyCeremonyId, string guardianId) + { + var filterBuilder = Builders.Filter; + var filter = filterBuilder.And(filterBuilder.Eq(DbConstants.KeyCeremonyId, keyCeremonyId), + filterBuilder.Eq(DbConstants.GuardianId, guardianId)); + + var list = await GetAllByFilterAsync(filter); + return list.FirstOrDefault(); + } + + public async Task> GetKeyCeremonyIdsAsync(string guardianId) + { + var list = await GetAllByFieldAsync(DbConstants.GuardianId, guardianId); + return list.Select(g => g.KeyCeremonyId!).ToList(); + } + +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/KeyCeremonyService.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/KeyCeremonyService.cs index e0a6ec3b0..62a5a1df5 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/KeyCeremonyService.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/KeyCeremonyService.cs @@ -1,96 +1,96 @@ -using MongoDB.Driver; -using ElectionGuard.UI.Lib.Models; - -namespace ElectionGuard.UI.Lib.Services; - -public interface IKeyCeremonyService : IDatabaseService -{ - Task?> GetAllCompleteAsync(); - Task?> GetAllNotCompleteAsync(); - Task GetByKeyCeremonyIdAsync(string keyCeremonyId); - Task UpdateCompleteAsync(string keyCeremonyId, ElectionJointKey jointKey); - Task UpdateStateAsync(string keyCeremonyId, KeyCeremonyState state); -} - - -/// -/// Data Service for Key Ceremonies -/// -public class KeyCeremonyService : BaseDatabaseService, IKeyCeremonyService -{ - /// - /// The collection name to use to get/save data into - /// - private readonly static string _collection = Constants.TableKeyCeremonies; - - /// - /// Default constructor that sets the collection name - /// - public KeyCeremonyService() : base(_collection, nameof(KeyCeremonyRecord)) { } - - /// - /// Gets a key ceremony - /// - /// key ceremony id to search for - public async Task GetByKeyCeremonyIdAsync(string keyCeremonyId) - { - return await GetByFieldAsync(Constants.KeyCeremonyId, keyCeremonyId); - } - - /// - /// Gets all key ceremonies that are not in a completed state - /// - public async Task?> GetAllNotCompleteAsync() - { - var filterBuilder = Builders.Filter; - var filter = filterBuilder.Ne(Constants.State, KeyCeremonyState.Complete); - - return await GetAllByFilterAsync(filter); - } - - /// - /// Gets all key ceremonies that are not in a completed state - /// - public async Task?> GetAllCompleteAsync() - { - var filterBuilder = Builders.Filter; - var filter = filterBuilder.Eq(Constants.State, KeyCeremonyState.Complete); - - return await GetAllByFilterAsync(filter); - } - - /// - /// Updated the current state of the key ceremony - /// - /// key cermony id to use - /// new state to put the key ceremony into - public virtual async Task UpdateStateAsync(string keyCeremonyId, KeyCeremonyState state) - { - var filterBuilder = Builders.Filter; - var filter = filterBuilder.And(filterBuilder.Eq(Constants.KeyCeremonyId, keyCeremonyId)); - - var updateBuilder = Builders.Update; - var update = updateBuilder.Set(Constants.State, state) - .Set(Constants.UpdatedAt, DateTime.UtcNow); - - await UpdateAsync(filter, update); - } - - /// - /// Updates the key cermeony to a completed state and sets the completed at date/time - /// - /// key ceremony id to update - public virtual async Task UpdateCompleteAsync(string keyCeremonyId, ElectionJointKey jointKey) - { - var filterBuilder = Builders.Filter; - var filter = filterBuilder.And(filterBuilder.Eq(Constants.KeyCeremonyId, keyCeremonyId)); - - var updateBuilder = Builders.Update; - var update = updateBuilder.Set(Constants.State, KeyCeremonyState.Complete) - .Set(Constants.CompletedAt, DateTime.UtcNow) - .Set(Constants.UpdatedAt, DateTime.UtcNow) - .Set(Constants.JointKey, jointKey); - - await UpdateAsync(filter, update); - } -} +using MongoDB.Driver; +using ElectionGuard.UI.Lib.Models; + +namespace ElectionGuard.UI.Lib.Services; + +public interface IKeyCeremonyService : IDatabaseService +{ + Task?> GetAllCompleteAsync(); + Task?> GetAllNotCompleteAsync(); + Task GetByKeyCeremonyIdAsync(string keyCeremonyId); + Task UpdateCompleteAsync(string keyCeremonyId, ElectionJointKey jointKey); + Task UpdateStateAsync(string keyCeremonyId, KeyCeremonyState state); +} + + +/// +/// Data Service for Key Ceremonies +/// +public class KeyCeremonyService : BaseDatabaseService, IKeyCeremonyService +{ + /// + /// The collection name to use to get/save data into + /// + private readonly static string _collection = DbConstants.TableKeyCeremonies; + + /// + /// Default constructor that sets the collection name + /// + public KeyCeremonyService() : base(_collection, nameof(KeyCeremonyRecord)) { } + + /// + /// Gets a key ceremony + /// + /// key ceremony id to search for + public async Task GetByKeyCeremonyIdAsync(string keyCeremonyId) + { + return await GetByFieldAsync(DbConstants.KeyCeremonyId, keyCeremonyId); + } + + /// + /// Gets all key ceremonies that are not in a completed state + /// + public async Task?> GetAllNotCompleteAsync() + { + var filterBuilder = Builders.Filter; + var filter = filterBuilder.Ne(DbConstants.State, KeyCeremonyState.Complete); + + return await GetAllByFilterAsync(filter); + } + + /// + /// Gets all key ceremonies that are not in a completed state + /// + public async Task?> GetAllCompleteAsync() + { + var filterBuilder = Builders.Filter; + var filter = filterBuilder.Eq(DbConstants.State, KeyCeremonyState.Complete); + + return await GetAllByFilterAsync(filter); + } + + /// + /// Updated the current state of the key ceremony + /// + /// key cermony id to use + /// new state to put the key ceremony into + public virtual async Task UpdateStateAsync(string keyCeremonyId, KeyCeremonyState state) + { + var filterBuilder = Builders.Filter; + var filter = filterBuilder.And(filterBuilder.Eq(DbConstants.KeyCeremonyId, keyCeremonyId)); + + var updateBuilder = Builders.Update; + var update = updateBuilder.Set(DbConstants.State, state) + .Set(DbConstants.UpdatedAt, DateTime.UtcNow); + + await UpdateAsync(filter, update); + } + + /// + /// Updates the key cermeony to a completed state and sets the completed at date/time + /// + /// key ceremony id to update + public virtual async Task UpdateCompleteAsync(string keyCeremonyId, ElectionJointKey jointKey) + { + var filterBuilder = Builders.Filter; + var filter = filterBuilder.And(filterBuilder.Eq(DbConstants.KeyCeremonyId, keyCeremonyId)); + + var updateBuilder = Builders.Update; + var update = updateBuilder.Set(DbConstants.State, KeyCeremonyState.Complete) + .Set(DbConstants.CompletedAt, DateTime.UtcNow) + .Set(DbConstants.UpdatedAt, DateTime.UtcNow) + .Set(DbConstants.JointKey, jointKey); + + await UpdateAsync(filter, update); + } +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/LagrangeCoefficientsService.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/LagrangeCoefficientsService.cs index 1e27ad8dd..41c6bd435 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/LagrangeCoefficientsService.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/LagrangeCoefficientsService.cs @@ -1,29 +1,29 @@ -using ElectionGuard.UI.Lib.Models; - -namespace ElectionGuard.UI.Lib.Services; - -/// -/// Data Service for LagrangeCoefficientsService -/// -public class LagrangeCoefficientsService : BaseDatabaseService -{ - /// - /// The collection name to use to get/save data into - /// - private readonly static string _collection = Constants.TableTallies; - - /// - /// Default constructor that sets the collection name - /// - public LagrangeCoefficientsService() : base(_collection, nameof(LagrangeCoefficientsRecord)) { } - - /// - /// Gets Lagrange Coefficients for an election - /// - /// tally id to search for - public async Task GetByTallyIdAsync(string tallyId) - { - return await GetByFieldAsync(Constants.TallyId, tallyId); - } - -} +using ElectionGuard.UI.Lib.Models; + +namespace ElectionGuard.UI.Lib.Services; + +/// +/// Data Service for LagrangeCoefficientsService +/// +public class LagrangeCoefficientsService : BaseDatabaseService +{ + /// + /// The collection name to use to get/save data into + /// + private readonly static string _collection = DbConstants.TableTallies; + + /// + /// Default constructor that sets the collection name + /// + public LagrangeCoefficientsService() : base(_collection, nameof(LagrangeCoefficientsRecord)) { } + + /// + /// Gets Lagrange Coefficients for an election + /// + /// tally id to search for + public async Task GetByTallyIdAsync(string tallyId) + { + return await GetByFieldAsync(DbConstants.TallyId, tallyId); + } + +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/ManifestService.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/ManifestService.cs index 84865f348..bd49bfe24 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/ManifestService.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/ManifestService.cs @@ -1,29 +1,29 @@ -using ElectionGuard.UI.Lib.Models; - -namespace ElectionGuard.UI.Lib.Services; - -/// -/// Data Service for Elections -/// -public class ManifestService : BaseDatabaseService -{ - /// - /// The collection name to use to get/save data into - /// - private readonly static string _collection = Constants.TableElections; - - /// - /// Default constructor that sets the collection name - /// - public ManifestService() : base(_collection, nameof(ManifestRecord)) { } - - /// - /// Gets a manifest - /// - /// election id to search for - public async Task GetByElectionIdAsync(string electionId) - { - return await GetByFieldAsync(Constants.ElectionId, electionId); - } - -} +using ElectionGuard.UI.Lib.Models; + +namespace ElectionGuard.UI.Lib.Services; + +/// +/// Data Service for Elections +/// +public class ManifestService : BaseDatabaseService +{ + /// + /// The collection name to use to get/save data into + /// + private readonly static string _collection = DbConstants.TableElections; + + /// + /// Default constructor that sets the collection name + /// + public ManifestService() : base(_collection, nameof(ManifestRecord)) { } + + /// + /// Gets a manifest + /// + /// election id to search for + public async Task GetByElectionIdAsync(string electionId) + { + return await GetByFieldAsync(DbConstants.ElectionId, electionId); + } + +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/MultiTallyService.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/MultiTallyService.cs index b6606720b..de83cb7d2 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/MultiTallyService.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/MultiTallyService.cs @@ -1,31 +1,31 @@ -using ElectionGuard.UI.Lib.Models; - -namespace ElectionGuard.UI.Lib.Services; - -/// -/// Data Service for Tallies -/// -public class MultiTallyService : BaseDatabaseService -{ - /// - /// The collection name to use to get/save data into - /// - private readonly static string _collection = Constants.TableTallies; - - /// - /// Default constructor that sets the collection name - /// - public MultiTallyService() : base(_collection, nameof(MultiTallyRecord)) { } - - /// - /// Gets multi tallies for an election - /// - /// multi tally id to search for - public async Task GetByMultiTallyIdAsync(string multiTallyId) - { - return await GetByFieldAsync(Constants.MultiTallyId, multiTallyId); - } - - - -} +using ElectionGuard.UI.Lib.Models; + +namespace ElectionGuard.UI.Lib.Services; + +/// +/// Data Service for Tallies +/// +public class MultiTallyService : BaseDatabaseService +{ + /// + /// The collection name to use to get/save data into + /// + private readonly static string _collection = DbConstants.TableTallies; + + /// + /// Default constructor that sets the collection name + /// + public MultiTallyService() : base(_collection, nameof(MultiTallyRecord)) { } + + /// + /// Gets multi tallies for an election + /// + /// multi tally id to search for + public async Task GetByMultiTallyIdAsync(string multiTallyId) + { + return await GetByFieldAsync(DbConstants.MultiTallyId, multiTallyId); + } + + + +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/PlaintextTallyService.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/PlaintextTallyService.cs index a41d93d57..df597e3e0 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/PlaintextTallyService.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/PlaintextTallyService.cs @@ -1,36 +1,36 @@ -using ElectionGuard.UI.Lib.Models; - -namespace ElectionGuard.UI.Lib.Services; - -/// -/// Data Service for Tallies -/// -public class PlaintextTallyService : BaseDatabaseService -{ - /// - /// The collection name to use to get/save data into - /// - private readonly static string _collection = Constants.TableTallies; - - /// - /// Default constructor that sets the collection name - /// - public PlaintextTallyService() : base(_collection, nameof(PlaintextTallyRecord)) { } - - /// - /// Gets plain text tally for an election - /// - /// tally id to search for - public async Task GetByTallyIdAsync(string tallyId) - { - return await GetByFieldAsync(Constants.TallyId, tallyId); - } - - public Task SaveAsync(PlaintextTallyRecord data) - { - var filter = FilterBuilder.Eq(Constants.TallyId, data.TallyId); - return SaveAsync(data, filter); - } - - -} +using ElectionGuard.UI.Lib.Models; + +namespace ElectionGuard.UI.Lib.Services; + +/// +/// Data Service for Tallies +/// +public class PlaintextTallyService : BaseDatabaseService +{ + /// + /// The collection name to use to get/save data into + /// + private readonly static string _collection = DbConstants.TableTallies; + + /// + /// Default constructor that sets the collection name + /// + public PlaintextTallyService() : base(_collection, nameof(PlaintextTallyRecord)) { } + + /// + /// Gets plain text tally for an election + /// + /// tally id to search for + public async Task GetByTallyIdAsync(string tallyId) + { + return await GetByFieldAsync(DbConstants.TallyId, tallyId); + } + + public Task SaveAsync(PlaintextTallyRecord data) + { + var filter = FilterBuilder.Eq(DbConstants.TallyId, data.TallyId); + return SaveAsync(data, filter); + } + + +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/TallyJoinedService.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/TallyJoinedService.cs index cef4b6cb5..4d47215f5 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/TallyJoinedService.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/TallyJoinedService.cs @@ -4,20 +4,20 @@ namespace ElectionGuard.UI.Lib.Services; public class TallyJoinedService : BaseDatabaseService { - private readonly static string _collection = Constants.TableTallies; + private readonly static string _collection = DbConstants.TableTallies; public TallyJoinedService() : base(_collection, nameof(TallyJoinedRecord)) { } public async Task> GetAllByTallyIdAsync(string tallyId) => - await GetAllByFieldAsync(Constants.TallyId, tallyId); + await GetAllByFieldAsync(DbConstants.TallyId, tallyId); public async Task JoinTallyAsync(TallyJoinedRecord joiner) { var filter = FilterBuilder.And( - FilterBuilder.Eq(Constants.TallyId, joiner.TallyId), - FilterBuilder.Eq(Constants.GuardianId, joiner.GuardianId)); + FilterBuilder.Eq(DbConstants.TallyId, joiner.TallyId), + FilterBuilder.Eq(DbConstants.GuardianId, joiner.GuardianId)); var count = await CountByFilterAsync(filter); if (count == 0) @@ -29,8 +29,8 @@ public async Task JoinTallyAsync(TallyJoinedRecord joiner) public async Task> GetGuardianRejectedIdsAsync(string guardianId) { var filter = FilterBuilder.And( - FilterBuilder.Eq(Constants.Joined, false), - FilterBuilder.Eq(Constants.GuardianId, guardianId)); + FilterBuilder.Eq(DbConstants.Joined, false), + FilterBuilder.Eq(DbConstants.GuardianId, guardianId)); var list = await GetAllByFilterAsync(filter); return list.Select(t => t.TallyId!).ToList(); @@ -41,7 +41,7 @@ public async Task> GetGuardianRejectedIdsAsync(string guardianId) /// public async Task> GetGuardianCountByTallyAsync(string tallyId) { - var filter = FilterBuilder.Eq(Constants.TallyId, tallyId); + var filter = FilterBuilder.Eq(DbConstants.TallyId, tallyId); List guardiansParticipating = await GetAllByFilterAsync(filter) ?? new(); return guardiansParticipating.GroupBy(g => g.Joined).ToDictionary(g => g.Key, g => g.Count()); @@ -50,8 +50,8 @@ public async Task> GetGuardianCountByTallyAsync(string tal public async Task GetCountByTallyJoinedAsync(string tallyId) { var filter = FilterBuilder.And( - FilterBuilder.Eq(Constants.TallyId, tallyId), - FilterBuilder.Eq(Constants.Joined, true)); + FilterBuilder.Eq(DbConstants.TallyId, tallyId), + FilterBuilder.Eq(DbConstants.Joined, true)); return await CountByFilterAsync(filter); } @@ -59,8 +59,8 @@ public async Task GetCountByTallyJoinedAsync(string tallyId) public async Task GetExistsByTallyAsync(string tallyId, string guardianId) { var filter = FilterBuilder.And( - FilterBuilder.Eq(Constants.TallyId, tallyId), - FilterBuilder.Eq(Constants.GuardianId, guardianId) + FilterBuilder.Eq(DbConstants.TallyId, tallyId), + FilterBuilder.Eq(DbConstants.GuardianId, guardianId) ); return await ExistsByFilterAsync(filter); } diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/TallyService.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/TallyService.cs index 7caeb5557..7008ca947 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/TallyService.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/TallyService.cs @@ -1,97 +1,97 @@ -using ElectionGuard.UI.Lib.Models; -using MongoDB.Bson; -using MongoDB.Driver; - -namespace ElectionGuard.UI.Lib.Services; - -/// -/// Data Service for Tallies -/// -public class TallyService : BaseDatabaseService -{ - /// - /// The collection name to use to get/save data into - /// - private readonly static string _collection = Constants.TableTallies; - - /// - /// Default constructor that sets the collection name - /// - public TallyService() : base(_collection, nameof(TallyRecord)) { } - - /// - /// Gets tallies for an election, including completed tallies. - /// - /// election id to search for - public async Task> GetAllActiveByElectionIdAsync(string electionId) - { - var filter = FilterBuilder.And( - FilterBuilder.Eq(Constants.ElectionId, electionId), - FilterBuilder.Ne(Constants.State, TallyState.Abandoned)); - - return await GetAllByFilterAsync(filter); - } - - /// - /// Gets tally state to determine if it is running - /// - /// tally id to search for - public async Task IsRunningByTallyIdAsync(string tallyId) - { - var tally = await GetByFieldAsync(Constants.TallyId, tallyId); - return tally?.State is not TallyState.Complete and not TallyState.Abandoned; - } - - /// - /// Gets tallies for an election - /// - /// tally id to search for - public async Task GetByTallyIdAsync(string tallyId) - { - return await GetByFieldAsync(Constants.TallyId, tallyId); - } - - public async Task TallyNameExistsAsync(string name) - { - var tally = await GetByNameAsync(name); - return tally != null; - } - - public async Task> GetAllByKeyCeremoniesAsync(List ids) - { - BsonArray array = new(ids); - return await GetAllByFieldInListAsync(Constants.KeyCeremonyId, array); - } - - /// - /// Updates the key cermeony to a completed state and sets the completed at date/time - /// - /// key ceremony id to update - virtual public async Task UpdateCompleteAsync(string tallyId) - { - var filter = FilterBuilder.And(FilterBuilder.Eq(Constants.TallyId, tallyId)); - - var updateBuilder = Builders.Update; - var update = updateBuilder.Set(Constants.State, TallyState.Complete) - .Set(Constants.CompletedAt, DateTime.UtcNow) - .Set(Constants.UpdatedAt, DateTime.UtcNow); - - await UpdateAsync(filter, update); - } - - /// - /// Update the state of the TallyRecord - /// - /// tally id to use - /// new state to put the tally into - public virtual async Task UpdateStateAsync(string tallyId, TallyState state) - { - var filter = FilterBuilder.And(FilterBuilder.Eq(Constants.TallyId, tallyId)); - - var updateBuilder = Builders.Update; - var update = updateBuilder.Set(Constants.State, state); - - await UpdateAsync(filter, update); - } - -} +using ElectionGuard.UI.Lib.Models; +using MongoDB.Bson; +using MongoDB.Driver; + +namespace ElectionGuard.UI.Lib.Services; + +/// +/// Data Service for Tallies +/// +public class TallyService : BaseDatabaseService +{ + /// + /// The collection name to use to get/save data into + /// + private readonly static string _collection = DbConstants.TableTallies; + + /// + /// Default constructor that sets the collection name + /// + public TallyService() : base(_collection, nameof(TallyRecord)) { } + + /// + /// Gets tallies for an election, including completed tallies. + /// + /// election id to search for + public async Task> GetAllActiveByElectionIdAsync(string electionId) + { + var filter = FilterBuilder.And( + FilterBuilder.Eq(DbConstants.ElectionId, electionId), + FilterBuilder.Ne(DbConstants.State, TallyState.Abandoned)); + + return await GetAllByFilterAsync(filter); + } + + /// + /// Gets tally state to determine if it is running + /// + /// tally id to search for + public async Task IsRunningByTallyIdAsync(string tallyId) + { + var tally = await GetByFieldAsync(DbConstants.TallyId, tallyId); + return tally?.State is not TallyState.Complete and not TallyState.Abandoned; + } + + /// + /// Gets tallies for an election + /// + /// tally id to search for + public async Task GetByTallyIdAsync(string tallyId) + { + return await GetByFieldAsync(DbConstants.TallyId, tallyId); + } + + public async Task TallyNameExistsAsync(string name) + { + var tally = await GetByNameAsync(name); + return tally != null; + } + + public async Task> GetAllByKeyCeremoniesAsync(List ids) + { + BsonArray array = new(ids); + return await GetAllByFieldInListAsync(DbConstants.KeyCeremonyId, array); + } + + /// + /// Updates the key cermeony to a completed state and sets the completed at date/time + /// + /// key ceremony id to update + virtual public async Task UpdateCompleteAsync(string tallyId) + { + var filter = FilterBuilder.And(FilterBuilder.Eq(DbConstants.TallyId, tallyId)); + + var updateBuilder = Builders.Update; + var update = updateBuilder.Set(DbConstants.State, TallyState.Complete) + .Set(DbConstants.CompletedAt, DateTime.UtcNow) + .Set(DbConstants.UpdatedAt, DateTime.UtcNow); + + await UpdateAsync(filter, update); + } + + /// + /// Update the state of the TallyRecord + /// + /// tally id to use + /// new state to put the tally into + public virtual async Task UpdateStateAsync(string tallyId, TallyState state) + { + var filter = FilterBuilder.And(FilterBuilder.Eq(DbConstants.TallyId, tallyId)); + + var updateBuilder = Builders.Update; + var update = updateBuilder.Set(DbConstants.State, state); + + await UpdateAsync(filter, update); + } + +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/UserService.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/UserService.cs index 173733b4b..3b4b9581b 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/UserService.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/UserService.cs @@ -1,19 +1,19 @@ -using ElectionGuard.UI.Lib.Models; - -namespace ElectionGuard.UI.Lib.Services; - -/// -/// Data Service for Users -/// -public class UserService : BaseDatabaseService -{ - /// - /// The collection name to use to get/save data into - /// - private readonly static string _collection = "users"; - - /// - /// Default constructor that sets the collection name - /// - public UserService() : base(_collection, nameof(User)) { } -} +using ElectionGuard.UI.Lib.Models; + +namespace ElectionGuard.UI.Lib.Services; + +/// +/// Data Service for Users +/// +public class UserService : BaseDatabaseService +{ + /// + /// The collection name to use to get/save data into + /// + private readonly static string _collection = "users"; + + /// + /// Default constructor that sets the collection name + /// + public UserService() : base(_collection, nameof(User)) { } +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/VerificationService.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/VerificationService.cs index 85cc4573e..6932c9cda 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/VerificationService.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Database/VerificationService.cs @@ -1,52 +1,52 @@ -using ElectionGuard.UI.Lib.Models; -using MongoDB.Driver; - -namespace ElectionGuard.UI.Lib.Services; - -public interface IVerificationService : IDatabaseService -{ - Task CountAsync(string keyCeremonyId, string guardianId); - Task CountAsync(string keyCeremonyId); - Task?> GetAllByKeyCeremonyIdAsync(string keyCeremonyId); -} - -/// -/// Data Service for backup verifications -/// -public class VerificationService : BaseDatabaseService, IVerificationService -{ - /// - /// The collection name to use to get/save data into - /// - private readonly static string _collection = Constants.TableKeyCeremonies; - - /// - /// Default constructor that sets the collection name - /// - public VerificationService() : base(_collection, nameof(ElectionPartialKeyVerification)) { } - - /// - /// Gets a key ceremony - /// - /// key ceremony id to search for - public async Task?> GetAllByKeyCeremonyIdAsync(string keyCeremonyId) - { - return await GetAllByFieldAsync(Constants.KeyCeremonyId, keyCeremonyId); - } - - public async Task CountAsync(string keyCeremonyId, string guardianId) - { - var filterBuilder = Builders.Filter; - var filter = filterBuilder.And(filterBuilder.Eq(Constants.KeyCeremonyId, keyCeremonyId), - filterBuilder.Eq(Constants.DesignatedId, guardianId)); - - return await CountByFilterAsync(filter); - } - public async Task CountAsync(string keyCeremonyId) - { - var filterBuilder = Builders.Filter; - var filter = filterBuilder.And(filterBuilder.Eq(Constants.KeyCeremonyId, keyCeremonyId)); - - return await CountByFilterAsync(filter); - } -} +using ElectionGuard.UI.Lib.Models; +using MongoDB.Driver; + +namespace ElectionGuard.UI.Lib.Services; + +public interface IVerificationService : IDatabaseService +{ + Task CountAsync(string keyCeremonyId, string guardianId); + Task CountAsync(string keyCeremonyId); + Task?> GetAllByKeyCeremonyIdAsync(string keyCeremonyId); +} + +/// +/// Data Service for backup verifications +/// +public class VerificationService : BaseDatabaseService, IVerificationService +{ + /// + /// The collection name to use to get/save data into + /// + private readonly static string _collection = DbConstants.TableKeyCeremonies; + + /// + /// Default constructor that sets the collection name + /// + public VerificationService() : base(_collection, nameof(ElectionPartialKeyVerification)) { } + + /// + /// Gets a key ceremony + /// + /// key ceremony id to search for + public async Task?> GetAllByKeyCeremonyIdAsync(string keyCeremonyId) + { + return await GetAllByFieldAsync(DbConstants.KeyCeremonyId, keyCeremonyId); + } + + public async Task CountAsync(string keyCeremonyId, string guardianId) + { + var filterBuilder = Builders.Filter; + var filter = filterBuilder.And(filterBuilder.Eq(DbConstants.KeyCeremonyId, keyCeremonyId), + filterBuilder.Eq(DbConstants.DesignatedId, guardianId)); + + return await CountByFilterAsync(filter); + } + public async Task CountAsync(string keyCeremonyId) + { + var filterBuilder = Builders.Filter; + var filter = filterBuilder.And(filterBuilder.Eq(DbConstants.KeyCeremonyId, keyCeremonyId)); + + return await CountByFilterAsync(filter); + } +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/FileSystem/DriveService.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/FileSystem/DriveService.cs index a8f77076e..926ecd11a 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/FileSystem/DriveService.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/FileSystem/DriveService.cs @@ -1,54 +1,54 @@ -using ElectionGuard.UI.Lib.Models; - -namespace ElectionGuard.UI.Lib.Services; - -public class DriveService : IStorageService -{ - private string _rootDirectoryPath; - - public DriveService(string rootDirectoryPath) - { - _rootDirectoryPath = rootDirectoryPath; - } - - public DriveService() : this(Path.GetTempPath()) - { - } - - public void ToFile(string fileName, string content) - { - var filePath = Path.Combine(_rootDirectoryPath, fileName); - File.WriteAllText(filePath, content); - } - - public void ToFiles(List fileContents) - { - _ = Parallel.ForEach(fileContents, fileContent => - { - ToFile(fileContent.FileName, fileContent.Contents); - }); - } - - public string FromFile(string fileName) - { - if (string.IsNullOrEmpty(fileName)) throw new ArgumentNullException(nameof(fileName)); - - var filePath = Path.Combine(_rootDirectoryPath, fileName); - - if (!File.Exists(filePath)) throw new FileNotFoundException(nameof(filePath)); - - return File.ReadAllText(filePath); - } - - public void UpdatePath(string path) - { - if (string.IsNullOrEmpty(path)) throw new ArgumentNullException(nameof(path)); - - if (!Directory.Exists(path)) - { - // create directory - _ = Directory.CreateDirectory(path); - } - _rootDirectoryPath = path; - } -} +using ElectionGuard.UI.Lib.Models; + +namespace ElectionGuard.UI.Lib.Services; + +public class DriveService : IStorageService +{ + private string _rootDirectoryPath; + + public DriveService(string rootDirectoryPath) + { + _rootDirectoryPath = rootDirectoryPath; + } + + public DriveService() : this(Path.GetTempPath()) + { + } + + public void ToFile(string fileName, string content) + { + var filePath = Path.Combine(_rootDirectoryPath, fileName); + File.WriteAllText(filePath, content); + } + + public void ToFiles(List fileContents) + { + _ = Parallel.ForEach(fileContents, fileContent => + { + ToFile(fileContent.FileName, fileContent.Contents); + }); + } + + public string FromFile(string fileName) + { + if (string.IsNullOrEmpty(fileName)) throw new ArgumentNullException(nameof(fileName)); + + var filePath = Path.Combine(_rootDirectoryPath, fileName); + + if (!File.Exists(filePath)) throw new FileNotFoundException(nameof(filePath)); + + return File.ReadAllText(filePath); + } + + public void UpdatePath(string path) + { + if (string.IsNullOrEmpty(path)) throw new ArgumentNullException(nameof(path)); + + if (!Directory.Exists(path)) + { + // create directory + _ = Directory.CreateDirectory(path); + } + _rootDirectoryPath = path; + } +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/FileSystem/ZipService.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/FileSystem/ZipService.cs index 706077fe7..2383aa55d 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/FileSystem/ZipService.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/FileSystem/ZipService.cs @@ -1,59 +1,59 @@ -using System.IO.Compression; -using ElectionGuard.UI.Lib.Models; - -namespace ElectionGuard.UI.Lib.Services; -public class ZipStorageService : IStorageService -{ - private string _zipFile = string.Empty; - - private ZipArchiveMode ZipMode => File.Exists(_zipFile) ? ZipArchiveMode.Update : ZipArchiveMode.Create; - - public ZipStorageService(string zipFile) - { - UpdatePath(zipFile); - } - - public ZipStorageService() : this(Path.GetTempFileName()) { } - - public void ToFile(string fileName, string content) - { - if (string.IsNullOrEmpty(fileName)) - { - throw new ArgumentNullException(nameof(fileName)); - } - - using var zipArchive = ZipFile.Open(_zipFile, ZipMode); - - var entry = zipArchive.CreateEntry(fileName); - using var stream = entry.Open(); - using var writer = new StreamWriter(stream); - - writer.Write(content); - } - - public void ToFiles(List fileContents) - { - using var zipArchive = ZipFile.Open(_zipFile, ZipMode); +using System.IO.Compression; +using ElectionGuard.UI.Lib.Models; + +namespace ElectionGuard.UI.Lib.Services; +public class ZipStorageService : IStorageService +{ + private string _zipFile = string.Empty; + + private ZipArchiveMode ZipMode => File.Exists(_zipFile) ? ZipArchiveMode.Update : ZipArchiveMode.Create; + + public ZipStorageService(string zipFile) + { + UpdatePath(zipFile); + } + + public ZipStorageService() : this(Path.GetTempFileName()) { } + + public void ToFile(string fileName, string content) + { + if (string.IsNullOrEmpty(fileName)) + { + throw new ArgumentNullException(nameof(fileName)); + } + + using var zipArchive = ZipFile.Open(_zipFile, ZipMode); + + var entry = zipArchive.CreateEntry(fileName); + using var stream = entry.Open(); + using var writer = new StreamWriter(stream); + + writer.Write(content); + } + + public void ToFiles(List fileContents) + { + using var zipArchive = ZipFile.Open(_zipFile, ZipMode); foreach (var fileContent in fileContents) - { - var entry = zipArchive.CreateEntry(fileContent.FileName); - using var stream = entry.Open(); - using var writer = new StreamWriter(stream); - writer.Write(fileContent.Contents); - } - } - - public string FromFile(string fileName) - { - using var zipArchive = ZipFile.OpenRead(_zipFile); - var entry = zipArchive.GetEntry(fileName) ?? throw new FileNotFoundException(nameof(fileName)); - using var stream = entry.Open(); - using var reader = new StreamReader(stream); - return reader.ReadToEnd(); - } - - public void UpdatePath(string zipFile) - { - _zipFile = zipFile; - } -} + { + var entry = zipArchive.CreateEntry(fileContent.FileName); + using var stream = entry.Open(); + using var writer = new StreamWriter(stream); + writer.Write(fileContent.Contents); + } + } + + public string FromFile(string fileName) + { + using var zipArchive = ZipFile.OpenRead(_zipFile); + var entry = zipArchive.GetEntry(fileName) ?? throw new FileNotFoundException(nameof(fileName)); + using var stream = entry.Open(); + using var reader = new StreamReader(stream); + return reader.ReadToEnd(); + } + + public void UpdatePath(string zipFile) + { + _zipFile = zipFile; + } +} diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Guardian/GuardianStorageExtensions.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/GuardianStorageExtensions.cs similarity index 88% rename from bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Guardian/GuardianStorageExtensions.cs rename to src/electionguard-ui/ElectionGuard.UI.Lib/Services/GuardianStorageExtensions.cs index 41ccef1b2..80a23a15e 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/Guardian/GuardianStorageExtensions.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/GuardianStorageExtensions.cs @@ -1,9 +1,11 @@ using ElectionGuard.Converters; using ElectionGuard.Guardians; +using ElectionGuard.ElectionSetup; using ElectionGuard.UI.Lib.Models; -using ElectionGuard.UI.Lib.Services; +using Newtonsoft.Json; +using ElectionGuard.ElectionSetup.Records; -namespace ElectionGuard.ElectionSetup; +namespace ElectionGuard.UI.Lib.Services; /// /// Guardian storage extensions for working with local storage @@ -20,12 +22,12 @@ public static Guardian FromPrivateRecord( int numberOfGuardians, int quorum, Dictionary? publicKeys = null, - Dictionary? otherBackups = null) + Dictionary? otherBackups = null) { return new( privateGuardianRecord.ElectionKeys, privateGuardianRecord.CommitmentSeed, - new(keyCeremonyId, numberOfGuardians, quorum), + new CeremonyDetails(keyCeremonyId, numberOfGuardians, quorum), publicKeys, otherBackups); } @@ -44,7 +46,7 @@ public static Guardian FromPrivateRecord( int guardianCount, int quorum, Dictionary? publicKeys = null, - Dictionary? otherBackups = null) + Dictionary? otherBackups = null) { var storage = StorageService.GetInstance(); @@ -53,7 +55,7 @@ public static Guardian FromPrivateRecord( var filePath = Path.Combine(basePath, PrivateKeyFolder, keyCeremonyId, filename); try - { + { var data = storage.FromFile(filePath); var privateGuardian = JsonConvert.DeserializeObject( @@ -78,7 +80,7 @@ public static Guardian FromPrivateRecord( string guardianId, KeyCeremonyRecord keyCeremony, Dictionary? publicKeys = null, - Dictionary? otherBackups = null) + Dictionary? otherBackups = null) { return Load(guardianId, keyCeremony.KeyCeremonyId!, keyCeremony.NumberOfGuardians, keyCeremony.Quorum, publicKeys, otherBackups); } diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Interfaces/IAuthenticationService.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Interfaces/IAuthenticationService.cs index d6e56b15f..f65340d58 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Interfaces/IAuthenticationService.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Interfaces/IAuthenticationService.cs @@ -1,5 +1,5 @@ -using Microsoft.Extensions.Logging; - +using Microsoft.Extensions.Logging; + namespace ElectionGuard.UI.Lib.Services; public interface IAuthenticationService diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Interfaces/IDatabaseService.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Interfaces/IDatabaseService.cs index bf9723a7c..23eb3dd76 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Interfaces/IDatabaseService.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Interfaces/IDatabaseService.cs @@ -1,90 +1,90 @@ -using MongoDB.Driver; - -namespace ElectionGuard.UI.Lib.Services; - -/// -/// static class used for constant strings used in database calls -/// -internal static class Constants -{ - public readonly static string DataType = "DataType"; - - public readonly static string DesignatedId = "DesignatedId"; - - public readonly static string ElectionId = "ElectionId"; - - public readonly static string BallotCode = "BallotCode"; - - public readonly static string SerialNumber = "SerialNumber"; - - public readonly static string TallyId = "TallyId"; - - public readonly static string MultiTallyId = "MultiTallyId"; - - public readonly static string UploadId = "UploadId"; - - public readonly static string GuardianId = "GuardianId"; - - public readonly static string Joined = "Joined"; - - public readonly static string Id = "Id"; - - public readonly static string KeyCeremonyId = "KeyCeremonyId"; - - public readonly static string Name = "Name"; - - public readonly static string PublicKey = "PublicKey"; - - public readonly static string SoftDeleted = "SoftDeleted"; - - public readonly static string State = "State"; - - public readonly static string ExportEncryptionDateTime = "ExportEncryptionDateTime"; - - public readonly static string TableBallots = "ballots"; - - public readonly static string TableElections = "elections"; - - public readonly static string TableKeyCeremonies = "key_ceremonies"; - - public readonly static string TableTallies = "tallies"; - - public readonly static string CompletedAt = "CompletedAt"; - - public readonly static string JointKey = "JointKey"; - - public readonly static string UpdatedAt = "UpdatedAt"; - - public readonly static string IsExportable = "IsExportable"; - - public readonly static string BallotState = "BallotState"; - - public readonly static string ObjectId = "ObjectId"; - - public readonly static string BallotChallenged = "BallotChallenged"; - - public readonly static string BallotSpoiled = "BallotSpoiled"; - -} - - -/// -/// Interface for defining the basic calls for the database for a given data type. -/// Any other functions that are not generic across all of the types can be added to -/// the specific Service created by this interface. -/// -/// Data type to use for the service -public interface IDatabaseService -{ - Task CountByFilterAsync(FilterDefinition filter, string? table = null); - Task ExistsByFilterAsync(FilterDefinition filter, string? table = null); - Task> GetAllAsync(string? table = null); - Task> GetAllByFilterAsync(FilterDefinition filter, string? table = null); - Task> GetAllByFieldAsync(string fieldName, object fieldValue, string? table = null); - Task GetByIdAsync(string id, string? table = null); - Task GetByNameAsync(string name, string? table = null); - Task GetByFieldAsync(string fieldName, object fieldValue, string? table = null); - Task SaveAsync(T data, FilterDefinition? customFilter = null, string? table = null); - Task UpdateAsync(FilterDefinition filter, UpdateDefinition update, string? table = null); - FilterDefinition UpdateFilter(FilterDefinition filter, bool getDeleted = false); -} +using MongoDB.Driver; + +namespace ElectionGuard.UI.Lib.Services; + +/// +/// static class used for constant strings used in database calls +/// +internal static class DbConstants +{ + public readonly static string DataType = "DataType"; + + public readonly static string DesignatedId = "DesignatedId"; + + public readonly static string ElectionId = "ElectionId"; + + public readonly static string BallotCode = "BallotCode"; + + public readonly static string SerialNumber = "SerialNumber"; + + public readonly static string TallyId = "TallyId"; + + public readonly static string MultiTallyId = "MultiTallyId"; + + public readonly static string UploadId = "UploadId"; + + public readonly static string GuardianId = "GuardianId"; + + public readonly static string Joined = "Joined"; + + public readonly static string Id = "Id"; + + public readonly static string KeyCeremonyId = "KeyCeremonyId"; + + public readonly static string Name = "Name"; + + public readonly static string PublicKey = "PublicKey"; + + public readonly static string SoftDeleted = "SoftDeleted"; + + public readonly static string State = "State"; + + public readonly static string ExportEncryptionDateTime = "ExportEncryptionDateTime"; + + public readonly static string TableBallots = "ballots"; + + public readonly static string TableElections = "elections"; + + public readonly static string TableKeyCeremonies = "key_ceremonies"; + + public readonly static string TableTallies = "tallies"; + + public readonly static string CompletedAt = "CompletedAt"; + + public readonly static string JointKey = "JointKey"; + + public readonly static string UpdatedAt = "UpdatedAt"; + + public readonly static string IsExportable = "IsExportable"; + + public readonly static string BallotState = "BallotState"; + + public readonly static string ObjectId = "ObjectId"; + + public readonly static string BallotChallenged = "BallotChallenged"; + + public readonly static string BallotSpoiled = "BallotSpoiled"; + +} + + +/// +/// Interface for defining the basic calls for the database for a given data type. +/// Any other functions that are not generic across all of the types can be added to +/// the specific Service created by this interface. +/// +/// Data type to use for the service +public interface IDatabaseService +{ + Task CountByFilterAsync(FilterDefinition filter, string? table = null); + Task ExistsByFilterAsync(FilterDefinition filter, string? table = null); + Task> GetAllAsync(string? table = null); + Task> GetAllByFilterAsync(FilterDefinition filter, string? table = null); + Task> GetAllByFieldAsync(string fieldName, object fieldValue, string? table = null); + Task GetByIdAsync(string id, string? table = null); + Task GetByNameAsync(string name, string? table = null); + Task GetByFieldAsync(string fieldName, object fieldValue, string? table = null); + Task SaveAsync(T data, FilterDefinition? customFilter = null, string? table = null); + Task UpdateAsync(FilterDefinition filter, UpdateDefinition update, string? table = null); + FilterDefinition UpdateFilter(FilterDefinition filter, bool getDeleted = false); +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Interfaces/IStorageService.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Interfaces/IStorageService.cs index 336c55a64..3646eb26e 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Interfaces/IStorageService.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/Interfaces/IStorageService.cs @@ -1,56 +1,56 @@ -using ElectionGuard.UI.Lib.Models; - -namespace ElectionGuard.UI.Lib.Services; - -/// -/// Interface to read/write file data -/// -public interface IStorageService -{ - /// - /// Write a string to a file on a drive - /// - /// folder where the file will be created - /// name of the file - /// data to save into file - public void ToFile(string filename, string content); - - /// - /// Write multiple files to a drive - /// - /// - public void ToFiles(List files); - - /// - /// Read in the contents of a file - /// - /// filename including path - /// the string data from the file - /// File does not exist - /// filename not provided - public string FromFile(string filename); - - /// - /// Update the path for a file - /// - /// new path - /// Path is null - /// Path does not exist - public void UpdatePath(string path); -} - -/// -/// static service to get the configured storage service to use -/// -public static class StorageService -{ - /// - /// Creates an instance of a storage service to use - /// - /// a storage service - public static IStorageService GetInstance() - { - // TODO: this will need to be enhanced when we add yubikey support - return new DriveService(); - } -} +using ElectionGuard.UI.Lib.Models; + +namespace ElectionGuard.UI.Lib.Services; + +/// +/// Interface to read/write file data +/// +public interface IStorageService +{ + /// + /// Write a string to a file on a drive + /// + /// folder where the file will be created + /// name of the file + /// data to save into file + public void ToFile(string filename, string content); + + /// + /// Write multiple files to a drive + /// + /// + public void ToFiles(List files); + + /// + /// Read in the contents of a file + /// + /// filename including path + /// the string data from the file + /// File does not exist + /// filename not provided + public string FromFile(string filename); + + /// + /// Update the path for a file + /// + /// new path + /// Path is null + /// Path does not exist + public void UpdatePath(string path); +} + +/// +/// static service to get the configured storage service to use +/// +public static class StorageService +{ + /// + /// Creates an instance of a storage service to use + /// + /// a storage service + public static IStorageService GetInstance() + { + // TODO: this will need to be enhanced when we add yubikey support + return new DriveService(); + } +} diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/KeyCeremonyMediator.cs b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/KeyCeremonyMediator.cs similarity index 96% rename from bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/KeyCeremonyMediator.cs rename to src/electionguard-ui/ElectionGuard.UI.Lib/Services/KeyCeremonyMediator.cs index 55cfbf93e..6f8922fca 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.ElectionSetup/KeyCeremonyMediator.cs +++ b/src/electionguard-ui/ElectionGuard.UI.Lib/Services/KeyCeremonyMediator.cs @@ -1,891 +1,893 @@ -using System.Diagnostics; -using ElectionGuard.ElectionSetup.Exceptions; -using ElectionGuard.ElectionSetup.Extensions; -using ElectionGuard.Extensions; -using ElectionGuard.Guardians; -using ElectionGuard.UI.Lib.Models; -using ElectionGuard.UI.Lib.Services; - -namespace ElectionGuard.ElectionSetup; - -public interface IKeyCeremonyMediator -{ - string UserId { get; } - string Id { get; } - CeremonyDetails CeremonyDetails { get; } - KeyCeremonyRecord _keyCeremony { get; } - - bool AllBackupsAvailable(); - bool AllBackupsVerified(); - bool AllGuardiansAnnounced(); - void Announce(ElectionPublicKey shareKey); - BackupVerificationState GetVerificationState(); - Task HasBackup(string guardianId); - Task<(bool, bool)> HasVerified(string guardianId); - ElectionJointKey? PublishJointKey(); - void ReceiveBackups(List backups); - void ReceiveBackupVerifications(List verifications); - void ReceiveElectionPartialKeyBackup(ElectionPartialKeyBackup backup); - void ReceiveElectionPartialKeyVerification(ElectionPartialKeyVerification verification); - List? ShareBackups(string? requestingGuardianId = null); - ElectionPartialKeyVerification VerifyChallenge(ElectionPartialKeyChallenge challenge); -} - -public interface IKeyCeremonyMediatorStateMachine -{ - Task RunKeyCeremony(bool isAdmin = false); - void Reset(CeremonyDetails ceremonyDetails); - - Task ShouldAdminStartStep2(); - Task ShouldAdminStartStep4(); - Task ShouldAdminStartStep6(); - - Task ShouldGuardianRunStep1(); - Task ShouldGuardianRunStep3(); - Task ShouldGuardianRunStep5(); - -} - -/// -/// KeyCeremonyMediator for assisting communication between guardians -/// -public class KeyCeremonyMediator - : DisposableBase, IKeyCeremonyMediator, IKeyCeremonyMediatorStateMachine -{ - public KeyCeremonyMediator( - string mediatorId, - string userId, - KeyCeremonyRecord keyCeremony, - IKeyCeremonyService keyCeremonyService, - IGuardianBackupService backupService, - IGuardianPublicKeyService publicKeyService, - IVerificationService verificationService) - { - Id = mediatorId; - UserId = userId; - CeremonyDetails = keyCeremony; - _keyCeremony = keyCeremony; - _keyCeremonyService = keyCeremonyService; - _backupService = backupService; - _publicKeyService = publicKeyService; - _verificationService = verificationService; - CreateAdminSteps(); - CreateGuardianSteps(); - } - - protected readonly IKeyCeremonyService _keyCeremonyService; - protected readonly IGuardianBackupService _backupService; - protected readonly IGuardianPublicKeyService _publicKeyService; - protected readonly IVerificationService _verificationService; - - private readonly List> _adminSteps = new(); - private readonly List> _guardianSteps = new(); - - // HACK: This only works as a mutex because we are using 5s long polling. - // TODO: figure out a more graceful way to support long polling - // without multiple steps running at once. - private static bool IsRunning = false; - - public string UserId { get; } - public string Id { get; } - public CeremonyDetails CeremonyDetails { get; internal set; } - public KeyCeremonyRecord _keyCeremony { get; internal set; } - - // From Guardians - // Round 1 - private readonly Dictionary _electionPublicKeys = new(); - - // Round 2 - private readonly Dictionary _electionPartialKeyBackups = new(); - - // Round 3 - private readonly Dictionary _electionPartialKeyVerification = new(); - - private readonly Dictionary _electionPartialKeyChallenges = new(); - - private void CreateAdminSteps() - { - _adminSteps.Add( - new StateMachineStep() - { - State = KeyCeremonyState.PendingGuardiansJoin, - RunStep = RunStep2, - ShouldRunStep = ShouldAdminStartStep2 - }); - _adminSteps.Add( - new StateMachineStep() - { - State = KeyCeremonyState.PendingAdminAnnounce, - RunStep = RunStep2, - ShouldRunStep = AlwaysRun - }); - _adminSteps.Add( - new StateMachineStep() - { - State = KeyCeremonyState.PendingGuardianBackups, - RunStep = RunStep4, - ShouldRunStep = ShouldAdminStartStep4 - }); - _adminSteps.Add( - new StateMachineStep() - { - State = KeyCeremonyState.PendingAdminToShareBackups, - RunStep = RunStep4, - ShouldRunStep = AlwaysRun - }); - _adminSteps.Add( - new StateMachineStep() - { - State = KeyCeremonyState.PendingGuardiansVerifyBackups, - RunStep = RunStep6, - ShouldRunStep = ShouldAdminStartStep6 - }); - _adminSteps.Add( - new StateMachineStep() - { - State = KeyCeremonyState.PendingAdminToPublishJointKey, - RunStep = RunStep6, - ShouldRunStep = AlwaysRun - }); - } - - private void CreateGuardianSteps() - { - _guardianSteps.Add( - new StateMachineStep() - { - State = KeyCeremonyState.PendingGuardiansJoin, - RunStep = RunStep1, - ShouldRunStep = ShouldGuardianRunStep1 - }); - _guardianSteps.Add( - new StateMachineStep() - { - State = KeyCeremonyState.PendingGuardianBackups, - RunStep = RunStep3, - ShouldRunStep = ShouldGuardianRunStep3 - }); - _guardianSteps.Add( - new StateMachineStep() - { - State = KeyCeremonyState.PendingGuardiansVerifyBackups, - RunStep = RunStep5, - ShouldRunStep = ShouldGuardianRunStep5 - }); - } - - public void Announce(ElectionPublicKey shareKey) - { - ReceiveElectionPublicKey(shareKey); - } - - /// - /// Check the annoucement of all the guardians expected - /// - /// True if all guardians in attendance are announced - public bool AllGuardiansAnnounced() - { - return _electionPublicKeys.Count == CeremonyDetails.NumberOfGuardians; - } - - /// - /// When all guardians have announced, share their public keys indicating their announcement - /// - /// - /// - protected virtual List? ShareAnnounced(string? requestingGuardianId) - { - if (AllGuardiansAnnounced() is false) - { - return null; - } - - List guardianKeys = new(); - var keys = _electionPublicKeys.Where(k => k.Key != requestingGuardianId) - .Select(k => k.Value); - guardianKeys.AddRange(keys); - - return guardianKeys; - } - - - // Round 2 - /// - /// Receive all the election partial key backups generated by a guardian - /// - /// - public void ReceiveBackups(List backups) - { - if (AllGuardiansAnnounced() is false) - { - return; - } - - foreach (var backup in backups) - { - ReceiveElectionPartialKeyBackup(backup.Backup!); - } - } - - /// - /// Receive election partial key backup from guardian - /// - /// Election partial key backup - public void ReceiveElectionPartialKeyBackup(ElectionPartialKeyBackup backup) - { - _electionPartialKeyBackups[new GuardianPair(backup.OwnerId!, backup.DesignatedId!)] = backup; - } - - /// - /// Check the availability of all the guardians backups - /// - /// True if all guardians have sent backups - public bool AllBackupsAvailable() - { - return AllGuardiansAnnounced() && AllElectionPartialKeyBackupsAvailable(); - } - - /// - /// True if all election partial key backups for all guardians available - /// - /// All election partial key backups for all guardians available - private bool AllElectionPartialKeyBackupsAvailable() - { - return _electionPartialKeyBackups.Count == CeremonyDetails.NumberOfGuardians * CeremonyDetails.NumberOfGuardians; - } - - /// - /// Share all backups designated for a specific guardian - /// - /// - /// - public List? ShareBackups(string? requestingGuardianId = null) - { - if (AllGuardiansAnnounced() == false || AllBackupsAvailable() == false) - { - return null; - } - - if (requestingGuardianId is null) - { - return _electionPartialKeyBackups.Values.ToList(); - } - - return ShareElectionPartialKeyBackupsToGuardian(requestingGuardianId); - } - - private IEnumerable GetAnnouncedGuardians() - { - return _electionPublicKeys.Keys; - } - - /// - /// Share all election partial key backups for designated guardian - /// - /// Recipients guardian id - /// List of guardians designated backups - private List ShareElectionPartialKeyBackupsToGuardian( - string guardianId) - { - List backups = new(); - var announcedGuardians = GetAnnouncedGuardians(); - var others = announcedGuardians; - foreach (var currentGuardianId in others) - { - _ = _electionPartialKeyBackups.TryGetValue( - new GuardianPair(currentGuardianId, guardianId), out var backup); - if (backup is not null) - { - backups.Add(backup); - } - } - return backups; - } - - // ROUND 3: Share verifications of backups - /// - /// Receive all the election partial key verifications performed by a guardian - /// - /// - public void ReceiveBackupVerifications(List verifications) - { - if (AllBackupsAvailable() == false) - { - return; - } - - foreach (var verification in verifications) - { - ReceiveElectionPartialKeyVerification(verification); - } - } - - // Partial Key Verifications - /// - /// Receive election partial key verification from guardian - /// - /// Election partial key verification - public void ReceiveElectionPartialKeyVerification(ElectionPartialKeyVerification verification) - { - _electionPartialKeyVerification[ - new GuardianPair( - verification.OwnerId!, verification.DesignatedId!)] = verification; - } - - - public BackupVerificationState GetVerificationState() - { - if (AllBackupsAvailable() is false || AllElectionPartialKeyVerificationsReceived() is false) - { - return new BackupVerificationState(); - } - - return CheckVerificationOfElectionPartialKeyBackups(); - } - - /// - /// True if all election partial key backups verified - /// - /// All election partial key backups verified - private BackupVerificationState CheckVerificationOfElectionPartialKeyBackups() - { - if (AllElectionPartialKeyVerificationsReceived() is false) - { - return new BackupVerificationState(); - } - - List failedVerifications = new(); - - var unverified = _electionPartialKeyVerification.Values.Where(v => v.Verified is false); - - foreach (var verification in unverified) - { - failedVerifications.Add(new GuardianPair(verification.OwnerId!, verification.DesignatedId!)); - } - - return new BackupVerificationState(true, failedVerifications.Count == 0, failedVerifications); - } - - - public bool AllBackupsVerified() - { - return GetVerificationState().AllVerified; - } - - /// - /// True if all election partial key verifications recieved - /// - /// All election partial key verifications received - private bool AllElectionPartialKeyVerificationsReceived() - { - var requiredVerificationsPerGuardian = CeremonyDetails.NumberOfGuardians; - var totalRequired = requiredVerificationsPerGuardian * CeremonyDetails.NumberOfGuardians; - return _electionPartialKeyVerification.Count == totalRequired; - } - - // ROUND 4 (Optional): If a verification fails, guardian must issue challenge - /// - /// Mediator receives challenge and will act to mediate and verify - /// - /// - /// - public ElectionPartialKeyVerification VerifyChallenge(ElectionPartialKeyChallenge challenge) - { - var verification = VerifyElectionPartialKeyChallenge(Id, challenge); - if (verification.Verified) - { - ReceiveElectionPartialKeyVerification(verification); - } - return verification; - } - - /// - /// Verify a challenge to a previous verification of a partial key backup - /// - /// verifier of the challenge - /// election partial key challenge - /// - private static ElectionPartialKeyVerification VerifyElectionPartialKeyChallenge( - string verifierId, ElectionPartialKeyChallenge challenge) - { - return new ElectionPartialKeyVerification() - { - OwnerId = challenge.OwnerId, - DesignatedId = challenge.DesignatedId, - VerifierId = verifierId, - Verified = ElectionPolynomial.VerifyCoordinate( - challenge.DesignatedSequenceOrder, - challenge.Value!, - challenge.CoefficientCommitments! - ) - }; - } - - // FINAL: Publish joint public election key - /// - /// Publish joint election key from the public keys of all guardians - /// - /// Joint key for election - public ElectionJointKey? PublishJointKey() - { - return AllBackupsVerified() is false - ? null - : CombineElectionPublicKeys(_electionPublicKeys.Values.ToList()); - } - - /// - /// Creates a joint election key from the public keys of all guardians - /// - /// all public keys of the guardians - /// ElectionJointKey for election - private static ElectionJointKey CombineElectionPublicKeys(List electionPublicKeys) - { - var publicKeys = electionPublicKeys.Select(k => k.Key).ToList(); - List commitments = new(); - foreach (var key in electionPublicKeys) - { - foreach (var item in key.CoefficientCommitments) - { - commitments.Add(item); - } - } - - return new ElectionJointKey() - { - JointPublicKey = ElgamalCombinePublicKeys(publicKeys!), - CommitmentHash = Hash.HashElems(commitments) - }; // H(K 1,0 , K 2,0 ... , K n,0 ) - } - - /// - /// Combine multiple elgamal public keys into a joint key - /// - /// list of public elgamal keys - /// joint key of elgamal keys - private static ElementModP ElgamalCombinePublicKeys(List keys) - { - var product = Constants.ONE_MOD_P; - _ = product.MultModP(keys); - return product; - } - - /// - /// Reset mediator to initial state - /// - /// Ceremony details of election - public void Reset(CeremonyDetails ceremonyDetails) - { - CeremonyDetails = ceremonyDetails; - _electionPublicKeys.Clear(); - _electionPartialKeyBackups.Clear(); - _electionPartialKeyChallenges.Clear(); - _electionPartialKeyVerification.Clear(); - } - - /// - /// Receive election public key from guardian - /// - /// Election public key - private void ReceiveElectionPublicKey(ElectionPublicKey publicKey) - { - _electionPublicKeys[publicKey.GuardianId] = publicKey; - } - - private static async Task GetGuardianSequenceOrderAsync( - IGuardianPublicKeyService service, string keyCeremonyId, string guardianId) - { - var list = await service.GetAllByKeyCeremonyIdAsync(keyCeremonyId); - if (list == null) - { - return 1; - } - - foreach ((var item, var index) in list.WithIndex()) - { - if (item.GuardianId == guardianId) - { - // the math functions need this to be a 1 based value instead of a 0 based value - return index + 1; - } - } - throw new ArgumentOutOfRangeException(nameof(guardianId)); - } - - #region IKeyCeremonyMediatorStateMachine - - /// - /// - /// - /// True if a step was run - public async Task RunKeyCeremony(bool isAdmin = false) - { - if (!IsRunning) - { - var keyCeremonyId = CeremonyDetails.KeyCeremonyId; - - var keyCeremony = await _keyCeremonyService.GetByKeyCeremonyIdAsync(keyCeremonyId); - if (keyCeremony == null) - { - throw new KeyCeremonyException( - KeyCeremonyState.DoesNotExist, - keyCeremonyId, - UserId, - $"Key Ceremony {keyCeremonyId} does not exist"); - } - _keyCeremony.State = keyCeremony.State; - - var state = keyCeremony.State; - - var steps = isAdmin ? _adminSteps : _guardianSteps; - var currentStep = steps.SingleOrDefault(s => s.State == state); - if (currentStep != null && await currentStep.ShouldRunStep!()) - { - IsRunning = true; - try - { - await currentStep.RunStep!(); - } - catch (Exception ex) - { - var message = ex.Message; - Debug.WriteLine($"error running key ceremony step: {currentStep.State} {ex}"); - } - IsRunning = false; - } - } - } - - private async Task AlwaysRun() - { - return await Task.FromResult(true); - } - - public async Task ShouldAdminStartStep2() - { - var keyCeremonyId = CeremonyDetails.KeyCeremonyId; - var guardians = await _publicKeyService.GetAllByKeyCeremonyIdAsync(keyCeremonyId); - - return guardians.Count == CeremonyDetails.NumberOfGuardians - && guardians.All(i => i.PublicKey != null); - } - - public async Task ShouldAdminStartStep4() - { - var keyCeremonyId = CeremonyDetails.KeyCeremonyId; - var guardianCount = await _publicKeyService.CountAsync(keyCeremonyId); - var backupCount = await _backupService.CountAsync(keyCeremonyId); - - return guardianCount == CeremonyDetails.NumberOfGuardians && - backupCount == guardianCount * guardianCount; - } - - public async Task ShouldAdminStartStep6() - { - var keyCeremonyId = CeremonyDetails.KeyCeremonyId; - var guardianCount = await _publicKeyService.CountAsync(keyCeremonyId); - var backupCount = await _backupService.CountAsync(keyCeremonyId); - var verificationCount = await _verificationService.CountAsync(keyCeremonyId); - - var verificationList = await _verificationService.GetAllByKeyCeremonyIdAsync(keyCeremonyId); - if (verificationList == null) - { - return false; - } - - var unverifiedCount = verificationList.Count(v => v.Verified == false); - Debug.WriteLine($"guardianCount: {guardianCount} backupCount: {backupCount} verificationCount: {verificationCount} unverifiedCount: {unverifiedCount}"); - - return guardianCount == CeremonyDetails.NumberOfGuardians && - backupCount == guardianCount * guardianCount && - verificationCount == guardianCount * guardianCount && - unverifiedCount == 0; - } - - public async Task ShouldGuardianRunStep1() - { - var keyCeremonyId = CeremonyDetails.KeyCeremonyId; - var guardianId = UserId; - var guardian = await _publicKeyService.GetByIdsAsync(keyCeremonyId, guardianId); - var guardianCount = await _publicKeyService.CountAsync(keyCeremonyId); - return guardian == null && guardianCount < CeremonyDetails.NumberOfGuardians; - } - - public async Task ShouldGuardianRunStep3() - { - var keyCeremonyId = CeremonyDetails.KeyCeremonyId; - var guardianId = UserId; - - // might want to switch this to use a count instead of loading the object - var guardian = await _publicKeyService.GetByIdsAsync(keyCeremonyId, guardianId); - if (guardian == null) - { - return false; - } - - var backupCount = await _backupService.CountAsync(keyCeremonyId, guardianId); - return backupCount != CeremonyDetails.NumberOfGuardians; - } - - public async Task ShouldGuardianRunStep5() - { - var keyCeremonyId = CeremonyDetails.KeyCeremonyId; - var guardianId = UserId; - - var guardian = await _publicKeyService.GetByIdsAsync(keyCeremonyId, guardianId); - if (guardian == null) - { - return false; - } - - var backupCount = await _backupService.CountAsync(keyCeremonyId, guardianId); - - - var verificationCount = await _verificationService.CountAsync(keyCeremonyId, guardianId); - - return backupCount == CeremonyDetails.NumberOfGuardians && - verificationCount != CeremonyDetails.NumberOfGuardians; - } - - private async Task RunStep1() - { - var keyCeremonyId = CeremonyDetails.KeyCeremonyId; - var currentGuardianUserName = UserId; - - // append guardian joined to key ceremony (db) - - using var newRecord = new GuardianPublicKey - { - KeyCeremonyId = keyCeremonyId, - GuardianId = currentGuardianUserName, - PublicKey = null - }; - _ = await _publicKeyService.SaveAsync(newRecord); - - // get guardian number - var sequenceOrder = await GetGuardianSequenceOrderAsync( - _publicKeyService, keyCeremonyId, currentGuardianUserName); - - // make guardian - var guardian = new Guardian( - currentGuardianUserName, - sequenceOrder, - CeremonyDetails.NumberOfGuardians, - CeremonyDetails.Quorum, - keyCeremonyId); - - // save guardian to local drive / yubikey - GuardianStorageExtensions.Save(guardian, keyCeremonyId); - - // get public key - var publicKey = guardian.SharePublicKey(); - if (publicKey == null || !publicKey.Key.IsAddressable) - { - throw new Exception("Error getting public key"); - } - - // append to key ceremony (db) - await _publicKeyService.UpdatePublicKeyAsync( - keyCeremonyId, currentGuardianUserName, publicKey); - - // notify change to admin (signalR) - } - - private void AnnounceGuardians(List guardians) - { - foreach (var item in guardians) - { - Announce(item.PublicKey!); - } - } - - private async Task Announce(string keyCeremonyId) - { - var guardians = await _publicKeyService.GetAllByKeyCeremonyIdAsync(keyCeremonyId); - - AnnounceGuardians(guardians); - } - - private async Task RunStep2() - { - // change state to step2 - var keyCeremonyId = CeremonyDetails.KeyCeremonyId; - _keyCeremony.State = KeyCeremonyState.PendingAdminAnnounce; - await _keyCeremonyService.UpdateStateAsync(keyCeremonyId, _keyCeremony.State); - // notify change to guardians (signalR) - - // call announce - await Announce(keyCeremonyId); - - // change state to step3 - _keyCeremony.State = KeyCeremonyState.PendingGuardianBackups; - await _keyCeremonyService.UpdateStateAsync(keyCeremonyId, _keyCeremony.State); - // notify change to guardians (signalR) - } - - private async Task RunStep3() - { - var keyCeremonyId = CeremonyDetails.KeyCeremonyId; - var keyCeremony = await _keyCeremonyService.GetByKeyCeremonyIdAsync(keyCeremonyId); - - // load guardian from key ceremony - var guardian = GuardianStorageExtensions.Load(UserId, keyCeremony!); - - // load other keys - var publicKeys = await _publicKeyService.GetAllByKeyCeremonyIdAsync( - keyCeremonyId); - foreach (var publicKey in publicKeys) - { - guardian!.AddGuardianKey(publicKey.PublicKey!); - } - - // generate election partial key backups - _ = guardian!.GenerateElectionPartialKeyBackups(); - - // share backups - var backups = guardian.ShareElectionPartialKeyBackups(); - - // save backups to database - foreach (var backup in backups) - { - using GuardianBackups data = new( - keyCeremonyId, - UserId, - backup.DesignatedId!, - backup - ); - - _ = await _backupService.SaveAsync(data); - } - - // notify change to admin (signalR) - } - - private async Task RunStep4() - { - var keyCeremonyId = CeremonyDetails.KeyCeremonyId; - - // change state - _keyCeremony.State = KeyCeremonyState.PendingAdminToShareBackups; - await _keyCeremonyService.UpdateStateAsync(keyCeremonyId, _keyCeremony.State); - // notify change to guardians (signalR) - - // Announce guardians - puts data into keyceremony mediator structures - await Announce(keyCeremonyId); - - // get backups - var backups = await _backupService.GetByKeyCeremonyIdAsync(keyCeremonyId); - - // verify that the backups are all complete - - // receive backups - ReceiveBackups(backups!); - - // change state - _keyCeremony.State = KeyCeremonyState.PendingGuardiansVerifyBackups; - await _keyCeremonyService.UpdateStateAsync(keyCeremonyId, _keyCeremony.State); - // notify change to guardians (signalR) - } - - private async Task RunStep5() - { - var keyCeremonyId = CeremonyDetails.KeyCeremonyId; - - var backups = await _backupService.GetByGuardianIdAsync(keyCeremonyId, UserId); - var keyCeremony = await _keyCeremonyService.GetByKeyCeremonyIdAsync(keyCeremonyId); - var guardian = GuardianStorageExtensions.Load(UserId, keyCeremony!); - var publicKeys = await _publicKeyService.GetAllByKeyCeremonyIdAsync(keyCeremonyId); - foreach (var publicKey in publicKeys) - { - guardian!.AddGuardianKey(publicKey.PublicKey!); - } - List verifications = new(); - // TODO: ISSUE #213 throw on invalid backup - foreach (var backup in backups!) - { - guardian!.SaveElectionPartialKeyBackup(backup.Backup!); - var verification = guardian.VerifyElectionPartialKeyBackup(backup.GuardianId!, keyCeremonyId); - if (verification == null) // TODO: ISSUE #213 throw on invalid backup - { - throw new KeyCeremonyException( - keyCeremony!.State, - keyCeremonyId, - UserId, - $"Error verifying back from {backup.Backup!.OwnerId!}"); - } - verifications.Add(verification); - } - // save verifications - foreach (var verification in verifications) - { - _ = await _verificationService.SaveAsync(verification); - } - - // notify change to admin (signalR) - } - - private async Task RunStep6() - { - var keyCeremonyId = CeremonyDetails.KeyCeremonyId; - - // change state - _keyCeremony.State = KeyCeremonyState.PendingAdminToPublishJointKey; - await _keyCeremonyService.UpdateStateAsync(keyCeremonyId, _keyCeremony.State); - // notify change to guardians (signalR) - - // Announce guardians - puts data into keyceremony mediator structures - await Announce(keyCeremonyId); - - // get backups - var backups = await _backupService.GetByKeyCeremonyIdAsync(keyCeremonyId); - ReceiveBackups(backups!); - - // get all verifications - var verifications = await _verificationService.GetAllByKeyCeremonyIdAsync(keyCeremonyId); - // receive verifications - ReceiveBackupVerifications(verifications!); - - // publish joint key - var jointKey = PublishJointKey(); - - // if null then throw - if (jointKey == null) - { - throw new KeyCeremonyException( - KeyCeremonyState.PendingAdminToPublishJointKey, - keyCeremonyId, - UserId, - $"Failed to publish joint key for {keyCeremonyId}"); - } - - // save joint key to key ceremony - // update state to complete - _keyCeremony.State = KeyCeremonyState.Complete; - await _keyCeremonyService.UpdateCompleteAsync(keyCeremonyId, jointKey); - // notify change to guardians (signalR) - } - - #endregion - - public async Task HasBackup(string guardianId) - { - var backups = await _backupService.GetByKeyCeremonyIdAsync(CeremonyDetails.KeyCeremonyId); - var list = backups?.Where(b => b.GuardianId == guardianId); - return list?.Count() > 0; - } - public async Task<(bool, bool)> HasVerified(string guardianId) - { - var verifications = await _verificationService.GetAllByKeyCeremonyIdAsync(CeremonyDetails.KeyCeremonyId); - var list = verifications?.Where(v => v.DesignatedId == guardianId); - var notVerified = list?.Where(v => v.Verified == false); - return (list?.Count() > 0, notVerified?.Count() > 0); - } - - protected override void DisposeUnmanaged() - { - base.DisposeUnmanaged(); - - _electionPublicKeys?.Dispose(); - _electionPartialKeyBackups?.Dispose(); - _electionPartialKeyChallenges?.Dispose(); - } -} +using System.Diagnostics; +using ElectionGuard.UI.Lib.Exceptions; +using ElectionGuard.ElectionSetup.Extensions; +using ElectionGuard.Extensions; +using ElectionGuard.Guardians; +using ElectionGuard.UI.Lib.Models; +using ElectionGuard.UI.Lib.Services; +using ElectionGuard.ElectionSetup; +using ElectionGuard.ElectionSetup.Records; + +namespace ElectionGuard.UI.Lib.Services; + +public interface IKeyCeremonyMediator +{ + string UserId { get; } + string Id { get; } + CeremonyDetails CeremonyDetails { get; } + KeyCeremonyRecord _keyCeremony { get; } + + bool AllBackupsAvailable(); + bool AllBackupsVerified(); + bool AllGuardiansAnnounced(); + void Announce(ElectionPublicKey shareKey); + BackupVerificationState GetVerificationState(); + Task HasBackup(string guardianId); + Task<(bool, bool)> HasVerified(string guardianId); + ElectionJointKey? PublishJointKey(); + void ReceiveBackups(List backups); + void ReceiveBackupVerifications(List verifications); + void ReceiveElectionPartialKeyBackup(ElectionPartialKeyBackup backup); + void ReceiveElectionPartialKeyVerification(ElectionPartialKeyVerification verification); + List? ShareBackups(string? requestingGuardianId = null); + ElectionPartialKeyVerification VerifyChallenge(ElectionPartialKeyChallenge challenge); +} + +public interface IKeyCeremonyMediatorStateMachine +{ + Task RunKeyCeremony(bool isAdmin = false); + void Reset(CeremonyDetails ceremonyDetails); + + Task ShouldAdminStartStep2(); + Task ShouldAdminStartStep4(); + Task ShouldAdminStartStep6(); + + Task ShouldGuardianRunStep1(); + Task ShouldGuardianRunStep3(); + Task ShouldGuardianRunStep5(); + +} + +/// +/// KeyCeremonyMediator for assisting communication between guardians +/// +public class KeyCeremonyMediator + : DisposableBase, IKeyCeremonyMediator, IKeyCeremonyMediatorStateMachine +{ + public KeyCeremonyMediator( + string mediatorId, + string userId, + KeyCeremonyRecord keyCeremony, + IKeyCeremonyService keyCeremonyService, + IGuardianBackupService backupService, + IGuardianPublicKeyService publicKeyService, + IVerificationService verificationService) + { + Id = mediatorId; + UserId = userId; + CeremonyDetails = keyCeremony; + _keyCeremony = keyCeremony; + _keyCeremonyService = keyCeremonyService; + _backupService = backupService; + _publicKeyService = publicKeyService; + _verificationService = verificationService; + CreateAdminSteps(); + CreateGuardianSteps(); + } + + protected readonly IKeyCeremonyService _keyCeremonyService; + protected readonly IGuardianBackupService _backupService; + protected readonly IGuardianPublicKeyService _publicKeyService; + protected readonly IVerificationService _verificationService; + + private readonly List> _adminSteps = new(); + private readonly List> _guardianSteps = new(); + + // HACK: This only works as a mutex because we are using 5s long polling. + // TODO: figure out a more graceful way to support long polling + // without multiple steps running at once. + private static bool IsRunning = false; + + public string UserId { get; } + public string Id { get; } + public CeremonyDetails CeremonyDetails { get; internal set; } + public KeyCeremonyRecord _keyCeremony { get; internal set; } + + // From Guardians + // Round 1 + private readonly Dictionary _electionPublicKeys = new(); + + // Round 2 + private readonly Dictionary _electionPartialKeyBackups = new(); + + // Round 3 + private readonly Dictionary _electionPartialKeyVerification = new(); + + private readonly Dictionary _electionPartialKeyChallenges = new(); + + private void CreateAdminSteps() + { + _adminSteps.Add( + new StateMachineStep() + { + State = KeyCeremonyState.PendingGuardiansJoin, + RunStep = RunStep2, + ShouldRunStep = ShouldAdminStartStep2 + }); + _adminSteps.Add( + new StateMachineStep() + { + State = KeyCeremonyState.PendingAdminAnnounce, + RunStep = RunStep2, + ShouldRunStep = AlwaysRun + }); + _adminSteps.Add( + new StateMachineStep() + { + State = KeyCeremonyState.PendingGuardianBackups, + RunStep = RunStep4, + ShouldRunStep = ShouldAdminStartStep4 + }); + _adminSteps.Add( + new StateMachineStep() + { + State = KeyCeremonyState.PendingAdminToShareBackups, + RunStep = RunStep4, + ShouldRunStep = AlwaysRun + }); + _adminSteps.Add( + new StateMachineStep() + { + State = KeyCeremonyState.PendingGuardiansVerifyBackups, + RunStep = RunStep6, + ShouldRunStep = ShouldAdminStartStep6 + }); + _adminSteps.Add( + new StateMachineStep() + { + State = KeyCeremonyState.PendingAdminToPublishJointKey, + RunStep = RunStep6, + ShouldRunStep = AlwaysRun + }); + } + + private void CreateGuardianSteps() + { + _guardianSteps.Add( + new StateMachineStep() + { + State = KeyCeremonyState.PendingGuardiansJoin, + RunStep = RunStep1, + ShouldRunStep = ShouldGuardianRunStep1 + }); + _guardianSteps.Add( + new StateMachineStep() + { + State = KeyCeremonyState.PendingGuardianBackups, + RunStep = RunStep3, + ShouldRunStep = ShouldGuardianRunStep3 + }); + _guardianSteps.Add( + new StateMachineStep() + { + State = KeyCeremonyState.PendingGuardiansVerifyBackups, + RunStep = RunStep5, + ShouldRunStep = ShouldGuardianRunStep5 + }); + } + + public void Announce(ElectionPublicKey shareKey) + { + ReceiveElectionPublicKey(shareKey); + } + + /// + /// Check the annoucement of all the guardians expected + /// + /// True if all guardians in attendance are announced + public bool AllGuardiansAnnounced() + { + return _electionPublicKeys.Count == CeremonyDetails.NumberOfGuardians; + } + + /// + /// When all guardians have announced, share their public keys indicating their announcement + /// + /// + /// + protected virtual List? ShareAnnounced(string? requestingGuardianId) + { + if (AllGuardiansAnnounced() is false) + { + return null; + } + + List guardianKeys = new(); + var keys = _electionPublicKeys.Where(k => k.Key != requestingGuardianId) + .Select(k => k.Value); + guardianKeys.AddRange(keys); + + return guardianKeys; + } + + + // Round 2 + /// + /// Receive all the election partial key backups generated by a guardian + /// + /// + public void ReceiveBackups(List backups) + { + if (AllGuardiansAnnounced() is false) + { + return; + } + + foreach (var backup in backups) + { + ReceiveElectionPartialKeyBackup(backup.Backup!); + } + } + + /// + /// Receive election partial key backup from guardian + /// + /// Election partial key backup + public void ReceiveElectionPartialKeyBackup(ElectionPartialKeyBackup backup) + { + _electionPartialKeyBackups[new GuardianPair(backup.OwnerId!, backup.DesignatedId!)] = backup; + } + + /// + /// Check the availability of all the guardians backups + /// + /// True if all guardians have sent backups + public bool AllBackupsAvailable() + { + return AllGuardiansAnnounced() && AllElectionPartialKeyBackupsAvailable(); + } + + /// + /// True if all election partial key backups for all guardians available + /// + /// All election partial key backups for all guardians available + private bool AllElectionPartialKeyBackupsAvailable() + { + return _electionPartialKeyBackups.Count == CeremonyDetails.NumberOfGuardians * CeremonyDetails.NumberOfGuardians; + } + + /// + /// Share all backups designated for a specific guardian + /// + /// + /// + public List? ShareBackups(string? requestingGuardianId = null) + { + if (AllGuardiansAnnounced() == false || AllBackupsAvailable() == false) + { + return null; + } + + if (requestingGuardianId is null) + { + return _electionPartialKeyBackups.Values.ToList(); + } + + return ShareElectionPartialKeyBackupsToGuardian(requestingGuardianId); + } + + private IEnumerable GetAnnouncedGuardians() + { + return _electionPublicKeys.Keys; + } + + /// + /// Share all election partial key backups for designated guardian + /// + /// Recipients guardian id + /// List of guardians designated backups + private List ShareElectionPartialKeyBackupsToGuardian( + string guardianId) + { + List backups = new(); + var announcedGuardians = GetAnnouncedGuardians(); + var others = announcedGuardians; + foreach (var currentGuardianId in others) + { + _ = _electionPartialKeyBackups.TryGetValue( + new GuardianPair(currentGuardianId, guardianId), out var backup); + if (backup is not null) + { + backups.Add(backup); + } + } + return backups; + } + + // ROUND 3: Share verifications of backups + /// + /// Receive all the election partial key verifications performed by a guardian + /// + /// + public void ReceiveBackupVerifications(List verifications) + { + if (AllBackupsAvailable() == false) + { + return; + } + + foreach (var verification in verifications) + { + ReceiveElectionPartialKeyVerification(verification); + } + } + + // Partial Key Verifications + /// + /// Receive election partial key verification from guardian + /// + /// Election partial key verification + public void ReceiveElectionPartialKeyVerification(ElectionPartialKeyVerification verification) + { + _electionPartialKeyVerification[ + new GuardianPair( + verification.OwnerId!, verification.DesignatedId!)] = verification; + } + + + public BackupVerificationState GetVerificationState() + { + if (AllBackupsAvailable() is false || AllElectionPartialKeyVerificationsReceived() is false) + { + return new BackupVerificationState(); + } + + return CheckVerificationOfElectionPartialKeyBackups(); + } + + /// + /// True if all election partial key backups verified + /// + /// All election partial key backups verified + private BackupVerificationState CheckVerificationOfElectionPartialKeyBackups() + { + if (AllElectionPartialKeyVerificationsReceived() is false) + { + return new BackupVerificationState(); + } + + List failedVerifications = new(); + + var unverified = _electionPartialKeyVerification.Values.Where(v => v.Verified is false); + + foreach (var verification in unverified) + { + failedVerifications.Add(new GuardianPair(verification.OwnerId!, verification.DesignatedId!)); + } + + return new BackupVerificationState(true, failedVerifications.Count == 0, failedVerifications); + } + + + public bool AllBackupsVerified() + { + return GetVerificationState().AllVerified; + } + + /// + /// True if all election partial key verifications recieved + /// + /// All election partial key verifications received + private bool AllElectionPartialKeyVerificationsReceived() + { + var requiredVerificationsPerGuardian = CeremonyDetails.NumberOfGuardians; + var totalRequired = requiredVerificationsPerGuardian * CeremonyDetails.NumberOfGuardians; + return _electionPartialKeyVerification.Count == totalRequired; + } + + // ROUND 4 (Optional): If a verification fails, guardian must issue challenge + /// + /// Mediator receives challenge and will act to mediate and verify + /// + /// + /// + public ElectionPartialKeyVerification VerifyChallenge(ElectionPartialKeyChallenge challenge) + { + var verification = VerifyElectionPartialKeyChallenge(Id, challenge); + if (verification.Verified) + { + ReceiveElectionPartialKeyVerification(verification); + } + return verification; + } + + /// + /// Verify a challenge to a previous verification of a partial key backup + /// + /// verifier of the challenge + /// election partial key challenge + /// + private static ElectionPartialKeyVerification VerifyElectionPartialKeyChallenge( + string verifierId, ElectionPartialKeyChallenge challenge) + { + return new ElectionPartialKeyVerification() + { + OwnerId = challenge.OwnerId, + DesignatedId = challenge.DesignatedId, + VerifierId = verifierId, + Verified = ElectionPolynomial.VerifyCoordinate( + challenge.DesignatedSequenceOrder, + challenge.Value!, + challenge.CoefficientCommitments! + ) + }; + } + + // FINAL: Publish joint public election key + /// + /// Publish joint election key from the public keys of all guardians + /// + /// Joint key for election + public ElectionJointKey? PublishJointKey() + { + return AllBackupsVerified() is false + ? null + : CombineElectionPublicKeys(_electionPublicKeys.Values.ToList()); + } + + /// + /// Creates a joint election key from the public keys of all guardians + /// + /// all public keys of the guardians + /// ElectionJointKey for election + private static ElectionJointKey CombineElectionPublicKeys(List electionPublicKeys) + { + var publicKeys = electionPublicKeys.Select(k => k.Key).ToList(); + List commitments = new(); + foreach (var key in electionPublicKeys) + { + foreach (var item in key.CoefficientCommitments) + { + commitments.Add(item); + } + } + + return new ElectionJointKey() + { + JointPublicKey = ElgamalCombinePublicKeys(publicKeys!), + CommitmentHash = Hash.HashElems(commitments) + }; // H(K 1,0 , K 2,0 ... , K n,0 ) + } + + /// + /// Combine multiple elgamal public keys into a joint key + /// + /// list of public elgamal keys + /// joint key of elgamal keys + private static ElementModP ElgamalCombinePublicKeys(List keys) + { + var product = Constants.ONE_MOD_P; + _ = product.MultModP(keys); + return product; + } + + /// + /// Reset mediator to initial state + /// + /// Ceremony details of election + public void Reset(CeremonyDetails ceremonyDetails) + { + CeremonyDetails = ceremonyDetails; + _electionPublicKeys.Clear(); + _electionPartialKeyBackups.Clear(); + _electionPartialKeyChallenges.Clear(); + _electionPartialKeyVerification.Clear(); + } + + /// + /// Receive election public key from guardian + /// + /// Election public key + private void ReceiveElectionPublicKey(ElectionPublicKey publicKey) + { + _electionPublicKeys[publicKey.GuardianId] = publicKey; + } + + private static async Task GetGuardianSequenceOrderAsync( + IGuardianPublicKeyService service, string keyCeremonyId, string guardianId) + { + var list = await service.GetAllByKeyCeremonyIdAsync(keyCeremonyId); + if (list == null) + { + return 1; + } + + foreach ((var item, var index) in list.WithIndex()) + { + if (item.GuardianId == guardianId) + { + // the math functions need this to be a 1 based value instead of a 0 based value + return index + 1; + } + } + throw new ArgumentOutOfRangeException(nameof(guardianId)); + } + + #region IKeyCeremonyMediatorStateMachine + + /// + /// + /// + /// True if a step was run + public async Task RunKeyCeremony(bool isAdmin = false) + { + if (!IsRunning) + { + var keyCeremonyId = CeremonyDetails.KeyCeremonyId; + + var keyCeremony = await _keyCeremonyService.GetByKeyCeremonyIdAsync(keyCeremonyId); + if (keyCeremony == null) + { + throw new KeyCeremonyException( + KeyCeremonyState.DoesNotExist, + keyCeremonyId, + UserId, + $"Key Ceremony {keyCeremonyId} does not exist"); + } + _keyCeremony.State = keyCeremony.State; + + var state = keyCeremony.State; + + var steps = isAdmin ? _adminSteps : _guardianSteps; + var currentStep = steps.SingleOrDefault(s => s.State == state); + if (currentStep != null && await currentStep.ShouldRunStep!()) + { + IsRunning = true; + try + { + await currentStep.RunStep!(); + } + catch (Exception ex) + { + var message = ex.Message; + Debug.WriteLine($"error running key ceremony step: {currentStep.State} {ex}"); + } + IsRunning = false; + } + } + } + + private async Task AlwaysRun() + { + return await Task.FromResult(true); + } + + public async Task ShouldAdminStartStep2() + { + var keyCeremonyId = CeremonyDetails.KeyCeremonyId; + var guardians = await _publicKeyService.GetAllByKeyCeremonyIdAsync(keyCeremonyId); + + return guardians.Count == CeremonyDetails.NumberOfGuardians + && guardians.All(i => i.PublicKey != null); + } + + public async Task ShouldAdminStartStep4() + { + var keyCeremonyId = CeremonyDetails.KeyCeremonyId; + var guardianCount = await _publicKeyService.CountAsync(keyCeremonyId); + var backupCount = await _backupService.CountAsync(keyCeremonyId); + + return guardianCount == CeremonyDetails.NumberOfGuardians && + backupCount == guardianCount * guardianCount; + } + + public async Task ShouldAdminStartStep6() + { + var keyCeremonyId = CeremonyDetails.KeyCeremonyId; + var guardianCount = await _publicKeyService.CountAsync(keyCeremonyId); + var backupCount = await _backupService.CountAsync(keyCeremonyId); + var verificationCount = await _verificationService.CountAsync(keyCeremonyId); + + var verificationList = await _verificationService.GetAllByKeyCeremonyIdAsync(keyCeremonyId); + if (verificationList == null) + { + return false; + } + + var unverifiedCount = verificationList.Count(v => v.Verified == false); + Debug.WriteLine($"guardianCount: {guardianCount} backupCount: {backupCount} verificationCount: {verificationCount} unverifiedCount: {unverifiedCount}"); + + return guardianCount == CeremonyDetails.NumberOfGuardians && + backupCount == guardianCount * guardianCount && + verificationCount == guardianCount * guardianCount && + unverifiedCount == 0; + } + + public async Task ShouldGuardianRunStep1() + { + var keyCeremonyId = CeremonyDetails.KeyCeremonyId; + var guardianId = UserId; + var guardian = await _publicKeyService.GetByIdsAsync(keyCeremonyId, guardianId); + var guardianCount = await _publicKeyService.CountAsync(keyCeremonyId); + return guardian == null && guardianCount < CeremonyDetails.NumberOfGuardians; + } + + public async Task ShouldGuardianRunStep3() + { + var keyCeremonyId = CeremonyDetails.KeyCeremonyId; + var guardianId = UserId; + + // might want to switch this to use a count instead of loading the object + var guardian = await _publicKeyService.GetByIdsAsync(keyCeremonyId, guardianId); + if (guardian == null) + { + return false; + } + + var backupCount = await _backupService.CountAsync(keyCeremonyId, guardianId); + return backupCount != CeremonyDetails.NumberOfGuardians; + } + + public async Task ShouldGuardianRunStep5() + { + var keyCeremonyId = CeremonyDetails.KeyCeremonyId; + var guardianId = UserId; + + var guardian = await _publicKeyService.GetByIdsAsync(keyCeremonyId, guardianId); + if (guardian == null) + { + return false; + } + + var backupCount = await _backupService.CountAsync(keyCeremonyId, guardianId); + + + var verificationCount = await _verificationService.CountAsync(keyCeremonyId, guardianId); + + return backupCount == CeremonyDetails.NumberOfGuardians && + verificationCount != CeremonyDetails.NumberOfGuardians; + } + + private async Task RunStep1() + { + var keyCeremonyId = CeremonyDetails.KeyCeremonyId; + var currentGuardianUserName = UserId; + + // append guardian joined to key ceremony (db) + + using var newRecord = new GuardianPublicKey + { + KeyCeremonyId = keyCeremonyId, + GuardianId = currentGuardianUserName, + PublicKey = null + }; + _ = await _publicKeyService.SaveAsync(newRecord); + + // get guardian number + var sequenceOrder = await GetGuardianSequenceOrderAsync( + _publicKeyService, keyCeremonyId, currentGuardianUserName); + + // make guardian + var guardian = new Guardian( + currentGuardianUserName, + sequenceOrder, + CeremonyDetails.NumberOfGuardians, + CeremonyDetails.Quorum, + keyCeremonyId); + + // save guardian to local drive / yubikey + GuardianStorageExtensions.Save(guardian, keyCeremonyId); + + // get public key + var publicKey = guardian.SharePublicKey(); + if (publicKey == null || !publicKey.Key.IsAddressable) + { + throw new Exception("Error getting public key"); + } + + // append to key ceremony (db) + await _publicKeyService.UpdatePublicKeyAsync( + keyCeremonyId, currentGuardianUserName, publicKey); + + // notify change to admin (signalR) + } + + private void AnnounceGuardians(List guardians) + { + foreach (var item in guardians) + { + Announce(item.PublicKey!); + } + } + + private async Task Announce(string keyCeremonyId) + { + var guardians = await _publicKeyService.GetAllByKeyCeremonyIdAsync(keyCeremonyId); + + AnnounceGuardians(guardians); + } + + private async Task RunStep2() + { + // change state to step2 + var keyCeremonyId = CeremonyDetails.KeyCeremonyId; + _keyCeremony.State = KeyCeremonyState.PendingAdminAnnounce; + await _keyCeremonyService.UpdateStateAsync(keyCeremonyId, _keyCeremony.State); + // notify change to guardians (signalR) + + // call announce + await Announce(keyCeremonyId); + + // change state to step3 + _keyCeremony.State = KeyCeremonyState.PendingGuardianBackups; + await _keyCeremonyService.UpdateStateAsync(keyCeremonyId, _keyCeremony.State); + // notify change to guardians (signalR) + } + + private async Task RunStep3() + { + var keyCeremonyId = CeremonyDetails.KeyCeremonyId; + var keyCeremony = await _keyCeremonyService.GetByKeyCeremonyIdAsync(keyCeremonyId); + + // load guardian from key ceremony + var guardian = GuardianStorageExtensions.Load(UserId, keyCeremony!); + + // load other keys + var publicKeys = await _publicKeyService.GetAllByKeyCeremonyIdAsync( + keyCeremonyId); + foreach (var publicKey in publicKeys) + { + guardian!.AddGuardianKey(publicKey.PublicKey!); + } + + // generate election partial key backups + _ = guardian!.GenerateElectionPartialKeyBackups(); + + // share backups + var backups = guardian.ShareElectionPartialKeyBackups(); + + // save backups to database + foreach (var backup in backups) + { + using GuardianBackups data = new( + keyCeremonyId, + UserId, + backup.DesignatedId!, + new(backup) + ); + + _ = await _backupService.SaveAsync(data); + } + + // notify change to admin (signalR) + } + + private async Task RunStep4() + { + var keyCeremonyId = CeremonyDetails.KeyCeremonyId; + + // change state + _keyCeremony.State = KeyCeremonyState.PendingAdminToShareBackups; + await _keyCeremonyService.UpdateStateAsync(keyCeremonyId, _keyCeremony.State); + // notify change to guardians (signalR) + + // Announce guardians - puts data into keyceremony mediator structures + await Announce(keyCeremonyId); + + // get backups + var backups = await _backupService.GetByKeyCeremonyIdAsync(keyCeremonyId); + + // verify that the backups are all complete + + // receive backups + ReceiveBackups(backups!); + + // change state + _keyCeremony.State = KeyCeremonyState.PendingGuardiansVerifyBackups; + await _keyCeremonyService.UpdateStateAsync(keyCeremonyId, _keyCeremony.State); + // notify change to guardians (signalR) + } + + private async Task RunStep5() + { + var keyCeremonyId = CeremonyDetails.KeyCeremonyId; + + var backups = await _backupService.GetByGuardianIdAsync(keyCeremonyId, UserId); + var keyCeremony = await _keyCeremonyService.GetByKeyCeremonyIdAsync(keyCeremonyId); + var guardian = GuardianStorageExtensions.Load(UserId, keyCeremony!); + var publicKeys = await _publicKeyService.GetAllByKeyCeremonyIdAsync(keyCeremonyId); + foreach (var publicKey in publicKeys) + { + guardian!.AddGuardianKey(publicKey.PublicKey!); + } + List verifications = new(); + // TODO: ISSUE #213 throw on invalid backup + foreach (var backup in backups!) + { + guardian!.SaveElectionPartialKeyBackup(backup.Backup!.ToRecord()); + var verification = guardian.VerifyElectionPartialKeyBackup(backup.GuardianId!, keyCeremonyId); + if (verification == null) // TODO: ISSUE #213 throw on invalid backup + { + throw new KeyCeremonyException( + keyCeremony!.State, + keyCeremonyId, + UserId, + $"Error verifying back from {backup.Backup!.OwnerId!}"); + } + verifications.Add(new(verification)); + } + // save verifications + foreach (var verification in verifications) + { + _ = await _verificationService.SaveAsync(verification); + } + + // notify change to admin (signalR) + } + + private async Task RunStep6() + { + var keyCeremonyId = CeremonyDetails.KeyCeremonyId; + + // change state + _keyCeremony.State = KeyCeremonyState.PendingAdminToPublishJointKey; + await _keyCeremonyService.UpdateStateAsync(keyCeremonyId, _keyCeremony.State); + // notify change to guardians (signalR) + + // Announce guardians - puts data into keyceremony mediator structures + await Announce(keyCeremonyId); + + // get backups + var backups = await _backupService.GetByKeyCeremonyIdAsync(keyCeremonyId); + ReceiveBackups(backups!); + + // get all verifications + var verifications = await _verificationService.GetAllByKeyCeremonyIdAsync(keyCeremonyId); + // receive verifications + ReceiveBackupVerifications(verifications!); + + // publish joint key + var jointKey = PublishJointKey(); + + // if null then throw + if (jointKey == null) + { + throw new KeyCeremonyException( + KeyCeremonyState.PendingAdminToPublishJointKey, + keyCeremonyId, + UserId, + $"Failed to publish joint key for {keyCeremonyId}"); + } + + // save joint key to key ceremony + // update state to complete + _keyCeremony.State = KeyCeremonyState.Complete; + await _keyCeremonyService.UpdateCompleteAsync(keyCeremonyId, jointKey); + // notify change to guardians (signalR) + } + + #endregion + + public async Task HasBackup(string guardianId) + { + var backups = await _backupService.GetByKeyCeremonyIdAsync(CeremonyDetails.KeyCeremonyId); + var list = backups?.Where(b => b.GuardianId == guardianId); + return list?.Count() > 0; + } + public async Task<(bool, bool)> HasVerified(string guardianId) + { + var verifications = await _verificationService.GetAllByKeyCeremonyIdAsync(CeremonyDetails.KeyCeremonyId); + var list = verifications?.Where(v => v.DesignatedId == guardianId); + var notVerified = list?.Where(v => v.Verified == false); + return (list?.Count() > 0, notVerified?.Count() > 0); + } + + protected override void DisposeUnmanaged() + { + base.DisposeUnmanaged(); + + _electionPublicKeys?.Dispose(); + _electionPartialKeyBackups?.Dispose(); + _electionPartialKeyChallenges?.Dispose(); + } +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Test/ElectionGuard.UI.Test.csproj b/src/electionguard-ui/ElectionGuard.UI.Test/ElectionGuard.UI.Test.csproj index 9159cd13c..893666e37 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Test/ElectionGuard.UI.Test.csproj +++ b/src/electionguard-ui/ElectionGuard.UI.Test/ElectionGuard.UI.Test.csproj @@ -1,63 +1,63 @@ - - - - net7.0 - enable - enable - false - true - arm64;x64;x86 - - - - - - - - - - - - - - - - - - - - - - full - true - 1701;1702 - 4 - SYSLIB0004 - - - - pdbonly - 1701;1702 - 4 - SYSLIB0004 - - - - ..\..\..\data - ..\..\..\build\libs - - - - - - - - - - - - + + + + net7.0 + enable + enable + false + true + arm64;x64;x86 + + + + + + + + + + + + + + + + + + + + + + full + true + 1701;1702 + 4 + SYSLIB0004 + + + + pdbonly + 1701;1702 + 4 + SYSLIB0004 + + + + ..\..\..\data + ..\..\..\build\libs + + + + + + + + + + + + diff --git a/src/electionguard-ui/ElectionGuard.UI.sln b/src/electionguard-ui/ElectionGuard.UI.sln index 5428ae671..bce3e0437 100644 --- a/src/electionguard-ui/ElectionGuard.UI.sln +++ b/src/electionguard-ui/ElectionGuard.UI.sln @@ -1,150 +1,186 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.31611.283 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.UI.Lib", "ElectionGuard.UI.Lib\ElectionGuard.UI.Lib.csproj", "{55329D53-88D4-41A2-A707-7B49B52C5C7A}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Files", "Solution Files", "{481B8903-5279-4324-93A8-5A23217171EA}" - ProjectSection(SolutionItems) = preProject - Directory.Packages.props = Directory.Packages.props - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.Encryption", "..\..\bindings\netstandard\ElectionGuard\ElectionGuard.Encryption\ElectionGuard.Encryption.csproj", "{FBEFD95B-EAB8-4CC0-A9D5-6FA3FFC4F32B}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.ElectionSetup", "..\..\bindings\netstandard\ElectionGuard\ElectionGuard.ElectionSetup\ElectionGuard.ElectionSetup.csproj", "{3C59A33A-5962-4BAD-8B9B-2E0613239B90}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.UI", "ElectionGuard.UI\ElectionGuard.UI.csproj", "{B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.Encryption.Utils", "..\..\bindings\netstandard\ElectionGuard\ElectionGuard.Encryption.Utils\ElectionGuard.Encryption.Utils.csproj", "{B52FBB88-26FC-456E-852C-1787ADA9CE64}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.Decryption", "..\..\bindings\netstandard\ElectionGuard\ElectionGuard.Decryption\ElectionGuard.Decryption.csproj", "{DF0CA84A-EC01-48A6-9140-EF546FD781C5}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.Decryption.Tests", "..\..\bindings\netstandard\ElectionGuard\ElectionGuard.Decryption.Tests\ElectionGuard.Decryption.Tests.csproj", "{72F8C1CA-FDD7-4B7B-A08A-C16589EEA187}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.ElectionSetup.Tests", "..\..\bindings\netstandard\ElectionGuard\ElectionGuard.ElectionSetup.Tests\ElectionGuard.ElectionSetup.Tests.csproj", "{123DF2EF-5EB9-4974-B834-F996D777CFAB}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{42BB40E3-87DD-44E6-A2B8-AE36B2B98AA1}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|arm64 = Debug|arm64 - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|arm64 = Release|arm64 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {55329D53-88D4-41A2-A707-7B49B52C5C7A}.Debug|arm64.ActiveCfg = Debug|arm64 - {55329D53-88D4-41A2-A707-7B49B52C5C7A}.Debug|arm64.Build.0 = Debug|arm64 - {55329D53-88D4-41A2-A707-7B49B52C5C7A}.Debug|x64.ActiveCfg = Debug|x64 - {55329D53-88D4-41A2-A707-7B49B52C5C7A}.Debug|x64.Build.0 = Debug|x64 - {55329D53-88D4-41A2-A707-7B49B52C5C7A}.Debug|x86.ActiveCfg = Debug|x86 - {55329D53-88D4-41A2-A707-7B49B52C5C7A}.Debug|x86.Build.0 = Debug|x86 - {55329D53-88D4-41A2-A707-7B49B52C5C7A}.Release|arm64.ActiveCfg = Release|arm64 - {55329D53-88D4-41A2-A707-7B49B52C5C7A}.Release|arm64.Build.0 = Release|arm64 - {55329D53-88D4-41A2-A707-7B49B52C5C7A}.Release|x64.ActiveCfg = Release|x64 - {55329D53-88D4-41A2-A707-7B49B52C5C7A}.Release|x64.Build.0 = Release|x64 - {55329D53-88D4-41A2-A707-7B49B52C5C7A}.Release|x86.ActiveCfg = Release|x86 - {55329D53-88D4-41A2-A707-7B49B52C5C7A}.Release|x86.Build.0 = Release|x86 - {FBEFD95B-EAB8-4CC0-A9D5-6FA3FFC4F32B}.Debug|arm64.ActiveCfg = Debug|arm64 - {FBEFD95B-EAB8-4CC0-A9D5-6FA3FFC4F32B}.Debug|arm64.Build.0 = Debug|arm64 - {FBEFD95B-EAB8-4CC0-A9D5-6FA3FFC4F32B}.Debug|x64.ActiveCfg = Debug|x64 - {FBEFD95B-EAB8-4CC0-A9D5-6FA3FFC4F32B}.Debug|x64.Build.0 = Debug|x64 - {FBEFD95B-EAB8-4CC0-A9D5-6FA3FFC4F32B}.Debug|x86.ActiveCfg = Debug|x86 - {FBEFD95B-EAB8-4CC0-A9D5-6FA3FFC4F32B}.Debug|x86.Build.0 = Debug|x86 - {FBEFD95B-EAB8-4CC0-A9D5-6FA3FFC4F32B}.Release|arm64.ActiveCfg = Release|arm64 - {FBEFD95B-EAB8-4CC0-A9D5-6FA3FFC4F32B}.Release|arm64.Build.0 = Release|arm64 - {FBEFD95B-EAB8-4CC0-A9D5-6FA3FFC4F32B}.Release|x64.ActiveCfg = Release|x64 - {FBEFD95B-EAB8-4CC0-A9D5-6FA3FFC4F32B}.Release|x64.Build.0 = Release|x64 - {FBEFD95B-EAB8-4CC0-A9D5-6FA3FFC4F32B}.Release|x86.ActiveCfg = Release|x86 - {FBEFD95B-EAB8-4CC0-A9D5-6FA3FFC4F32B}.Release|x86.Build.0 = Release|x86 - {3C59A33A-5962-4BAD-8B9B-2E0613239B90}.Debug|arm64.ActiveCfg = Debug|arm64 - {3C59A33A-5962-4BAD-8B9B-2E0613239B90}.Debug|arm64.Build.0 = Debug|arm64 - {3C59A33A-5962-4BAD-8B9B-2E0613239B90}.Debug|x64.ActiveCfg = Debug|x64 - {3C59A33A-5962-4BAD-8B9B-2E0613239B90}.Debug|x64.Build.0 = Debug|x64 - {3C59A33A-5962-4BAD-8B9B-2E0613239B90}.Debug|x86.ActiveCfg = Debug|x86 - {3C59A33A-5962-4BAD-8B9B-2E0613239B90}.Debug|x86.Build.0 = Debug|x86 - {3C59A33A-5962-4BAD-8B9B-2E0613239B90}.Release|arm64.ActiveCfg = Release|arm64 - {3C59A33A-5962-4BAD-8B9B-2E0613239B90}.Release|arm64.Build.0 = Release|arm64 - {3C59A33A-5962-4BAD-8B9B-2E0613239B90}.Release|x64.ActiveCfg = Release|x64 - {3C59A33A-5962-4BAD-8B9B-2E0613239B90}.Release|x64.Build.0 = Release|x64 - {3C59A33A-5962-4BAD-8B9B-2E0613239B90}.Release|x86.ActiveCfg = Release|x86 - {3C59A33A-5962-4BAD-8B9B-2E0613239B90}.Release|x86.Build.0 = Release|x86 - {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Debug|arm64.ActiveCfg = Debug|Any CPU - {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Debug|arm64.Build.0 = Debug|Any CPU - {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Debug|x64.ActiveCfg = Debug|Any CPU - {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Debug|x64.Build.0 = Debug|Any CPU - {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Debug|x64.Deploy.0 = Debug|Any CPU - {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Debug|x86.ActiveCfg = Debug|Any CPU - {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Debug|x86.Build.0 = Debug|Any CPU - {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Debug|x86.Deploy.0 = Debug|Any CPU - {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Release|arm64.ActiveCfg = Release|Any CPU - {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Release|arm64.Build.0 = Release|Any CPU - {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Release|arm64.Deploy.0 = Release|Any CPU - {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Release|x64.ActiveCfg = Release|Any CPU - {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Release|x64.Build.0 = Release|Any CPU - {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Release|x64.Deploy.0 = Release|Any CPU - {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Release|x86.ActiveCfg = Release|Any CPU - {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Release|x86.Build.0 = Release|Any CPU - {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Release|x86.Deploy.0 = Release|Any CPU - {B52FBB88-26FC-456E-852C-1787ADA9CE64}.Debug|arm64.ActiveCfg = Debug|arm64 - {B52FBB88-26FC-456E-852C-1787ADA9CE64}.Debug|arm64.Build.0 = Debug|arm64 - {B52FBB88-26FC-456E-852C-1787ADA9CE64}.Debug|x64.ActiveCfg = Debug|x64 - {B52FBB88-26FC-456E-852C-1787ADA9CE64}.Debug|x64.Build.0 = Debug|x64 - {B52FBB88-26FC-456E-852C-1787ADA9CE64}.Debug|x86.ActiveCfg = Debug|x86 - {B52FBB88-26FC-456E-852C-1787ADA9CE64}.Debug|x86.Build.0 = Debug|x86 - {B52FBB88-26FC-456E-852C-1787ADA9CE64}.Release|arm64.ActiveCfg = Release|arm64 - {B52FBB88-26FC-456E-852C-1787ADA9CE64}.Release|arm64.Build.0 = Release|arm64 - {B52FBB88-26FC-456E-852C-1787ADA9CE64}.Release|x64.ActiveCfg = Release|x64 - {B52FBB88-26FC-456E-852C-1787ADA9CE64}.Release|x64.Build.0 = Release|x64 - {B52FBB88-26FC-456E-852C-1787ADA9CE64}.Release|x86.ActiveCfg = Release|x86 - {B52FBB88-26FC-456E-852C-1787ADA9CE64}.Release|x86.Build.0 = Release|x86 - {DF0CA84A-EC01-48A6-9140-EF546FD781C5}.Debug|arm64.ActiveCfg = Debug|arm64 - {DF0CA84A-EC01-48A6-9140-EF546FD781C5}.Debug|arm64.Build.0 = Debug|arm64 - {DF0CA84A-EC01-48A6-9140-EF546FD781C5}.Debug|x64.ActiveCfg = Debug|x64 - {DF0CA84A-EC01-48A6-9140-EF546FD781C5}.Debug|x64.Build.0 = Debug|x64 - {DF0CA84A-EC01-48A6-9140-EF546FD781C5}.Debug|x86.ActiveCfg = Debug|x86 - {DF0CA84A-EC01-48A6-9140-EF546FD781C5}.Debug|x86.Build.0 = Debug|x86 - {DF0CA84A-EC01-48A6-9140-EF546FD781C5}.Release|arm64.ActiveCfg = Release|arm64 - {DF0CA84A-EC01-48A6-9140-EF546FD781C5}.Release|arm64.Build.0 = Release|arm64 - {DF0CA84A-EC01-48A6-9140-EF546FD781C5}.Release|x64.ActiveCfg = Release|x64 - {DF0CA84A-EC01-48A6-9140-EF546FD781C5}.Release|x64.Build.0 = Release|x64 - {DF0CA84A-EC01-48A6-9140-EF546FD781C5}.Release|x86.ActiveCfg = Release|x86 - {DF0CA84A-EC01-48A6-9140-EF546FD781C5}.Release|x86.Build.0 = Release|x86 - {72F8C1CA-FDD7-4B7B-A08A-C16589EEA187}.Debug|arm64.ActiveCfg = Debug|arm64 - {72F8C1CA-FDD7-4B7B-A08A-C16589EEA187}.Debug|arm64.Build.0 = Debug|arm64 - {72F8C1CA-FDD7-4B7B-A08A-C16589EEA187}.Debug|x64.ActiveCfg = Debug|x64 - {72F8C1CA-FDD7-4B7B-A08A-C16589EEA187}.Debug|x64.Build.0 = Debug|x64 - {72F8C1CA-FDD7-4B7B-A08A-C16589EEA187}.Debug|x86.ActiveCfg = Debug|x86 - {72F8C1CA-FDD7-4B7B-A08A-C16589EEA187}.Debug|x86.Build.0 = Debug|x86 - {72F8C1CA-FDD7-4B7B-A08A-C16589EEA187}.Release|arm64.ActiveCfg = Release|arm64 - {72F8C1CA-FDD7-4B7B-A08A-C16589EEA187}.Release|arm64.Build.0 = Release|arm64 - {72F8C1CA-FDD7-4B7B-A08A-C16589EEA187}.Release|x64.ActiveCfg = Release|x64 - {72F8C1CA-FDD7-4B7B-A08A-C16589EEA187}.Release|x64.Build.0 = Release|x64 - {72F8C1CA-FDD7-4B7B-A08A-C16589EEA187}.Release|x86.ActiveCfg = Release|x86 - {72F8C1CA-FDD7-4B7B-A08A-C16589EEA187}.Release|x86.Build.0 = Release|x86 - {123DF2EF-5EB9-4974-B834-F996D777CFAB}.Debug|arm64.ActiveCfg = Debug|arm64 - {123DF2EF-5EB9-4974-B834-F996D777CFAB}.Debug|arm64.Build.0 = Debug|arm64 - {123DF2EF-5EB9-4974-B834-F996D777CFAB}.Debug|x64.ActiveCfg = Debug|x64 - {123DF2EF-5EB9-4974-B834-F996D777CFAB}.Debug|x64.Build.0 = Debug|x64 - {123DF2EF-5EB9-4974-B834-F996D777CFAB}.Debug|x86.ActiveCfg = Debug|x86 - {123DF2EF-5EB9-4974-B834-F996D777CFAB}.Debug|x86.Build.0 = Debug|x86 - {123DF2EF-5EB9-4974-B834-F996D777CFAB}.Release|arm64.ActiveCfg = Release|arm64 - {123DF2EF-5EB9-4974-B834-F996D777CFAB}.Release|arm64.Build.0 = Release|arm64 - {123DF2EF-5EB9-4974-B834-F996D777CFAB}.Release|x64.ActiveCfg = Release|x64 - {123DF2EF-5EB9-4974-B834-F996D777CFAB}.Release|x64.Build.0 = Release|x64 - {123DF2EF-5EB9-4974-B834-F996D777CFAB}.Release|x86.ActiveCfg = Release|x86 - {123DF2EF-5EB9-4974-B834-F996D777CFAB}.Release|x86.Build.0 = Release|x86 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {72F8C1CA-FDD7-4B7B-A08A-C16589EEA187} = {42BB40E3-87DD-44E6-A2B8-AE36B2B98AA1} - {123DF2EF-5EB9-4974-B834-F996D777CFAB} = {42BB40E3-87DD-44E6-A2B8-AE36B2B98AA1} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {61F7FB11-1E47-470C-91E2-47F8143E1572} - EndGlobalSection -EndGlobal +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31611.283 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.UI.Lib", "ElectionGuard.UI.Lib\ElectionGuard.UI.Lib.csproj", "{55329D53-88D4-41A2-A707-7B49B52C5C7A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Files", "Solution Files", "{481B8903-5279-4324-93A8-5A23217171EA}" + ProjectSection(SolutionItems) = preProject + Directory.Packages.props = Directory.Packages.props + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.Encryption", "..\..\bindings\netstandard\ElectionGuard\ElectionGuard.Encryption\ElectionGuard.Encryption.csproj", "{FBEFD95B-EAB8-4CC0-A9D5-6FA3FFC4F32B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.ElectionSetup", "..\..\bindings\netstandard\ElectionGuard\ElectionGuard.ElectionSetup\ElectionGuard.ElectionSetup.csproj", "{3C59A33A-5962-4BAD-8B9B-2E0613239B90}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.UI", "ElectionGuard.UI\ElectionGuard.UI.csproj", "{B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.Encryption.Utils", "..\..\bindings\netstandard\ElectionGuard\ElectionGuard.Encryption.Utils\ElectionGuard.Encryption.Utils.csproj", "{B52FBB88-26FC-456E-852C-1787ADA9CE64}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.Decryption", "..\..\bindings\netstandard\ElectionGuard\ElectionGuard.Decryption\ElectionGuard.Decryption.csproj", "{DF0CA84A-EC01-48A6-9140-EF546FD781C5}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.Decryption.Tests", "..\..\bindings\netstandard\ElectionGuard\ElectionGuard.Decryption.Tests\ElectionGuard.Decryption.Tests.csproj", "{72F8C1CA-FDD7-4B7B-A08A-C16589EEA187}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.ElectionSetup.Tests", "..\..\bindings\netstandard\ElectionGuard\ElectionGuard.ElectionSetup.Tests\ElectionGuard.ElectionSetup.Tests.csproj", "{123DF2EF-5EB9-4974-B834-F996D777CFAB}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{42BB40E3-87DD-44E6-A2B8-AE36B2B98AA1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|arm64 = Debug|arm64 + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|arm64 = Release|arm64 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {55329D53-88D4-41A2-A707-7B49B52C5C7A}.Debug|Any CPU.ActiveCfg = Debug|x64 + {55329D53-88D4-41A2-A707-7B49B52C5C7A}.Debug|Any CPU.Build.0 = Debug|x64 + {55329D53-88D4-41A2-A707-7B49B52C5C7A}.Debug|arm64.ActiveCfg = Debug|arm64 + {55329D53-88D4-41A2-A707-7B49B52C5C7A}.Debug|arm64.Build.0 = Debug|arm64 + {55329D53-88D4-41A2-A707-7B49B52C5C7A}.Debug|x64.ActiveCfg = Debug|x64 + {55329D53-88D4-41A2-A707-7B49B52C5C7A}.Debug|x64.Build.0 = Debug|x64 + {55329D53-88D4-41A2-A707-7B49B52C5C7A}.Debug|x86.ActiveCfg = Debug|x86 + {55329D53-88D4-41A2-A707-7B49B52C5C7A}.Debug|x86.Build.0 = Debug|x86 + {55329D53-88D4-41A2-A707-7B49B52C5C7A}.Release|Any CPU.ActiveCfg = Release|x64 + {55329D53-88D4-41A2-A707-7B49B52C5C7A}.Release|Any CPU.Build.0 = Release|x64 + {55329D53-88D4-41A2-A707-7B49B52C5C7A}.Release|arm64.ActiveCfg = Release|arm64 + {55329D53-88D4-41A2-A707-7B49B52C5C7A}.Release|arm64.Build.0 = Release|arm64 + {55329D53-88D4-41A2-A707-7B49B52C5C7A}.Release|x64.ActiveCfg = Release|x64 + {55329D53-88D4-41A2-A707-7B49B52C5C7A}.Release|x64.Build.0 = Release|x64 + {55329D53-88D4-41A2-A707-7B49B52C5C7A}.Release|x86.ActiveCfg = Release|x86 + {55329D53-88D4-41A2-A707-7B49B52C5C7A}.Release|x86.Build.0 = Release|x86 + {FBEFD95B-EAB8-4CC0-A9D5-6FA3FFC4F32B}.Debug|Any CPU.ActiveCfg = Debug|x64 + {FBEFD95B-EAB8-4CC0-A9D5-6FA3FFC4F32B}.Debug|Any CPU.Build.0 = Debug|x64 + {FBEFD95B-EAB8-4CC0-A9D5-6FA3FFC4F32B}.Debug|arm64.ActiveCfg = Debug|arm64 + {FBEFD95B-EAB8-4CC0-A9D5-6FA3FFC4F32B}.Debug|arm64.Build.0 = Debug|arm64 + {FBEFD95B-EAB8-4CC0-A9D5-6FA3FFC4F32B}.Debug|x64.ActiveCfg = Debug|x64 + {FBEFD95B-EAB8-4CC0-A9D5-6FA3FFC4F32B}.Debug|x64.Build.0 = Debug|x64 + {FBEFD95B-EAB8-4CC0-A9D5-6FA3FFC4F32B}.Debug|x86.ActiveCfg = Debug|x86 + {FBEFD95B-EAB8-4CC0-A9D5-6FA3FFC4F32B}.Debug|x86.Build.0 = Debug|x86 + {FBEFD95B-EAB8-4CC0-A9D5-6FA3FFC4F32B}.Release|Any CPU.ActiveCfg = Release|x64 + {FBEFD95B-EAB8-4CC0-A9D5-6FA3FFC4F32B}.Release|Any CPU.Build.0 = Release|x64 + {FBEFD95B-EAB8-4CC0-A9D5-6FA3FFC4F32B}.Release|arm64.ActiveCfg = Release|arm64 + {FBEFD95B-EAB8-4CC0-A9D5-6FA3FFC4F32B}.Release|arm64.Build.0 = Release|arm64 + {FBEFD95B-EAB8-4CC0-A9D5-6FA3FFC4F32B}.Release|x64.ActiveCfg = Release|x64 + {FBEFD95B-EAB8-4CC0-A9D5-6FA3FFC4F32B}.Release|x64.Build.0 = Release|x64 + {FBEFD95B-EAB8-4CC0-A9D5-6FA3FFC4F32B}.Release|x86.ActiveCfg = Release|x86 + {FBEFD95B-EAB8-4CC0-A9D5-6FA3FFC4F32B}.Release|x86.Build.0 = Release|x86 + {3C59A33A-5962-4BAD-8B9B-2E0613239B90}.Debug|Any CPU.ActiveCfg = Debug|x64 + {3C59A33A-5962-4BAD-8B9B-2E0613239B90}.Debug|Any CPU.Build.0 = Debug|x64 + {3C59A33A-5962-4BAD-8B9B-2E0613239B90}.Debug|arm64.ActiveCfg = Debug|arm64 + {3C59A33A-5962-4BAD-8B9B-2E0613239B90}.Debug|arm64.Build.0 = Debug|arm64 + {3C59A33A-5962-4BAD-8B9B-2E0613239B90}.Debug|x64.ActiveCfg = Debug|x64 + {3C59A33A-5962-4BAD-8B9B-2E0613239B90}.Debug|x64.Build.0 = Debug|x64 + {3C59A33A-5962-4BAD-8B9B-2E0613239B90}.Debug|x86.ActiveCfg = Debug|x86 + {3C59A33A-5962-4BAD-8B9B-2E0613239B90}.Debug|x86.Build.0 = Debug|x86 + {3C59A33A-5962-4BAD-8B9B-2E0613239B90}.Release|Any CPU.ActiveCfg = Release|x64 + {3C59A33A-5962-4BAD-8B9B-2E0613239B90}.Release|Any CPU.Build.0 = Release|x64 + {3C59A33A-5962-4BAD-8B9B-2E0613239B90}.Release|arm64.ActiveCfg = Release|arm64 + {3C59A33A-5962-4BAD-8B9B-2E0613239B90}.Release|arm64.Build.0 = Release|arm64 + {3C59A33A-5962-4BAD-8B9B-2E0613239B90}.Release|x64.ActiveCfg = Release|x64 + {3C59A33A-5962-4BAD-8B9B-2E0613239B90}.Release|x64.Build.0 = Release|x64 + {3C59A33A-5962-4BAD-8B9B-2E0613239B90}.Release|x86.ActiveCfg = Release|x86 + {3C59A33A-5962-4BAD-8B9B-2E0613239B90}.Release|x86.Build.0 = Release|x86 + {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Debug|arm64.ActiveCfg = Debug|Any CPU + {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Debug|arm64.Build.0 = Debug|Any CPU + {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Debug|x64.ActiveCfg = Debug|Any CPU + {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Debug|x64.Build.0 = Debug|Any CPU + {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Debug|x64.Deploy.0 = Debug|Any CPU + {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Debug|x86.ActiveCfg = Debug|Any CPU + {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Debug|x86.Build.0 = Debug|Any CPU + {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Debug|x86.Deploy.0 = Debug|Any CPU + {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Release|Any CPU.Build.0 = Release|Any CPU + {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Release|Any CPU.Deploy.0 = Release|Any CPU + {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Release|arm64.ActiveCfg = Release|Any CPU + {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Release|arm64.Build.0 = Release|Any CPU + {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Release|arm64.Deploy.0 = Release|Any CPU + {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Release|x64.ActiveCfg = Release|Any CPU + {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Release|x64.Build.0 = Release|Any CPU + {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Release|x64.Deploy.0 = Release|Any CPU + {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Release|x86.ActiveCfg = Release|Any CPU + {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Release|x86.Build.0 = Release|Any CPU + {B4301667-EB87-4A9D-BE2E-5E8611F6EAAA}.Release|x86.Deploy.0 = Release|Any CPU + {B52FBB88-26FC-456E-852C-1787ADA9CE64}.Debug|Any CPU.ActiveCfg = Debug|x64 + {B52FBB88-26FC-456E-852C-1787ADA9CE64}.Debug|Any CPU.Build.0 = Debug|x64 + {B52FBB88-26FC-456E-852C-1787ADA9CE64}.Debug|arm64.ActiveCfg = Debug|arm64 + {B52FBB88-26FC-456E-852C-1787ADA9CE64}.Debug|arm64.Build.0 = Debug|arm64 + {B52FBB88-26FC-456E-852C-1787ADA9CE64}.Debug|x64.ActiveCfg = Debug|x64 + {B52FBB88-26FC-456E-852C-1787ADA9CE64}.Debug|x64.Build.0 = Debug|x64 + {B52FBB88-26FC-456E-852C-1787ADA9CE64}.Debug|x86.ActiveCfg = Debug|x86 + {B52FBB88-26FC-456E-852C-1787ADA9CE64}.Debug|x86.Build.0 = Debug|x86 + {B52FBB88-26FC-456E-852C-1787ADA9CE64}.Release|Any CPU.ActiveCfg = Release|x64 + {B52FBB88-26FC-456E-852C-1787ADA9CE64}.Release|Any CPU.Build.0 = Release|x64 + {B52FBB88-26FC-456E-852C-1787ADA9CE64}.Release|arm64.ActiveCfg = Release|arm64 + {B52FBB88-26FC-456E-852C-1787ADA9CE64}.Release|arm64.Build.0 = Release|arm64 + {B52FBB88-26FC-456E-852C-1787ADA9CE64}.Release|x64.ActiveCfg = Release|x64 + {B52FBB88-26FC-456E-852C-1787ADA9CE64}.Release|x64.Build.0 = Release|x64 + {B52FBB88-26FC-456E-852C-1787ADA9CE64}.Release|x86.ActiveCfg = Release|x86 + {B52FBB88-26FC-456E-852C-1787ADA9CE64}.Release|x86.Build.0 = Release|x86 + {DF0CA84A-EC01-48A6-9140-EF546FD781C5}.Debug|Any CPU.ActiveCfg = Debug|x64 + {DF0CA84A-EC01-48A6-9140-EF546FD781C5}.Debug|Any CPU.Build.0 = Debug|x64 + {DF0CA84A-EC01-48A6-9140-EF546FD781C5}.Debug|arm64.ActiveCfg = Debug|arm64 + {DF0CA84A-EC01-48A6-9140-EF546FD781C5}.Debug|arm64.Build.0 = Debug|arm64 + {DF0CA84A-EC01-48A6-9140-EF546FD781C5}.Debug|x64.ActiveCfg = Debug|x64 + {DF0CA84A-EC01-48A6-9140-EF546FD781C5}.Debug|x64.Build.0 = Debug|x64 + {DF0CA84A-EC01-48A6-9140-EF546FD781C5}.Debug|x86.ActiveCfg = Debug|x86 + {DF0CA84A-EC01-48A6-9140-EF546FD781C5}.Debug|x86.Build.0 = Debug|x86 + {DF0CA84A-EC01-48A6-9140-EF546FD781C5}.Release|Any CPU.ActiveCfg = Release|x64 + {DF0CA84A-EC01-48A6-9140-EF546FD781C5}.Release|Any CPU.Build.0 = Release|x64 + {DF0CA84A-EC01-48A6-9140-EF546FD781C5}.Release|arm64.ActiveCfg = Release|arm64 + {DF0CA84A-EC01-48A6-9140-EF546FD781C5}.Release|arm64.Build.0 = Release|arm64 + {DF0CA84A-EC01-48A6-9140-EF546FD781C5}.Release|x64.ActiveCfg = Release|x64 + {DF0CA84A-EC01-48A6-9140-EF546FD781C5}.Release|x64.Build.0 = Release|x64 + {DF0CA84A-EC01-48A6-9140-EF546FD781C5}.Release|x86.ActiveCfg = Release|x86 + {DF0CA84A-EC01-48A6-9140-EF546FD781C5}.Release|x86.Build.0 = Release|x86 + {72F8C1CA-FDD7-4B7B-A08A-C16589EEA187}.Debug|Any CPU.ActiveCfg = Debug|x64 + {72F8C1CA-FDD7-4B7B-A08A-C16589EEA187}.Debug|Any CPU.Build.0 = Debug|x64 + {72F8C1CA-FDD7-4B7B-A08A-C16589EEA187}.Debug|arm64.ActiveCfg = Debug|arm64 + {72F8C1CA-FDD7-4B7B-A08A-C16589EEA187}.Debug|arm64.Build.0 = Debug|arm64 + {72F8C1CA-FDD7-4B7B-A08A-C16589EEA187}.Debug|x64.ActiveCfg = Debug|x64 + {72F8C1CA-FDD7-4B7B-A08A-C16589EEA187}.Debug|x64.Build.0 = Debug|x64 + {72F8C1CA-FDD7-4B7B-A08A-C16589EEA187}.Debug|x86.ActiveCfg = Debug|x86 + {72F8C1CA-FDD7-4B7B-A08A-C16589EEA187}.Debug|x86.Build.0 = Debug|x86 + {72F8C1CA-FDD7-4B7B-A08A-C16589EEA187}.Release|Any CPU.ActiveCfg = Release|x64 + {72F8C1CA-FDD7-4B7B-A08A-C16589EEA187}.Release|Any CPU.Build.0 = Release|x64 + {72F8C1CA-FDD7-4B7B-A08A-C16589EEA187}.Release|arm64.ActiveCfg = Release|arm64 + {72F8C1CA-FDD7-4B7B-A08A-C16589EEA187}.Release|arm64.Build.0 = Release|arm64 + {72F8C1CA-FDD7-4B7B-A08A-C16589EEA187}.Release|x64.ActiveCfg = Release|x64 + {72F8C1CA-FDD7-4B7B-A08A-C16589EEA187}.Release|x64.Build.0 = Release|x64 + {72F8C1CA-FDD7-4B7B-A08A-C16589EEA187}.Release|x86.ActiveCfg = Release|x86 + {72F8C1CA-FDD7-4B7B-A08A-C16589EEA187}.Release|x86.Build.0 = Release|x86 + {123DF2EF-5EB9-4974-B834-F996D777CFAB}.Debug|Any CPU.ActiveCfg = Debug|x64 + {123DF2EF-5EB9-4974-B834-F996D777CFAB}.Debug|Any CPU.Build.0 = Debug|x64 + {123DF2EF-5EB9-4974-B834-F996D777CFAB}.Debug|arm64.ActiveCfg = Debug|arm64 + {123DF2EF-5EB9-4974-B834-F996D777CFAB}.Debug|arm64.Build.0 = Debug|arm64 + {123DF2EF-5EB9-4974-B834-F996D777CFAB}.Debug|x64.ActiveCfg = Debug|x64 + {123DF2EF-5EB9-4974-B834-F996D777CFAB}.Debug|x64.Build.0 = Debug|x64 + {123DF2EF-5EB9-4974-B834-F996D777CFAB}.Debug|x86.ActiveCfg = Debug|x86 + {123DF2EF-5EB9-4974-B834-F996D777CFAB}.Debug|x86.Build.0 = Debug|x86 + {123DF2EF-5EB9-4974-B834-F996D777CFAB}.Release|Any CPU.ActiveCfg = Release|x64 + {123DF2EF-5EB9-4974-B834-F996D777CFAB}.Release|Any CPU.Build.0 = Release|x64 + {123DF2EF-5EB9-4974-B834-F996D777CFAB}.Release|arm64.ActiveCfg = Release|arm64 + {123DF2EF-5EB9-4974-B834-F996D777CFAB}.Release|arm64.Build.0 = Release|arm64 + {123DF2EF-5EB9-4974-B834-F996D777CFAB}.Release|x64.ActiveCfg = Release|x64 + {123DF2EF-5EB9-4974-B834-F996D777CFAB}.Release|x64.Build.0 = Release|x64 + {123DF2EF-5EB9-4974-B834-F996D777CFAB}.Release|x86.ActiveCfg = Release|x86 + {123DF2EF-5EB9-4974-B834-F996D777CFAB}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {72F8C1CA-FDD7-4B7B-A08A-C16589EEA187} = {42BB40E3-87DD-44E6-A2B8-AE36B2B98AA1} + {123DF2EF-5EB9-4974-B834-F996D777CFAB} = {42BB40E3-87DD-44E6-A2B8-AE36B2B98AA1} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {61F7FB11-1E47-470C-91E2-47F8143E1572} + EndGlobalSection +EndGlobal diff --git a/src/electionguard-ui/ElectionGuard.UI/App.xaml b/src/electionguard-ui/ElectionGuard.UI/App.xaml index 66ed4ffa3..edb7fd711 100644 --- a/src/electionguard-ui/ElectionGuard.UI/App.xaml +++ b/src/electionguard-ui/ElectionGuard.UI/App.xaml @@ -1,16 +1,16 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/src/electionguard-ui/ElectionGuard.UI/App.xaml.cs b/src/electionguard-ui/ElectionGuard.UI/App.xaml.cs index a9b4bdcaf..35d5cc996 100644 --- a/src/electionguard-ui/ElectionGuard.UI/App.xaml.cs +++ b/src/electionguard-ui/ElectionGuard.UI/App.xaml.cs @@ -1,91 +1,91 @@ -using System.Globalization; -using CommunityToolkit.Maui.Views; -using ElectionGuard.Converters; -using Newtonsoft.Json; - -namespace ElectionGuard.UI; - -public partial class App -{ - public static User CurrentUser { get; set; } = new(); - private readonly ILogger _logger; - - public App(ILogger logger) - { - _logger = logger; - - AddUnhandledExceptionHandler(); - - JsonConvert.DefaultSettings = SerializationSettings.NewtonsoftSettings; - - InitializeComponent(); - UserAppTheme = AppTheme.Light; - - SetupLanguageSupport(); - MainPage = new AppShell(); - _logger.LogInformation("Application Started"); - - DbService.DatabaseDisconnected += DbService_DatabaseDisconnected; - } - - private async void DbService_DatabaseDisconnected(object? sender, DbEventArgs e) - { - if (Shell.Current.CurrentPage as LoginPage is null) - { - await Shell.Current.Dispatcher.DispatchAsync(async () => - { - _ = await Shell.Current.CurrentPage.ShowPopupAsync(new NetworkPopup()); - }); - } - } - - private void AddUnhandledExceptionHandler() - { -#if WINDOWS - Microsoft.UI.Xaml.Application.Current.UnhandledException += Current_UnhandledException; - } - - private void Current_UnhandledException(object sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e) - { - _logger.LogCritical(e.Exception, "Unhandled Exception"); - ErrorLog.CreateCrashedFile(); -#endif - } - - private void SetupLanguageSupport() - { - LocalizationResourceManager.Current.PropertyChanged += CurrentLanguage_Changed; - LocalizationResourceManager.Current.Init(AppResources.ResourceManager, CultureInfo.CurrentCulture); - - var currentLanguage = Preferences.Get("CurrentLanguage", null); - LocalizationResourceManager.Current.CurrentCulture = currentLanguage is null ? CultureInfo.CurrentCulture : new CultureInfo(currentLanguage); - } - - private void CurrentLanguage_Changed(object? sender, System.ComponentModel.PropertyChangedEventArgs e) - { - AppResources.Culture = LocalizationResourceManager.Current.CurrentCulture; - - // change the first windows title to the new language - if (Windows.Count > 0) - { - Windows[0].Title = GetWindowTitle(); - } - } - - protected override Window CreateWindow(IActivationState? activationState) - { - var window = base.CreateWindow(activationState); - - if (string.IsNullOrEmpty(window.Title)) - { - window.Title = GetWindowTitle(); - } - - return window; - } - - private static string GetWindowTitle() - { - return AppResources.WindowTitle; - } -} +using System.Globalization; +using CommunityToolkit.Maui.Views; +using ElectionGuard.Converters; +using Newtonsoft.Json; + +namespace ElectionGuard.UI; + +public partial class App +{ + public static User CurrentUser { get; set; } = new(); + private readonly ILogger _logger; + + public App(ILogger logger) + { + _logger = logger; + + AddUnhandledExceptionHandler(); + + JsonConvert.DefaultSettings = SerializationSettings.NewtonsoftSettings; + + InitializeComponent(); + UserAppTheme = AppTheme.Light; + + SetupLanguageSupport(); + MainPage = new AppShell(); + _logger.LogInformation("Application Started"); + + DbService.DatabaseDisconnected += DbService_DatabaseDisconnected; + } + + private async void DbService_DatabaseDisconnected(object? sender, DbEventArgs e) + { + if (Shell.Current.CurrentPage as LoginPage is null) + { + await Shell.Current.Dispatcher.DispatchAsync(async () => + { + _ = await Shell.Current.CurrentPage.ShowPopupAsync(new NetworkPopup()); + }); + } + } + + private void AddUnhandledExceptionHandler() + { +#if WINDOWS + Microsoft.UI.Xaml.Application.Current.UnhandledException += Current_UnhandledException; + } + + private void Current_UnhandledException(object sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e) + { + _logger.LogCritical(e.Exception, "Unhandled Exception"); + ErrorLog.CreateCrashedFile(); +#endif + } + + private void SetupLanguageSupport() + { + LocalizationResourceManager.Current.PropertyChanged += CurrentLanguage_Changed; + LocalizationResourceManager.Current.Init(AppResources.ResourceManager, CultureInfo.CurrentCulture); + + var currentLanguage = Preferences.Get("CurrentLanguage", null); + LocalizationResourceManager.Current.CurrentCulture = currentLanguage is null ? CultureInfo.CurrentCulture : new CultureInfo(currentLanguage); + } + + private void CurrentLanguage_Changed(object? sender, System.ComponentModel.PropertyChangedEventArgs e) + { + AppResources.Culture = LocalizationResourceManager.Current.CurrentCulture; + + // change the first windows title to the new language + if (Windows.Count > 0) + { + Windows[0].Title = GetWindowTitle(); + } + } + + protected override Window CreateWindow(IActivationState? activationState) + { + var window = base.CreateWindow(activationState); + + if (string.IsNullOrEmpty(window.Title)) + { + window.Title = GetWindowTitle(); + } + + return window; + } + + private static string GetWindowTitle() + { + return AppResources.WindowTitle; + } +} diff --git a/src/electionguard-ui/ElectionGuard.UI/AppShell.xaml b/src/electionguard-ui/ElectionGuard.UI/AppShell.xaml index b0a601e14..abc51cf4b 100644 --- a/src/electionguard-ui/ElectionGuard.UI/AppShell.xaml +++ b/src/electionguard-ui/ElectionGuard.UI/AppShell.xaml @@ -1,22 +1,22 @@ - - - - - - - + + + + + + + diff --git a/src/electionguard-ui/ElectionGuard.UI/AppShell.xaml.cs b/src/electionguard-ui/ElectionGuard.UI/AppShell.xaml.cs index 480765099..ec5d6b41f 100644 --- a/src/electionguard-ui/ElectionGuard.UI/AppShell.xaml.cs +++ b/src/electionguard-ui/ElectionGuard.UI/AppShell.xaml.cs @@ -1,15 +1,15 @@ -using ElectionGuard.UI.Lib.Extensions; -using CommunityToolkit.Mvvm.DependencyInjection; - -namespace ElectionGuard.UI; - -public partial class AppShell -{ - public AppShell() - { - InitializeComponent(); - - var navigationService = Ioc.Default.GetInstance (); - navigationService.RegisterRoutes(); - } -} +using ElectionGuard.UI.Helpers; +using CommunityToolkit.Mvvm.DependencyInjection; + +namespace ElectionGuard.UI; + +public partial class AppShell +{ + public AppShell() + { + InitializeComponent(); + + var navigationService = Ioc.Default.GetInstance (); + navigationService.RegisterRoutes(); + } +} diff --git a/src/electionguard-ui/ElectionGuard.UI/Controls/ContestControl.xaml b/src/electionguard-ui/ElectionGuard.UI/Controls/ContestControl.xaml index b0a922277..982cab13a 100644 --- a/src/electionguard-ui/ElectionGuard.UI/Controls/ContestControl.xaml +++ b/src/electionguard-ui/ElectionGuard.UI/Controls/ContestControl.xaml @@ -1,103 +1,103 @@ - - - - - - - - - - - + + + + + + + + + + + diff --git a/src/electionguard-ui/ElectionGuard.UI/Controls/ContestControl.xaml.cs b/src/electionguard-ui/ElectionGuard.UI/Controls/ContestControl.xaml.cs index b96a77f02..a27a02878 100644 --- a/src/electionguard-ui/ElectionGuard.UI/Controls/ContestControl.xaml.cs +++ b/src/electionguard-ui/ElectionGuard.UI/Controls/ContestControl.xaml.cs @@ -1,9 +1,9 @@ -namespace ElectionGuard.UI.Controls; - -public partial class ContestControl : ContentView -{ - public ContestControl() - { - InitializeComponent(); - } -} +namespace ElectionGuard.UI.Controls; + +public partial class ContestControl : ContentView +{ + public ContestControl() + { + InitializeComponent(); + } +} diff --git a/src/electionguard-ui/ElectionGuard.UI/Controls/ExpanderControl.xaml b/src/electionguard-ui/ElectionGuard.UI/Controls/ExpanderControl.xaml index a5aa6663a..a1a98f90e 100644 --- a/src/electionguard-ui/ElectionGuard.UI/Controls/ExpanderControl.xaml +++ b/src/electionguard-ui/ElectionGuard.UI/Controls/ExpanderControl.xaml @@ -1,40 +1,40 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/src/electionguard-ui/ElectionGuard.UI/Controls/ExpanderControl.xaml.cs b/src/electionguard-ui/ElectionGuard.UI/Controls/ExpanderControl.xaml.cs index 4a41b347b..fd0ccfd3e 100644 --- a/src/electionguard-ui/ElectionGuard.UI/Controls/ExpanderControl.xaml.cs +++ b/src/electionguard-ui/ElectionGuard.UI/Controls/ExpanderControl.xaml.cs @@ -1,19 +1,19 @@ -namespace ElectionGuard.UI.Controls; - -public partial class ExpanderControl : ContentView -{ - public ExpanderControl() - { - InitializeComponent(); - } - - public static readonly BindableProperty TitleProperty = BindableProperty.Create(nameof(Title), typeof(string), typeof(ExpanderControl)); - - public string Title - { - get => (string)GetValue(TitleProperty); - set => SetValue(TitleProperty, value); - } - - -} +namespace ElectionGuard.UI.Controls; + +public partial class ExpanderControl : ContentView +{ + public ExpanderControl() + { + InitializeComponent(); + } + + public static readonly BindableProperty TitleProperty = BindableProperty.Create(nameof(Title), typeof(string), typeof(ExpanderControl)); + + public string Title + { + get => (string)GetValue(TitleProperty); + set => SetValue(TitleProperty, value); + } + + +} diff --git a/src/electionguard-ui/ElectionGuard.UI/Controls/LabelValueControl.xaml b/src/electionguard-ui/ElectionGuard.UI/Controls/LabelValueControl.xaml index 0469084a8..678cb9abf 100644 --- a/src/electionguard-ui/ElectionGuard.UI/Controls/LabelValueControl.xaml +++ b/src/electionguard-ui/ElectionGuard.UI/Controls/LabelValueControl.xaml @@ -1,20 +1,20 @@ - - - - - + + + + + diff --git a/src/electionguard-ui/ElectionGuard.UI/Controls/LabelValueControl.xaml.cs b/src/electionguard-ui/ElectionGuard.UI/Controls/LabelValueControl.xaml.cs index f95642485..3a25d2c50 100644 --- a/src/electionguard-ui/ElectionGuard.UI/Controls/LabelValueControl.xaml.cs +++ b/src/electionguard-ui/ElectionGuard.UI/Controls/LabelValueControl.xaml.cs @@ -1,26 +1,26 @@ -namespace ElectionGuard.UI.Controls; - -public partial class LabelValueControl : ContentView -{ - public LabelValueControl() - { - InitializeComponent(); - } - - public static readonly BindableProperty TitleProperty = BindableProperty.Create(nameof(Title), typeof(string), typeof(LabelValueControl)); - - public string Title - { - get => (string)GetValue(TitleProperty); - set => SetValue(TitleProperty, value); - } - - public static readonly BindableProperty TextProperty = BindableProperty.Create(nameof(Text), typeof(string), typeof(LabelValueControl), string.Empty); - - public string Text - { - get => (string)GetValue(TextProperty); - set => SetValue(TextProperty, value); - } - -} +namespace ElectionGuard.UI.Controls; + +public partial class LabelValueControl : ContentView +{ + public LabelValueControl() + { + InitializeComponent(); + } + + public static readonly BindableProperty TitleProperty = BindableProperty.Create(nameof(Title), typeof(string), typeof(LabelValueControl)); + + public string Title + { + get => (string)GetValue(TitleProperty); + set => SetValue(TitleProperty, value); + } + + public static readonly BindableProperty TextProperty = BindableProperty.Create(nameof(Text), typeof(string), typeof(LabelValueControl), string.Empty); + + public string Text + { + get => (string)GetValue(TextProperty); + set => SetValue(TextProperty, value); + } + +} diff --git a/src/electionguard-ui/ElectionGuard.UI/Controls/UploadsControl.xaml b/src/electionguard-ui/ElectionGuard.UI/Controls/UploadsControl.xaml index 69d4de551..af285eba1 100644 --- a/src/electionguard-ui/ElectionGuard.UI/Controls/UploadsControl.xaml +++ b/src/electionguard-ui/ElectionGuard.UI/Controls/UploadsControl.xaml @@ -1,118 +1,118 @@ - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/electionguard-ui/ElectionGuard.UI/Controls/UploadsControl.xaml.cs b/src/electionguard-ui/ElectionGuard.UI/Controls/UploadsControl.xaml.cs index 1f981f294..566482795 100644 --- a/src/electionguard-ui/ElectionGuard.UI/Controls/UploadsControl.xaml.cs +++ b/src/electionguard-ui/ElectionGuard.UI/Controls/UploadsControl.xaml.cs @@ -1,9 +1,9 @@ -namespace ElectionGuard.UI.Controls; - -public partial class UploadsControl : ContentView -{ - public UploadsControl() - { - InitializeComponent(); - } +namespace ElectionGuard.UI.Controls; + +public partial class UploadsControl : ContentView +{ + public UploadsControl() + { + InitializeComponent(); + } } \ No newline at end of file diff --git a/src/electionguard-ui/ElectionGuard.UI/ElectionGuard.UI.csproj b/src/electionguard-ui/ElectionGuard.UI/ElectionGuard.UI.csproj index ba006981e..5a6501207 100644 --- a/src/electionguard-ui/ElectionGuard.UI/ElectionGuard.UI.csproj +++ b/src/electionguard-ui/ElectionGuard.UI/ElectionGuard.UI.csproj @@ -1,266 +1,244 @@ - - - - net7.0-maccatalyst - net7.0-windows10.0.19041.0 - Exe - true - true - true - enable - - ElectionGuard.UI - en-us - ElectionGuard Election Manager - - - com.microsoft.electionguard.ui - c0679a79-bc22-46ad-9c49-93de983e3fa2 - - - 1.92.0 - 19 - - 15.3 - 10.0.19041.0 - 10.0.19041.0 - enable - true - PackageReference - - arm64;x64 - AnyCPU - efb177b9-29c3-4df1-adaa-be7e64bdc8ce - - - - $(DefineConstants);APPCENTER_SECRET_MACOS=$(APPCENTER_SECRET_MACOS);APPCENTER_SECRET_UWP=$(APPCENTER_SECRET_UWP) - - - - - false - maccatalyst-arm64;maccatalyst-x64 - - - - true - maccatalyst-arm64;maccatalyst-x64 - - - - false - maccatalyst-x64 - - - - false - maccatalyst-x64 - - - - false - - - - true - - - - - - - - - - - - true - false - - true - - - false - false - - - - - Default - - - - enable - - - - - - - - - - - true - false - - true - - - false - false - - - - - Default - - anycpu - - enable - - - - - - - - - - - - - - - - - - MSBuild:Compile - - - - - - - - - - - - - - - - - - - - - - - - - - ContestControl.xaml - - - True - True - AppResources.resx - - - NetworkPopup.xaml - - - CreateElectionAdminPage.xaml - - - ChallengedPopup.xaml - - - TallyProcessPage.xaml - - - ViewKeyCeremonyPage.xaml - - - - - - - - - ResXFileCodeGenerator - AppResources.Designer.cs - - - - - - - - - - MSBuild:Compile - - - MSBuild:Compile - - - MSBuild:Compile - - - MSBuild:Compile - - - - ..\..\..\data - ..\..\..\build\libs - ..\..\..\scripts - - - $(DefineConstants);DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION - portable - - - $(DefineConstants);DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION - portable - - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - - PreserveNewest - - - PreserveNewest - - - - - - - + + + + + net9.0-windows10.0.19041.0 + Exe + true + true + true + enable + + ElectionGuard.UI + en-us + ElectionGuard Election Manager + + + com.microsoft.electionguard.ui + c0679a79-bc22-46ad-9c49-93de983e3fa2 + + + 1.92.0 + 19 + + 10.0.19041.0 + 10.0.19041.0 + enable + true + PackageReference + + AnyCPU + efb177b9-29c3-4df1-adaa-be7e64bdc8ce + + + + $(DefineConstants);APPCENTER_SECRET_MACOS=$(APPCENTER_SECRET_MACOS);APPCENTER_SECRET_UWP=$(APPCENTER_SECRET_UWP) + + + + false + + + + true + + + + + + + False + + + + + true + false + + true + + + false + false + + + + + Default + + + + enable + + + + + + False + + + + + true + false + + true + + + false + false + + + + + Default + + anycpu + + enable + + + + + + + + + + + + + + + + + + MSBuild:Compile + + + + + + + + + + + + + + + + + + + + + + + + + + + ContestControl.xaml + + + True + True + AppResources.resx + + + NetworkPopup.xaml + + + CreateElectionAdminPage.xaml + + + ChallengedPopup.xaml + + + TallyProcessPage.xaml + + + ViewKeyCeremonyPage.xaml + + + + + + + + + ResXFileCodeGenerator + AppResources.Designer.cs + + + + + + + + + + MSBuild:Compile + + + MSBuild:Compile + + + MSBuild:Compile + + + MSBuild:Compile + + + + ..\..\..\data + ..\..\..\build\libs + ..\..\..\scripts + + + $(DefineConstants);DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION + portable + + + $(DefineConstants);DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION + portable + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + PreserveNewest + + + PreserveNewest + + + + + + + diff --git a/src/electionguard-ui/ElectionGuard.UI/Helpers/ErrorLog.cs b/src/electionguard-ui/ElectionGuard.UI/Helpers/ErrorLog.cs index afb61963f..b47969c43 100644 --- a/src/electionguard-ui/ElectionGuard.UI/Helpers/ErrorLog.cs +++ b/src/electionguard-ui/ElectionGuard.UI/Helpers/ErrorLog.cs @@ -1,51 +1,51 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Microsoft.Maui.Storage; - -namespace ElectionGuard.UI.Helpers -{ - static class ErrorLog - { - private static string ElectionGuardPath = "electionguard"; - private static string LogPath = "logs"; - private static string LogCrashedFile = "crashed.txt"; - - public static string CreateLogPath() - { - var folder = Path.Combine(FileSystem.Current.AppDataDirectory, ElectionGuardPath, LogPath); - _ = Directory.CreateDirectory(folder); - return folder; - } - - /// - /// Create an empty file when the app crashes. - /// - public static void CreateCrashedFile() - { - var folder = CreateLogPath(); - File.AppendAllText(Path.Combine(folder, LogCrashedFile), " "); - } - - /// - /// Remove the file used to determine a crash - /// - public static void DeleteCrashedFile() - { - var folder = CreateLogPath(); - File.Delete(Path.Combine(folder, LogCrashedFile)); - } - - /// - /// Indicator if the application crashed the last time it was run - /// - /// Last run caused the app to crash - public static bool AppPreviousCrashed() - { - var folder = CreateLogPath(); - return File.Exists(Path.Combine(folder, LogCrashedFile)); - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Maui.Storage; + +namespace ElectionGuard.UI.Helpers +{ + static class ErrorLog + { + private static string ElectionGuardPath = "electionguard"; + private static string LogPath = "logs"; + private static string LogCrashedFile = "crashed.txt"; + + public static string CreateLogPath() + { + var folder = Path.Combine(FileSystem.Current.AppDataDirectory, ElectionGuardPath, LogPath); + _ = Directory.CreateDirectory(folder); + return folder; + } + + /// + /// Create an empty file when the app crashes. + /// + public static void CreateCrashedFile() + { + var folder = CreateLogPath(); + File.AppendAllText(Path.Combine(folder, LogCrashedFile), " "); + } + + /// + /// Remove the file used to determine a crash + /// + public static void DeleteCrashedFile() + { + var folder = CreateLogPath(); + File.Delete(Path.Combine(folder, LogCrashedFile)); + } + + /// + /// Indicator if the application crashed the last time it was run + /// + /// Last run caused the app to crash + public static bool AppPreviousCrashed() + { + var folder = CreateLogPath(); + return File.Exists(Path.Combine(folder, LogCrashedFile)); + } + } +} diff --git a/src/electionguard-ui/ElectionGuard.UI.Lib/Extensions/ServiceProviderExtension.cs b/src/electionguard-ui/ElectionGuard.UI/Helpers/ServiceProviderExtension.cs similarity index 88% rename from src/electionguard-ui/ElectionGuard.UI.Lib/Extensions/ServiceProviderExtension.cs rename to src/electionguard-ui/ElectionGuard.UI/Helpers/ServiceProviderExtension.cs index d5a5e01b2..4d6e16f9f 100644 --- a/src/electionguard-ui/ElectionGuard.UI.Lib/Extensions/ServiceProviderExtension.cs +++ b/src/electionguard-ui/ElectionGuard.UI/Helpers/ServiceProviderExtension.cs @@ -1,4 +1,4 @@ -namespace ElectionGuard.UI.Lib.Extensions; +namespace ElectionGuard.UI.Helpers; public static class ServiceProviderExtension { diff --git a/src/electionguard-ui/ElectionGuard.UI/MauiProgram.cs b/src/electionguard-ui/ElectionGuard.UI/MauiProgram.cs index d8345961a..7f71afd27 100644 --- a/src/electionguard-ui/ElectionGuard.UI/MauiProgram.cs +++ b/src/electionguard-ui/ElectionGuard.UI/MauiProgram.cs @@ -1,144 +1,144 @@ -using CommunityToolkit.Maui; -using ElectionGuard.Decryption; -using ElectionGuard.UI.Services; -using Microsoft.AppCenter; -using Microsoft.AppCenter.Crashes; -using Microsoft.AppCenter.Analytics; -using MetroLog.MicrosoftExtensions; -using System.Reflection; - -namespace ElectionGuard.UI; - -public static class MauiProgram -{ - public static MauiApp CreateMauiApp() - { - - if (!string.IsNullOrEmpty(DbContext.DbConnection)) - { - DbService.Init(DbContext.DbConnection); - } - else - { - DbService.Init(DbContext.DbHost, DbContext.DbPassword); - } - - var builder = MauiApp.CreateBuilder(); - builder - .UseMauiApp() - .UseMauiCommunityToolkit() - .SetupFonts() - .SetupServices() - .SetupLogging() - .ConfigureEssentials(essentials => - { - essentials.UseVersionTracking(); - }); - - - return builder.Build(); - } - - public static MauiAppBuilder SetupLogging(this MauiAppBuilder builder) - { -#if DEBUG - builder.Logging.AddDebug(); - //builder.Logging.add(); -#endif - builder.Logging.AddStreamingFileLogger(configure => - { - configure.FolderPath = ErrorLog.CreateLogPath(); - }); - return builder; - } - - - public static MauiAppBuilder SetupFonts(this MauiAppBuilder builder) - { - builder.ConfigureFonts(fonts => - { - fonts.AddFont("opensans_regular.ttf", "OpenSansRegular"); - fonts.AddFont("opensans_semibold.ttf", "OpenSansSemibold"); - }); - - return builder; - } - - public static MauiAppBuilder SetupServices(this MauiAppBuilder builder) - { - // setup services - builder.Services.AddSingleton(new EgServiceProvider()); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - // LocalizationService has to be singleton because it uses events to propagate changes to language changed - builder.Services.AddSingleton(); - // NavigationService has to be singleton because it stores the current page and vm - builder.Services.AddSingleton(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - - // setup database services - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - - // setup view models - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddSingleton(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddSingleton(); - builder.Services.AddSingleton(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - - // setup views - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - - // popup pages - builder.Services.AddTransient(); - - return builder; - } -} +using CommunityToolkit.Maui; +using ElectionGuard.Decryption; +using ElectionGuard.UI.Services; +using Microsoft.AppCenter; +using Microsoft.AppCenter.Crashes; +using Microsoft.AppCenter.Analytics; +using MetroLog.MicrosoftExtensions; +using System.Reflection; + +namespace ElectionGuard.UI; + +public static class MauiProgram +{ + public static MauiApp CreateMauiApp() + { + + if (!string.IsNullOrEmpty(DbContext.DbConnection)) + { + DbService.Init(DbContext.DbConnection); + } + else + { + DbService.Init(DbContext.DbHost, DbContext.DbPassword); + } + + var builder = MauiApp.CreateBuilder(); + builder + .UseMauiApp() + .UseMauiCommunityToolkit() + .SetupFonts() + .SetupServices() + .SetupLogging() + .ConfigureEssentials(essentials => + { + essentials.UseVersionTracking(); + }); + + + return builder.Build(); + } + + public static MauiAppBuilder SetupLogging(this MauiAppBuilder builder) + { +#if DEBUG + builder.Logging.AddDebug(); + //builder.Logging.add(); +#endif + builder.Logging.AddStreamingFileLogger(configure => + { + configure.FolderPath = ErrorLog.CreateLogPath(); + }); + return builder; + } + + + public static MauiAppBuilder SetupFonts(this MauiAppBuilder builder) + { + builder.ConfigureFonts(fonts => + { + fonts.AddFont("opensans_regular.ttf", "OpenSansRegular"); + fonts.AddFont("opensans_semibold.ttf", "OpenSansSemibold"); + }); + + return builder; + } + + public static MauiAppBuilder SetupServices(this MauiAppBuilder builder) + { + // setup services + builder.Services.AddSingleton(new EgServiceProvider()); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + // LocalizationService has to be singleton because it uses events to propagate changes to language changed + builder.Services.AddSingleton(); + // NavigationService has to be singleton because it stores the current page and vm + builder.Services.AddSingleton(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + + // setup database services + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + + // setup view models + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddSingleton(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddSingleton(); + builder.Services.AddSingleton(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + + // setup views + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + + // popup pages + builder.Services.AddTransient(); + + return builder; + } +} diff --git a/src/electionguard-ui/ElectionGuard.UI/Models/GuardianItem.cs b/src/electionguard-ui/ElectionGuard.UI/Models/GuardianItem.cs index ccdf8901b..7f4367be8 100644 --- a/src/electionguard-ui/ElectionGuard.UI/Models/GuardianItem.cs +++ b/src/electionguard-ui/ElectionGuard.UI/Models/GuardianItem.cs @@ -1,7 +1,7 @@ -namespace ElectionGuard.UI.Models; - -public partial class GuardianItem : ObservableObject -{ +namespace ElectionGuard.UI.Models; + +public partial class GuardianItem : ObservableObject +{ [ObservableProperty] private string _name; diff --git a/src/electionguard-ui/ElectionGuard.UI/Models/GuardianTallyItem.cs b/src/electionguard-ui/ElectionGuard.UI/Models/GuardianTallyItem.cs index 759d867e3..d6112efd5 100644 --- a/src/electionguard-ui/ElectionGuard.UI/Models/GuardianTallyItem.cs +++ b/src/electionguard-ui/ElectionGuard.UI/Models/GuardianTallyItem.cs @@ -1,9 +1,9 @@ -using System.ComponentModel.DataAnnotations; - -namespace ElectionGuard.UI.Models; - -public partial class GuardianTallyItem : ObservableObject, IEquatable -{ +using System.ComponentModel.DataAnnotations; + +namespace ElectionGuard.UI.Models; + +public partial class GuardianTallyItem : ObservableObject, IEquatable +{ [ObservableProperty] private string _name = string.Empty; @@ -14,16 +14,16 @@ public partial class GuardianTallyItem : ObservableObject, IEquatable= _quorum; - State = tally.State; + QuorumReached = _guardiansJoined >= _quorum; + State = tally.State; SubtaliesCombined = State >= TallyState.PendingGuardianDecryptShares; - AllDecryptionSharesComputed = SubtaliesCombined && + AllDecryptionSharesComputed = SubtaliesCombined && (State > TallyState.PendingGuardianDecryptShares || (State == TallyState.PendingGuardianDecryptShares && _sharesComputed >= _quorum)); - ChallengeCreated = AllDecryptionSharesComputed && State >= TallyState.PendingGuardianRespondChallenge; - AllChallengesResponded = ChallengeCreated && + ChallengeCreated = AllDecryptionSharesComputed && State >= TallyState.PendingGuardianRespondChallenge; + AllChallengesResponded = ChallengeCreated && (State > TallyState.PendingGuardianRespondChallenge || - (State == TallyState.PendingGuardianRespondChallenge && _challengesResponded == _quorum)); - TallyComplete = State == TallyState.Complete; + (State == TallyState.PendingGuardianRespondChallenge && _challengesResponded == _quorum)); + TallyComplete = State == TallyState.Complete; TallyStarted = State >= TallyState.TallyStarted; - IsAbandoned = State == TallyState.Abandoned; + IsAbandoned = State == TallyState.Abandoned; } } diff --git a/src/electionguard-ui/ElectionGuard.UI/Properties/launchSettings.json b/src/electionguard-ui/ElectionGuard.UI/Properties/launchSettings.json index c16206a81..edf8aadcc 100644 --- a/src/electionguard-ui/ElectionGuard.UI/Properties/launchSettings.json +++ b/src/electionguard-ui/ElectionGuard.UI/Properties/launchSettings.json @@ -1,8 +1,8 @@ -{ - "profiles": { - "Windows Machine": { - "commandName": "MsixPackage", - "nativeDebugging": false - } - } +{ + "profiles": { + "Windows Machine": { + "commandName": "MsixPackage", + "nativeDebugging": false + } + } } \ No newline at end of file diff --git a/src/electionguard-ui/ElectionGuard.UI/Resources/Styles/Colors.xaml b/src/electionguard-ui/ElectionGuard.UI/Resources/Styles/Colors.xaml index 80e1d76fc..f320d8f07 100644 --- a/src/electionguard-ui/ElectionGuard.UI/Resources/Styles/Colors.xaml +++ b/src/electionguard-ui/ElectionGuard.UI/Resources/Styles/Colors.xaml @@ -1,49 +1,49 @@ - - - - - #409388 - #DFD8F7 - #2B0B98 - White - Black - #E1E1E1 - #C8C8C8 - #ACACAC - #919191 - #6E6E6E - #404040 - #212121 - #141414 - - - - - - - - - - - - - - - #F7B548 - #FFD590 - #FFE5B9 - #28C2D1 - #7BDDEF - #C3F2F4 - #3E8EED - #72ACF1 - #A7CBF6 - - #409388 - #70cab8 - #3E8EED - #F8F9FA - #555555 - - + + + + + #409388 + #DFD8F7 + #2B0B98 + White + Black + #E1E1E1 + #C8C8C8 + #ACACAC + #919191 + #6E6E6E + #404040 + #212121 + #141414 + + + + + + + + + + + + + + + #F7B548 + #FFD590 + #FFE5B9 + #28C2D1 + #7BDDEF + #C3F2F4 + #3E8EED + #72ACF1 + #A7CBF6 + + #409388 + #70cab8 + #3E8EED + #F8F9FA + #555555 + + \ No newline at end of file diff --git a/src/electionguard-ui/ElectionGuard.UI/Resources/Styles/EgStyles.xaml b/src/electionguard-ui/ElectionGuard.UI/Resources/Styles/EgStyles.xaml index 568f17c11..39452949b 100644 --- a/src/electionguard-ui/ElectionGuard.UI/Resources/Styles/EgStyles.xaml +++ b/src/electionguard-ui/ElectionGuard.UI/Resources/Styles/EgStyles.xaml @@ -1,258 +1,258 @@ - - - - - 16 - 600 - 750 - 850 - #F0F0F0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + 16 + 600 + 750 + 850 + #F0F0F0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/electionguard-ui/ElectionGuard.UI/Resources/Styles/Styles.xaml b/src/electionguard-ui/ElectionGuard.UI/Resources/Styles/Styles.xaml index 9e97d276b..94257d583 100644 --- a/src/electionguard-ui/ElectionGuard.UI/Resources/Styles/Styles.xaml +++ b/src/electionguard-ui/ElectionGuard.UI/Resources/Styles/Styles.xaml @@ -1,413 +1,413 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/electionguard-ui/ElectionGuard.UI/Resx/AppResources.Designer.cs b/src/electionguard-ui/ElectionGuard.UI/Resx/AppResources.Designer.cs index 1367534e0..fd40604a5 100644 --- a/src/electionguard-ui/ElectionGuard.UI/Resx/AppResources.Designer.cs +++ b/src/electionguard-ui/ElectionGuard.UI/Resx/AppResources.Designer.cs @@ -1,1656 +1,1656 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace ElectionGuard.UI.Resx { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class AppResources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal AppResources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ElectionGuard.UI.Resx.AppResources", typeof(AppResources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to Tally has been canceled by election administrator. See administrator for addional details.. - /// - internal static string AbandonTallyText { - get { - return ResourceManager.GetString("AbandonTallyText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Tally Canceled. - /// - internal static string AbandonTallyTitle { - get { - return ResourceManager.GetString("AbandonTallyTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Add Ballots. - /// - internal static string AddBallots { - get { - return ResourceManager.GetString("AddBallots", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Added. - /// - internal static string AddedText { - get { - return ResourceManager.GetString("AddedText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Admin Home. - /// - internal static string AdminHome { - get { - return ResourceManager.GetString("AdminHome", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to What Do You Want To Do?. - /// - internal static string AdminHomePageTitle { - get { - return ResourceManager.GetString("AdminHomePageTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to already exists. Try a different name.. - /// - internal static string AlreadyExists { - get { - return ResourceManager.GetString("AlreadyExists", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Backup. - /// - internal static string BackupText { - get { - return ResourceManager.GetString("BackupText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Bad Verification. - /// - internal static string BadVerified { - get { - return ResourceManager.GetString("BadVerified", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Count. - /// - internal static string BallotCountText { - get { - return ResourceManager.GetString("BallotCountText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Ballot Folder. - /// - internal static string BallotFolderText { - get { - return ResourceManager.GetString("BallotFolderText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Ballots. - /// - internal static string BallotsText { - get { - return ResourceManager.GetString("BallotsText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Ballot Styles. - /// - internal static string BallotStylesText { - get { - return ResourceManager.GetString("BallotStylesText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Ballot Upload. - /// - internal static string BallotUploadText { - get { - return ResourceManager.GetString("BallotUploadText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Cancel. - /// - internal static string CancelText { - get { - return ResourceManager.GetString("CancelText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Candidates. - /// - internal static string CandidatesText { - get { - return ResourceManager.GetString("CandidatesText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Enter the verification code in the search box to limit the ballots shown. Select that ballot from the list to be set to a spoiled ballot.. - /// - internal static string ChallengedInstructionsText { - get { - return ResourceManager.GetString("ChallengedInstructionsText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Challenge. - /// - internal static string ChallengedText { - get { - return ResourceManager.GetString("ChallengedText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Choice. - /// - internal static string ChoiceText { - get { - return ResourceManager.GetString("ChoiceText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Choose File. - /// - internal static string ChooseFile { - get { - return ResourceManager.GetString("ChooseFile", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Choose File(s). - /// - internal static string ChooseFiles { - get { - return ResourceManager.GetString("ChooseFiles", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Choose Folder. - /// - internal static string ChooseFolder { - get { - return ResourceManager.GetString("ChooseFolder", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Close. - /// - internal static string CloseText { - get { - return ResourceManager.GetString("CloseText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Complete. - /// - internal static string Complete { - get { - return ResourceManager.GetString("Complete", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Connection string to get to database. - /// - internal static string ConnectionStringPlaceholder { - get { - return ResourceManager.GetString("ConnectionStringPlaceholder", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Connection String. - /// - internal static string ConnectionStringText { - get { - return ResourceManager.GetString("ConnectionStringText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Contact the election administrator!. - /// - internal static string ContactAdmin { - get { - return ResourceManager.GetString("ContactAdmin", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Contests. - /// - internal static string ContestsText { - get { - return ResourceManager.GetString("ContestsText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Created By. - /// - internal static string CreatedByText { - get { - return ResourceManager.GetString("CreatedByText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Created. - /// - internal static string CreatedText { - get { - return ResourceManager.GetString("CreatedText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Create Election. - /// - internal static string CreateElection { - get { - return ResourceManager.GetString("CreateElection", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Create Key Ceremony. - /// - internal static string CreateKeyCeremony { - get { - return ResourceManager.GetString("CreateKeyCeremony", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Select the elections to make tallies. - /// - internal static string CreateMultiInstructionsText { - get { - return ResourceManager.GetString("CreateMultiInstructionsText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Create Multiple Tallies. - /// - internal static string CreateMultipleTalliesText { - get { - return ResourceManager.GetString("CreateMultipleTalliesText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Create Multiple Tallies. - /// - internal static string CreateMultiTally { - get { - return ResourceManager.GetString("CreateMultiTally", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to There are no Key Ceremonies that are used for multi-tallies. - /// - internal static string CreateMultiTallyError { - get { - return ResourceManager.GetString("CreateMultiTallyError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Create Tallies. - /// - internal static string CreateTallies { - get { - return ResourceManager.GetString("CreateTallies", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Create Tally. - /// - internal static string CreateTally { - get { - return ResourceManager.GetString("CreateTally", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Custom Range for Ballot Selection. - /// - internal static string CustomRangeText { - get { - return ResourceManager.GetString("CustomRangeText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Database IP Address. - /// - internal static string DatabaseAddress { - get { - return ResourceManager.GetString("DatabaseAddress", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Unable to login. Please check your database settings.. - /// - internal static string DatabaseLoginError { - get { - return ResourceManager.GetString("DatabaseLoginError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Database Password. - /// - internal static string DatabasePassword { - get { - return ResourceManager.GetString("DatabasePassword", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Database is not available. Please check your settings.. - /// - internal static string DatabaseUnavailable { - get { - return ResourceManager.GetString("DatabaseUnavailable", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Dates. - /// - internal static string DatesText { - get { - return ResourceManager.GetString("DatesText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Partial Decryption Complete. - /// - internal static string DecryptionComplete { - get { - return ResourceManager.GetString("DecryptionComplete", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Device File. - /// - internal static string DeviceFileText { - get { - return ResourceManager.GetString("DeviceFileText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Devices. - /// - internal static string DevicesText { - get { - return ResourceManager.GetString("DevicesText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Does Not Exist. - /// - internal static string DoesNotExist { - get { - return ResourceManager.GetString("DoesNotExist", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to EGDrive already used. - /// - internal static string DriveUsedText { - get { - return ResourceManager.GetString("DriveUsedText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Duplicated. - /// - internal static string DuplicatedText { - get { - return ResourceManager.GetString("DuplicatedText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Election Checklist. - /// - internal static string ElectionChecklist { - get { - return ResourceManager.GetString("ElectionChecklist", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Election Details. - /// - internal static string ElectionDetails { - get { - return ResourceManager.GetString("ElectionDetails", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to ElectionGuard. - /// - internal static string ElectionGuardTitle { - get { - return ResourceManager.GetString("ElectionGuardTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Election Name. - /// - internal static string ElectionNameText { - get { - return ResourceManager.GetString("ElectionNameText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Election Record Export Path. - /// - internal static string ElectionRecordPathText { - get { - return ResourceManager.GetString("ElectionRecordPathText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to elections created.. - /// - internal static string ElectionsCreated { - get { - return ResourceManager.GetString("ElectionsCreated", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Elections. - /// - internal static string ElectionsText { - get { - return ResourceManager.GetString("ElectionsText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Election URL. - /// - internal static string ElectionUrl { - get { - return ResourceManager.GetString("ElectionUrl", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Error Creating election. - /// - internal static string ErrorCreatingElection { - get { - return ResourceManager.GetString("ErrorCreatingElection", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Unable to load guardian data.. - /// - internal static string ErrorLoadingGuardian { - get { - return ResourceManager.GetString("ErrorLoadingGuardian", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The manifest file could not be loaded.. - /// - internal static string ErrorLoadingManifest { - get { - return ResourceManager.GetString("ErrorLoadingManifest", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to View Error Logs. - /// - internal static string ErrorLogs { - get { - return ResourceManager.GetString("ErrorLogs", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Error in manifest files. - /// - internal static string ErrorManifest { - get { - return ResourceManager.GetString("ErrorManifest", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Please ensure the EGDrive removable storage is connected to the device. Please note, this will replace any encryption package currently on all EGDrive devices. - /// - internal static string ExportDriveWarning { - get { - return ResourceManager.GetString("ExportDriveWarning", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Export Encryption Package. - /// - internal static string ExportDriveWarningTitle { - get { - return ResourceManager.GetString("ExportDriveWarningTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Export Encryption. - /// - internal static string ExportEncryptionText { - get { - return ResourceManager.GetString("ExportEncryptionText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Export Election Record. - /// - internal static string ExportTally { - get { - return ResourceManager.GetString("ExportTally", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Geopolitical Units. - /// - internal static string GeopoliticalUnitsText { - get { - return ResourceManager.GetString("GeopoliticalUnitsText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Create Key Ceremony. - /// - internal static string GoToCreateKeyCeremonyAdmin { - get { - return ResourceManager.GetString("GoToCreateKeyCeremonyAdmin", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Guardian Home. - /// - internal static string GuardianHome { - get { - return ResourceManager.GetString("GuardianHome", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Guardians. - /// - internal static string GuardiansText { - get { - return ResourceManager.GetString("GuardiansText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Hello, World!. - /// - internal static string HelloWorld { - get { - return ResourceManager.GetString("HelloWorld", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Would you like to import from this EGDrive again?. - /// - internal static string ImportAgainText { - get { - return ResourceManager.GetString("ImportAgainText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Information. - /// - internal static string InformationText { - get { - return ResourceManager.GetString("InformationText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Insert an EGDrive (USB drive) containing ballots. - /// - internal static string InsertUsbText { - get { - return ResourceManager.GetString("InsertUsbText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to IP address of the database. - /// - internal static string IPAddressPlaceholder { - get { - return ResourceManager.GetString("IPAddressPlaceholder", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Join. - /// - internal static string Join { - get { - return ResourceManager.GetString("Join", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Joined Guardians. - /// - internal static string JoinedGuardians { - get { - return ResourceManager.GetString("JoinedGuardians", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Joined. - /// - internal static string JoinedText { - get { - return ResourceManager.GetString("JoinedText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Select the tallies to join. - /// - internal static string JoinMultiInstructionsText { - get { - return ResourceManager.GetString("JoinMultiInstructionsText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Join Tallies. - /// - internal static string JoinTallies { - get { - return ResourceManager.GetString("JoinTallies", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Key Ceremonies. - /// - internal static string KeyCeremoniesText { - get { - return ResourceManager.GetString("KeyCeremoniesText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Key Ceremony Name. - /// - internal static string KeyCeremonyName { - get { - return ResourceManager.GetString("KeyCeremonyName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Key Ceremony State. - /// - internal static string KeyCeremonyState { - get { - return ResourceManager.GetString("KeyCeremonyState", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Key Ceremony. - /// - internal static string KeyCeremonyText { - get { - return ResourceManager.GetString("KeyCeremonyText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Location. - /// - internal static string LocationText { - get { - return ResourceManager.GetString("LocationText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Enter your name or other identifier. - /// - internal static string LoginPlaceholder { - get { - return ResourceManager.GetString("LoginPlaceholder", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Login. - /// - internal static string LoginText { - get { - return ResourceManager.GetString("LoginText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Manifest. - /// - internal static string ManifestText { - get { - return ResourceManager.GetString("ManifestText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Cancel wizard and manually upload ballots. - /// - internal static string ManuelUploadText { - get { - return ResourceManager.GetString("ManuelUploadText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to MultiTally Name. - /// - internal static string MultiTallyNameText { - get { - return ResourceManager.GetString("MultiTallyNameText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Names will be generated from manifest names. - /// - internal static string NameFromManifest { - get { - return ResourceManager.GetString("NameFromManifest", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Name. - /// - internal static string NameText { - get { - return ResourceManager.GetString("NameText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to There was an issue with the network that caused an issue with what you were doing. Please log back in when the network connection has been restored. - /// - internal static string NetworkIssueText { - get { - return ResourceManager.GetString("NetworkIssueText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to No Ballots Uploaded. - /// - internal static string NoBallotUploads { - get { - return ResourceManager.GetString("NoBallotUploads", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to No elections found. - /// - internal static string NoElections { - get { - return ResourceManager.GetString("NoElections", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to No file chosen. - /// - internal static string NoFileText { - get { - return ResourceManager.GetString("NoFileText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to No folder chosen. - /// - internal static string NoFolderText { - get { - return ResourceManager.GetString("NoFolderText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to No guardians joined. - /// - internal static string NoGuardians { - get { - return ResourceManager.GetString("NoGuardians", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to No key ceremonies found. - /// - internal static string NoKeyCeremonies { - get { - return ResourceManager.GetString("NoKeyCeremonies", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to No tallies found. - /// - internal static string NoTallies { - get { - return ResourceManager.GetString("NoTallies", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to No Tallies Created. - /// - internal static string NoTalliesCreated { - get { - return ResourceManager.GetString("NoTalliesCreated", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to No. - /// - internal static string NoText { - get { - return ResourceManager.GetString("NoText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Number of Guardians. - /// - internal static string NumberOfGuardians { - get { - return ResourceManager.GetString("NumberOfGuardians", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Ok. - /// - internal static string OkText { - get { - return ResourceManager.GetString("OkText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Parties. - /// - internal static string PartiesText { - get { - return ResourceManager.GetString("PartiesText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Party. - /// - internal static string PartyText { - get { - return ResourceManager.GetString("PartyText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Password to use for the database. - /// - internal static string PasswordDefaultPlaceholder { - get { - return ResourceManager.GetString("PasswordDefaultPlaceholder", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Waiting for Admin to Announce the Guardians. - /// - internal static string PendingAdminAnnounce { - get { - return ResourceManager.GetString("PendingAdminAnnounce", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Waiting for Admin to Create and Publish the Joint Key. - /// - internal static string PendingAdminToPublishJointKey { - get { - return ResourceManager.GetString("PendingAdminToPublishJointKey", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Waiting for Admin to Share the Election Key Backups. - /// - internal static string PendingAdminToShareBackups { - get { - return ResourceManager.GetString("PendingAdminToShareBackups", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Waiting for the Guardians to Backup Election Keys. - /// - internal static string PendingGuardianBackups { - get { - return ResourceManager.GetString("PendingGuardianBackups", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Waiting for Guardians to Join. - /// - internal static string PendingGuardianJoin { - get { - return ResourceManager.GetString("PendingGuardianJoin", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Waiting for Guardians to Verify the Backups. - /// - internal static string PendingGuardiansVerifyBackups { - get { - return ResourceManager.GetString("PendingGuardiansVerifyBackups", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to %. - /// - internal static string PercentText { - get { - return ResourceManager.GetString("PercentText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Error Detected. - /// - internal static string PreviousCrash { - get { - return ResourceManager.GetString("PreviousCrash", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Cancel Tally. - /// - internal static string ProcessTallyAbandon { - get { - return ResourceManager.GetString("ProcessTallyAbandon", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to No, Do not Join Tally. - /// - internal static string ProcessTallyJoinNo { - get { - return ResourceManager.GetString("ProcessTallyJoinNo", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Yes, Join Tally. - /// - internal static string ProcessTallyJoinYes { - get { - return ResourceManager.GetString("ProcessTallyJoinYes", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Start Tally. - /// - internal static string ProcessTallyStartTally { - get { - return ResourceManager.GetString("ProcessTallyStartTally", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Quorum. - /// - internal static string Quorum { - get { - return ResourceManager.GetString("Quorum", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Quorum. - /// - internal static string QuorumText { - get { - return ResourceManager.GetString("QuorumText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Rejected. - /// - internal static string RejectedText { - get { - return ResourceManager.GetString("RejectedText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Removing files from the list. - /// - internal static string RemovingList { - get { - return ResourceManager.GetString("RemovingList", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Guardian has responded to Admin Challenge. - /// - internal static string ResponseComplete { - get { - return ResourceManager.GetString("ResponseComplete", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Results. - /// - internal static string ResultsText { - get { - return ResourceManager.GetString("ResultsText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Review Challenge. - /// - internal static string ReviewSpoiledText { - get { - return ResourceManager.GetString("ReviewSpoiledText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Save. - /// - internal static string Save { - get { - return ResourceManager.GetString("Save", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Select All Elections. - /// - internal static string SelectAllElectionsText { - get { - return ResourceManager.GetString("SelectAllElectionsText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Selection one or more manifest files. - /// - internal static string SelectManifest { - get { - return ResourceManager.GetString("SelectManifest", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Settings. - /// - internal static string Settings { - get { - return ResourceManager.GetString("Settings", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move Challenged to Spoiled. - /// - internal static string SpoilBallotText { - get { - return ResourceManager.GetString("SpoilBallotText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Spoil Ballots. - /// - internal static string SpoilChallengedText { - get { - return ResourceManager.GetString("SpoilChallengedText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Are you sure that you would like to move this ballot into a Spoiled state? This will remove it from the election record.. - /// - internal static string SpoilConfirmationText { - get { - return ResourceManager.GetString("SpoilConfirmationText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Spoiled. - /// - internal static string SpoiledText { - get { - return ResourceManager.GetString("SpoiledText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Start Ceremony. - /// - internal static string StartCeremony { - get { - return ResourceManager.GetString("StartCeremony", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Status. - /// - internal static string Status { - get { - return ResourceManager.GetString("Status", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Export the encryption package. - /// - internal static string Step1Text { - get { - return ResourceManager.GetString("Step1Text", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Upload ballots using EGDrive (1 or more). - /// - internal static string Step2Text { - get { - return ResourceManager.GetString("Step2Text", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Review Challenge Ballots (if needed). - /// - internal static string Step3Text { - get { - return ResourceManager.GetString("Step3Text", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Perform a tally with the guardians (1 or more). - /// - internal static string Step4Text { - get { - return ResourceManager.GetString("Step4Text", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to View and export a tally. - /// - internal static string Step5Text { - get { - return ResourceManager.GetString("Step5Text", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to ballots.. - /// - internal static string Success2Text { - get { - return ResourceManager.GetString("Success2Text", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Successfully uploaded. - /// - internal static string SuccessText { - get { - return ResourceManager.GetString("SuccessText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Switch Languages. - /// - internal static string SwitchLanguages { - get { - return ResourceManager.GetString("SwitchLanguages", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Tallies. - /// - internal static string TalliesText { - get { - return ResourceManager.GetString("TalliesText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to All Guardians responded to Challenge. - /// - internal static string TallyAllChallengesResponded { - get { - return ResourceManager.GetString("TallyAllChallengesResponded", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to All Guardian Shares Calculated. - /// - internal static string TallyAllDecryptionsComputed { - get { - return ResourceManager.GetString("TallyAllDecryptionsComputed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Challenge Created. - /// - internal static string TallyChallengeCreated { - get { - return ResourceManager.GetString("TallyChallengeCreated", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Tally Process. - /// - internal static string TallyChecklist { - get { - return ResourceManager.GetString("TallyChecklist", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Tally Verified and results computed. - /// - internal static string TallyComplete { - get { - return ResourceManager.GetString("TallyComplete", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Tally Name. - /// - internal static string TallyNameText { - get { - return ResourceManager.GetString("TallyNameText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Tally Process. - /// - internal static string TallyProcess { - get { - return ResourceManager.GetString("TallyProcess", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Quorum has been reached. - /// - internal static string TallyQuorumReachedText { - get { - return ResourceManager.GetString("TallyQuorumReachedText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Ballots have been tallied. - /// - internal static string TallySubtalliesCombined { - get { - return ResourceManager.GetString("TallySubtalliesCombined", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Tally. - /// - internal static string TallyText { - get { - return ResourceManager.GetString("TallyText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Total. - /// - internal static string TotalText { - get { - return ResourceManager.GetString("TotalText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Uploaded. - /// - internal static string UploadedText { - get { - return ResourceManager.GetString("UploadedText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Uploading. - /// - internal static string Uploading { - get { - return ResourceManager.GetString("Uploading", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Upload More Ballots. - /// - internal static string UploadMoreText { - get { - return ResourceManager.GetString("UploadMoreText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Upload. - /// - internal static string UploadText { - get { - return ResourceManager.GetString("UploadText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Upload Wizard. - /// - internal static string UploadWizardText { - get { - return ResourceManager.GetString("UploadWizardText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Use All Ballots For Tally. - /// - internal static string UseAllBallotsText { - get { - return ResourceManager.GetString("UseAllBallotsText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to User ID. - /// - internal static string UserID { - get { - return ResourceManager.GetString("UserID", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to User Login. - /// - internal static string UserLogin { - get { - return ResourceManager.GetString("UserLogin", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to User Setup. - /// - internal static string UserSetup { - get { - return ResourceManager.GetString("UserSetup", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Verification Code. - /// - internal static string VerificationCodeText { - get { - return ResourceManager.GetString("VerificationCodeText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Verified. - /// - internal static string Verified { - get { - return ResourceManager.GetString("Verified", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to View Key Ceremony. - /// - internal static string ViewKeyCeremony { - get { - return ResourceManager.GetString("ViewKeyCeremony", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to It appears that something went wrong. You can contine with what you were doing before this happened. Details are available in the log files in the Settings page.. - /// - internal static string ViewLogsText { - get { - return ResourceManager.GetString("ViewLogsText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to View Manifest. - /// - internal static string ViewManifest { - get { - return ResourceManager.GetString("ViewManifest", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to View Tally. - /// - internal static string ViewTally { - get { - return ResourceManager.GetString("ViewTally", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Votes. - /// - internal static string VotesText { - get { - return ResourceManager.GetString("VotesText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to ElectionGuard Election Manager. - /// - internal static string WindowTitle { - get { - return ResourceManager.GetString("WindowTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Writein Candidate. - /// - internal static string WriteinText { - get { - return ResourceManager.GetString("WriteinText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Drive contains ballots for a different election.. - /// - internal static string WrongElectionText { - get { - return ResourceManager.GetString("WrongElectionText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Yes. - /// - internal static string YesText { - get { - return ResourceManager.GetString("YesText", resourceCulture); - } - } - } -} +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace ElectionGuard.UI.Resx { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class AppResources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal AppResources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ElectionGuard.UI.Resx.AppResources", typeof(AppResources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Tally has been canceled by election administrator. See administrator for addional details.. + /// + internal static string AbandonTallyText { + get { + return ResourceManager.GetString("AbandonTallyText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Tally Canceled. + /// + internal static string AbandonTallyTitle { + get { + return ResourceManager.GetString("AbandonTallyTitle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Add Ballots. + /// + internal static string AddBallots { + get { + return ResourceManager.GetString("AddBallots", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Added. + /// + internal static string AddedText { + get { + return ResourceManager.GetString("AddedText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Admin Home. + /// + internal static string AdminHome { + get { + return ResourceManager.GetString("AdminHome", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to What Do You Want To Do?. + /// + internal static string AdminHomePageTitle { + get { + return ResourceManager.GetString("AdminHomePageTitle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to already exists. Try a different name.. + /// + internal static string AlreadyExists { + get { + return ResourceManager.GetString("AlreadyExists", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Backup. + /// + internal static string BackupText { + get { + return ResourceManager.GetString("BackupText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Bad Verification. + /// + internal static string BadVerified { + get { + return ResourceManager.GetString("BadVerified", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Count. + /// + internal static string BallotCountText { + get { + return ResourceManager.GetString("BallotCountText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Ballot Folder. + /// + internal static string BallotFolderText { + get { + return ResourceManager.GetString("BallotFolderText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Ballots. + /// + internal static string BallotsText { + get { + return ResourceManager.GetString("BallotsText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Ballot Styles. + /// + internal static string BallotStylesText { + get { + return ResourceManager.GetString("BallotStylesText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Ballot Upload. + /// + internal static string BallotUploadText { + get { + return ResourceManager.GetString("BallotUploadText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cancel. + /// + internal static string CancelText { + get { + return ResourceManager.GetString("CancelText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Candidates. + /// + internal static string CandidatesText { + get { + return ResourceManager.GetString("CandidatesText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enter the verification code in the search box to limit the ballots shown. Select that ballot from the list to be set to a spoiled ballot.. + /// + internal static string ChallengedInstructionsText { + get { + return ResourceManager.GetString("ChallengedInstructionsText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Challenge. + /// + internal static string ChallengedText { + get { + return ResourceManager.GetString("ChallengedText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Choice. + /// + internal static string ChoiceText { + get { + return ResourceManager.GetString("ChoiceText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Choose File. + /// + internal static string ChooseFile { + get { + return ResourceManager.GetString("ChooseFile", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Choose File(s). + /// + internal static string ChooseFiles { + get { + return ResourceManager.GetString("ChooseFiles", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Choose Folder. + /// + internal static string ChooseFolder { + get { + return ResourceManager.GetString("ChooseFolder", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Close. + /// + internal static string CloseText { + get { + return ResourceManager.GetString("CloseText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Complete. + /// + internal static string Complete { + get { + return ResourceManager.GetString("Complete", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Connection string to get to database. + /// + internal static string ConnectionStringPlaceholder { + get { + return ResourceManager.GetString("ConnectionStringPlaceholder", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Connection String. + /// + internal static string ConnectionStringText { + get { + return ResourceManager.GetString("ConnectionStringText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Contact the election administrator!. + /// + internal static string ContactAdmin { + get { + return ResourceManager.GetString("ContactAdmin", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Contests. + /// + internal static string ContestsText { + get { + return ResourceManager.GetString("ContestsText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Created By. + /// + internal static string CreatedByText { + get { + return ResourceManager.GetString("CreatedByText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Created. + /// + internal static string CreatedText { + get { + return ResourceManager.GetString("CreatedText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Create Election. + /// + internal static string CreateElection { + get { + return ResourceManager.GetString("CreateElection", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Create Key Ceremony. + /// + internal static string CreateKeyCeremony { + get { + return ResourceManager.GetString("CreateKeyCeremony", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Select the elections to make tallies. + /// + internal static string CreateMultiInstructionsText { + get { + return ResourceManager.GetString("CreateMultiInstructionsText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Create Multiple Tallies. + /// + internal static string CreateMultipleTalliesText { + get { + return ResourceManager.GetString("CreateMultipleTalliesText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Create Multiple Tallies. + /// + internal static string CreateMultiTally { + get { + return ResourceManager.GetString("CreateMultiTally", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There are no Key Ceremonies that are used for multi-tallies. + /// + internal static string CreateMultiTallyError { + get { + return ResourceManager.GetString("CreateMultiTallyError", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Create Tallies. + /// + internal static string CreateTallies { + get { + return ResourceManager.GetString("CreateTallies", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Create Tally. + /// + internal static string CreateTally { + get { + return ResourceManager.GetString("CreateTally", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Custom Range for Ballot Selection. + /// + internal static string CustomRangeText { + get { + return ResourceManager.GetString("CustomRangeText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Database IP Address. + /// + internal static string DatabaseAddress { + get { + return ResourceManager.GetString("DatabaseAddress", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to login. Please check your database settings.. + /// + internal static string DatabaseLoginError { + get { + return ResourceManager.GetString("DatabaseLoginError", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Database Password. + /// + internal static string DatabasePassword { + get { + return ResourceManager.GetString("DatabasePassword", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Database is not available. Please check your settings.. + /// + internal static string DatabaseUnavailable { + get { + return ResourceManager.GetString("DatabaseUnavailable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Dates. + /// + internal static string DatesText { + get { + return ResourceManager.GetString("DatesText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Partial Decryption Complete. + /// + internal static string DecryptionComplete { + get { + return ResourceManager.GetString("DecryptionComplete", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device File. + /// + internal static string DeviceFileText { + get { + return ResourceManager.GetString("DeviceFileText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Devices. + /// + internal static string DevicesText { + get { + return ResourceManager.GetString("DevicesText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Does Not Exist. + /// + internal static string DoesNotExist { + get { + return ResourceManager.GetString("DoesNotExist", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to EGDrive already used. + /// + internal static string DriveUsedText { + get { + return ResourceManager.GetString("DriveUsedText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Duplicated. + /// + internal static string DuplicatedText { + get { + return ResourceManager.GetString("DuplicatedText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Election Checklist. + /// + internal static string ElectionChecklist { + get { + return ResourceManager.GetString("ElectionChecklist", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Election Details. + /// + internal static string ElectionDetails { + get { + return ResourceManager.GetString("ElectionDetails", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ElectionGuard. + /// + internal static string ElectionGuardTitle { + get { + return ResourceManager.GetString("ElectionGuardTitle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Election Name. + /// + internal static string ElectionNameText { + get { + return ResourceManager.GetString("ElectionNameText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Election Record Export Path. + /// + internal static string ElectionRecordPathText { + get { + return ResourceManager.GetString("ElectionRecordPathText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to elections created.. + /// + internal static string ElectionsCreated { + get { + return ResourceManager.GetString("ElectionsCreated", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Elections. + /// + internal static string ElectionsText { + get { + return ResourceManager.GetString("ElectionsText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Election URL. + /// + internal static string ElectionUrl { + get { + return ResourceManager.GetString("ElectionUrl", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Error Creating election. + /// + internal static string ErrorCreatingElection { + get { + return ResourceManager.GetString("ErrorCreatingElection", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to load guardian data.. + /// + internal static string ErrorLoadingGuardian { + get { + return ResourceManager.GetString("ErrorLoadingGuardian", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The manifest file could not be loaded.. + /// + internal static string ErrorLoadingManifest { + get { + return ResourceManager.GetString("ErrorLoadingManifest", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to View Error Logs. + /// + internal static string ErrorLogs { + get { + return ResourceManager.GetString("ErrorLogs", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Error in manifest files. + /// + internal static string ErrorManifest { + get { + return ResourceManager.GetString("ErrorManifest", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Please ensure the EGDrive removable storage is connected to the device. Please note, this will replace any encryption package currently on all EGDrive devices. + /// + internal static string ExportDriveWarning { + get { + return ResourceManager.GetString("ExportDriveWarning", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Export Encryption Package. + /// + internal static string ExportDriveWarningTitle { + get { + return ResourceManager.GetString("ExportDriveWarningTitle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Export Encryption. + /// + internal static string ExportEncryptionText { + get { + return ResourceManager.GetString("ExportEncryptionText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Export Election Record. + /// + internal static string ExportTally { + get { + return ResourceManager.GetString("ExportTally", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Geopolitical Units. + /// + internal static string GeopoliticalUnitsText { + get { + return ResourceManager.GetString("GeopoliticalUnitsText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Create Key Ceremony. + /// + internal static string GoToCreateKeyCeremonyAdmin { + get { + return ResourceManager.GetString("GoToCreateKeyCeremonyAdmin", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Guardian Home. + /// + internal static string GuardianHome { + get { + return ResourceManager.GetString("GuardianHome", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Guardians. + /// + internal static string GuardiansText { + get { + return ResourceManager.GetString("GuardiansText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Hello, World!. + /// + internal static string HelloWorld { + get { + return ResourceManager.GetString("HelloWorld", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Would you like to import from this EGDrive again?. + /// + internal static string ImportAgainText { + get { + return ResourceManager.GetString("ImportAgainText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Information. + /// + internal static string InformationText { + get { + return ResourceManager.GetString("InformationText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Insert an EGDrive (USB drive) containing ballots. + /// + internal static string InsertUsbText { + get { + return ResourceManager.GetString("InsertUsbText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to IP address of the database. + /// + internal static string IPAddressPlaceholder { + get { + return ResourceManager.GetString("IPAddressPlaceholder", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Join. + /// + internal static string Join { + get { + return ResourceManager.GetString("Join", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Joined Guardians. + /// + internal static string JoinedGuardians { + get { + return ResourceManager.GetString("JoinedGuardians", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Joined. + /// + internal static string JoinedText { + get { + return ResourceManager.GetString("JoinedText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Select the tallies to join. + /// + internal static string JoinMultiInstructionsText { + get { + return ResourceManager.GetString("JoinMultiInstructionsText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Join Tallies. + /// + internal static string JoinTallies { + get { + return ResourceManager.GetString("JoinTallies", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Key Ceremonies. + /// + internal static string KeyCeremoniesText { + get { + return ResourceManager.GetString("KeyCeremoniesText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Key Ceremony Name. + /// + internal static string KeyCeremonyName { + get { + return ResourceManager.GetString("KeyCeremonyName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Key Ceremony State. + /// + internal static string KeyCeremonyState { + get { + return ResourceManager.GetString("KeyCeremonyState", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Key Ceremony. + /// + internal static string KeyCeremonyText { + get { + return ResourceManager.GetString("KeyCeremonyText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Location. + /// + internal static string LocationText { + get { + return ResourceManager.GetString("LocationText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enter your name or other identifier. + /// + internal static string LoginPlaceholder { + get { + return ResourceManager.GetString("LoginPlaceholder", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Login. + /// + internal static string LoginText { + get { + return ResourceManager.GetString("LoginText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Manifest. + /// + internal static string ManifestText { + get { + return ResourceManager.GetString("ManifestText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cancel wizard and manually upload ballots. + /// + internal static string ManuelUploadText { + get { + return ResourceManager.GetString("ManuelUploadText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MultiTally Name. + /// + internal static string MultiTallyNameText { + get { + return ResourceManager.GetString("MultiTallyNameText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Names will be generated from manifest names. + /// + internal static string NameFromManifest { + get { + return ResourceManager.GetString("NameFromManifest", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Name. + /// + internal static string NameText { + get { + return ResourceManager.GetString("NameText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There was an issue with the network that caused an issue with what you were doing. Please log back in when the network connection has been restored. + /// + internal static string NetworkIssueText { + get { + return ResourceManager.GetString("NetworkIssueText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No Ballots Uploaded. + /// + internal static string NoBallotUploads { + get { + return ResourceManager.GetString("NoBallotUploads", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No elections found. + /// + internal static string NoElections { + get { + return ResourceManager.GetString("NoElections", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No file chosen. + /// + internal static string NoFileText { + get { + return ResourceManager.GetString("NoFileText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No folder chosen. + /// + internal static string NoFolderText { + get { + return ResourceManager.GetString("NoFolderText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No guardians joined. + /// + internal static string NoGuardians { + get { + return ResourceManager.GetString("NoGuardians", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No key ceremonies found. + /// + internal static string NoKeyCeremonies { + get { + return ResourceManager.GetString("NoKeyCeremonies", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No tallies found. + /// + internal static string NoTallies { + get { + return ResourceManager.GetString("NoTallies", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No Tallies Created. + /// + internal static string NoTalliesCreated { + get { + return ResourceManager.GetString("NoTalliesCreated", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No. + /// + internal static string NoText { + get { + return ResourceManager.GetString("NoText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Number of Guardians. + /// + internal static string NumberOfGuardians { + get { + return ResourceManager.GetString("NumberOfGuardians", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Ok. + /// + internal static string OkText { + get { + return ResourceManager.GetString("OkText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Parties. + /// + internal static string PartiesText { + get { + return ResourceManager.GetString("PartiesText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Party. + /// + internal static string PartyText { + get { + return ResourceManager.GetString("PartyText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Password to use for the database. + /// + internal static string PasswordDefaultPlaceholder { + get { + return ResourceManager.GetString("PasswordDefaultPlaceholder", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Waiting for Admin to Announce the Guardians. + /// + internal static string PendingAdminAnnounce { + get { + return ResourceManager.GetString("PendingAdminAnnounce", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Waiting for Admin to Create and Publish the Joint Key. + /// + internal static string PendingAdminToPublishJointKey { + get { + return ResourceManager.GetString("PendingAdminToPublishJointKey", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Waiting for Admin to Share the Election Key Backups. + /// + internal static string PendingAdminToShareBackups { + get { + return ResourceManager.GetString("PendingAdminToShareBackups", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Waiting for the Guardians to Backup Election Keys. + /// + internal static string PendingGuardianBackups { + get { + return ResourceManager.GetString("PendingGuardianBackups", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Waiting for Guardians to Join. + /// + internal static string PendingGuardianJoin { + get { + return ResourceManager.GetString("PendingGuardianJoin", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Waiting for Guardians to Verify the Backups. + /// + internal static string PendingGuardiansVerifyBackups { + get { + return ResourceManager.GetString("PendingGuardiansVerifyBackups", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to %. + /// + internal static string PercentText { + get { + return ResourceManager.GetString("PercentText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Error Detected. + /// + internal static string PreviousCrash { + get { + return ResourceManager.GetString("PreviousCrash", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cancel Tally. + /// + internal static string ProcessTallyAbandon { + get { + return ResourceManager.GetString("ProcessTallyAbandon", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No, Do not Join Tally. + /// + internal static string ProcessTallyJoinNo { + get { + return ResourceManager.GetString("ProcessTallyJoinNo", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Yes, Join Tally. + /// + internal static string ProcessTallyJoinYes { + get { + return ResourceManager.GetString("ProcessTallyJoinYes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Start Tally. + /// + internal static string ProcessTallyStartTally { + get { + return ResourceManager.GetString("ProcessTallyStartTally", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Quorum. + /// + internal static string Quorum { + get { + return ResourceManager.GetString("Quorum", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Quorum. + /// + internal static string QuorumText { + get { + return ResourceManager.GetString("QuorumText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Rejected. + /// + internal static string RejectedText { + get { + return ResourceManager.GetString("RejectedText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Removing files from the list. + /// + internal static string RemovingList { + get { + return ResourceManager.GetString("RemovingList", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Guardian has responded to Admin Challenge. + /// + internal static string ResponseComplete { + get { + return ResourceManager.GetString("ResponseComplete", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Results. + /// + internal static string ResultsText { + get { + return ResourceManager.GetString("ResultsText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Review Challenge. + /// + internal static string ReviewSpoiledText { + get { + return ResourceManager.GetString("ReviewSpoiledText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Save. + /// + internal static string Save { + get { + return ResourceManager.GetString("Save", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Select All Elections. + /// + internal static string SelectAllElectionsText { + get { + return ResourceManager.GetString("SelectAllElectionsText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Selection one or more manifest files. + /// + internal static string SelectManifest { + get { + return ResourceManager.GetString("SelectManifest", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Settings. + /// + internal static string Settings { + get { + return ResourceManager.GetString("Settings", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Move Challenged to Spoiled. + /// + internal static string SpoilBallotText { + get { + return ResourceManager.GetString("SpoilBallotText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Spoil Ballots. + /// + internal static string SpoilChallengedText { + get { + return ResourceManager.GetString("SpoilChallengedText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Are you sure that you would like to move this ballot into a Spoiled state? This will remove it from the election record.. + /// + internal static string SpoilConfirmationText { + get { + return ResourceManager.GetString("SpoilConfirmationText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Spoiled. + /// + internal static string SpoiledText { + get { + return ResourceManager.GetString("SpoiledText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Start Ceremony. + /// + internal static string StartCeremony { + get { + return ResourceManager.GetString("StartCeremony", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Status. + /// + internal static string Status { + get { + return ResourceManager.GetString("Status", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Export the encryption package. + /// + internal static string Step1Text { + get { + return ResourceManager.GetString("Step1Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Upload ballots using EGDrive (1 or more). + /// + internal static string Step2Text { + get { + return ResourceManager.GetString("Step2Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Review Challenge Ballots (if needed). + /// + internal static string Step3Text { + get { + return ResourceManager.GetString("Step3Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Perform a tally with the guardians (1 or more). + /// + internal static string Step4Text { + get { + return ResourceManager.GetString("Step4Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to View and export a tally. + /// + internal static string Step5Text { + get { + return ResourceManager.GetString("Step5Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ballots.. + /// + internal static string Success2Text { + get { + return ResourceManager.GetString("Success2Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Successfully uploaded. + /// + internal static string SuccessText { + get { + return ResourceManager.GetString("SuccessText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Switch Languages. + /// + internal static string SwitchLanguages { + get { + return ResourceManager.GetString("SwitchLanguages", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Tallies. + /// + internal static string TalliesText { + get { + return ResourceManager.GetString("TalliesText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to All Guardians responded to Challenge. + /// + internal static string TallyAllChallengesResponded { + get { + return ResourceManager.GetString("TallyAllChallengesResponded", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to All Guardian Shares Calculated. + /// + internal static string TallyAllDecryptionsComputed { + get { + return ResourceManager.GetString("TallyAllDecryptionsComputed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Challenge Created. + /// + internal static string TallyChallengeCreated { + get { + return ResourceManager.GetString("TallyChallengeCreated", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Tally Process. + /// + internal static string TallyChecklist { + get { + return ResourceManager.GetString("TallyChecklist", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Tally Verified and results computed. + /// + internal static string TallyComplete { + get { + return ResourceManager.GetString("TallyComplete", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Tally Name. + /// + internal static string TallyNameText { + get { + return ResourceManager.GetString("TallyNameText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Tally Process. + /// + internal static string TallyProcess { + get { + return ResourceManager.GetString("TallyProcess", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Quorum has been reached. + /// + internal static string TallyQuorumReachedText { + get { + return ResourceManager.GetString("TallyQuorumReachedText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Ballots have been tallied. + /// + internal static string TallySubtalliesCombined { + get { + return ResourceManager.GetString("TallySubtalliesCombined", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Tally. + /// + internal static string TallyText { + get { + return ResourceManager.GetString("TallyText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Total. + /// + internal static string TotalText { + get { + return ResourceManager.GetString("TotalText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Uploaded. + /// + internal static string UploadedText { + get { + return ResourceManager.GetString("UploadedText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Uploading. + /// + internal static string Uploading { + get { + return ResourceManager.GetString("Uploading", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Upload More Ballots. + /// + internal static string UploadMoreText { + get { + return ResourceManager.GetString("UploadMoreText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Upload. + /// + internal static string UploadText { + get { + return ResourceManager.GetString("UploadText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Upload Wizard. + /// + internal static string UploadWizardText { + get { + return ResourceManager.GetString("UploadWizardText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Use All Ballots For Tally. + /// + internal static string UseAllBallotsText { + get { + return ResourceManager.GetString("UseAllBallotsText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to User ID. + /// + internal static string UserID { + get { + return ResourceManager.GetString("UserID", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to User Login. + /// + internal static string UserLogin { + get { + return ResourceManager.GetString("UserLogin", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to User Setup. + /// + internal static string UserSetup { + get { + return ResourceManager.GetString("UserSetup", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Verification Code. + /// + internal static string VerificationCodeText { + get { + return ResourceManager.GetString("VerificationCodeText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Verified. + /// + internal static string Verified { + get { + return ResourceManager.GetString("Verified", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to View Key Ceremony. + /// + internal static string ViewKeyCeremony { + get { + return ResourceManager.GetString("ViewKeyCeremony", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to It appears that something went wrong. You can contine with what you were doing before this happened. Details are available in the log files in the Settings page.. + /// + internal static string ViewLogsText { + get { + return ResourceManager.GetString("ViewLogsText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to View Manifest. + /// + internal static string ViewManifest { + get { + return ResourceManager.GetString("ViewManifest", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to View Tally. + /// + internal static string ViewTally { + get { + return ResourceManager.GetString("ViewTally", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Votes. + /// + internal static string VotesText { + get { + return ResourceManager.GetString("VotesText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ElectionGuard Election Manager. + /// + internal static string WindowTitle { + get { + return ResourceManager.GetString("WindowTitle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Writein Candidate. + /// + internal static string WriteinText { + get { + return ResourceManager.GetString("WriteinText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive contains ballots for a different election.. + /// + internal static string WrongElectionText { + get { + return ResourceManager.GetString("WrongElectionText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Yes. + /// + internal static string YesText { + get { + return ResourceManager.GetString("YesText", resourceCulture); + } + } + } +} diff --git a/src/electionguard-ui/ElectionGuard.UI/Resx/AppResources.es.resx b/src/electionguard-ui/ElectionGuard.UI/Resx/AppResources.es.resx index bd45c22a2..d998be9a0 100644 --- a/src/electionguard-ui/ElectionGuard.UI/Resx/AppResources.es.resx +++ b/src/electionguard-ui/ElectionGuard.UI/Resx/AppResources.es.resx @@ -1,654 +1,654 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - hola, mundo - - - ¡Gerente de Elecciones de ElectionGuard! - - - ID de usuario - - - Iniciar sesión - - - Configuración de usuario - - - ¡Introduzca su nombre u otro identificador! - - - Sesión Iniciada - - - Tutor - - - Ceremonia - - - ¡No se han encontrado ceremonias clave! - - - ¡No se han encontrado cuentas! - - - ¡Tallies! - - - Inicio de Administrador - - - ¡Crear elección! - - - ¡ElectionGuard! - - - Elecciones - - - No se han encontrado elecciones - - - ¡ElectionGuard versión 2.0! - - - ¡Cambia de idioma! - - - Configuración - - - ¡Detalles de la elección! - - - Tutores - - - manifiesto - - - ¡Lista de verificación de elecciones! - - - Quórum. - - - Papeletas - - - ¡Estilos de papeleta! - - - Candidatos - - - COMPETENCIAS - - - ¡Creado! - - - ¡Crear recuento! - - - ¡URL de la elección! - - - ¡Unidades geopolíticas! - - - ¡Ubicación¡ - - - Nombre - - - Las Partes - - - ¡Cargado! - - - Papeletas - - - ¿Qué quieres hacer? - - - Go To Key Ceremony in spanish - - - Key Ceremony - - - Quórum. - - - ¡Número de guardianes! - - - ¡Nombre clave de la ceremonia! - - - Inicio ceremonia: - - - ¡Ver ceremonia de llaves! - - - Unirse - - - ya existe. ¡Prueba con otro nombre! - - - ¡Dirección IP de la base de datos! - - - Contraseña de la base de datos - - - ¡Dirección IP de la base de datos! - - - ¡Contraseña para usar para la base de datos! - - - Guardar - - - ¡No se han unido guardianes! - - - ¡Estado de la Ceremonia de Llaves! - - - Completo - - - ¡No existe! - - - ¡A la espera de que el administrador anuncie a los Guardianes! - - - ¡Esperando a que el administrador cree y publique la clave conjunta! - - - ¡Esperando que el administrador comparta las copias de seguridad de la clave electoral! - - - ¡Esperando a que los Guardianes respalden las claves electorales! - - - ¡Esperando a que se unan los guardianes! - - - ¡Esperando a que los guardianes verifiquen las copias de seguridad! - - - Verificación incorrecta - - - Comprobado - - - Contacta con el administrador de elecciones!! - - - Copia de seguridad - - - Unido - - - La base de datos no está disponible. Por favor, compruebe su configuración.! - - - Ceremonia - - - Seleccionar archivo(s) - - - Seleccione uno o más archivos de manifiesto. - - - ¡Los nombres se generarán a partir de los nombres de manifiesto! - - - El archivo de fuente no se pudo cargar. - - - Error al crear elecciones! - - - Error en los archivos de manifiesto! - - - ¡Eliminando archivos de la lista! - - - ¡Elecciones creadas! - - - Información - - - Creado por - - - ¡No se han cargado boletas! - - - ¡No se han creado recuentos! - - - Ver manifiesto - - - ¡Carpeta de boletas! - - - Cancelar - - - Archivo de dispositivo - - - ¡Inserte un EGDrive (unidad USB) que contenga boletas! - - - ¡Cancela el asistente y sube las papeletas manualmente! - - - Cargar - - - Asistente de carga de archivo - - - Ningún archivo elegido - - - ¡No se ha elegido ninguna carpeta! - - - ¡Sube la papeleta! - - - Elegir archivo - - - Elegir carpeta - - - TOTAL - - - ¡EGDrive ya está en uso! - - - ¿Te gustaría importar desde este EGDrive de nuevo? - - - No - - - - - - Agregado - - - Rechazado - - - Estropeado - - - ¡Sube más boletas! - - - Se cargó correctamente - - - Votos - - - ¡Exportar cifrado! - - - ¡Cadena de conexión para llegar a la base de datos! - - - Cadena de conexión - - - Duplicado - - - ¡Exporta el paquete de cifrado! - - - ¡Sube boletas usando EGDrive (1 o más)! - - - ¡Ver y exportar un recuento! - - - ¡Revise las boletas de desafío (si es necesario)! - - - ¡Ver y exportar un recuento! - - - ¡Crea varios recuentos! - - - ¡Rango personalizado para la selección de boletas! - - - Fechas - - - Dispositivos: - - - Conteo - - - ¡Proceso de recuento! - - - Recuento - - - ¡Utilice todas las boletas para el recuento! - - - ¡Revisa el desafío! - - - Asegúrese de que el almacenamiento extraíble de EGDrive esté conectado al dispositivo. ¡Tenga en cuenta que esto reemplazará cualquier paquete de cifrado actualmente en todos los dispositivos EGDrive! - - - ¡Exportar paquete de cifrado! - - - ¡No, no te unas a Tally! - - - ¡Únete a Tally! - - - Opción - - - Entidad - - - %! - - - Votos - - - Conteo - - - ¡Exportar registro de elección! - - - Cargando... - - - Recuento - - - Cuestionado - - - Elección - - - ¡Únete a los Guardianes! - - - Estado - - - ¡Todos los Guardianes respondieron al Desafío! - - - ¡Todas las acciones de Guardian calculadas! - - - Desafío creado - - - ¡Verificado y resultados calculados! - - - ¡Se ha alcanzado el quórum! - - - ¡Las papeletas han sido contadas! - - - ¡Proceso de recuento! - - - ¡Cancela Tally! - - - ¡Empieza Tally! - - - Aceptar - - - Tally ha sido cancelada por el administrador de elecciones. Consulte el administrador para obtener detalles adicionales.! - - - ¡Cuenta cancelada! - - - Resultados - - - ¡Escribe al candidato! - - - ¡Seleccione las elecciones para hacer recuentos! - - - ¡Crea varios recuentos! - - - ¡Crear recuentos! - - - ¡Selecciona los recuentos para unirte! - - - ¡Únete a Tallies! - - - ¡Selecciona todas las elecciones! - - - Nombre MultiTally! - - - ¡Ruta de exportación del registro de elecciones! - - - No se puede iniciar sesión. Compruebe la configuración de su base de datos.! - - - No se puede cargar datos. - - - ¡Muévete Desafiado a Mimado! - - - ¿Está seguro de que le gustaría mover esta boleta a un estado estropeado? ¡Esto lo eliminará del registro electoral! - - - Introduzca el código de verificación en el cuadro de búsqueda para limitar las papeletas mostradas. Seleccione esa boleta de la lista que se establecerá en una boleta estropeada. - - - ¡Boletas estropeadas! - - - Código de verificación - - - ¡No hay ceremonias clave que se utilicen para multitallies! - - - Ver registros de errores - - - ¡Descifrado parcial completo! - - - ¡El tutor ha respondido al desafío del administrador! - - - ¡Cerca! - - - ¡Error detectado! - - - Parece que algo ha salido mal. Puedes seguir con lo que estabas haciendo antes de que esto sucediera. Los detalles están disponibles en los archivos de registro en la página Configuración.! - - - Hubo un problema con la red que causó un problema con lo que estabas haciendo. ¡Vuelve a iniciar sesión cuando se haya restablecido la conexión de red! - - - Drive contiene papeletas para una elección diferente.! - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + hola, mundo + + + ¡Gerente de Elecciones de ElectionGuard! + + + ID de usuario + + + Iniciar sesión + + + Configuración de usuario + + + ¡Introduzca su nombre u otro identificador! + + + Sesión Iniciada + + + Tutor + + + Ceremonia + + + ¡No se han encontrado ceremonias clave! + + + ¡No se han encontrado cuentas! + + + ¡Tallies! + + + Inicio de Administrador + + + ¡Crear elección! + + + ¡ElectionGuard! + + + Elecciones + + + No se han encontrado elecciones + + + ¡ElectionGuard versión 2.0! + + + ¡Cambia de idioma! + + + Configuración + + + ¡Detalles de la elección! + + + Tutores + + + manifiesto + + + ¡Lista de verificación de elecciones! + + + Quórum. + + + Papeletas + + + ¡Estilos de papeleta! + + + Candidatos + + + COMPETENCIAS + + + ¡Creado! + + + ¡Crear recuento! + + + ¡URL de la elección! + + + ¡Unidades geopolíticas! + + + ¡Ubicación¡ + + + Nombre + + + Las Partes + + + ¡Cargado! + + + Papeletas + + + ¿Qué quieres hacer? + + + Go To Key Ceremony in spanish + + + Key Ceremony + + + Quórum. + + + ¡Número de guardianes! + + + ¡Nombre clave de la ceremonia! + + + Inicio ceremonia: + + + ¡Ver ceremonia de llaves! + + + Unirse + + + ya existe. ¡Prueba con otro nombre! + + + ¡Dirección IP de la base de datos! + + + Contraseña de la base de datos + + + ¡Dirección IP de la base de datos! + + + ¡Contraseña para usar para la base de datos! + + + Guardar + + + ¡No se han unido guardianes! + + + ¡Estado de la Ceremonia de Llaves! + + + Completo + + + ¡No existe! + + + ¡A la espera de que el administrador anuncie a los Guardianes! + + + ¡Esperando a que el administrador cree y publique la clave conjunta! + + + ¡Esperando que el administrador comparta las copias de seguridad de la clave electoral! + + + ¡Esperando a que los Guardianes respalden las claves electorales! + + + ¡Esperando a que se unan los guardianes! + + + ¡Esperando a que los guardianes verifiquen las copias de seguridad! + + + Verificación incorrecta + + + Comprobado + + + Contacta con el administrador de elecciones!! + + + Copia de seguridad + + + Unido + + + La base de datos no está disponible. Por favor, compruebe su configuración.! + + + Ceremonia + + + Seleccionar archivo(s) + + + Seleccione uno o más archivos de manifiesto. + + + ¡Los nombres se generarán a partir de los nombres de manifiesto! + + + El archivo de fuente no se pudo cargar. + + + Error al crear elecciones! + + + Error en los archivos de manifiesto! + + + ¡Eliminando archivos de la lista! + + + ¡Elecciones creadas! + + + Información + + + Creado por + + + ¡No se han cargado boletas! + + + ¡No se han creado recuentos! + + + Ver manifiesto + + + ¡Carpeta de boletas! + + + Cancelar + + + Archivo de dispositivo + + + ¡Inserte un EGDrive (unidad USB) que contenga boletas! + + + ¡Cancela el asistente y sube las papeletas manualmente! + + + Cargar + + + Asistente de carga de archivo + + + Ningún archivo elegido + + + ¡No se ha elegido ninguna carpeta! + + + ¡Sube la papeleta! + + + Elegir archivo + + + Elegir carpeta + + + TOTAL + + + ¡EGDrive ya está en uso! + + + ¿Te gustaría importar desde este EGDrive de nuevo? + + + No + + + + + + Agregado + + + Rechazado + + + Estropeado + + + ¡Sube más boletas! + + + Se cargó correctamente + + + Votos + + + ¡Exportar cifrado! + + + ¡Cadena de conexión para llegar a la base de datos! + + + Cadena de conexión + + + Duplicado + + + ¡Exporta el paquete de cifrado! + + + ¡Sube boletas usando EGDrive (1 o más)! + + + ¡Ver y exportar un recuento! + + + ¡Revise las boletas de desafío (si es necesario)! + + + ¡Ver y exportar un recuento! + + + ¡Crea varios recuentos! + + + ¡Rango personalizado para la selección de boletas! + + + Fechas + + + Dispositivos: + + + Conteo + + + ¡Proceso de recuento! + + + Recuento + + + ¡Utilice todas las boletas para el recuento! + + + ¡Revisa el desafío! + + + Asegúrese de que el almacenamiento extraíble de EGDrive esté conectado al dispositivo. ¡Tenga en cuenta que esto reemplazará cualquier paquete de cifrado actualmente en todos los dispositivos EGDrive! + + + ¡Exportar paquete de cifrado! + + + ¡No, no te unas a Tally! + + + ¡Únete a Tally! + + + Opción + + + Entidad + + + %! + + + Votos + + + Conteo + + + ¡Exportar registro de elección! + + + Cargando... + + + Recuento + + + Cuestionado + + + Elección + + + ¡Únete a los Guardianes! + + + Estado + + + ¡Todos los Guardianes respondieron al Desafío! + + + ¡Todas las acciones de Guardian calculadas! + + + Desafío creado + + + ¡Verificado y resultados calculados! + + + ¡Se ha alcanzado el quórum! + + + ¡Las papeletas han sido contadas! + + + ¡Proceso de recuento! + + + ¡Cancela Tally! + + + ¡Empieza Tally! + + + Aceptar + + + Tally ha sido cancelada por el administrador de elecciones. Consulte el administrador para obtener detalles adicionales.! + + + ¡Cuenta cancelada! + + + Resultados + + + ¡Escribe al candidato! + + + ¡Seleccione las elecciones para hacer recuentos! + + + ¡Crea varios recuentos! + + + ¡Crear recuentos! + + + ¡Selecciona los recuentos para unirte! + + + ¡Únete a Tallies! + + + ¡Selecciona todas las elecciones! + + + Nombre MultiTally! + + + ¡Ruta de exportación del registro de elecciones! + + + No se puede iniciar sesión. Compruebe la configuración de su base de datos.! + + + No se puede cargar datos. + + + ¡Muévete Desafiado a Mimado! + + + ¿Está seguro de que le gustaría mover esta boleta a un estado estropeado? ¡Esto lo eliminará del registro electoral! + + + Introduzca el código de verificación en el cuadro de búsqueda para limitar las papeletas mostradas. Seleccione esa boleta de la lista que se establecerá en una boleta estropeada. + + + ¡Boletas estropeadas! + + + Código de verificación + + + ¡No hay ceremonias clave que se utilicen para multitallies! + + + Ver registros de errores + + + ¡Descifrado parcial completo! + + + ¡El tutor ha respondido al desafío del administrador! + + + ¡Cerca! + + + ¡Error detectado! + + + Parece que algo ha salido mal. Puedes seguir con lo que estabas haciendo antes de que esto sucediera. Los detalles están disponibles en los archivos de registro en la página Configuración.! + + + Hubo un problema con la red que causó un problema con lo que estabas haciendo. ¡Vuelve a iniciar sesión cuando se haya restablecido la conexión de red! + + + Drive contiene papeletas para una elección diferente.! + \ No newline at end of file diff --git a/src/electionguard-ui/ElectionGuard.UI/Resx/AppResources.resx b/src/electionguard-ui/ElectionGuard.UI/Resx/AppResources.resx index 8406eb111..65f4b2b33 100644 --- a/src/electionguard-ui/ElectionGuard.UI/Resx/AppResources.resx +++ b/src/electionguard-ui/ElectionGuard.UI/Resx/AppResources.resx @@ -1,651 +1,651 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Add Ballots - - - Admin Home - - - What Do You Want To Do? - - - Count - - - Ballots - - - Ballot Styles - - - Candidates - - - Contests - - - Created - - - Create Election - - - Create Tally - - - Election Checklist - - - Election Details - - - ElectionGuard - - - Elections - - - Election URL - - - Geopolitical Units - - - Guardian Home - - - Guardians - - - Hello, World! - - - Key Ceremonies - - - Location - - - Enter your name or other identifier - - - Login - - - Manifest - - - Name - - - No elections found - - - No key ceremonies found - - - No tallies found - - - Parties - - - Quorum - - - Settings - - - Switch Languages - - - Tallies - - - Uploaded - - - User ID - - - User Login - - - User Setup - - - ElectionGuard Election Manager - - - Create Key Ceremony - - - Create Key Ceremony - - - Quorum - - - Number of Guardians - - - Key Ceremony Name - - - Start Ceremony - - - View Key Ceremony - - - Join - - - already exists. Try a different name. - - - Database IP Address - - - Database Password - - - IP address of the database - - - Password to use for the database - - - Save - - - No guardians joined - - - Complete - - - Does Not Exist - - - Key Ceremony State - - - Waiting for Admin to Announce the Guardians - - - Waiting for Admin to Create and Publish the Joint Key - - - Waiting for Admin to Share the Election Key Backups - - - Waiting for the Guardians to Backup Election Keys - - - Waiting for Guardians to Join - - - Waiting for Guardians to Verify the Backups - - - Bad Verification - - - Verified - - - Backup - - - Contact the election administrator! - - - Joined - - - Database is not available. Please check your settings. - - - Choose File(s) - - - elections created. - - - Error Creating election - - - The manifest file could not be loaded. - - - Error in manifest files - - - Information - - - Key Ceremony - - - Names will be generated from manifest names - - - Removing files from the list - - - Selection one or more manifest files - - - Created By - - - No Ballots Uploaded - - - No Tallies Created - - - View Manifest - - - Ballot Folder - - - Ballot Upload - - - Cancel - - - Choose File - - - Choose Folder - - - Device File - - - Insert an EGDrive (USB drive) containing ballots - - - Cancel wizard and manually upload ballots - - - No file chosen - - - No folder chosen - - - Total - - - Upload - - - Upload Wizard - - - EGDrive already used - - - Would you like to import from this EGDrive again? - - - No - - - Yes - - - Added - - - Rejected - - - Spoiled - - - Upload More Ballots - - - ballots. - - - Successfully uploaded - - - Export Encryption - - - Duplicated - - - Connection string to get to database - - - Connection String - - - Export the encryption package - - - Upload ballots using EGDrive (1 or more) - - - Review Challenge Ballots (if needed) - - - Perform a tally with the guardians (1 or more) - - - View and export a tally - - - Create Multiple Tallies - - - Custom Range for Ballot Selection - - - Dates - - - Devices - - - Tally Name - - - Tally Process - - - Tally - - - Use All Ballots For Tally - - - Review Challenge - - - Select the elections to make tallies - - - Create Multiple Tallies - - - Create Tallies - - - Select the tallies to join - - - Join Tallies - - - Choice - - - Party - - - % - - - Votes - - - Please ensure the EGDrive removable storage is connected to the device. Please note, this will replace any encryption package currently on all EGDrive devices - - - Export Encryption Package - - - No, Do not Join Tally - - - Yes, Join Tally - - - View Tally - - - Challenge - - - Election Name - - - Export Election Record - - - Joined Guardians - - - Status - - - Uploading - - - All Guardians responded to Challenge - - - All Guardian Shares Calculated - - - Challenge Created - - - Tally Process - - - Tally Verified and results computed - - - Quorum has been reached - - - Ballots have been tallied - - - Cancel Tally - - - Start Tally - - - Ok - - - Tally has been canceled by election administrator. See administrator for addional details. - - - Tally Canceled - - - Results - - - Writein Candidate - - - Select All Elections - - - MultiTally Name - - - Election Record Export Path - - - Unable to login. Please check your database settings. - - - Unable to load guardian data. - - - Enter the verification code in the search box to limit the ballots shown. Select that ballot from the list to be set to a spoiled ballot. - - - Move Challenged to Spoiled - - - Spoil Ballots - - - Are you sure that you would like to move this ballot into a Spoiled state? This will remove it from the election record. - - - Verification Code - - - There are no Key Ceremonies that are used for multi-tallies - - - View Error Logs - - - Partial Decryption Complete - - - Guardian has responded to Admin Challenge - - - Close - - - Error Detected - - - It appears that something went wrong. You can contine with what you were doing before this happened. Details are available in the log files in the Settings page. - - - There was an issue with the network that caused an issue with what you were doing. Please log back in when the network connection has been restored - - - Drive contains ballots for a different election. - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Add Ballots + + + Admin Home + + + What Do You Want To Do? + + + Count + + + Ballots + + + Ballot Styles + + + Candidates + + + Contests + + + Created + + + Create Election + + + Create Tally + + + Election Checklist + + + Election Details + + + ElectionGuard + + + Elections + + + Election URL + + + Geopolitical Units + + + Guardian Home + + + Guardians + + + Hello, World! + + + Key Ceremonies + + + Location + + + Enter your name or other identifier + + + Login + + + Manifest + + + Name + + + No elections found + + + No key ceremonies found + + + No tallies found + + + Parties + + + Quorum + + + Settings + + + Switch Languages + + + Tallies + + + Uploaded + + + User ID + + + User Login + + + User Setup + + + ElectionGuard Election Manager + + + Create Key Ceremony + + + Create Key Ceremony + + + Quorum + + + Number of Guardians + + + Key Ceremony Name + + + Start Ceremony + + + View Key Ceremony + + + Join + + + already exists. Try a different name. + + + Database IP Address + + + Database Password + + + IP address of the database + + + Password to use for the database + + + Save + + + No guardians joined + + + Complete + + + Does Not Exist + + + Key Ceremony State + + + Waiting for Admin to Announce the Guardians + + + Waiting for Admin to Create and Publish the Joint Key + + + Waiting for Admin to Share the Election Key Backups + + + Waiting for the Guardians to Backup Election Keys + + + Waiting for Guardians to Join + + + Waiting for Guardians to Verify the Backups + + + Bad Verification + + + Verified + + + Backup + + + Contact the election administrator! + + + Joined + + + Database is not available. Please check your settings. + + + Choose File(s) + + + elections created. + + + Error Creating election + + + The manifest file could not be loaded. + + + Error in manifest files + + + Information + + + Key Ceremony + + + Names will be generated from manifest names + + + Removing files from the list + + + Selection one or more manifest files + + + Created By + + + No Ballots Uploaded + + + No Tallies Created + + + View Manifest + + + Ballot Folder + + + Ballot Upload + + + Cancel + + + Choose File + + + Choose Folder + + + Device File + + + Insert an EGDrive (USB drive) containing ballots + + + Cancel wizard and manually upload ballots + + + No file chosen + + + No folder chosen + + + Total + + + Upload + + + Upload Wizard + + + EGDrive already used + + + Would you like to import from this EGDrive again? + + + No + + + Yes + + + Added + + + Rejected + + + Spoiled + + + Upload More Ballots + + + ballots. + + + Successfully uploaded + + + Export Encryption + + + Duplicated + + + Connection string to get to database + + + Connection String + + + Export the encryption package + + + Upload ballots using EGDrive (1 or more) + + + Review Challenge Ballots (if needed) + + + Perform a tally with the guardians (1 or more) + + + View and export a tally + + + Create Multiple Tallies + + + Custom Range for Ballot Selection + + + Dates + + + Devices + + + Tally Name + + + Tally Process + + + Tally + + + Use All Ballots For Tally + + + Review Challenge + + + Select the elections to make tallies + + + Create Multiple Tallies + + + Create Tallies + + + Select the tallies to join + + + Join Tallies + + + Choice + + + Party + + + % + + + Votes + + + Please ensure the EGDrive removable storage is connected to the device. Please note, this will replace any encryption package currently on all EGDrive devices + + + Export Encryption Package + + + No, Do not Join Tally + + + Yes, Join Tally + + + View Tally + + + Challenge + + + Election Name + + + Export Election Record + + + Joined Guardians + + + Status + + + Uploading + + + All Guardians responded to Challenge + + + All Guardian Shares Calculated + + + Challenge Created + + + Tally Process + + + Tally Verified and results computed + + + Quorum has been reached + + + Ballots have been tallied + + + Cancel Tally + + + Start Tally + + + Ok + + + Tally has been canceled by election administrator. See administrator for addional details. + + + Tally Canceled + + + Results + + + Writein Candidate + + + Select All Elections + + + MultiTally Name + + + Election Record Export Path + + + Unable to login. Please check your database settings. + + + Unable to load guardian data. + + + Enter the verification code in the search box to limit the ballots shown. Select that ballot from the list to be set to a spoiled ballot. + + + Move Challenged to Spoiled + + + Spoil Ballots + + + Are you sure that you would like to move this ballot into a Spoiled state? This will remove it from the election record. + + + Verification Code + + + There are no Key Ceremonies that are used for multi-tallies + + + View Error Logs + + + Partial Decryption Complete + + + Guardian has responded to Admin Challenge + + + Close + + + Error Detected + + + It appears that something went wrong. You can contine with what you were doing before this happened. Details are available in the log files in the Settings page. + + + There was an issue with the network that caused an issue with what you were doing. Please log back in when the network connection has been restored + + + Drive contains ballots for a different election. + \ No newline at end of file diff --git a/src/electionguard-ui/ElectionGuard.UI/Services/AuthenticationService.cs b/src/electionguard-ui/ElectionGuard.UI/Services/AuthenticationService.cs index dc6185181..2635a5b5e 100644 --- a/src/electionguard-ui/ElectionGuard.UI/Services/AuthenticationService.cs +++ b/src/electionguard-ui/ElectionGuard.UI/Services/AuthenticationService.cs @@ -14,13 +14,13 @@ public AuthenticationService(INavigationService navigationService, UserService u } public async Task Login(string username, ILogger logger) - { - await Task.Run(() => - { - App.CurrentUser = new(); - App.CurrentUser.Name = username; - var isAdmin = username.ToLower(CultureInfo.CurrentCulture).Contains(UISettings.AdminUser); - App.CurrentUser.IsAdmin = isAdmin; + { + await Task.Run(() => + { + App.CurrentUser = new(); + App.CurrentUser.Name = username; + var isAdmin = username.ToLower(CultureInfo.CurrentCulture).Contains(UISettings.AdminUser); + App.CurrentUser.IsAdmin = isAdmin; logger.LogInformation("Logging in as {UserName} {admin}", UserName, isAdmin ? "(admin)" : string.Empty); }); } diff --git a/src/electionguard-ui/ElectionGuard.UI/Services/EgServiceProvider.cs b/src/electionguard-ui/ElectionGuard.UI/Services/EgServiceProvider.cs index 371d0ca3b..09ca0d587 100644 --- a/src/electionguard-ui/ElectionGuard.UI/Services/EgServiceProvider.cs +++ b/src/electionguard-ui/ElectionGuard.UI/Services/EgServiceProvider.cs @@ -1,11 +1,11 @@ -using CommunityToolkit.Mvvm.DependencyInjection; - -namespace ElectionGuard.UI.Services; - -public class EgServiceProvider : IMauiInitializeService -{ - public void Initialize(IServiceProvider services) - { - Ioc.Default.ConfigureServices(services); - } -} +using CommunityToolkit.Mvvm.DependencyInjection; + +namespace ElectionGuard.UI.Services; + +public class EgServiceProvider : IMauiInitializeService +{ + public void Initialize(IServiceProvider services) + { + Ioc.Default.ConfigureServices(services); + } +} diff --git a/src/electionguard-ui/ElectionGuard.UI/Services/NavigationService.cs b/src/electionguard-ui/ElectionGuard.UI/Services/NavigationService.cs index 11a8027d0..9dfdb2807 100644 --- a/src/electionguard-ui/ElectionGuard.UI/Services/NavigationService.cs +++ b/src/electionguard-ui/ElectionGuard.UI/Services/NavigationService.cs @@ -1,5 +1,5 @@ using CommunityToolkit.Maui.Views; -using CommunityToolkit.Mvvm.DependencyInjection; +using CommunityToolkit.Mvvm.DependencyInjection; namespace ElectionGuard.UI.Services; @@ -88,13 +88,13 @@ public async Task GoToPage(Type viewModel, Dictionary? pageParam _currentPage = contentPage.Page; var url = contentPage.IsGlobal ? $"//{_currentPage.Name}" : _currentPage.Name; await Shell.Current.GoToAsync(url, pageParams ?? new()); - } - + } + public async Task GoBack() - { + { await Shell.Current.GoToAsync(".."); - } - + } + private static PageType GetPage(Type viewModel) { var pageType = PageTypes.FirstOrDefault(i => i.ViewModel == viewModel); diff --git a/src/electionguard-ui/ElectionGuard.UI/Services/TallyManager.cs b/src/electionguard-ui/ElectionGuard.UI/Services/TallyManager.cs index f6795d123..ab8937d81 100644 --- a/src/electionguard-ui/ElectionGuard.UI/Services/TallyManager.cs +++ b/src/electionguard-ui/ElectionGuard.UI/Services/TallyManager.cs @@ -5,12 +5,12 @@ using ElectionGuard.Decryption.Extensions; using ElectionGuard.Decryption.Shares; using ElectionGuard.Decryption.Tally; -using ElectionGuard.ElectionSetup; using ElectionGuard.Converters; using ElectionGuard.Extensions; using ElectionGuard.Guardians; using MongoDB.Driver; using Newtonsoft.Json; +using ElectionGuard.ElectionSetup; namespace ElectionGuard.UI.Services { @@ -322,11 +322,11 @@ private async Task LoadAllShares(DecryptionMediator mediator, TallyRecord tally) var challengeBallots = await GetBallotsByState(tally.ElectionId, BallotBoxState.Challenged); var shares = await _decryptionShareService.GetAllByTallyIdAsync(tally.TallyId); - foreach (var share in shares) - { - var shareData = JsonConvert.DeserializeObject(share.ShareData)!; - mediator.SubmitShares(shareData, challengeBallots.ToList()); - } + foreach (var share in shares) + { + var shareData = JsonConvert.DeserializeObject(share.ShareData)!; + mediator.SubmitShares(shareData, challengeBallots.ToList()); + } } private async Task AddSpoiledBallots(DecryptionMediator mediator, TallyRecord tally) @@ -375,18 +375,18 @@ private async Task HydrateGuardian( var backups = await _guardianBackupService.GetByGuardianIdAsync(keyCeremony.KeyCeremonyId!, userId) ?? throw new ArgumentException(nameof(keyCeremony.KeyCeremonyId)); - try - { - var guardian = GuardianStorageExtensions.Load( - userId, - keyCeremony, - publicKeys, - backups.ToDictionary(k => k.GuardianId!, v => v.Backup!)) ?? throw new ElectionGuardException(nameof(userId)); - return guardian; + try + { + var guardian = GuardianStorageExtensions.Load( + userId, + keyCeremony, + publicKeys, + backups.ToDictionary(k => k.GuardianId!, v => v.Backup!.ToRecord())) ?? throw new ElectionGuardException(nameof(userId)); + return guardian; } - catch (Exception ex) - { - throw new ElectionGuardException(AppResources.ErrorLoadingGuardian, ex); + catch (Exception ex) + { + throw new ElectionGuardException(AppResources.ErrorLoadingGuardian, ex); } } #endregion diff --git a/src/electionguard-ui/ElectionGuard.UI/Services/TallyStateMachine.cs b/src/electionguard-ui/ElectionGuard.UI/Services/TallyStateMachine.cs index a4112a96c..01e00ce90 100644 --- a/src/electionguard-ui/ElectionGuard.UI/Services/TallyStateMachine.cs +++ b/src/electionguard-ui/ElectionGuard.UI/Services/TallyStateMachine.cs @@ -1,255 +1,255 @@ -using System.Threading; -using ElectionGuard.Decryption.Shares; -using ElectionGuard.ElectionSetup; -using ElectionGuard.UI.Lib.Models; - -namespace ElectionGuard.UI.Services; - -public class TallyStateMachine : ITallyStateMachine -{ - private Dictionary>> _steps = new(); - - private IAuthenticationService _authenticationService; - private readonly ChallengeResponseService _challengeResponseService; - private readonly DecryptionShareService _decryptionShareService; - private readonly TallyJoinedService _tallyJoinedService; - private readonly TallyService _tallyService; - private TallyManager _tallyManager; - - public TallyStateMachine( - IAuthenticationService authenticationService, - ChallengeResponseService challengeResponseService, - DecryptionShareService decryptionShareService, - TallyService tallyService, - TallyManager tallyManager, - TallyJoinedService tallyJoinedService) - { - _authenticationService = authenticationService; - _challengeResponseService = challengeResponseService; - _decryptionShareService = decryptionShareService; - _tallyService = tallyService; - _tallyJoinedService = tallyJoinedService; - _tallyManager = tallyManager; - GenerateGuardianSteps(); - GenerateAdminSteps(); - } - - public async Task Run(TallyRecord tally) - { - bool ran = false; - string label = $"Electionguard.UI.TallyStateMachine-{_authenticationService.UserName}"; - - using var mutex = new Mutex(true, label, out var owned); - if (owned) - { - try - { - if (mutex.WaitOne(10)) - { - Task.WaitAll(RunAsync(tally)); - ran = true; - } - } - catch (AbandonedMutexException) - { - mutex.ReleaseMutex(); - } - catch - { - throw; - } - finally - { - mutex.ReleaseMutex(); - } - } - return ran; - } - - private async Task RunAsync(TallyRecord tally) - { - try - { - var steps = _steps[_authenticationService.IsAdmin]; - var currentStep = steps.SingleOrDefault(s => s.State == tally.State); - if (currentStep is not null && await currentStep.ShouldRunStep(tally)) - { - await currentStep.RunStep(tally); - } - } - catch (Exception) - { - throw; - } - } - - - - #region Should Run - private async Task ShouldAutoStartTally(TallyRecord tally) - { - const bool GUARDIAN_JOINED_TALLY = true; - - var joinedGuardians = await _tallyJoinedService.GetGuardianCountByTallyAsync(tally.TallyId); - joinedGuardians.TryGetValue(GUARDIAN_JOINED_TALLY, out var consentCount); - joinedGuardians.TryGetValue(!GUARDIAN_JOINED_TALLY, out var rejectCount); - - var isQuorumReached = consentCount >= tally.Quorum; - var haveAllGuardiansJoined = (consentCount + rejectCount) == tally.NumberOfGuardians; - - return isQuorumReached && haveAllGuardiansJoined; - } - - private async Task ShouldDecryptShares(TallyRecord tally) - { - return !await _decryptionShareService.GetExistsByTallyAsync(tally.TallyId, _authenticationService.UserName ?? string.Empty); - } - - private async Task ShouldGenerateChallenge(TallyRecord tally) - { - var joinedGuardians = await _tallyJoinedService.GetCountByTallyJoinedAsync(tally.TallyId); - var decryptionShares = await _decryptionShareService.GetCountByTallyAsync(tally.TallyId); - - return decryptionShares == joinedGuardians; - } - - private async Task ShouldRespondChallenge(TallyRecord tally) - { - return !await _challengeResponseService.GetExistsByTallyAsync( - tally.TallyId, - _authenticationService.UserName ?? string.Empty); - } - - private async Task ShouldVerifyChallenge(TallyRecord tally) - { - var joinedGuardians = await _tallyJoinedService.GetCountByTallyJoinedAsync(tally.TallyId); - var challengeResponse = await _challengeResponseService.GetCountByTallyAsync(tally.TallyId); - - return challengeResponse == joinedGuardians; - } - #endregion - - #region Run Steps - - private async Task StartTally(TallyRecord tally) - { - await _tallyService.UpdateStateAsync(tally.TallyId, TallyState.TallyStarted); - } - - private async Task RespondChallenge(TallyRecord tally) - { - await _tallyManager.ComputeChallengeResponse( - _authenticationService.UserName!, - tally); - } - - private async Task DecryptShares(TallyRecord tally) - { - await _tallyManager.DecryptShare( - _authenticationService.UserName!, - tally - ); - } - - private async Task VerifyChallenge(TallyRecord tally) - { - await _tallyService.UpdateStateAsync(tally.TallyId, TallyState.AdminVerifyChallenge); - - await _tallyManager.ValidateChallengeResponse(tally); - - await _tallyService.UpdateStateAsync(tally.TallyId, TallyState.Complete); - } - - private async Task GenerateChallenge(TallyRecord tally) - { - await _tallyService.UpdateStateAsync(tally.TallyId, TallyState.AdminGenerateChallenge); - - await _tallyManager.CreateChallenge(tally); - - await _tallyService.UpdateStateAsync(tally.TallyId, TallyState.PendingGuardianRespondChallenge); - } - - private async Task AccumulateTally(TallyRecord tally) - { - await _tallyService.UpdateStateAsync(tally.TallyId, TallyState.AdminAccumulateTally); - - await _tallyManager.AccumulateAllUploadTallies(tally); - - await _tallyService.UpdateStateAsync(tally.TallyId, TallyState.PendingGuardianDecryptShares); - } - - #endregion - - private void GenerateGuardianSteps() - { - var guardianSteps = new List>() - { - new() - { - State = TallyState.PendingGuardianDecryptShares, - ShouldRunStep = ShouldDecryptShares, - RunStep = DecryptShares, - }, - new() - { - State = TallyState.PendingGuardianRespondChallenge, - ShouldRunStep = ShouldRespondChallenge, - RunStep = RespondChallenge, - }, - }; - - _steps.Add(false, guardianSteps); - } - private void GenerateAdminSteps() - { - var adminSteps = new List>() - { - new() - { - State = TallyState.PendingGuardiansJoin, - ShouldRunStep = ShouldAutoStartTally, - RunStep = StartTally, - }, - new() - { - State = TallyState.TallyStarted, - ShouldRunStep = StateMachineStep.AlwaysRun, - RunStep = AccumulateTally, - }, - new() - { - State = TallyState.PendingGuardianDecryptShares, - ShouldRunStep = ShouldGenerateChallenge, - RunStep = GenerateChallenge, - }, - new() - { - State = TallyState.PendingGuardianRespondChallenge, - ShouldRunStep = ShouldVerifyChallenge, - RunStep = VerifyChallenge, - }, - - // these are error states, allowing the tally to continue if failure occurs - new() - { - State = TallyState.AdminAccumulateTally, - ShouldRunStep = StateMachineStep.AlwaysRun, - RunStep = AccumulateTally, - }, - new() - { - State = TallyState.AdminGenerateChallenge, - ShouldRunStep = StateMachineStep < TallyState, TallyRecord >.AlwaysRun, - RunStep = GenerateChallenge, - }, - new() - { - State = TallyState.AdminVerifyChallenge, - ShouldRunStep = StateMachineStep < TallyState, TallyRecord >.AlwaysRun, - RunStep = VerifyChallenge, - } - }; - - _steps.Add(true, adminSteps); - } -} +using System.Threading; +using ElectionGuard.Decryption.Shares; +using ElectionGuard.ElectionSetup; +using ElectionGuard.UI.Lib.Models; + +namespace ElectionGuard.UI.Services; + +public class TallyStateMachine : ITallyStateMachine +{ + private Dictionary>> _steps = new(); + + private IAuthenticationService _authenticationService; + private readonly ChallengeResponseService _challengeResponseService; + private readonly DecryptionShareService _decryptionShareService; + private readonly TallyJoinedService _tallyJoinedService; + private readonly TallyService _tallyService; + private TallyManager _tallyManager; + + public TallyStateMachine( + IAuthenticationService authenticationService, + ChallengeResponseService challengeResponseService, + DecryptionShareService decryptionShareService, + TallyService tallyService, + TallyManager tallyManager, + TallyJoinedService tallyJoinedService) + { + _authenticationService = authenticationService; + _challengeResponseService = challengeResponseService; + _decryptionShareService = decryptionShareService; + _tallyService = tallyService; + _tallyJoinedService = tallyJoinedService; + _tallyManager = tallyManager; + GenerateGuardianSteps(); + GenerateAdminSteps(); + } + + public async Task Run(TallyRecord tally) + { + bool ran = false; + string label = $"Electionguard.UI.TallyStateMachine-{_authenticationService.UserName}"; + + using var mutex = new Mutex(true, label, out var owned); + if (owned) + { + try + { + if (mutex.WaitOne(10)) + { + Task.WaitAll(RunAsync(tally)); + ran = true; + } + } + catch (AbandonedMutexException) + { + mutex.ReleaseMutex(); + } + catch + { + throw; + } + finally + { + mutex.ReleaseMutex(); + } + } + return ran; + } + + private async Task RunAsync(TallyRecord tally) + { + try + { + var steps = _steps[_authenticationService.IsAdmin]; + var currentStep = steps.SingleOrDefault(s => s.State == tally.State); + if (currentStep is not null && await currentStep.ShouldRunStep(tally)) + { + await currentStep.RunStep(tally); + } + } + catch (Exception) + { + throw; + } + } + + + + #region Should Run + private async Task ShouldAutoStartTally(TallyRecord tally) + { + const bool GUARDIAN_JOINED_TALLY = true; + + var joinedGuardians = await _tallyJoinedService.GetGuardianCountByTallyAsync(tally.TallyId); + joinedGuardians.TryGetValue(GUARDIAN_JOINED_TALLY, out var consentCount); + joinedGuardians.TryGetValue(!GUARDIAN_JOINED_TALLY, out var rejectCount); + + var isQuorumReached = consentCount >= tally.Quorum; + var haveAllGuardiansJoined = (consentCount + rejectCount) == tally.NumberOfGuardians; + + return isQuorumReached && haveAllGuardiansJoined; + } + + private async Task ShouldDecryptShares(TallyRecord tally) + { + return !await _decryptionShareService.GetExistsByTallyAsync(tally.TallyId, _authenticationService.UserName ?? string.Empty); + } + + private async Task ShouldGenerateChallenge(TallyRecord tally) + { + var joinedGuardians = await _tallyJoinedService.GetCountByTallyJoinedAsync(tally.TallyId); + var decryptionShares = await _decryptionShareService.GetCountByTallyAsync(tally.TallyId); + + return decryptionShares == joinedGuardians; + } + + private async Task ShouldRespondChallenge(TallyRecord tally) + { + return !await _challengeResponseService.GetExistsByTallyAsync( + tally.TallyId, + _authenticationService.UserName ?? string.Empty); + } + + private async Task ShouldVerifyChallenge(TallyRecord tally) + { + var joinedGuardians = await _tallyJoinedService.GetCountByTallyJoinedAsync(tally.TallyId); + var challengeResponse = await _challengeResponseService.GetCountByTallyAsync(tally.TallyId); + + return challengeResponse == joinedGuardians; + } + #endregion + + #region Run Steps + + private async Task StartTally(TallyRecord tally) + { + await _tallyService.UpdateStateAsync(tally.TallyId, TallyState.TallyStarted); + } + + private async Task RespondChallenge(TallyRecord tally) + { + await _tallyManager.ComputeChallengeResponse( + _authenticationService.UserName!, + tally); + } + + private async Task DecryptShares(TallyRecord tally) + { + await _tallyManager.DecryptShare( + _authenticationService.UserName!, + tally + ); + } + + private async Task VerifyChallenge(TallyRecord tally) + { + await _tallyService.UpdateStateAsync(tally.TallyId, TallyState.AdminVerifyChallenge); + + await _tallyManager.ValidateChallengeResponse(tally); + + await _tallyService.UpdateStateAsync(tally.TallyId, TallyState.Complete); + } + + private async Task GenerateChallenge(TallyRecord tally) + { + await _tallyService.UpdateStateAsync(tally.TallyId, TallyState.AdminGenerateChallenge); + + await _tallyManager.CreateChallenge(tally); + + await _tallyService.UpdateStateAsync(tally.TallyId, TallyState.PendingGuardianRespondChallenge); + } + + private async Task AccumulateTally(TallyRecord tally) + { + await _tallyService.UpdateStateAsync(tally.TallyId, TallyState.AdminAccumulateTally); + + await _tallyManager.AccumulateAllUploadTallies(tally); + + await _tallyService.UpdateStateAsync(tally.TallyId, TallyState.PendingGuardianDecryptShares); + } + + #endregion + + private void GenerateGuardianSteps() + { + var guardianSteps = new List>() + { + new() + { + State = TallyState.PendingGuardianDecryptShares, + ShouldRunStep = ShouldDecryptShares, + RunStep = DecryptShares, + }, + new() + { + State = TallyState.PendingGuardianRespondChallenge, + ShouldRunStep = ShouldRespondChallenge, + RunStep = RespondChallenge, + }, + }; + + _steps.Add(false, guardianSteps); + } + private void GenerateAdminSteps() + { + var adminSteps = new List>() + { + new() + { + State = TallyState.PendingGuardiansJoin, + ShouldRunStep = ShouldAutoStartTally, + RunStep = StartTally, + }, + new() + { + State = TallyState.TallyStarted, + ShouldRunStep = StateMachineStep.AlwaysRun, + RunStep = AccumulateTally, + }, + new() + { + State = TallyState.PendingGuardianDecryptShares, + ShouldRunStep = ShouldGenerateChallenge, + RunStep = GenerateChallenge, + }, + new() + { + State = TallyState.PendingGuardianRespondChallenge, + ShouldRunStep = ShouldVerifyChallenge, + RunStep = VerifyChallenge, + }, + + // these are error states, allowing the tally to continue if failure occurs + new() + { + State = TallyState.AdminAccumulateTally, + ShouldRunStep = StateMachineStep.AlwaysRun, + RunStep = AccumulateTally, + }, + new() + { + State = TallyState.AdminGenerateChallenge, + ShouldRunStep = StateMachineStep < TallyState, TallyRecord >.AlwaysRun, + RunStep = GenerateChallenge, + }, + new() + { + State = TallyState.AdminVerifyChallenge, + ShouldRunStep = StateMachineStep < TallyState, TallyRecord >.AlwaysRun, + RunStep = VerifyChallenge, + } + }; + + _steps.Add(true, adminSteps); + } +} diff --git a/src/electionguard-ui/ElectionGuard.UI/ViewModels/AdminHomeViewModel.cs b/src/electionguard-ui/ElectionGuard.UI/ViewModels/AdminHomeViewModel.cs index f847e1f8f..57df6f6ae 100644 --- a/src/electionguard-ui/ElectionGuard.UI/ViewModels/AdminHomeViewModel.cs +++ b/src/electionguard-ui/ElectionGuard.UI/ViewModels/AdminHomeViewModel.cs @@ -1,15 +1,15 @@ using CommunityToolkit.Mvvm.Input; -using ElectionGuard.UI.Lib.Extensions; - +using ElectionGuard.ElectionSetup.Extensions; + namespace ElectionGuard.UI.ViewModels; public partial class AdminHomeViewModel : BaseViewModel -{ +{ private readonly KeyCeremonyService _keyCeremonyService; - private readonly ElectionService _electionService; - private readonly MultiTallyService _multiTallyService; - private readonly TallyService _tallyService; - + private readonly ElectionService _electionService; + private readonly MultiTallyService _multiTallyService; + private readonly TallyService _tallyService; + [ObservableProperty] private ObservableCollection _elections = new(); @@ -24,17 +24,17 @@ public partial class AdminHomeViewModel : BaseViewModel [NotifyCanExecuteChangedFor(nameof(CreateMultipleTalliesCommand))] private bool _canCreateMultiTally = false; - [ObservableProperty] - private ObservableCollection _multiTallies = new(); + [ObservableProperty] + private ObservableCollection _multiTallies = new(); [ObservableProperty] private Election? _currentElection; [ObservableProperty] - private KeyCeremonyRecord? _currentKeyCeremony; - - [ObservableProperty] - private MultiTallyRecord? _currentMultiTally; + private KeyCeremonyRecord? _currentKeyCeremony; + + [ObservableProperty] + private MultiTallyRecord? _currentMultiTally; public AdminHomeViewModel( IServiceProvider serviceProvider, @@ -50,65 +50,65 @@ public AdminHomeViewModel( } public override async Task OnAppearing() - { - await base.OnAppearing(); - + { + await base.OnAppearing(); + var keyCeremonies = await _keyCeremonyService.GetAllAsync(); - if (keyCeremonies is not null) - { - var keyCeremoniesInProgress = keyCeremonies.Where(ceremony => ceremony.State != KeyCeremonyState.Complete).ToList(); - var keyCeremoniesCompleted = keyCeremonies.Count - keyCeremoniesInProgress.Count; - // only incomplete key ceremonies - KeyCeremonies = new ObservableCollection(keyCeremoniesInProgress); - HasCompletedKeyCeremonies = keyCeremoniesCompleted > 0; + if (keyCeremonies is not null) + { + var keyCeremoniesInProgress = keyCeremonies.Where(ceremony => ceremony.State != KeyCeremonyState.Complete).ToList(); + var keyCeremoniesCompleted = keyCeremonies.Count - keyCeremoniesInProgress.Count; + // only incomplete key ceremonies + KeyCeremonies = new ObservableCollection(keyCeremoniesInProgress); + HasCompletedKeyCeremonies = keyCeremoniesCompleted > 0; } - var elections = await _electionService.GetAllAsync(); - - if (elections is not null) - { - Elections = new ObservableCollection(elections); - CanCreateMultiTally = Elections.Count > 1; + var elections = await _electionService.GetAllAsync(); + + if (elections is not null) + { + Elections = new ObservableCollection(elections); + CanCreateMultiTally = Elections.Count > 1; } - var multiTallies = await _multiTallyService.GetAllAsync(); - var newMultiTallies = new List(); - foreach (var multiTally in multiTallies) - { - var addMultiTally = false; - - // check each tally in the multitally to see if any are not complete / abandoned - foreach (var (tallyId, _, _) in multiTally.TallyIds) - { - if (await _tallyService.IsRunningByTallyIdAsync(tallyId)) - { - addMultiTally = true; - break; - } - } - if (addMultiTally) - { - newMultiTallies.Add(multiTally); - } - } - - MultiTallies.Clear(); - MultiTallies.AddRange(newMultiTallies); - } - - partial void OnCurrentMultiTallyChanged(MultiTallyRecord? value) - { - if (value == null) - { - return; - } - - MainThread.BeginInvokeOnMainThread(async () => - await NavigationService.GoToPage(typeof(TallyProcessViewModel), new() - { - { CreateMultiTallyViewModel.MultiTallyIdParam, value.MultiTallyId! } - })); - } + var multiTallies = await _multiTallyService.GetAllAsync(); + var newMultiTallies = new List(); + foreach (var multiTally in multiTallies) + { + var addMultiTally = false; + + // check each tally in the multitally to see if any are not complete / abandoned + foreach (var (tallyId, _, _) in multiTally.TallyIds) + { + if (await _tallyService.IsRunningByTallyIdAsync(tallyId)) + { + addMultiTally = true; + break; + } + } + if (addMultiTally) + { + newMultiTallies.Add(multiTally); + } + } + + MultiTallies.Clear(); + MultiTallies.AddRange(newMultiTallies); + } + + partial void OnCurrentMultiTallyChanged(MultiTallyRecord? value) + { + if (value == null) + { + return; + } + + MainThread.BeginInvokeOnMainThread(async () => + await NavigationService.GoToPage(typeof(TallyProcessViewModel), new() + { + { CreateMultiTallyViewModel.MultiTallyIdParam, value.MultiTallyId! } + })); + } [RelayCommand(AllowConcurrentExecutions = true)] diff --git a/src/electionguard-ui/ElectionGuard.UI/ViewModels/BallotUploadPanel.cs b/src/electionguard-ui/ElectionGuard.UI/ViewModels/BallotUploadPanel.cs index 8f066d0b8..145f2cb3a 100644 --- a/src/electionguard-ui/ElectionGuard.UI/ViewModels/BallotUploadPanel.cs +++ b/src/electionguard-ui/ElectionGuard.UI/ViewModels/BallotUploadPanel.cs @@ -1,8 +1,8 @@ -namespace ElectionGuard.UI.ViewModels; - -public enum BallotUploadPanel -{ - AutoUpload, - ManualUpload, - Results -} +namespace ElectionGuard.UI.ViewModels; + +public enum BallotUploadPanel +{ + AutoUpload, + ManualUpload, + Results +} diff --git a/src/electionguard-ui/ElectionGuard.UI/ViewModels/BallotUploadViewModel.cs b/src/electionguard-ui/ElectionGuard.UI/ViewModels/BallotUploadViewModel.cs index c8f8ea1f0..6b0c45e3e 100644 --- a/src/electionguard-ui/ElectionGuard.UI/ViewModels/BallotUploadViewModel.cs +++ b/src/electionguard-ui/ElectionGuard.UI/ViewModels/BallotUploadViewModel.cs @@ -1,508 +1,508 @@ -using System.Text; -using System.Text.Json; -using CommunityToolkit.Maui.Storage; -using CommunityToolkit.Mvvm.Input; -using ElectionGuard.Decryption; -using ElectionGuard.Decryption.Tally; - -namespace ElectionGuard.UI.ViewModels; - -[QueryProperty(ElectionIdParam, nameof(ElectionId))] -public partial class BallotUploadViewModel : BaseViewModel -{ - public const string ElectionIdParam = "ElectionId"; - private const string _artifactSubFolder = "artifacts"; - private const string _contextFilename = "context.json"; - private const string _ballotSubFolder = "encrypted_ballots"; - private readonly string[] _deviceFolderNames = { "devices", "encryption_devices" }; - - [ObservableProperty] - private string _electionId = string.Empty; - - [ObservableProperty] - private string _fileErrorMessage = string.Empty; - - [ObservableProperty] - private string _folderErrorMessage = string.Empty; - - [ObservableProperty] - private BallotUploadPanel _showPanel = BallotUploadPanel.AutoUpload; - - [ObservableProperty] - [NotifyCanExecuteChangedFor(nameof(UploadCommand))] - private string _deviceFile = string.Empty; - - [ObservableProperty] - [NotifyCanExecuteChangedFor(nameof(UploadCommand))] - private string _ballotFolder = string.Empty; - - [ObservableProperty] - private string _ballotFolderName = string.Empty; - - [ObservableProperty] - private string _resultsText = string.Empty; - - [ObservableProperty] - private string _uploadText = string.Empty; - - private uint _serialNumber; - - private ElementModQ? _manifestHash; - - private InternalManifest? _internalManifest; - - private CiphertextElectionContext? _context; - - partial void OnElectionIdChanged(string value) - { - _ = Task.Run(async () => - { - var record = await _manifestService.GetByElectionIdAsync(value); - using var manifest = new Manifest(record?.ManifestData); - _internalManifest = new InternalManifest(manifest); - _manifestHash = new(_internalManifest.ManifestHash); - - var contextRecord = await _contextService.GetByElectionIdAsync(value); - _context = new CiphertextElectionContext(contextRecord?.ContextData); - }); - } - - [RelayCommand] - private void Manual() - { - ShowPanel = BallotUploadPanel.ManualUpload; - _timer?.Stop(); - } - - [RelayCommand] - private void Auto() - { - ShowPanel = BallotUploadPanel.AutoUpload; - _timer?.Start(); - } - - [RelayCommand] - private async Task Cancel() - { - await NavigationService.GoToPage(typeof(ElectionViewModel), new() { { ElectionViewModel.ElectionIdParam, ElectionId } }); - } - - private async Task ReadFileAsync(string path, CancellationToken cancellationToken = new()) - { - if (!File.Exists(path)) - { - return string.Empty; - } - - using var stream = new StreamReader(path, Encoding.UTF8); - return await stream.ReadToEndAsync(cancellationToken); - } - - private static string RemoveSpoiled(string ballotData) - { - return ballotData.Replace("\"state\":3,", "\"state\":2,"); - } - - [RelayCommand(CanExecute = nameof(CanUpload))] - private async Task Upload() - { - // create the device file - var deviceData = await ReadFileAsync(DeviceFile); - - // TODO: enhance the EncryptionDevice object to have this info coming out of the json constructor - var deviceDocument = JsonDocument.Parse(deviceData); - var location = string.Empty; - long deviceId = -1; - long sessionId = -1; - long launchCode = -1; - - using (var jsonDoc = JsonDocument.Parse(deviceData)) - { - location = jsonDoc.RootElement.GetProperty("location").GetString(); - deviceId = jsonDoc.RootElement.GetProperty("device_id").GetInt64(); - sessionId = jsonDoc.RootElement.GetProperty("session_id").GetInt64(); - launchCode = jsonDoc.RootElement.GetProperty("launch_code").GetInt64(); - } - - // save the ballot upload - var ballots = Directory.GetFiles(BallotFolder); - if (ballots.Length == 0) - { - _logger.LogWarning($"0 ballots in {nameof(BallotFolder)}: {BallotFolder}"); - return; - } - - BallotUpload upload = new() - { - ElectionId = ElectionId, - DeviceFileName = DeviceFile, - DeviceFileContents = deviceData, - Location = location, - DeviceId = deviceId, - SessionId = sessionId, - LaunchCode = launchCode, - BallotCount = ballots.LongLength, - SerialNumber = _serialNumber, - CreatedBy = UserName, - }; - - var totalCount = 0L; - var totalImported = 0L; - var totalDuplicated = 0L; - var totalRejected = 0L; - var totalChallenged = 0L; - var totalSpoiled = 0L; - var startDate = ulong.MaxValue; - var endDate = ulong.MinValue; - object tallyLock = new(); - - using var mediator = new TallyMediator(); - using var ciphertextTally = mediator.CreateTally(Guid.NewGuid().ToString(), - "subtally", - _context!, - _internalManifest!); - - UploadText = $"{AppResources.Uploading} {ballots.Length} {AppResources.Success2Text}"; - - await Parallel.ForEachAsync(ballots, async (currentBallot, cancellationToken) => - { - try - { - var filename = Path.GetFileName(currentBallot); - var ballotOriginalData = await ReadFileAsync(currentBallot, cancellationToken); - var ballotData = RemoveSpoiled(ballotOriginalData); - using var ballot = new CiphertextBallot(ballotData); - - if (ballot.Timestamp < startDate) - { - _ = Interlocked.Exchange(ref startDate, ballot.Timestamp); - } - if (ballot.Timestamp > endDate) - { - _ = Interlocked.Exchange(ref endDate, ballot.Timestamp); - } - - if (ballot.ManifestHash != _manifestHash) - { - _ = Interlocked.Increment(ref totalRejected); - return; - } - - var exists = await _ballotService.BallotExistsAsync(ballot.BallotCode.ToHex()); - if (!exists) - { - BallotRecord ballotRecord = new() - { - ElectionId = ElectionId, - TimeStamp = DateTime.UnixEpoch.AddSeconds(ballot.Timestamp), - UploadId = upload.UploadId, - FileName = filename, - BallotCode = ballot.BallotCode.ToHex(), - BallotState = ballot.State, - BallotData = ballotData - }; - _ = await _ballotService.SaveAsync(ballotRecord); - - - _ = ballot.State switch - { - BallotBoxState.Cast => Interlocked.Increment(ref totalImported), - BallotBoxState.Challenged => Interlocked.Increment(ref totalChallenged), - BallotBoxState.Spoiled => Interlocked.Increment(ref totalSpoiled), - BallotBoxState.NotSet => throw new NotImplementedException(), - BallotBoxState.Unknown => throw new NotImplementedException(), - _ => throw new NotImplementedException() - }; - - lock (tallyLock) - { - var result = ciphertextTally.Accumulate(ballot, true); - } - } - else - { - _ = Interlocked.Increment(ref totalDuplicated); - } - - _ = Interlocked.Increment(ref totalCount); - UploadText = $"{AppResources.SuccessText} {totalCount} / {ballots.Length} {AppResources.Success2Text}"; - } - catch (Exception ex) - { - _ = Interlocked.Increment(ref totalRejected); - _logger.LogWarning(ex, "Ballot being rejected {currentBallot}", currentBallot); - } - }); - - // update totals before saving - upload.BallotCount = totalCount; - upload.BallotImported = totalImported; - upload.BallotDuplicated = totalDuplicated; - upload.BallotRejected = totalRejected; - upload.BallotSpoiled = totalSpoiled; - upload.BallotChallenged = totalChallenged; - - upload.BallotsStart = DateTime.UnixEpoch.AddSeconds(startDate); - upload.BallotsEnd = DateTime.UnixEpoch.AddSeconds(endDate); - - try - { - _ = await _uploadService.SaveAsync(upload); - _timer?.Stop(); - ResultsText = $"{AppResources.SuccessText} {totalCount} {AppResources.Success2Text}"; - ShowPanel = BallotUploadPanel.Results; - - if (totalChallenged + totalImported > 0) - { - var record = new ElectionGuard.UI.Lib.Models.CiphertextTallyRecord() - { - ElectionId = ElectionId, - UploadId = upload.UploadId!, - IsExportable = false, - CiphertextTallyData = ciphertextTally.ToJson() - }; - _ = await _ciphertextTallyService.SaveAsync(record); - } - } - catch (Exception) - { - } - } - - private bool CanUpload() - { - return DeviceFile != string.Empty && BallotFolder != string.Empty; - } - - [RelayCommand] - private async Task PickDeviceFile() - { - FileErrorMessage = string.Empty; - var options = new PickOptions() { PickerTitle = AppResources.SelectManifest }; - - var file = await FilePicker.PickAsync(options); - if (file == null) - { - FileErrorMessage = "No file was picked"; - // if the picking was canceled then do not change anything - return; - } - // check if it is a device file. If it's not, this will throw an exception. - try - { - var data = await ReadFileAsync(file.FullPath); - EncryptionDevice device = new(data); - DeviceFile = file.FullPath; - } - catch (Exception) - { - FileErrorMessage = "File is not a device file"; - } - } - - [RelayCommand] - private async Task PickBallotFolder() - { - CancellationToken token = new(); - try - { - var folder = await FolderPicker.Default.PickAsync(token); - BallotFolder = folder.Folder!.Path; - BallotFolderName = folder.Folder.Name; - FolderErrorMessage = folder.Exception?.Message ?? string.Empty; - // verify folder - } - catch (Exception ex) - { - BallotFolder = string.Empty; - BallotFolderName = string.Empty; - FolderErrorMessage = ex.Message; - } - } - - [RelayCommand] - private void UploadMore() - { - ShowPanel = BallotUploadPanel.AutoUpload; - ResultsText = string.Empty; - UploadText = string.Empty; - _lastDrive = -1; - _timer?.Start(); - } - - private readonly BallotUploadService _uploadService; - private readonly BallotService _ballotService; - private readonly ManifestService _manifestService; - private readonly ContextService _contextService; - private readonly CiphertextTallyService _ciphertextTallyService; - private bool _importing; - private long _lastDrive = -1; - - public BallotUploadViewModel(IServiceProvider serviceProvider, - BallotUploadService uploadService, - BallotService ballotService, - ManifestService manifestService, - ContextService contextService, - CiphertextTallyService ciphertextTallyService, - ILogger logger) : base("BallotUploadText", serviceProvider) - { - _logger = logger; - _uploadService = uploadService; - _ballotService = ballotService; - _manifestService = manifestService; - _contextService = contextService; - _ciphertextTallyService = ciphertextTallyService; - - _timer!.Tick += _timer_Tick; - _timer?.Start(); - } - - private void _timer_Tick(object? sender, EventArgs e) - { - if (_importing) - { - return; - } - _importing = true; - - _ = Task.Run(async () => - { - // check for a usb drive - var drives = DriveInfo.GetDrives(); - foreach (var drive in drives) - { - if (drive.DriveType == DriveType.Removable && drive.IsReady && drive.VolumeLabel.ToLower() == "egdrive") - { - _serialNumber = 0; - _ = StorageUtils.GetVolumeInformation(drive.Name, out _serialNumber); - - if (_serialNumber == _lastDrive) - { - _importing = false; - return; - } - - var used = await _uploadService.DriveUsed(_serialNumber, ElectionId); - if (used) - { - await Shell.Current.CurrentPage.Dispatcher.DispatchAsync(async () => - { - var answer = await Shell.Current.CurrentPage.DisplayAlert(AppResources.DriveUsedText, AppResources.ImportAgainText, AppResources.YesText, AppResources.NoText); - if (!answer) - { - _lastDrive = _serialNumber; - _importing = false; - return; - } - }); - } - - var devicePath = GetDevicesPath(drive); - if (string.IsNullOrEmpty(devicePath)) - { - _importing = false; - return; - } - - if (await ValidateElectionId(drive, _manifestHash!) == false) - { - ErrorMessage = AppResources.WrongElectionText; - _importing = false; - return; - } - else - { - ErrorMessage = string.Empty; - } - - // find device file - var devices = Directory.GetFiles(devicePath); - foreach (var device in devices) - { - try - { - var data = await ReadFileAsync(device); - EncryptionDevice dev = new(data); - DeviceFile = device; - break; - } - catch (Exception) - { - _logger.LogInformation($"file {device} is not an EncryptionDevice"); - } - } - - // find submitted ballots folder - var ballotPath = Path.Combine(drive.Name, _artifactSubFolder, _ballotSubFolder); - if (!Directory.Exists(ballotPath)) - { - DeviceFile = string.Empty; - _importing = false; - return; - } - - try - { - Shell.Current.CurrentPage.Dispatcher.Dispatch(() => - { - BallotFolder = ballotPath; - }); - await Task.Run(Upload).ContinueWith((i) => - { - _importing = false; - }); - } - catch (Exception) - { - throw; - } - - } - } - _importing = false; - }); - } - - private string GetDevicesPath(DriveInfo drive) - { - foreach (var deviceFolderName in _deviceFolderNames) - { - var devicePath = Path.Combine(drive.Name, _artifactSubFolder, deviceFolderName); - if (Directory.Exists(devicePath)) - { - return devicePath; - } - } - - // If we get here, we didn't find a device folder. - return string.Empty; - } - - private async Task ValidateElectionId(DriveInfo drive, ElementModQ electionHash) - { - var filePath = Path.Combine(drive.Name, _artifactSubFolder, _contextFilename); - if (File.Exists(filePath)) - { - var contextData = await ReadFileAsync(filePath); - var context = new CiphertextElectionContext(contextData); - return context.ManifestHash.Equals(electionHash); - } - return false; - } - - public override async Task OnAppearing() - { - await base.OnAppearing(); - } - - public override async Task OnLeavingPage() - { - _internalManifest?.Dispose(); - _manifestHash?.Dispose(); - _context?.Dispose(); - - _timer?.Stop(); - _timer!.Tick -= _timer_Tick; - await base.OnLeavingPage(); - } -} +using System.Text; +using System.Text.Json; +using CommunityToolkit.Maui.Storage; +using CommunityToolkit.Mvvm.Input; +using ElectionGuard.Decryption; +using ElectionGuard.Decryption.Tally; + +namespace ElectionGuard.UI.ViewModels; + +[QueryProperty(ElectionIdParam, nameof(ElectionId))] +public partial class BallotUploadViewModel : BaseViewModel +{ + public const string ElectionIdParam = "ElectionId"; + private const string _artifactSubFolder = "artifacts"; + private const string _contextFilename = "context.json"; + private const string _ballotSubFolder = "encrypted_ballots"; + private readonly string[] _deviceFolderNames = { "devices", "encryption_devices" }; + + [ObservableProperty] + private string _electionId = string.Empty; + + [ObservableProperty] + private string _fileErrorMessage = string.Empty; + + [ObservableProperty] + private string _folderErrorMessage = string.Empty; + + [ObservableProperty] + private BallotUploadPanel _showPanel = BallotUploadPanel.AutoUpload; + + [ObservableProperty] + [NotifyCanExecuteChangedFor(nameof(UploadCommand))] + private string _deviceFile = string.Empty; + + [ObservableProperty] + [NotifyCanExecuteChangedFor(nameof(UploadCommand))] + private string _ballotFolder = string.Empty; + + [ObservableProperty] + private string _ballotFolderName = string.Empty; + + [ObservableProperty] + private string _resultsText = string.Empty; + + [ObservableProperty] + private string _uploadText = string.Empty; + + private uint _serialNumber; + + private ElementModQ? _manifestHash; + + private InternalManifest? _internalManifest; + + private CiphertextElectionContext? _context; + + partial void OnElectionIdChanged(string value) + { + _ = Task.Run(async () => + { + var record = await _manifestService.GetByElectionIdAsync(value); + using var manifest = new Manifest(record?.ManifestData); + _internalManifest = new InternalManifest(manifest); + _manifestHash = new(_internalManifest.ManifestHash); + + var contextRecord = await _contextService.GetByElectionIdAsync(value); + _context = new CiphertextElectionContext(contextRecord?.ContextData); + }); + } + + [RelayCommand] + private void Manual() + { + ShowPanel = BallotUploadPanel.ManualUpload; + _timer?.Stop(); + } + + [RelayCommand] + private void Auto() + { + ShowPanel = BallotUploadPanel.AutoUpload; + _timer?.Start(); + } + + [RelayCommand] + private async Task Cancel() + { + await NavigationService.GoToPage(typeof(ElectionViewModel), new() { { ElectionViewModel.ElectionIdParam, ElectionId } }); + } + + private async Task ReadFileAsync(string path, CancellationToken cancellationToken = new()) + { + if (!File.Exists(path)) + { + return string.Empty; + } + + using var stream = new StreamReader(path, Encoding.UTF8); + return await stream.ReadToEndAsync(cancellationToken); + } + + private static string RemoveSpoiled(string ballotData) + { + return ballotData.Replace("\"state\":3,", "\"state\":2,"); + } + + [RelayCommand(CanExecute = nameof(CanUpload))] + private async Task Upload() + { + // create the device file + var deviceData = await ReadFileAsync(DeviceFile); + + // TODO: enhance the EncryptionDevice object to have this info coming out of the json constructor + var deviceDocument = JsonDocument.Parse(deviceData); + var location = string.Empty; + long deviceId = -1; + long sessionId = -1; + long launchCode = -1; + + using (var jsonDoc = JsonDocument.Parse(deviceData)) + { + location = jsonDoc.RootElement.GetProperty("location").GetString(); + deviceId = jsonDoc.RootElement.GetProperty("device_id").GetInt64(); + sessionId = jsonDoc.RootElement.GetProperty("session_id").GetInt64(); + launchCode = jsonDoc.RootElement.GetProperty("launch_code").GetInt64(); + } + + // save the ballot upload + var ballots = Directory.GetFiles(BallotFolder); + if (ballots.Length == 0) + { + _logger.LogWarning($"0 ballots in {nameof(BallotFolder)}: {BallotFolder}"); + return; + } + + BallotUpload upload = new() + { + ElectionId = ElectionId, + DeviceFileName = DeviceFile, + DeviceFileContents = deviceData, + Location = location, + DeviceId = deviceId, + SessionId = sessionId, + LaunchCode = launchCode, + BallotCount = ballots.LongLength, + SerialNumber = _serialNumber, + CreatedBy = UserName, + }; + + var totalCount = 0L; + var totalImported = 0L; + var totalDuplicated = 0L; + var totalRejected = 0L; + var totalChallenged = 0L; + var totalSpoiled = 0L; + var startDate = ulong.MaxValue; + var endDate = ulong.MinValue; + object tallyLock = new(); + + using var mediator = new TallyMediator(); + using var ciphertextTally = mediator.CreateTally(Guid.NewGuid().ToString(), + "subtally", + _context!, + _internalManifest!); + + UploadText = $"{AppResources.Uploading} {ballots.Length} {AppResources.Success2Text}"; + + await Parallel.ForEachAsync(ballots, async (currentBallot, cancellationToken) => + { + try + { + var filename = Path.GetFileName(currentBallot); + var ballotOriginalData = await ReadFileAsync(currentBallot, cancellationToken); + var ballotData = RemoveSpoiled(ballotOriginalData); + using var ballot = new CiphertextBallot(ballotData); + + if (ballot.Timestamp < startDate) + { + _ = Interlocked.Exchange(ref startDate, ballot.Timestamp); + } + if (ballot.Timestamp > endDate) + { + _ = Interlocked.Exchange(ref endDate, ballot.Timestamp); + } + + if (ballot.ManifestHash != _manifestHash) + { + _ = Interlocked.Increment(ref totalRejected); + return; + } + + var exists = await _ballotService.BallotExistsAsync(ballot.BallotCode.ToHex()); + if (!exists) + { + BallotRecord ballotRecord = new() + { + ElectionId = ElectionId, + TimeStamp = DateTime.UnixEpoch.AddSeconds(ballot.Timestamp), + UploadId = upload.UploadId, + FileName = filename, + BallotCode = ballot.BallotCode.ToHex(), + BallotState = ballot.State, + BallotData = ballotData + }; + _ = await _ballotService.SaveAsync(ballotRecord); + + + _ = ballot.State switch + { + BallotBoxState.Cast => Interlocked.Increment(ref totalImported), + BallotBoxState.Challenged => Interlocked.Increment(ref totalChallenged), + BallotBoxState.Spoiled => Interlocked.Increment(ref totalSpoiled), + BallotBoxState.NotSet => throw new NotImplementedException(), + BallotBoxState.Unknown => throw new NotImplementedException(), + _ => throw new NotImplementedException() + }; + + lock (tallyLock) + { + var result = ciphertextTally.Accumulate(ballot, true); + } + } + else + { + _ = Interlocked.Increment(ref totalDuplicated); + } + + _ = Interlocked.Increment(ref totalCount); + UploadText = $"{AppResources.SuccessText} {totalCount} / {ballots.Length} {AppResources.Success2Text}"; + } + catch (Exception ex) + { + _ = Interlocked.Increment(ref totalRejected); + _logger.LogWarning(ex, "Ballot being rejected {currentBallot}", currentBallot); + } + }); + + // update totals before saving + upload.BallotCount = totalCount; + upload.BallotImported = totalImported; + upload.BallotDuplicated = totalDuplicated; + upload.BallotRejected = totalRejected; + upload.BallotSpoiled = totalSpoiled; + upload.BallotChallenged = totalChallenged; + + upload.BallotsStart = DateTime.UnixEpoch.AddSeconds(startDate); + upload.BallotsEnd = DateTime.UnixEpoch.AddSeconds(endDate); + + try + { + _ = await _uploadService.SaveAsync(upload); + _timer?.Stop(); + ResultsText = $"{AppResources.SuccessText} {totalCount} {AppResources.Success2Text}"; + ShowPanel = BallotUploadPanel.Results; + + if (totalChallenged + totalImported > 0) + { + var record = new ElectionGuard.UI.Lib.Models.CiphertextTallyRecord() + { + ElectionId = ElectionId, + UploadId = upload.UploadId!, + IsExportable = false, + CiphertextTallyData = ciphertextTally.ToJson() + }; + _ = await _ciphertextTallyService.SaveAsync(record); + } + } + catch (Exception) + { + } + } + + private bool CanUpload() + { + return DeviceFile != string.Empty && BallotFolder != string.Empty; + } + + [RelayCommand] + private async Task PickDeviceFile() + { + FileErrorMessage = string.Empty; + var options = new PickOptions() { PickerTitle = AppResources.SelectManifest }; + + var file = await FilePicker.PickAsync(options); + if (file == null) + { + FileErrorMessage = "No file was picked"; + // if the picking was canceled then do not change anything + return; + } + // check if it is a device file. If it's not, this will throw an exception. + try + { + var data = await ReadFileAsync(file.FullPath); + EncryptionDevice device = new(data); + DeviceFile = file.FullPath; + } + catch (Exception) + { + FileErrorMessage = "File is not a device file"; + } + } + + [RelayCommand] + private async Task PickBallotFolder() + { + CancellationToken token = new(); + try + { + var folder = await FolderPicker.Default.PickAsync(token); + BallotFolder = folder.Folder!.Path; + BallotFolderName = folder.Folder.Name; + FolderErrorMessage = folder.Exception?.Message ?? string.Empty; + // verify folder + } + catch (Exception ex) + { + BallotFolder = string.Empty; + BallotFolderName = string.Empty; + FolderErrorMessage = ex.Message; + } + } + + [RelayCommand] + private void UploadMore() + { + ShowPanel = BallotUploadPanel.AutoUpload; + ResultsText = string.Empty; + UploadText = string.Empty; + _lastDrive = -1; + _timer?.Start(); + } + + private readonly BallotUploadService _uploadService; + private readonly BallotService _ballotService; + private readonly ManifestService _manifestService; + private readonly ContextService _contextService; + private readonly CiphertextTallyService _ciphertextTallyService; + private bool _importing; + private long _lastDrive = -1; + + public BallotUploadViewModel(IServiceProvider serviceProvider, + BallotUploadService uploadService, + BallotService ballotService, + ManifestService manifestService, + ContextService contextService, + CiphertextTallyService ciphertextTallyService, + ILogger logger) : base("BallotUploadText", serviceProvider) + { + _logger = logger; + _uploadService = uploadService; + _ballotService = ballotService; + _manifestService = manifestService; + _contextService = contextService; + _ciphertextTallyService = ciphertextTallyService; + + _timer!.Tick += _timer_Tick; + _timer?.Start(); + } + + private void _timer_Tick(object? sender, EventArgs e) + { + if (_importing) + { + return; + } + _importing = true; + + _ = Task.Run(async () => + { + // check for a usb drive + var drives = DriveInfo.GetDrives(); + foreach (var drive in drives) + { + if (drive.DriveType == DriveType.Removable && drive.IsReady && drive.VolumeLabel.ToLower() == "egdrive") + { + _serialNumber = 0; + _ = StorageUtils.GetVolumeInformation(drive.Name, out _serialNumber); + + if (_serialNumber == _lastDrive) + { + _importing = false; + return; + } + + var used = await _uploadService.DriveUsed(_serialNumber, ElectionId); + if (used) + { + await Shell.Current.CurrentPage.Dispatcher.DispatchAsync(async () => + { + var answer = await Shell.Current.CurrentPage.DisplayAlert(AppResources.DriveUsedText, AppResources.ImportAgainText, AppResources.YesText, AppResources.NoText); + if (!answer) + { + _lastDrive = _serialNumber; + _importing = false; + return; + } + }); + } + + var devicePath = GetDevicesPath(drive); + if (string.IsNullOrEmpty(devicePath)) + { + _importing = false; + return; + } + + if (await ValidateElectionId(drive, _manifestHash!) == false) + { + ErrorMessage = AppResources.WrongElectionText; + _importing = false; + return; + } + else + { + ErrorMessage = string.Empty; + } + + // find device file + var devices = Directory.GetFiles(devicePath); + foreach (var device in devices) + { + try + { + var data = await ReadFileAsync(device); + EncryptionDevice dev = new(data); + DeviceFile = device; + break; + } + catch (Exception) + { + _logger.LogInformation($"file {device} is not an EncryptionDevice"); + } + } + + // find submitted ballots folder + var ballotPath = Path.Combine(drive.Name, _artifactSubFolder, _ballotSubFolder); + if (!Directory.Exists(ballotPath)) + { + DeviceFile = string.Empty; + _importing = false; + return; + } + + try + { + Shell.Current.CurrentPage.Dispatcher.Dispatch(() => + { + BallotFolder = ballotPath; + }); + await Task.Run(Upload).ContinueWith((i) => + { + _importing = false; + }); + } + catch (Exception) + { + throw; + } + + } + } + _importing = false; + }); + } + + private string GetDevicesPath(DriveInfo drive) + { + foreach (var deviceFolderName in _deviceFolderNames) + { + var devicePath = Path.Combine(drive.Name, _artifactSubFolder, deviceFolderName); + if (Directory.Exists(devicePath)) + { + return devicePath; + } + } + + // If we get here, we didn't find a device folder. + return string.Empty; + } + + private async Task ValidateElectionId(DriveInfo drive, ElementModQ electionHash) + { + var filePath = Path.Combine(drive.Name, _artifactSubFolder, _contextFilename); + if (File.Exists(filePath)) + { + var contextData = await ReadFileAsync(filePath); + var context = new CiphertextElectionContext(contextData); + return context.ManifestHash.Equals(electionHash); + } + return false; + } + + public override async Task OnAppearing() + { + await base.OnAppearing(); + } + + public override async Task OnLeavingPage() + { + _internalManifest?.Dispose(); + _manifestHash?.Dispose(); + _context?.Dispose(); + + _timer?.Stop(); + _timer!.Tick -= _timer_Tick; + await base.OnLeavingPage(); + } +} diff --git a/src/electionguard-ui/ElectionGuard.UI/ViewModels/BaseViewModel.cs b/src/electionguard-ui/ElectionGuard.UI/ViewModels/BaseViewModel.cs index f07459e04..f8da8e032 100644 --- a/src/electionguard-ui/ElectionGuard.UI/ViewModels/BaseViewModel.cs +++ b/src/electionguard-ui/ElectionGuard.UI/ViewModels/BaseViewModel.cs @@ -1,5 +1,5 @@ using CommunityToolkit.Mvvm.Input; -using ElectionGuard.UI.Lib.Extensions; + namespace ElectionGuard.UI.ViewModels; @@ -24,7 +24,7 @@ public partial class BaseViewModel : ObservableObject, IDisposable private string _pageTitle = ""; protected IDispatcherTimer? _timer; - protected ILogger? _logger; + protected ILogger? _logger; private void InitTimer() { @@ -56,13 +56,13 @@ public virtual async Task OnLeavingPage() [RelayCommand] protected async Task Logout() { - if (Shell.Current.CurrentPage as LoginPage is null) - { - _logger?.LogInformation("Logging out as {UserName}", UserName); - await OnLeavingPage(); - await Shell.Current.CurrentPage.Dispatcher.DispatchAsync(async () => - await NavigationService.GoToPage(typeof(LoginViewModel))); - Dispose(); + if (Shell.Current.CurrentPage as LoginPage is null) + { + _logger?.LogInformation("Logging out as {UserName}", UserName); + await OnLeavingPage(); + await Shell.Current.CurrentPage.Dispatcher.DispatchAsync(async () => + await NavigationService.GoToPage(typeof(LoginViewModel))); + Dispose(); } } @@ -70,11 +70,11 @@ await Shell.Current.CurrentPage.Dispatcher.DispatchAsync(async () => private void ChangeLanguage() => LocalizationService.ToggleLanguage(); [RelayCommand(CanExecute = nameof(CanChangeSettings), AllowConcurrentExecutions = true)] - protected async Task Settings() - { - await NavigationService.GoToModal(typeof(SettingsViewModel)); - } - + protected async Task Settings() + { + await NavigationService.GoToModal(typeof(SettingsViewModel)); + } + [RelayCommand(CanExecute = nameof(CanGoHome))] private async Task Home() { diff --git a/src/electionguard-ui/ElectionGuard.UI/ViewModels/ChallengedPopupViewModel.cs b/src/electionguard-ui/ElectionGuard.UI/ViewModels/ChallengedPopupViewModel.cs index d02f38ee0..2de883987 100644 --- a/src/electionguard-ui/ElectionGuard.UI/ViewModels/ChallengedPopupViewModel.cs +++ b/src/electionguard-ui/ElectionGuard.UI/ViewModels/ChallengedPopupViewModel.cs @@ -1,9 +1,9 @@ -using CommunityToolkit.Maui.Core.Extensions; -using CommunityToolkit.Mvvm.Input; -using ElectionGuard.Decryption.Tally; -using MongoDB.Driver; -using Newtonsoft.Json; - +using CommunityToolkit.Maui.Core.Extensions; +using CommunityToolkit.Mvvm.Input; +using ElectionGuard.Decryption.Tally; +using MongoDB.Driver; +using Newtonsoft.Json; + namespace ElectionGuard.UI.ViewModels; public partial class ChallengedPopupViewModel : BaseViewModel @@ -12,8 +12,8 @@ public partial class ChallengedPopupViewModel : BaseViewModel private string _searchText = string.Empty; [ObservableProperty] - private ObservableCollection _filteredBallotList = new(); - + private ObservableCollection _filteredBallotList = new(); + [ObservableProperty] private BallotRecord? _currentBallot = null; @@ -25,47 +25,47 @@ public partial class ChallengedPopupViewModel : BaseViewModel private BallotUploadService _ballotUploadService; private CiphertextTallyService _ciphertextTallyService; - public ChallengedPopupViewModel( - IServiceProvider serviceProvider, - BallotService ballotService, - BallotUploadService ballotUploadService, - CiphertextTallyService ciphertextTallyService) : - base(null, serviceProvider) + public ChallengedPopupViewModel( + IServiceProvider serviceProvider, + BallotService ballotService, + BallotUploadService ballotUploadService, + CiphertextTallyService ciphertextTallyService) : + base(null, serviceProvider) { _ballotService = ballotService; _ballotUploadService = ballotUploadService; _ciphertextTallyService = ciphertextTallyService; } - partial void OnElectionIdChanged(string value) - { - if (!string.IsNullOrEmpty(value)) - { - _ = Shell.Current.CurrentPage.Dispatcher.DispatchAsync(async () => - { - SearchText = string.Empty; - await SetElection(value); - }); - } + partial void OnElectionIdChanged(string value) + { + if (!string.IsNullOrEmpty(value)) + { + _ = Shell.Current.CurrentPage.Dispatcher.DispatchAsync(async () => + { + SearchText = string.Empty; + await SetElection(value); + }); + } } - partial void OnSearchTextChanged(string value) - { - FilteredBallotList = string.IsNullOrWhiteSpace(value) ? - _challengedBallots.ToObservableCollection() : - _challengedBallots.Where(b => b.BallotCode!.StartsWith(value.ToUpper())).ToObservableCollection(); + partial void OnSearchTextChanged(string value) + { + FilteredBallotList = string.IsNullOrWhiteSpace(value) ? + _challengedBallots.ToObservableCollection() : + _challengedBallots.Where(b => b.BallotCode!.StartsWith(value.ToUpper())).ToObservableCollection(); } [RelayCommand] private async Task SpoilBallot() { - if (CurrentBallot is null) - { - return; - } - var answer = await Shell.Current.CurrentPage.DisplayAlert(AppResources.SpoilBallotText, AppResources.SpoilConfirmationText, AppResources.YesText, AppResources.NoText); - if (answer) - { + if (CurrentBallot is null) + { + return; + } + var answer = await Shell.Current.CurrentPage.DisplayAlert(AppResources.SpoilBallotText, AppResources.SpoilConfirmationText, AppResources.YesText, AppResources.NoText); + if (answer) + { // update the ballot data to spoiled var ballot = JsonConvert.DeserializeObject(CurrentBallot.BallotData!); ballot!.Spoil(); @@ -74,9 +74,9 @@ private async Task SpoilBallot() // change the ballot record to spoiled await _ballotService.ConvertToSpoiledByBallotCodeAsync(CurrentBallot.BallotCode!); - - // remove ballot from the list of challenged ballots - _ = _challengedBallots.Remove(CurrentBallot); + + // remove ballot from the list of challenged ballots + _ = _challengedBallots.Remove(CurrentBallot); SearchText = string.Empty; // reset the filtered list back to the entire list @@ -92,13 +92,13 @@ private async Task SpoilBallot() _ = tallyData!.SpoiledBallotIds.Add(ballot!.ObjectId); tally.CiphertextTallyData = tallyData.ToJson(); _ = await _ciphertextTallyService.SaveAsync(tally); - } + } } - public async Task SetElection(string electionId) - { - var challengedBallotCursor = await _ballotService.GetCursorBallotsByElectionIdStateAsync(electionId, BallotBoxState.Challenged); - _challengedBallots = challengedBallotCursor.ToList(); + public async Task SetElection(string electionId) + { + var challengedBallotCursor = await _ballotService.GetCursorBallotsByElectionIdStateAsync(electionId, BallotBoxState.Challenged); + _challengedBallots = challengedBallotCursor.ToList(); FilteredBallotList = _challengedBallots.ToObservableCollection(); } } diff --git a/src/electionguard-ui/ElectionGuard.UI/ViewModels/CreateElectionViewModel.cs b/src/electionguard-ui/ElectionGuard.UI/ViewModels/CreateElectionViewModel.cs index a1c6ead8c..dc17e91b0 100644 --- a/src/electionguard-ui/ElectionGuard.UI/ViewModels/CreateElectionViewModel.cs +++ b/src/electionguard-ui/ElectionGuard.UI/ViewModels/CreateElectionViewModel.cs @@ -1,299 +1,299 @@ -using CommunityToolkit.Mvvm.DependencyInjection; -using CommunityToolkit.Mvvm.Input; -using ElectionGuard.UI.Models; - -namespace ElectionGuard.UI.ViewModels; - -public partial class CreateElectionViewModel : BaseViewModel -{ - private readonly KeyCeremonyService _keyCeremonyService; - private readonly ElectionService _electionService; - private readonly ManifestService _manifestService; - private readonly ContextService _contextService; - private readonly ConstantsService _constantsService; - private const string PageName = "CreateElection"; - - public CreateElectionViewModel(IServiceProvider serviceProvider, - KeyCeremonyService keyCeremonyService, - ElectionService electionService, - ManifestService manifestService, - ContextService contextService, - ConstantsService constantsService, - ILogger logger) : base(PageName, serviceProvider) - { - _keyCeremonyService = keyCeremonyService; - _electionService = electionService; - _manifestService = manifestService; - _contextService = contextService; - _constantsService = constantsService; - _logger = logger; - } - - public override async Task OnAppearing() - { - await base.OnAppearing(); - - try - { - KeyCeremonies = await _keyCeremonyService.GetAllCompleteAsync() ?? new(); - } - catch (Exception e) - { - _logger.LogError($"{nameof(_keyCeremonyService.GetAllCompleteAsync)} error: {e}"); - await Logout(); - } - } - - [ObservableProperty] - private string? _errorMessage; - - [ObservableProperty] - [NotifyCanExecuteChangedFor(nameof(CreateElectionCommand))] - private string? _manifestErrorMessage; - - [ObservableProperty] - [NotifyCanExecuteChangedFor(nameof(CreateElectionCommand))] - private string _electionName = string.Empty; - - [ObservableProperty] - [NotifyCanExecuteChangedFor(nameof(CreateElectionCommand))] - private KeyCeremonyRecord? _keyCeremony = null; - - [ObservableProperty] - private List _keyCeremonies = new(); - - [ObservableProperty] - private string _electionUrl = string.Empty; - - [ObservableProperty] - [NotifyCanExecuteChangedFor(nameof(CreateElectionCommand))] - private string _manifestNames = string.Empty; - - private List _manifestFiles = new(); - - [ObservableProperty] - private bool _isNameEnabled = true; - - [RelayCommand(CanExecute = nameof(CanCreate))] - private async Task CreateElection() - { - ElectionGuardException.ThrowIfNull(KeyCeremony); - ElectionGuardException.ThrowIfNull(KeyCeremony.JointKey); - - var multiple = _manifestFiles.Count > 1; - ErrorMessage = string.Empty; - - await Parallel.ForEachAsync(_manifestFiles, async (file, cancel) => - { - // create an election for each file - try - { - ZipStorageService storageService = new(); - - // create the manifest - using var manifest = new Manifest(File.ReadAllText(file.FullPath)); - var electionName = multiple ? manifest.Name.GetTextAt(0).Value : ElectionName; - - // check if the election name exists - var election = new Election() - { - KeyCeremonyId = KeyCeremony.KeyCeremonyId, - Name = await MakeNameUnique(electionName), - ElectionUrl = ElectionUrl, - CreatedBy = UserName! - }; - - var extendedData = new LinkedList(); - if (!string.IsNullOrWhiteSpace(ElectionUrl)) - { - extendedData.Append("verification_url", ElectionUrl); - } - - // create the context - using var context = extendedData.Count == 0 ? - new CiphertextElectionContext( - (ulong)KeyCeremony.NumberOfGuardians, - (ulong)KeyCeremony.Quorum, - KeyCeremony.JointKey.JointPublicKey, - KeyCeremony.JointKey.CommitmentHash, - manifest.CryptoHash()) : - new CiphertextElectionContext( - (ulong)KeyCeremony.NumberOfGuardians, - (ulong)KeyCeremony.Quorum, - KeyCeremony.JointKey.JointPublicKey, - KeyCeremony.JointKey.CommitmentHash, - manifest.CryptoHash(), extendedData); - - var contextRecord = new ContextRecord() { ElectionId = election.ElectionId, ContextData = context.ToJson() }; - - var constantsRecord = new ConstantsRecord() { ElectionId = election.ElectionId, ConstantsData = Constants.ToJson() }; - - var manifestRecord = new ManifestRecord() { ElectionId = election.ElectionId, ManifestData = manifest.ToJson() }; - - // save the election - _ = await _electionService.SaveAsync(election); - - // save the context - _ = await _contextService.SaveAsync(contextRecord); - - // save the constants - _ = await _constantsService.SaveAsync(constantsRecord); - - // save the manifest - _ = await _manifestService.SaveAsync(manifestRecord); - - if (multiple) - { - // create the export file for each election - // need to add the path from the manifest - var zipPath = file.FullPath.ToLower().Replace(".json", ".zip"); - var encryptionPackage = new EncryptionPackage(contextRecord, constantsRecord, manifestRecord); - storageService.UpdatePath(zipPath); - storageService.ToFiles(encryptionPackage); - } - - if (!multiple) - { - var loadElection = await _electionService.GetByElectionIdAsync(election.ElectionId); - var pageParams = new Dictionary - { - { ElectionViewModel.CurrentElectionParam, loadElection } - }; - await Shell.Current.CurrentPage.Dispatcher.DispatchAsync(async () => - { - await NavigationService.GoToPage(typeof(ElectionViewModel), pageParams); - }); - } - } - catch (Exception) - { - ExceptionHandler.GetData(out var function, out var message, out var code); - ErrorMessage += $"{AppResources.ErrorCreatingElection} - {file.FileName}\n"; - } - }).ContinueWith((t) => - { - if (string.IsNullOrEmpty(ErrorMessage)) - { - // goto the email page or go to the home page - if (multiple) - { - _ = Shell.Current.CurrentPage.Dispatcher.DispatchAsync(() => - { - HomeCommand.Execute(null); - }); - } - } - }); - } - - private async Task MakeNameUnique(string electionName) - { - var count = 2; - var name = electionName; - bool found; - do - { - found = await _electionService.ElectionNameExists(name); - if (found) - { - name = $"{electionName} ({count++})"; - } - } while (found); - return name; - } - - private bool CanCreate() - { - return string.IsNullOrEmpty(ManifestErrorMessage) && _manifestFiles.Any() && ElectionName.Any() && KeyCeremony != null; - } - - [RelayCommand] - private async Task PickManifestFiles() - { - var badFiles = new List(); - var customFileType = new FilePickerFileType( - new Dictionary> - { - { DevicePlatform.WinUI, new[] { ".json" } }, // file extension - { DevicePlatform.macOS, new[] { "json" } }, // UTType values - }); - var options = new PickOptions() { FileTypes = customFileType, PickerTitle = AppResources.SelectManifest }; - var files = await FilePicker.PickMultipleAsync(options); - if (files == null || files.Count() == 0) - { - // if the picking was canceled then do not change anything - return; - } - _manifestFiles.Clear(); - _manifestFiles.AddRange(files); - ManifestErrorMessage = null; - IsNameEnabled = _manifestFiles.Count <= 1; - if (IsNameEnabled) - { - try - { - var data = File.ReadAllText(_manifestFiles.First().FullPath, System.Text.Encoding.UTF8); - using var manifest = new Manifest(data); - - ElectionName = manifest.Name.GetTextAt(0).Value; - } - catch (Exception) - { - ExceptionHandler.GetData(out var function, out var message, out var code); - ManifestErrorMessage = AppResources.ErrorLoadingManifest; - ElectionName = string.Empty; - } - } - else - { - _ = Parallel.ForEach(_manifestFiles, (file) => - { - try - { - using var manifest = new Manifest(File.ReadAllText(file.FullPath)); - if (!manifest.IsValid()) - { - badFiles.Add(file.FileName); - } - } - catch (Exception) - { - badFiles.Add(file.FileName); - } - }); - ElectionName = AppResources.NameFromManifest; - } - - // remove the last ", " - var names = string.Empty; - _manifestFiles.ForEach(file => - { - if (!badFiles.Contains(file.FileName)) - { - names += $"{file.FileName}, "; - } - }); - char[] trim = { ' ', ',' }; - ManifestNames = names.TrimEnd(trim); - - // remove the bad files from the manifest list of files - badFiles.ForEach(file => _manifestFiles.Remove(_manifestFiles.First(f => f.FileName == file))); - if (badFiles.Any()) - { - var message = string.Empty; - badFiles.ForEach(file => message += $"{file}, "); - message = message.TrimEnd(trim); - ManifestErrorMessage = $"{AppResources.ErrorManifest}: {message}\n{AppResources.RemovingList}"; - } - - // commenting out the display of the manifest until we can get it not throwing an exception - //if (_manifestFiles.Count == 1) - //{ - // var vm = (ManifestViewModel)Ioc.Default.GetService(typeof(ManifestViewModel)); - // vm.ManifestFile = _manifestFiles.First().FullPath; - - // await NavigationService.GoToModal(typeof(ManifestViewModel)); - //} - } - -} +using CommunityToolkit.Mvvm.DependencyInjection; +using CommunityToolkit.Mvvm.Input; +using ElectionGuard.UI.Models; + +namespace ElectionGuard.UI.ViewModels; + +public partial class CreateElectionViewModel : BaseViewModel +{ + private readonly KeyCeremonyService _keyCeremonyService; + private readonly ElectionService _electionService; + private readonly ManifestService _manifestService; + private readonly ContextService _contextService; + private readonly ConstantsService _constantsService; + private const string PageName = "CreateElection"; + + public CreateElectionViewModel(IServiceProvider serviceProvider, + KeyCeremonyService keyCeremonyService, + ElectionService electionService, + ManifestService manifestService, + ContextService contextService, + ConstantsService constantsService, + ILogger logger) : base(PageName, serviceProvider) + { + _keyCeremonyService = keyCeremonyService; + _electionService = electionService; + _manifestService = manifestService; + _contextService = contextService; + _constantsService = constantsService; + _logger = logger; + } + + public override async Task OnAppearing() + { + await base.OnAppearing(); + + try + { + KeyCeremonies = await _keyCeremonyService.GetAllCompleteAsync() ?? new(); + } + catch (Exception e) + { + _logger.LogError($"{nameof(_keyCeremonyService.GetAllCompleteAsync)} error: {e}"); + await Logout(); + } + } + + [ObservableProperty] + private string? _errorMessage; + + [ObservableProperty] + [NotifyCanExecuteChangedFor(nameof(CreateElectionCommand))] + private string? _manifestErrorMessage; + + [ObservableProperty] + [NotifyCanExecuteChangedFor(nameof(CreateElectionCommand))] + private string _electionName = string.Empty; + + [ObservableProperty] + [NotifyCanExecuteChangedFor(nameof(CreateElectionCommand))] + private KeyCeremonyRecord? _keyCeremony = null; + + [ObservableProperty] + private List _keyCeremonies = new(); + + [ObservableProperty] + private string _electionUrl = string.Empty; + + [ObservableProperty] + [NotifyCanExecuteChangedFor(nameof(CreateElectionCommand))] + private string _manifestNames = string.Empty; + + private List _manifestFiles = new(); + + [ObservableProperty] + private bool _isNameEnabled = true; + + [RelayCommand(CanExecute = nameof(CanCreate))] + private async Task CreateElection() + { + ElectionGuardException.ThrowIfNull(KeyCeremony); + ElectionGuardException.ThrowIfNull(KeyCeremony.JointKey); + + var multiple = _manifestFiles.Count > 1; + ErrorMessage = string.Empty; + + await Parallel.ForEachAsync(_manifestFiles, async (file, cancel) => + { + // create an election for each file + try + { + ZipStorageService storageService = new(); + + // create the manifest + using var manifest = new Manifest(File.ReadAllText(file.FullPath)); + var electionName = multiple ? manifest.Name.GetTextAt(0).Value : ElectionName; + + // check if the election name exists + var election = new Election() + { + KeyCeremonyId = KeyCeremony.KeyCeremonyId, + Name = await MakeNameUnique(electionName), + ElectionUrl = ElectionUrl, + CreatedBy = UserName! + }; + + var extendedData = new LinkedList(); + if (!string.IsNullOrWhiteSpace(ElectionUrl)) + { + extendedData.Append("verification_url", ElectionUrl); + } + + // create the context + using var context = extendedData.Count == 0 ? + new CiphertextElectionContext( + (ulong)KeyCeremony.NumberOfGuardians, + (ulong)KeyCeremony.Quorum, + KeyCeremony.JointKey.JointPublicKey, + KeyCeremony.JointKey.CommitmentHash, + manifest.CryptoHash()) : + new CiphertextElectionContext( + (ulong)KeyCeremony.NumberOfGuardians, + (ulong)KeyCeremony.Quorum, + KeyCeremony.JointKey.JointPublicKey, + KeyCeremony.JointKey.CommitmentHash, + manifest.CryptoHash(), extendedData); + + var contextRecord = new ContextRecord() { ElectionId = election.ElectionId, ContextData = context.ToJson() }; + + var constantsRecord = new ConstantsRecord() { ElectionId = election.ElectionId, ConstantsData = Constants.ToJson() }; + + var manifestRecord = new ManifestRecord() { ElectionId = election.ElectionId, ManifestData = manifest.ToJson() }; + + // save the election + _ = await _electionService.SaveAsync(election); + + // save the context + _ = await _contextService.SaveAsync(contextRecord); + + // save the constants + _ = await _constantsService.SaveAsync(constantsRecord); + + // save the manifest + _ = await _manifestService.SaveAsync(manifestRecord); + + if (multiple) + { + // create the export file for each election + // need to add the path from the manifest + var zipPath = file.FullPath.ToLower().Replace(".json", ".zip"); + var encryptionPackage = new EncryptionPackage(contextRecord, constantsRecord, manifestRecord); + storageService.UpdatePath(zipPath); + storageService.ToFiles(encryptionPackage); + } + + if (!multiple) + { + var loadElection = await _electionService.GetByElectionIdAsync(election.ElectionId); + var pageParams = new Dictionary + { + { ElectionViewModel.CurrentElectionParam, loadElection } + }; + await Shell.Current.CurrentPage.Dispatcher.DispatchAsync(async () => + { + await NavigationService.GoToPage(typeof(ElectionViewModel), pageParams); + }); + } + } + catch (Exception) + { + ExceptionHandler.GetData(out var function, out var message, out var code); + ErrorMessage += $"{AppResources.ErrorCreatingElection} - {file.FileName}\n"; + } + }).ContinueWith((t) => + { + if (string.IsNullOrEmpty(ErrorMessage)) + { + // goto the email page or go to the home page + if (multiple) + { + _ = Shell.Current.CurrentPage.Dispatcher.DispatchAsync(() => + { + HomeCommand.Execute(null); + }); + } + } + }); + } + + private async Task MakeNameUnique(string electionName) + { + var count = 2; + var name = electionName; + bool found; + do + { + found = await _electionService.ElectionNameExists(name); + if (found) + { + name = $"{electionName} ({count++})"; + } + } while (found); + return name; + } + + private bool CanCreate() + { + return string.IsNullOrEmpty(ManifestErrorMessage) && _manifestFiles.Any() && ElectionName.Any() && KeyCeremony != null; + } + + [RelayCommand] + private async Task PickManifestFiles() + { + var badFiles = new List(); + var customFileType = new FilePickerFileType( + new Dictionary> + { + { DevicePlatform.WinUI, new[] { ".json" } }, // file extension + { DevicePlatform.macOS, new[] { "json" } }, // UTType values + }); + var options = new PickOptions() { FileTypes = customFileType, PickerTitle = AppResources.SelectManifest }; + var files = await FilePicker.PickMultipleAsync(options); + if (files == null || files.Count() == 0) + { + // if the picking was canceled then do not change anything + return; + } + _manifestFiles.Clear(); + _manifestFiles.AddRange(files); + ManifestErrorMessage = null; + IsNameEnabled = _manifestFiles.Count <= 1; + if (IsNameEnabled) + { + try + { + var data = File.ReadAllText(_manifestFiles.First().FullPath, System.Text.Encoding.UTF8); + using var manifest = new Manifest(data); + + ElectionName = manifest.Name.GetTextAt(0).Value; + } + catch (Exception) + { + ExceptionHandler.GetData(out var function, out var message, out var code); + ManifestErrorMessage = AppResources.ErrorLoadingManifest; + ElectionName = string.Empty; + } + } + else + { + _ = Parallel.ForEach(_manifestFiles, (file) => + { + try + { + using var manifest = new Manifest(File.ReadAllText(file.FullPath)); + if (!manifest.IsValid()) + { + badFiles.Add(file.FileName); + } + } + catch (Exception) + { + badFiles.Add(file.FileName); + } + }); + ElectionName = AppResources.NameFromManifest; + } + + // remove the last ", " + var names = string.Empty; + _manifestFiles.ForEach(file => + { + if (!badFiles.Contains(file.FileName)) + { + names += $"{file.FileName}, "; + } + }); + char[] trim = { ' ', ',' }; + ManifestNames = names.TrimEnd(trim); + + // remove the bad files from the manifest list of files + badFiles.ForEach(file => _manifestFiles.Remove(_manifestFiles.First(f => f.FileName == file))); + if (badFiles.Any()) + { + var message = string.Empty; + badFiles.ForEach(file => message += $"{file}, "); + message = message.TrimEnd(trim); + ManifestErrorMessage = $"{AppResources.ErrorManifest}: {message}\n{AppResources.RemovingList}"; + } + + // commenting out the display of the manifest until we can get it not throwing an exception + //if (_manifestFiles.Count == 1) + //{ + // var vm = (ManifestViewModel)Ioc.Default.GetService(typeof(ManifestViewModel)); + // vm.ManifestFile = _manifestFiles.First().FullPath; + + // await NavigationService.GoToModal(typeof(ManifestViewModel)); + //} + } + +} diff --git a/src/electionguard-ui/ElectionGuard.UI/ViewModels/CreateKeyCeremonyAdminViewModel.cs b/src/electionguard-ui/ElectionGuard.UI/ViewModels/CreateKeyCeremonyAdminViewModel.cs index b7980f49b..d824f289c 100644 --- a/src/electionguard-ui/ElectionGuard.UI/ViewModels/CreateKeyCeremonyAdminViewModel.cs +++ b/src/electionguard-ui/ElectionGuard.UI/ViewModels/CreateKeyCeremonyAdminViewModel.cs @@ -1,68 +1,68 @@ -using CommunityToolkit.Mvvm.Input; - -namespace ElectionGuard.UI.ViewModels; - -public partial class CreateKeyCeremonyAdminViewModel : BaseViewModel -{ - private readonly KeyCeremonyService _keyCeremonyService; - private const string PageName = "CreateKeyCeremony"; - - public CreateKeyCeremonyAdminViewModel(IServiceProvider serviceProvider, KeyCeremonyService keyCeremonyService) : base(PageName, serviceProvider) - { - _keyCeremonyService = keyCeremonyService; - } - - [ObservableProperty] - private string? _errorMessage; - - [ObservableProperty] - [NotifyCanExecuteChangedFor(nameof(CreateKeyCeremonyCommand))] - private string _keyCeremonyName = string.Empty; - - [ObservableProperty] - [NotifyCanExecuteChangedFor(nameof(CreateKeyCeremonyCommand))] - private int _numberOfGuardians = 3; - - [ObservableProperty] - [NotifyCanExecuteChangedFor(nameof(CreateKeyCeremonyCommand))] - private int _quorum = 3; - - [RelayCommand(CanExecute = nameof(CanCreate), AllowConcurrentExecutions = true)] - public async Task CreateKeyCeremony() - { - try - { - var existingKeyCeremony = await _keyCeremonyService.GetByNameAsync(KeyCeremonyName); - if (existingKeyCeremony != null) - { - var alreadyExists = LocalizationService.GetValue("AlreadyExists"); - ErrorMessage = $"{KeyCeremonyName} {alreadyExists}"; - CreateKeyCeremonyCommand.NotifyCanExecuteChanged(); - return; - } - - var keyCeremony = new KeyCeremonyRecord(KeyCeremonyName, NumberOfGuardians, Quorum, UserName!); - var ret = await _keyCeremonyService.SaveAsync(keyCeremony); - await NavigationService.GoToPage(typeof(ViewKeyCeremonyViewModel), new Dictionary - { - { ViewKeyCeremonyViewModel.CurrentKeyCeremonyParam, ret } - }); - } - catch (Exception) - { - } - } - - private bool CanCreate() - { - return KeyCeremonyName.Trim().Length > 0 && - Quorum <= NumberOfGuardians; - } - - public override async Task OnAppearing() - { - await base.OnAppearing(); - } - -} - +using CommunityToolkit.Mvvm.Input; + +namespace ElectionGuard.UI.ViewModels; + +public partial class CreateKeyCeremonyAdminViewModel : BaseViewModel +{ + private readonly KeyCeremonyService _keyCeremonyService; + private const string PageName = "CreateKeyCeremony"; + + public CreateKeyCeremonyAdminViewModel(IServiceProvider serviceProvider, KeyCeremonyService keyCeremonyService) : base(PageName, serviceProvider) + { + _keyCeremonyService = keyCeremonyService; + } + + [ObservableProperty] + private string? _errorMessage; + + [ObservableProperty] + [NotifyCanExecuteChangedFor(nameof(CreateKeyCeremonyCommand))] + private string _keyCeremonyName = string.Empty; + + [ObservableProperty] + [NotifyCanExecuteChangedFor(nameof(CreateKeyCeremonyCommand))] + private int _numberOfGuardians = 3; + + [ObservableProperty] + [NotifyCanExecuteChangedFor(nameof(CreateKeyCeremonyCommand))] + private int _quorum = 3; + + [RelayCommand(CanExecute = nameof(CanCreate), AllowConcurrentExecutions = true)] + public async Task CreateKeyCeremony() + { + try + { + var existingKeyCeremony = await _keyCeremonyService.GetByNameAsync(KeyCeremonyName); + if (existingKeyCeremony != null) + { + var alreadyExists = LocalizationService.GetValue("AlreadyExists"); + ErrorMessage = $"{KeyCeremonyName} {alreadyExists}"; + CreateKeyCeremonyCommand.NotifyCanExecuteChanged(); + return; + } + + var keyCeremony = new KeyCeremonyRecord(KeyCeremonyName, NumberOfGuardians, Quorum, UserName!); + var ret = await _keyCeremonyService.SaveAsync(keyCeremony); + await NavigationService.GoToPage(typeof(ViewKeyCeremonyViewModel), new Dictionary + { + { ViewKeyCeremonyViewModel.CurrentKeyCeremonyParam, ret } + }); + } + catch (Exception) + { + } + } + + private bool CanCreate() + { + return KeyCeremonyName.Trim().Length > 0 && + Quorum <= NumberOfGuardians; + } + + public override async Task OnAppearing() + { + await base.OnAppearing(); + } + +} + diff --git a/src/electionguard-ui/ElectionGuard.UI/ViewModels/CreateMultiTallyViewModel.cs b/src/electionguard-ui/ElectionGuard.UI/ViewModels/CreateMultiTallyViewModel.cs index b9f23a620..5c2c262b3 100644 --- a/src/electionguard-ui/ElectionGuard.UI/ViewModels/CreateMultiTallyViewModel.cs +++ b/src/electionguard-ui/ElectionGuard.UI/ViewModels/CreateMultiTallyViewModel.cs @@ -1,349 +1,349 @@ -using CommunityToolkit.Maui.Storage; -using CommunityToolkit.Mvvm.Input; - -namespace ElectionGuard.UI.ViewModels; - -[QueryProperty(MultiTallyIdParam, nameof(MultiTallyId))] - -public partial class CreateMultiTallyViewModel : BaseViewModel -{ - public const string MultiTallyIdParam = "MultiTallyId"; - - private TallyService _tallyService; - private ElectionService _electionService; - private ManifestService _manifestService; - private KeyCeremonyService _keyCeremonyService; - private BallotUploadService _ballotUploadService; - private BallotService _ballotService; - private TallyJoinedService _tallyJoinedService; - private MultiTallyService _multiTallyService; - - public CreateMultiTallyViewModel( - IServiceProvider serviceProvider, - TallyService tallyService, - ManifestService manifestService, - ElectionService electionService, - KeyCeremonyService keyCeremonyService, - BallotUploadService ballotUploadService, - BallotService ballotService, - TallyJoinedService tallyJoinedService, - MultiTallyService multiTallyService) : base("CreateMultiTally", serviceProvider) - { - _tallyService = tallyService; - _manifestService = manifestService; - _electionService = electionService; - _keyCeremonyService = keyCeremonyService; - _ballotUploadService = ballotUploadService; - _ballotService = ballotService; - _tallyJoinedService = tallyJoinedService; - _multiTallyService = multiTallyService; - _ = Task.Run(FillKeyCeremonies); - } - - [ObservableProperty] - private string? _errorMessage; - - [ObservableProperty] - private bool _selectAll; - - [ObservableProperty] - private string _multiTallyId = string.Empty; - - [ObservableProperty] - private bool _electionsLoaded; - - [ObservableProperty] - private ObservableCollection _keyCeremonies = new(); - - [ObservableProperty] - private KeyCeremonyRecord _selectedKeyCeremony; - - [ObservableProperty] - private MultiTallyRecord? _currentMultiTally; - - [ObservableProperty] - [NotifyCanExecuteChangedFor(nameof(CreateTalliesCommand))] - [NotifyCanExecuteChangedFor(nameof(JoinTalliesCommand))] - private string _currentResultsPath = string.Empty; - - [ObservableProperty] - private ObservableCollection _elections = new(); - - [ObservableProperty] - private ObservableCollection _selectedElections = new(); - - partial void OnMultiTallyIdChanged(string value) - { - if (string.IsNullOrEmpty(value)) - { - CurrentMultiTally = null; - } - - _ = Shell.Current.CurrentPage.Dispatcher.DispatchAsync(async () => - { - // load the elections that are in the multitally - var multiTally = await _multiTallyService.GetByMultiTallyIdAsync(value); - if (multiTally != null) - { - foreach (var (tallyId, electionId, name) in multiTally.TallyIds) - { - var election = await _electionService.GetByElectionIdAsync(electionId); - await LoadElectionData(election, tallyId); - } - ElectionsLoaded = true; - CurrentMultiTally = multiTally; - CurrentResultsPath = CurrentMultiTally.ResultsPath; - } - }); - } - - partial void OnSelectAllChanged(bool value) - { - if (value) - { - foreach (var election in Elections) - { - if (!SelectedElections.Contains(election)) - { - SelectedElections.Add(election); - } - } - } - } - - partial void OnSelectedKeyCeremonyChanged(KeyCeremonyRecord value) - { - // fill in the list of the elections that use the current key ceremony - _ = Task.Run(async () => - { - var allElections = await _electionService.GetAllByKeyCeremonyIdAsync(value.KeyCeremonyId); - foreach (var election in allElections) - { - await LoadElectionData(election); - } - ElectionsLoaded = true; - }); - } - - private async Task LoadElectionData(Election election, string tallyId = "") - { - ElectionGuardException.ThrowIfNull(election.ElectionId, $"Election did not have an electionId {election.Id}"); - - var allUploads = await _ballotUploadService.GetByElectionIdAsync(election.ElectionId); - if (allUploads.Count() > 0) - { - var ballotCountTotal = 0L; - var ballotAddedTotal = 0L; - var ballotChallengedTotal = 0L; - var ballotSpoiledTotal = 0L; - var ballotDuplicateTotal = 0L; - var ballotRejectedTotal = 0L; - - allUploads.ForEach((upload) => - { - ballotCountTotal += upload.BallotCount; - ballotAddedTotal += upload.BallotImported; - ballotChallengedTotal += upload.BallotChallenged; - ballotSpoiledTotal += upload.BallotSpoiled; - ballotDuplicateTotal += upload.BallotDuplicated; - ballotRejectedTotal += upload.BallotRejected; - }); - var electionItem = new ElectionItem - { - Election = election, - TallyId = tallyId, - BallotUploads = new(allUploads), - BallotAddedTotal = ballotAddedTotal, - BallotChallengedTotal = ballotChallengedTotal, - BallotDuplicateTotal = ballotDuplicateTotal, - BallotRejectedTotal = ballotDuplicateTotal, - BallotSpoiledTotal = ballotSpoiledTotal, - BallotCountTotal = ballotCountTotal - }; - Elections.Add(electionItem); - } - } - - private async Task FillKeyCeremonies() - { - var allKeys = await _keyCeremonyService.GetAllCompleteAsync(); - if (allKeys is not null) - { - foreach (var keyCeremony in allKeys) - { - var count = await _electionService.CountByKeyCeremonyIdAsync(keyCeremony.KeyCeremonyId); - if (count > 1) - { - KeyCeremonies.Add(keyCeremony); - } - } - } - else - { - await Shell.Current.CurrentPage.DisplayAlert(AppResources.CreateMultiTally, AppResources.CreateMultiTallyError, AppResources.OkText); - } - } - - [RelayCommand] - private void SelectionChanged() - { - SelectAll = SelectedElections.Count != Elections.Count; - CreateTalliesCommand.NotifyCanExecuteChanged(); - JoinTalliesCommand.NotifyCanExecuteChanged(); - } - - private async Task<(string, string)> CreateNewTally(ElectionItem electionItem, bool multi=false) - { - ElectionGuardException.ThrowIfNull(electionItem, $"Could not load election selected"); - ElectionGuardException.ThrowIfNull(electionItem.Election, $"ElectionItem does not contain an election"); - ElectionGuardException.ThrowIfNull(electionItem.Election.ElectionId, $"Election does not have an election id"); - ElectionGuardException.ThrowIfNull(electionItem.Election.KeyCeremonyId, $"Election does not have a key ceremony id"); - - // calculate ballot count and upload count - var ballotCount = await _ballotService.GetCountBallotsByElectionIdStateAsync(electionItem.Election.ElectionId, BallotBoxState.Cast); - var challengedCount = await _ballotService.GetCountBallotsByElectionIdStateAsync(electionItem.Election.ElectionId, BallotBoxState.Challenged); - var spoiledCount = await _ballotService.GetCountBallotsByElectionIdStateAsync(electionItem.Election.ElectionId, BallotBoxState.Spoiled); - - var keyCeremony = await _keyCeremonyService.GetByKeyCeremonyIdAsync(electionItem.Election.KeyCeremonyId); - ElectionGuardException.ThrowIfNull(keyCeremony, $"Could not load key ceremony {electionItem.Election.KeyCeremonyId}"); - - var tallyName = $"{electionItem.Election.Name} {AppResources.TallyText}"; - - TallyRecord newTally = new() - { - Name = tallyName, - ElectionId = electionItem.Election.ElectionId, - KeyCeremonyId = electionItem.Election.KeyCeremonyId, - Quorum = keyCeremony.Quorum, - NumberOfGuardians = keyCeremony.NumberOfGuardians, - CastBallotCount = ballotCount, - ChallengedBallotCount = challengedCount, - SpoiledBallotCount = spoiledCount, - State = TallyState.PendingGuardiansJoin, - MultiTally = multi, - }; - - _ = await _tallyService.SaveAsync(newTally); - - return (newTally.TallyId, newTally.Name); - } - - - [RelayCommand(CanExecute = nameof(TalliesSelected))] - private async Task CreateTallies() - { - if(SelectedElections.Count == 1) - { - // do a normal tally for a single election - var election = SelectedElections.First() as ElectionItem; - - var (tallyId, _) = await CreateNewTally(election); - - // go to the processing page - await NavigationService.GoToPage(typeof(TallyProcessViewModel), new() - { - { TallyProcessViewModel.CurrentTallyIdParam, tallyId } - }); - } - else - { - List<(string, string, string)> tallys = new(); - // create tally records for each election selected - foreach (var electionItem in SelectedElections) - { - var election = electionItem as ElectionItem; - var (tallyId, electionName) = await CreateNewTally(election, true); - tallys.Add((tallyId, election!.Election!.ElectionId!, electionName)); - } - - // create a multi-tally record for the db - MultiTallyRecord multiTallyRecord = new() - { - Name = $"MultiTally for {SelectedKeyCeremony.Name}", - KeyCeremonyId = SelectedKeyCeremony.KeyCeremonyId, - TallyIds = tallys, - ResultsPath = CurrentResultsPath - }; - - _ = await _multiTallyService.SaveAsync(multiTallyRecord); - - // go to the processing page - await NavigationService.GoToPage(typeof(TallyProcessViewModel), new() - { - { TallyProcessViewModel.MultiTallyIdParam, multiTallyRecord.MultiTallyId } - }); - } - } - - private async Task JoinTally(string tallyId, bool join = true) - { - // join the tally - var joiner = new TallyJoinedRecord() - { - TallyId = tallyId, - GuardianId = UserName!, // can assume not null, since you need to be signed into - Joined = join, - }; - - await _tallyJoinedService.JoinTallyAsync(joiner); - } - - [RelayCommand(CanExecute = nameof(TalliesSelected))] - private async Task JoinTallies() - { - List tallys = new(); - foreach (var election in Elections) - { - if (SelectedElections.Contains(election)) - { - // join the tally - await JoinTally(election.TallyId); - tallys.Add(election.TallyId); - } - else - { - // reject the tally - await JoinTally(election.TallyId, false); - } - } - - // do a normal tally for a single election but reject all of the others - if (SelectedElections.Count == 1) - { - var election = SelectedElections.First() as ElectionItem; - ElectionGuardException.ThrowIfNull(election, $"Could not load election selected"); - - // go to the processing page - await NavigationService.GoToPage(typeof(TallyProcessViewModel), new() - { - { TallyProcessViewModel.CurrentTallyIdParam, election.TallyId } - }); - } - else - { - // go to the processing page - await NavigationService.GoToPage(typeof(TallyProcessViewModel), new() - { - { TallyProcessViewModel.MultiTallyIdParam, MultiTallyId } - }); - } - } - - private bool TalliesSelected() => SelectedElections.Count > 0 && !string.IsNullOrEmpty(CurrentResultsPath); - - [RelayCommand] - private async Task PickFolder() - { - CancellationToken token = new(); - try - { - var folder = await FolderPicker.Default.PickAsync(token); - CurrentResultsPath = folder.Folder?.Path; - } - catch (Exception ex) - { - CurrentResultsPath = string.Empty; - } - } -} - +using CommunityToolkit.Maui.Storage; +using CommunityToolkit.Mvvm.Input; + +namespace ElectionGuard.UI.ViewModels; + +[QueryProperty(MultiTallyIdParam, nameof(MultiTallyId))] + +public partial class CreateMultiTallyViewModel : BaseViewModel +{ + public const string MultiTallyIdParam = "MultiTallyId"; + + private TallyService _tallyService; + private ElectionService _electionService; + private ManifestService _manifestService; + private KeyCeremonyService _keyCeremonyService; + private BallotUploadService _ballotUploadService; + private BallotService _ballotService; + private TallyJoinedService _tallyJoinedService; + private MultiTallyService _multiTallyService; + + public CreateMultiTallyViewModel( + IServiceProvider serviceProvider, + TallyService tallyService, + ManifestService manifestService, + ElectionService electionService, + KeyCeremonyService keyCeremonyService, + BallotUploadService ballotUploadService, + BallotService ballotService, + TallyJoinedService tallyJoinedService, + MultiTallyService multiTallyService) : base("CreateMultiTally", serviceProvider) + { + _tallyService = tallyService; + _manifestService = manifestService; + _electionService = electionService; + _keyCeremonyService = keyCeremonyService; + _ballotUploadService = ballotUploadService; + _ballotService = ballotService; + _tallyJoinedService = tallyJoinedService; + _multiTallyService = multiTallyService; + _ = Task.Run(FillKeyCeremonies); + } + + [ObservableProperty] + private string? _errorMessage; + + [ObservableProperty] + private bool _selectAll; + + [ObservableProperty] + private string _multiTallyId = string.Empty; + + [ObservableProperty] + private bool _electionsLoaded; + + [ObservableProperty] + private ObservableCollection _keyCeremonies = new(); + + [ObservableProperty] + private KeyCeremonyRecord _selectedKeyCeremony; + + [ObservableProperty] + private MultiTallyRecord? _currentMultiTally; + + [ObservableProperty] + [NotifyCanExecuteChangedFor(nameof(CreateTalliesCommand))] + [NotifyCanExecuteChangedFor(nameof(JoinTalliesCommand))] + private string _currentResultsPath = string.Empty; + + [ObservableProperty] + private ObservableCollection _elections = new(); + + [ObservableProperty] + private ObservableCollection _selectedElections = new(); + + partial void OnMultiTallyIdChanged(string value) + { + if (string.IsNullOrEmpty(value)) + { + CurrentMultiTally = null; + } + + _ = Shell.Current.CurrentPage.Dispatcher.DispatchAsync(async () => + { + // load the elections that are in the multitally + var multiTally = await _multiTallyService.GetByMultiTallyIdAsync(value); + if (multiTally != null) + { + foreach (var (tallyId, electionId, name) in multiTally.TallyIds) + { + var election = await _electionService.GetByElectionIdAsync(electionId); + await LoadElectionData(election, tallyId); + } + ElectionsLoaded = true; + CurrentMultiTally = multiTally; + CurrentResultsPath = CurrentMultiTally.ResultsPath; + } + }); + } + + partial void OnSelectAllChanged(bool value) + { + if (value) + { + foreach (var election in Elections) + { + if (!SelectedElections.Contains(election)) + { + SelectedElections.Add(election); + } + } + } + } + + partial void OnSelectedKeyCeremonyChanged(KeyCeremonyRecord value) + { + // fill in the list of the elections that use the current key ceremony + _ = Task.Run(async () => + { + var allElections = await _electionService.GetAllByKeyCeremonyIdAsync(value.KeyCeremonyId); + foreach (var election in allElections) + { + await LoadElectionData(election); + } + ElectionsLoaded = true; + }); + } + + private async Task LoadElectionData(Election election, string tallyId = "") + { + ElectionGuardException.ThrowIfNull(election.ElectionId, $"Election did not have an electionId {election.Id}"); + + var allUploads = await _ballotUploadService.GetByElectionIdAsync(election.ElectionId); + if (allUploads.Count() > 0) + { + var ballotCountTotal = 0L; + var ballotAddedTotal = 0L; + var ballotChallengedTotal = 0L; + var ballotSpoiledTotal = 0L; + var ballotDuplicateTotal = 0L; + var ballotRejectedTotal = 0L; + + allUploads.ForEach((upload) => + { + ballotCountTotal += upload.BallotCount; + ballotAddedTotal += upload.BallotImported; + ballotChallengedTotal += upload.BallotChallenged; + ballotSpoiledTotal += upload.BallotSpoiled; + ballotDuplicateTotal += upload.BallotDuplicated; + ballotRejectedTotal += upload.BallotRejected; + }); + var electionItem = new ElectionItem + { + Election = election, + TallyId = tallyId, + BallotUploads = new(allUploads), + BallotAddedTotal = ballotAddedTotal, + BallotChallengedTotal = ballotChallengedTotal, + BallotDuplicateTotal = ballotDuplicateTotal, + BallotRejectedTotal = ballotDuplicateTotal, + BallotSpoiledTotal = ballotSpoiledTotal, + BallotCountTotal = ballotCountTotal + }; + Elections.Add(electionItem); + } + } + + private async Task FillKeyCeremonies() + { + var allKeys = await _keyCeremonyService.GetAllCompleteAsync(); + if (allKeys is not null) + { + foreach (var keyCeremony in allKeys) + { + var count = await _electionService.CountByKeyCeremonyIdAsync(keyCeremony.KeyCeremonyId); + if (count > 1) + { + KeyCeremonies.Add(keyCeremony); + } + } + } + else + { + await Shell.Current.CurrentPage.DisplayAlert(AppResources.CreateMultiTally, AppResources.CreateMultiTallyError, AppResources.OkText); + } + } + + [RelayCommand] + private void SelectionChanged() + { + SelectAll = SelectedElections.Count != Elections.Count; + CreateTalliesCommand.NotifyCanExecuteChanged(); + JoinTalliesCommand.NotifyCanExecuteChanged(); + } + + private async Task<(string, string)> CreateNewTally(ElectionItem electionItem, bool multi=false) + { + ElectionGuardException.ThrowIfNull(electionItem, $"Could not load election selected"); + ElectionGuardException.ThrowIfNull(electionItem.Election, $"ElectionItem does not contain an election"); + ElectionGuardException.ThrowIfNull(electionItem.Election.ElectionId, $"Election does not have an election id"); + ElectionGuardException.ThrowIfNull(electionItem.Election.KeyCeremonyId, $"Election does not have a key ceremony id"); + + // calculate ballot count and upload count + var ballotCount = await _ballotService.GetCountBallotsByElectionIdStateAsync(electionItem.Election.ElectionId, BallotBoxState.Cast); + var challengedCount = await _ballotService.GetCountBallotsByElectionIdStateAsync(electionItem.Election.ElectionId, BallotBoxState.Challenged); + var spoiledCount = await _ballotService.GetCountBallotsByElectionIdStateAsync(electionItem.Election.ElectionId, BallotBoxState.Spoiled); + + var keyCeremony = await _keyCeremonyService.GetByKeyCeremonyIdAsync(electionItem.Election.KeyCeremonyId); + ElectionGuardException.ThrowIfNull(keyCeremony, $"Could not load key ceremony {electionItem.Election.KeyCeremonyId}"); + + var tallyName = $"{electionItem.Election.Name} {AppResources.TallyText}"; + + TallyRecord newTally = new() + { + Name = tallyName, + ElectionId = electionItem.Election.ElectionId, + KeyCeremonyId = electionItem.Election.KeyCeremonyId, + Quorum = keyCeremony.Quorum, + NumberOfGuardians = keyCeremony.NumberOfGuardians, + CastBallotCount = ballotCount, + ChallengedBallotCount = challengedCount, + SpoiledBallotCount = spoiledCount, + State = TallyState.PendingGuardiansJoin, + MultiTally = multi, + }; + + _ = await _tallyService.SaveAsync(newTally); + + return (newTally.TallyId, newTally.Name); + } + + + [RelayCommand(CanExecute = nameof(TalliesSelected))] + private async Task CreateTallies() + { + if(SelectedElections.Count == 1) + { + // do a normal tally for a single election + var election = SelectedElections.First() as ElectionItem; + + var (tallyId, _) = await CreateNewTally(election); + + // go to the processing page + await NavigationService.GoToPage(typeof(TallyProcessViewModel), new() + { + { TallyProcessViewModel.CurrentTallyIdParam, tallyId } + }); + } + else + { + List<(string, string, string)> tallys = new(); + // create tally records for each election selected + foreach (var electionItem in SelectedElections) + { + var election = electionItem as ElectionItem; + var (tallyId, electionName) = await CreateNewTally(election, true); + tallys.Add((tallyId, election!.Election!.ElectionId!, electionName)); + } + + // create a multi-tally record for the db + MultiTallyRecord multiTallyRecord = new() + { + Name = $"MultiTally for {SelectedKeyCeremony.Name}", + KeyCeremonyId = SelectedKeyCeremony.KeyCeremonyId, + TallyIds = tallys, + ResultsPath = CurrentResultsPath + }; + + _ = await _multiTallyService.SaveAsync(multiTallyRecord); + + // go to the processing page + await NavigationService.GoToPage(typeof(TallyProcessViewModel), new() + { + { TallyProcessViewModel.MultiTallyIdParam, multiTallyRecord.MultiTallyId } + }); + } + } + + private async Task JoinTally(string tallyId, bool join = true) + { + // join the tally + var joiner = new TallyJoinedRecord() + { + TallyId = tallyId, + GuardianId = UserName!, // can assume not null, since you need to be signed into + Joined = join, + }; + + await _tallyJoinedService.JoinTallyAsync(joiner); + } + + [RelayCommand(CanExecute = nameof(TalliesSelected))] + private async Task JoinTallies() + { + List tallys = new(); + foreach (var election in Elections) + { + if (SelectedElections.Contains(election)) + { + // join the tally + await JoinTally(election.TallyId); + tallys.Add(election.TallyId); + } + else + { + // reject the tally + await JoinTally(election.TallyId, false); + } + } + + // do a normal tally for a single election but reject all of the others + if (SelectedElections.Count == 1) + { + var election = SelectedElections.First() as ElectionItem; + ElectionGuardException.ThrowIfNull(election, $"Could not load election selected"); + + // go to the processing page + await NavigationService.GoToPage(typeof(TallyProcessViewModel), new() + { + { TallyProcessViewModel.CurrentTallyIdParam, election.TallyId } + }); + } + else + { + // go to the processing page + await NavigationService.GoToPage(typeof(TallyProcessViewModel), new() + { + { TallyProcessViewModel.MultiTallyIdParam, MultiTallyId } + }); + } + } + + private bool TalliesSelected() => SelectedElections.Count > 0 && !string.IsNullOrEmpty(CurrentResultsPath); + + [RelayCommand] + private async Task PickFolder() + { + CancellationToken token = new(); + try + { + var folder = await FolderPicker.Default.PickAsync(token); + CurrentResultsPath = folder.Folder?.Path; + } + catch (Exception ex) + { + CurrentResultsPath = string.Empty; + } + } +} + diff --git a/src/electionguard-ui/ElectionGuard.UI/ViewModels/CreateTallyViewModel.cs b/src/electionguard-ui/ElectionGuard.UI/ViewModels/CreateTallyViewModel.cs index 8107be37a..919be09d2 100644 --- a/src/electionguard-ui/ElectionGuard.UI/ViewModels/CreateTallyViewModel.cs +++ b/src/electionguard-ui/ElectionGuard.UI/ViewModels/CreateTallyViewModel.cs @@ -1,138 +1,138 @@ -using CommunityToolkit.Maui.Core.Extensions; -using CommunityToolkit.Mvvm.Input; - -namespace ElectionGuard.UI.ViewModels; - -[QueryProperty(ElectionIdParam, nameof(ElectionId))] -public partial class CreateTallyViewModel : BaseViewModel -{ - public const string ElectionIdParam = "ElectionId"; - - private TallyService _tallyService; - private ElectionService _electionService; - private ManifestService _manifestService; - private KeyCeremonyService _keyCeremonyService; - private BallotUploadService _ballotUploadService; - private BallotService _ballotService; - - public CreateTallyViewModel( - IServiceProvider serviceProvider, - TallyService tallyService, - ManifestService manifestService, - ElectionService electionService, - KeyCeremonyService keyCeremonyService, - BallotUploadService ballotUploadService, - BallotService ballotService) : base("CreateTally", serviceProvider) - { - _tallyService = tallyService; - _manifestService = manifestService; - _electionService = electionService; - _keyCeremonyService = keyCeremonyService; - _ballotUploadService = ballotUploadService; - _ballotService = ballotService; - } - - [ObservableProperty] - private string _electionId = string.Empty; - - [ObservableProperty] - [NotifyCanExecuteChangedFor(nameof(CreateTallyCommand))] - private string _tallyName = string.Empty; - - [ObservableProperty] - private string? _errorMessage; - - [ObservableProperty] - private bool _useAllBallots = true; - - partial void OnUseAllBallotsChanged(bool value) - { - - } - - [ObservableProperty] - private Election _currentElection = new(); - - [ObservableProperty] - private KeyCeremonyRecord? _currentKeyCeremony; - - [ObservableProperty] - private Manifest _currentManifest; - - [ObservableProperty] - private ObservableCollection _deviceList = new(); - - [ObservableProperty] - private ObservableCollection _dateList = new(); - - [ObservableProperty] - private ObservableCollection _ballotUploads = new(); - - partial void OnElectionIdChanged(string value) - { - _ = Task.Run(async () => - { - var currentElection = await _electionService.GetByElectionIdAsync(value); - var record = await _manifestService.GetByElectionIdAsync(value); - var uploads = await _ballotUploadService.GetByElectionIdAsync(value); - var startDate = uploads.Min(u => u.BallotsStart); - var endDate = uploads.Max(u => u.BallotsEnd); - - _ = Shell.Current.CurrentPage.Dispatcher.Dispatch(async () => - { - CurrentElection = currentElection!; - BallotUploads = uploads.DistinctBy(u => u.DeviceId).ToObservableCollection(); - CurrentManifest = new(record?.ManifestData); - CurrentKeyCeremony = await _keyCeremonyService.GetByKeyCeremonyIdAsync(CurrentElection.KeyCeremonyId!); - TallyName = $"{CurrentElection.Name} {AppResources.TallyText}"; - DateList.Clear(); - for (DateTime currentDate = startDate; currentDate <= endDate; currentDate = currentDate.AddDays(1)) - { - DateList.Add(currentDate.ToShortDateString()); - } - }); - }); - } - - [RelayCommand(CanExecute = nameof(CanCreateTally))] - private async Task CreateTally() - { - // calculate ballot count and upload count - var ballotCount = await _ballotService.GetCountBallotsByElectionIdStateAsync(ElectionId, BallotBoxState.Cast); - var challengedCount = await _ballotService.GetCountBallotsByElectionIdStateAsync(ElectionId, BallotBoxState.Challenged); - var spoiledCount = await _ballotService.GetCountBallotsByElectionIdStateAsync(ElectionId, BallotBoxState.Spoiled); - - TallyRecord newTally = new() - { - Name = TallyName, - ElectionId = ElectionId, - KeyCeremonyId = CurrentElection.KeyCeremonyId, - Quorum = CurrentKeyCeremony.Quorum, - NumberOfGuardians = CurrentKeyCeremony.NumberOfGuardians, - CastBallotCount = ballotCount, - ChallengedBallotCount = challengedCount, - SpoiledBallotCount = spoiledCount, - State = TallyState.PendingGuardiansJoin, - }; - - _ = await _tallyService.SaveAsync(newTally); - - var pageParams = new Dictionary - { - { TallyProcessViewModel.CurrentTallyIdParam, newTally.TallyId } - }; - await NavigationService.GoToPage(typeof(TallyProcessViewModel), pageParams); - - } - - private bool CanCreateTally() - { - return !string.IsNullOrWhiteSpace(TallyName); - } - - public override async Task OnAppearing() - { - await base.OnAppearing(); - } - -} +using CommunityToolkit.Maui.Core.Extensions; +using CommunityToolkit.Mvvm.Input; + +namespace ElectionGuard.UI.ViewModels; + +[QueryProperty(ElectionIdParam, nameof(ElectionId))] +public partial class CreateTallyViewModel : BaseViewModel +{ + public const string ElectionIdParam = "ElectionId"; + + private TallyService _tallyService; + private ElectionService _electionService; + private ManifestService _manifestService; + private KeyCeremonyService _keyCeremonyService; + private BallotUploadService _ballotUploadService; + private BallotService _ballotService; + + public CreateTallyViewModel( + IServiceProvider serviceProvider, + TallyService tallyService, + ManifestService manifestService, + ElectionService electionService, + KeyCeremonyService keyCeremonyService, + BallotUploadService ballotUploadService, + BallotService ballotService) : base("CreateTally", serviceProvider) + { + _tallyService = tallyService; + _manifestService = manifestService; + _electionService = electionService; + _keyCeremonyService = keyCeremonyService; + _ballotUploadService = ballotUploadService; + _ballotService = ballotService; + } + + [ObservableProperty] + private string _electionId = string.Empty; + + [ObservableProperty] + [NotifyCanExecuteChangedFor(nameof(CreateTallyCommand))] + private string _tallyName = string.Empty; + + [ObservableProperty] + private string? _errorMessage; + + [ObservableProperty] + private bool _useAllBallots = true; + + partial void OnUseAllBallotsChanged(bool value) + { + + } + + [ObservableProperty] + private Election _currentElection = new(); + + [ObservableProperty] + private KeyCeremonyRecord? _currentKeyCeremony; + + [ObservableProperty] + private Manifest _currentManifest; + + [ObservableProperty] + private ObservableCollection _deviceList = new(); + + [ObservableProperty] + private ObservableCollection _dateList = new(); + + [ObservableProperty] + private ObservableCollection _ballotUploads = new(); + + partial void OnElectionIdChanged(string value) + { + _ = Task.Run(async () => + { + var currentElection = await _electionService.GetByElectionIdAsync(value); + var record = await _manifestService.GetByElectionIdAsync(value); + var uploads = await _ballotUploadService.GetByElectionIdAsync(value); + var startDate = uploads.Min(u => u.BallotsStart); + var endDate = uploads.Max(u => u.BallotsEnd); + + _ = Shell.Current.CurrentPage.Dispatcher.Dispatch(async () => + { + CurrentElection = currentElection!; + BallotUploads = uploads.DistinctBy(u => u.DeviceId).ToObservableCollection(); + CurrentManifest = new(record?.ManifestData); + CurrentKeyCeremony = await _keyCeremonyService.GetByKeyCeremonyIdAsync(CurrentElection.KeyCeremonyId!); + TallyName = $"{CurrentElection.Name} {AppResources.TallyText}"; + DateList.Clear(); + for (DateTime currentDate = startDate; currentDate <= endDate; currentDate = currentDate.AddDays(1)) + { + DateList.Add(currentDate.ToShortDateString()); + } + }); + }); + } + + [RelayCommand(CanExecute = nameof(CanCreateTally))] + private async Task CreateTally() + { + // calculate ballot count and upload count + var ballotCount = await _ballotService.GetCountBallotsByElectionIdStateAsync(ElectionId, BallotBoxState.Cast); + var challengedCount = await _ballotService.GetCountBallotsByElectionIdStateAsync(ElectionId, BallotBoxState.Challenged); + var spoiledCount = await _ballotService.GetCountBallotsByElectionIdStateAsync(ElectionId, BallotBoxState.Spoiled); + + TallyRecord newTally = new() + { + Name = TallyName, + ElectionId = ElectionId, + KeyCeremonyId = CurrentElection.KeyCeremonyId, + Quorum = CurrentKeyCeremony.Quorum, + NumberOfGuardians = CurrentKeyCeremony.NumberOfGuardians, + CastBallotCount = ballotCount, + ChallengedBallotCount = challengedCount, + SpoiledBallotCount = spoiledCount, + State = TallyState.PendingGuardiansJoin, + }; + + _ = await _tallyService.SaveAsync(newTally); + + var pageParams = new Dictionary + { + { TallyProcessViewModel.CurrentTallyIdParam, newTally.TallyId } + }; + await NavigationService.GoToPage(typeof(TallyProcessViewModel), pageParams); + + } + + private bool CanCreateTally() + { + return !string.IsNullOrWhiteSpace(TallyName); + } + + public override async Task OnAppearing() + { + await base.OnAppearing(); + } + +} diff --git a/src/electionguard-ui/ElectionGuard.UI/ViewModels/ElectionViewModel.cs b/src/electionguard-ui/ElectionGuard.UI/ViewModels/ElectionViewModel.cs index 6c873e38c..86454c5c2 100644 --- a/src/electionguard-ui/ElectionGuard.UI/ViewModels/ElectionViewModel.cs +++ b/src/electionguard-ui/ElectionGuard.UI/ViewModels/ElectionViewModel.cs @@ -1,14 +1,14 @@ using CommunityToolkit.Mvvm.DependencyInjection; using CommunityToolkit.Mvvm.Input; -using ElectionGuard.UI.Models; - +using ElectionGuard.UI.Models; + namespace ElectionGuard.UI.ViewModels; [QueryProperty(CurrentElectionParam, nameof(CurrentElection))] [QueryProperty(ElectionIdParam, nameof(ElectionId))] public partial class ElectionViewModel : BaseViewModel -{ - public const string CurrentElectionParam = "CurrentElection"; +{ + public const string CurrentElectionParam = "CurrentElection"; public const string ElectionIdParam = "ElectionId"; private readonly IStorageService _storageService; @@ -17,10 +17,10 @@ public partial class ElectionViewModel : BaseViewModel private readonly ManifestService _manifestService; private readonly BallotUploadService _uploadService; private readonly ElectionService _electionService; - private readonly TallyService _tallyService; - private readonly ConstantsService _constantsService; - private readonly ContextService _contextService; - + private readonly TallyService _tallyService; + private readonly ConstantsService _constantsService; + private readonly ContextService _contextService; + public ElectionViewModel( IServiceProvider serviceProvider, KeyCeremonyService keyCeremonyService, @@ -99,8 +99,8 @@ public ElectionViewModel( private DateTime _ballotsUploadedDateTime; [ObservableProperty] - private bool _step1Complete; - + private bool _step1Complete; + [ObservableProperty] private bool _step2Complete; @@ -111,61 +111,61 @@ public ElectionViewModel( private bool _step4Complete; [ObservableProperty] - private bool _step5Complete; - + private bool _step5Complete; + [ObservableProperty] private TallyRecord? _currentTally; - partial void OnBallotsUploadedDateTimeChanged(DateTime value) - { - Step2Complete = true; - } - - partial void OnCurrentTallyChanged(TallyRecord? value) - { - if (value is null) - { - return; - } - - if (value.State == TallyState.Complete) - { - MainThread.BeginInvokeOnMainThread(async () => - await NavigationService.GoToPage(typeof(ViewTallyViewModel), new Dictionary + partial void OnBallotsUploadedDateTimeChanged(DateTime value) + { + Step2Complete = true; + } + + partial void OnCurrentTallyChanged(TallyRecord? value) + { + if (value is null) + { + return; + } + + if (value.State == TallyState.Complete) + { + MainThread.BeginInvokeOnMainThread(async () => + await NavigationService.GoToPage(typeof(ViewTallyViewModel), new Dictionary { - { "TallyId", value.TallyId! } + { "TallyId", value.TallyId! } })); } - else if (value.State != TallyState.Abandoned) - { + else if (value.State != TallyState.Abandoned) + { MainThread.BeginInvokeOnMainThread(async () => await NavigationService.GoToPage(typeof(TallyProcessViewModel), new Dictionary { { "TallyId", value.TallyId! } - })); + })); } } - private async Task RefreshUploads(string electionId) - { - var uploads = await _uploadService.GetByElectionIdAsync(electionId); - BallotUploads.Clear(); - BallotCountTotal = 0; - BallotAddedTotal = 0; - BallotSpoiledTotal = 0; - BallotChallengedTotal = 0; - BallotDuplicateTotal = 0; - BallotRejectedTotal = 0; - uploads.ForEach((upload) => - { - BallotUploads.Add(upload); - BallotCountTotal += upload.BallotCount; - BallotAddedTotal += upload.BallotImported; - BallotChallengedTotal += upload.BallotChallenged; - BallotSpoiledTotal += upload.BallotSpoiled; - BallotDuplicateTotal += upload.BallotDuplicated; - BallotRejectedTotal += upload.BallotRejected; - }); + private async Task RefreshUploads(string electionId) + { + var uploads = await _uploadService.GetByElectionIdAsync(electionId); + BallotUploads.Clear(); + BallotCountTotal = 0; + BallotAddedTotal = 0; + BallotSpoiledTotal = 0; + BallotChallengedTotal = 0; + BallotDuplicateTotal = 0; + BallotRejectedTotal = 0; + uploads.ForEach((upload) => + { + BallotUploads.Add(upload); + BallotCountTotal += upload.BallotCount; + BallotAddedTotal += upload.BallotImported; + BallotChallengedTotal += upload.BallotChallenged; + BallotSpoiledTotal += upload.BallotSpoiled; + BallotDuplicateTotal += upload.BallotDuplicated; + BallotRejectedTotal += upload.BallotRejected; + }); } partial void OnCurrentElectionChanged(Election? value) @@ -174,22 +174,22 @@ partial void OnCurrentElectionChanged(Election? value) _ = Shell.Current.CurrentPage.Dispatcher.DispatchAsync(async () => { try - { - ManifestRecord = await _manifestService.GetByElectionIdAsync(value?.ElectionId!); - KeyCeremony = await _keyCeremonyService.GetByKeyCeremonyIdAsync(value?.KeyCeremonyId!); - await RefreshUploads(value?.ElectionId!); - - Tallies.Clear(); - var tallies = await _tallyService.GetAllActiveByElectionIdAsync(value?.ElectionId!); - foreach (var item in tallies) - { - Tallies.Add(item); - } - - Step1Complete = CurrentElection?.ExportEncryptionDateTime != null; - Step2Complete = BallotAddedTotal + BallotSpoiledTotal > 0; - Step4Complete = Tallies.Count > 0; - Step5Complete = Tallies.Count(t => t.LastExport != null) > 0; + { + ManifestRecord = await _manifestService.GetByElectionIdAsync(value?.ElectionId!); + KeyCeremony = await _keyCeremonyService.GetByKeyCeremonyIdAsync(value?.KeyCeremonyId!); + await RefreshUploads(value?.ElectionId!); + + Tallies.Clear(); + var tallies = await _tallyService.GetAllActiveByElectionIdAsync(value?.ElectionId!); + foreach (var item in tallies) + { + Tallies.Add(item); + } + + Step1Complete = CurrentElection?.ExportEncryptionDateTime != null; + Step2Complete = BallotAddedTotal + BallotSpoiledTotal > 0; + Step4Complete = Tallies.Count > 0; + Step5Complete = Tallies.Count(t => t.LastExport != null) > 0; } catch (Exception) { @@ -197,32 +197,32 @@ partial void OnCurrentElectionChanged(Election? value) }); } - partial void OnElectionIdChanged(string value) - { - if (string.IsNullOrEmpty(value)) - { - return; - } - - _ = Shell.Current.CurrentPage.Dispatcher.DispatchAsync(async () => CurrentElection = await _electionService.GetByElectionIdAsync(value)); + partial void OnElectionIdChanged(string value) + { + if (string.IsNullOrEmpty(value)) + { + return; + } + + _ = Shell.Current.CurrentPage.Dispatcher.DispatchAsync(async () => CurrentElection = await _electionService.GetByElectionIdAsync(value)); } [RelayCommand(CanExecute = nameof(CanCreateTally))] - private async Task CreateTally() - { + private async Task CreateTally() + { var pageParams = new Dictionary { { CreateTallyViewModel.ElectionIdParam, CurrentElection.ElectionId } }; await NavigationService.GoToPage(typeof(CreateTallyViewModel), pageParams); - } - - private bool CanCreateTally() - { - return BallotCountTotal > 0 || BallotChallengedTotal > 0; - } - + } + + private bool CanCreateTally() + { + return BallotCountTotal > 0 || BallotChallengedTotal > 0; + } + [RelayCommand(CanExecute = nameof(CanUpload))] private async Task AddBallots() { @@ -234,9 +234,9 @@ private async Task AddBallots() await NavigationService.GoToPage(typeof(BallotUploadViewModel), pageParams); } - private bool CanUpload() - { - return CurrentElection?.ExportEncryptionDateTime != null; + private bool CanUpload() + { + return CurrentElection?.ExportEncryptionDateTime != null; } [RelayCommand(CanExecute = nameof(CanReview))] @@ -251,72 +251,72 @@ private async Task ReviewChallenged() await NavigationService.GoToModal(typeof(ChallengedPopupViewModel)); await RefreshUploads(CurrentElection!.ElectionId!); } - - private bool CanReview() - { - return BallotChallengedTotal > 0; + + private bool CanReview() + { + return BallotChallengedTotal > 0; } [RelayCommand] private async Task ExportEncryption() - { - const string egDriveLabel = "egdrive"; - - var answer = await Shell.Current.CurrentPage.DisplayAlert( - AppResources.ExportDriveWarningTitle, - AppResources.ExportDriveWarning, - AppResources.YesText, - AppResources.NoText); - - if (!answer) - { - return; - } - - // check for any usb drives named egDrive - var egDrives = from drive in DriveInfo.GetDrives() - where drive != null - where drive.DriveType == DriveType.Removable - where drive.IsReady - where drive.VolumeLabel.ToLower() == egDriveLabel + { + const string egDriveLabel = "egdrive"; + + var answer = await Shell.Current.CurrentPage.DisplayAlert( + AppResources.ExportDriveWarningTitle, + AppResources.ExportDriveWarning, + AppResources.YesText, + AppResources.NoText); + + if (!answer) + { + return; + } + + // check for any usb drives named egDrive + var egDrives = from drive in DriveInfo.GetDrives() + where drive != null + where drive.DriveType == DriveType.Removable + where drive.IsReady + where drive.VolumeLabel.ToLower() == egDriveLabel select drive; - var context = await _contextService.GetByElectionIdAsync(CurrentElection.ElectionId); - var constants = await _constantsService.GetByElectionIdAsync(CurrentElection.ElectionId); - var manifest = await _manifestService.GetByElectionIdAsync(CurrentElection.ElectionId); - - if (context == null || constants == null || manifest == null) - { - // there's a data problem. This should never happen. - return; - } - - var encryptionPackage = new EncryptionPackage(context, constants, manifest); - - foreach (var drive in egDrives) - { - const string artifactFolder = "artifacts"; - - var destinationFolder = Path.Combine(drive.Name, artifactFolder); - _ = Directory.CreateDirectory(destinationFolder); - - _driveService.UpdatePath(destinationFolder); - _driveService.ToFiles(encryptionPackage); - + var context = await _contextService.GetByElectionIdAsync(CurrentElection.ElectionId); + var constants = await _constantsService.GetByElectionIdAsync(CurrentElection.ElectionId); + var manifest = await _manifestService.GetByElectionIdAsync(CurrentElection.ElectionId); + + if (context == null || constants == null || manifest == null) + { + // there's a data problem. This should never happen. + return; + } + + var encryptionPackage = new EncryptionPackage(context, constants, manifest); + + foreach (var drive in egDrives) + { + const string artifactFolder = "artifacts"; + + var destinationFolder = Path.Combine(drive.Name, artifactFolder); + _ = Directory.CreateDirectory(destinationFolder); + + _driveService.UpdatePath(destinationFolder); + _driveService.ToFiles(encryptionPackage); + } - if (egDrives.Count() >= 0) - { - await MarkCurrentElectionAsExported(); + if (egDrives.Count() >= 0) + { + await MarkCurrentElectionAsExported(); } - } - - private async Task MarkCurrentElectionAsExported() - { - CurrentElection.ExportEncryptionDateTime = DateTime.UtcNow; - await _electionService.UpdateEncryptionExportDateAsync(CurrentElection.ElectionId, CurrentElection.ExportEncryptionDateTime.Value); - AddBallotsCommand.NotifyCanExecuteChanged(); - Step1Complete = true; + } + + private async Task MarkCurrentElectionAsExported() + { + CurrentElection.ExportEncryptionDateTime = DateTime.UtcNow; + await _electionService.UpdateEncryptionExportDateAsync(CurrentElection.ElectionId, CurrentElection.ExportEncryptionDateTime.Value); + AddBallotsCommand.NotifyCanExecuteChanged(); + Step1Complete = true; } [RelayCommand(CanExecute = nameof(CanView))] @@ -326,30 +326,30 @@ private async Task View() var vm = (ManifestViewModel)Ioc.Default.GetService(typeof(ManifestViewModel)); vm.Manifest = new Manifest(Manifest.ToJson()); - await NavigationService.GoToModal(typeof(ManifestViewModel)); + await NavigationService.GoToModal(typeof(ManifestViewModel)); IsViewing = false; } - - private bool CanView() - { - return !IsViewing; - } + + private bool CanView() + { + return !IsViewing; + } partial void OnManifestRecordChanged(ManifestRecord value) { Manifest = new Manifest(value.ManifestData); ManifestName = Manifest.Name.GetTextAt(0).Value; - } - + } + public override void Dispose() { base.Dispose(); GC.SuppressFinalize(this); } - - public override async Task OnAppearing() - { - await base.OnAppearing(); - } + + public override async Task OnAppearing() + { + await base.OnAppearing(); + } } diff --git a/src/electionguard-ui/ElectionGuard.UI/ViewModels/GuardianHomeViewModel.cs b/src/electionguard-ui/ElectionGuard.UI/ViewModels/GuardianHomeViewModel.cs index 6d0d7d676..0b777c7eb 100644 --- a/src/electionguard-ui/ElectionGuard.UI/ViewModels/GuardianHomeViewModel.cs +++ b/src/electionguard-ui/ElectionGuard.UI/ViewModels/GuardianHomeViewModel.cs @@ -1,165 +1,165 @@ -namespace ElectionGuard.UI.ViewModels; - -public partial class GuardianHomeViewModel : BaseViewModel -{ - private readonly KeyCeremonyService _keyCeremonyService; - private readonly GuardianPublicKeyService _guardianService; - private readonly TallyService _tallyService; - private readonly TallyJoinedService _tallyJoinedService; - private readonly MultiTallyService _multiTallyService; - - public GuardianHomeViewModel(IServiceProvider serviceProvider, - KeyCeremonyService keyCeremonyService, - GuardianPublicKeyService guardianService, - TallyService tallyService, - TallyJoinedService tallyJoinedService, - MultiTallyService multiTallyService) : base("GuardianHome", serviceProvider) - { - _keyCeremonyService = keyCeremonyService; - _guardianService = guardianService; - _tallyService = tallyService; - _tallyJoinedService = tallyJoinedService; - _multiTallyService = multiTallyService; - } - - public override async Task OnAppearing() - { - await base.OnAppearing(); - - _timer.Tick += PollingTimer_Tick; - _timer.Start(); - - PollingTimer_Tick(this, null); - } - - [ObservableProperty] - private ObservableCollection _keyCeremonies = new(); - - [ObservableProperty] - private ObservableCollection _multiTallies = new(); - - [ObservableProperty] - private ObservableCollection _tallies = new(); - - [ObservableProperty] - private KeyCeremonyRecord? _currentKeyCeremony; - - [ObservableProperty] - private TallyRecord? _currentTally; - - [ObservableProperty] - private MultiTallyRecord? _currentMultiTally; - - - public override async Task OnLeavingPage() - { - _timer.Stop(); - await Task.Yield(); - } - - partial void OnCurrentKeyCeremonyChanged(KeyCeremonyRecord? value) - { - if (value is null) - { - return; - } - - MainThread.BeginInvokeOnMainThread(async() => - await NavigationService.GoToPage(typeof(ViewKeyCeremonyViewModel), new Dictionary - { - { ViewKeyCeremonyViewModel.CurrentKeyCeremonyParam, value } - })); - } - - partial void OnCurrentTallyChanged(TallyRecord? value) - { - if (value == null) - { - return; - } - - MainThread.BeginInvokeOnMainThread(async () => - await NavigationService.GoToPage(typeof(TallyProcessViewModel), new Dictionary - { - { "TallyId", value.TallyId! } - })); - } - - partial void OnCurrentMultiTallyChanged(MultiTallyRecord? value) - { - if (value == null) - { - return; - } - - MainThread.BeginInvokeOnMainThread(async () => - await NavigationService.GoToPage(typeof(CreateMultiTallyViewModel), new Dictionary - { - { CreateMultiTallyViewModel.MultiTallyIdParam, value.MultiTallyId! } - })); - } - - private async void PollingTimer_Tick(object? sender, EventArgs e) - { - try - { - var keyCeremonies = await _keyCeremonyService.GetAllNotCompleteAsync(); - KeyCeremonies.Clear(); - foreach (var item in keyCeremonies) - { - KeyCeremonies.Add(item); - } - - var keys = await _guardianService.GetKeyCeremonyIdsAsync(UserName!); - var tallies = await _tallyService.GetAllByKeyCeremoniesAsync(keys); - var rejected = await _tallyJoinedService.GetGuardianRejectedIdsAsync(UserName!); - Tallies.Clear(); - foreach (var item in tallies) - { - if (!rejected.Contains(item.TallyId) && item.State < TallyState.Complete) - { - Tallies.Add(item); - } - } - - var multiTallies = await _multiTallyService.GetAllAsync(); - foreach (var tally in multiTallies) - { - if (!keys.Contains(tally.KeyCeremonyId!)) - { - continue; - } - - var addMulti = false; - // check each tally in the multitally to see if any are not complete / abandoned - foreach (var (tallyId, _, _) in tally.TallyIds) - { - if (await _tallyService.IsRunningByTallyIdAsync(tallyId)) - { - addMulti = true; - break; - } - } - if (addMulti) - { - if (MultiTallies.Count(m => m.MultiTallyId == tally.MultiTallyId) == 0) - { - MultiTallies.Add(tally); - } - } - else - { - if (MultiTallies.Count(m => m.MultiTallyId == tally.MultiTallyId) > 0) - { - MultiTallies.Remove(tally); - } - } - } - } - catch(Exception) - { - // if we have an exception, do not try to update anymore - _timer.Stop(); - } - } -} +namespace ElectionGuard.UI.ViewModels; + +public partial class GuardianHomeViewModel : BaseViewModel +{ + private readonly KeyCeremonyService _keyCeremonyService; + private readonly GuardianPublicKeyService _guardianService; + private readonly TallyService _tallyService; + private readonly TallyJoinedService _tallyJoinedService; + private readonly MultiTallyService _multiTallyService; + + public GuardianHomeViewModel(IServiceProvider serviceProvider, + KeyCeremonyService keyCeremonyService, + GuardianPublicKeyService guardianService, + TallyService tallyService, + TallyJoinedService tallyJoinedService, + MultiTallyService multiTallyService) : base("GuardianHome", serviceProvider) + { + _keyCeremonyService = keyCeremonyService; + _guardianService = guardianService; + _tallyService = tallyService; + _tallyJoinedService = tallyJoinedService; + _multiTallyService = multiTallyService; + } + + public override async Task OnAppearing() + { + await base.OnAppearing(); + + _timer.Tick += PollingTimer_Tick; + _timer.Start(); + + PollingTimer_Tick(this, null); + } + + [ObservableProperty] + private ObservableCollection _keyCeremonies = new(); + + [ObservableProperty] + private ObservableCollection _multiTallies = new(); + + [ObservableProperty] + private ObservableCollection _tallies = new(); + + [ObservableProperty] + private KeyCeremonyRecord? _currentKeyCeremony; + + [ObservableProperty] + private TallyRecord? _currentTally; + + [ObservableProperty] + private MultiTallyRecord? _currentMultiTally; + + + public override async Task OnLeavingPage() + { + _timer.Stop(); + await Task.Yield(); + } + + partial void OnCurrentKeyCeremonyChanged(KeyCeremonyRecord? value) + { + if (value is null) + { + return; + } + + MainThread.BeginInvokeOnMainThread(async() => + await NavigationService.GoToPage(typeof(ViewKeyCeremonyViewModel), new Dictionary + { + { ViewKeyCeremonyViewModel.CurrentKeyCeremonyParam, value } + })); + } + + partial void OnCurrentTallyChanged(TallyRecord? value) + { + if (value == null) + { + return; + } + + MainThread.BeginInvokeOnMainThread(async () => + await NavigationService.GoToPage(typeof(TallyProcessViewModel), new Dictionary + { + { "TallyId", value.TallyId! } + })); + } + + partial void OnCurrentMultiTallyChanged(MultiTallyRecord? value) + { + if (value == null) + { + return; + } + + MainThread.BeginInvokeOnMainThread(async () => + await NavigationService.GoToPage(typeof(CreateMultiTallyViewModel), new Dictionary + { + { CreateMultiTallyViewModel.MultiTallyIdParam, value.MultiTallyId! } + })); + } + + private async void PollingTimer_Tick(object? sender, EventArgs e) + { + try + { + var keyCeremonies = await _keyCeremonyService.GetAllNotCompleteAsync(); + KeyCeremonies.Clear(); + foreach (var item in keyCeremonies) + { + KeyCeremonies.Add(item); + } + + var keys = await _guardianService.GetKeyCeremonyIdsAsync(UserName!); + var tallies = await _tallyService.GetAllByKeyCeremoniesAsync(keys); + var rejected = await _tallyJoinedService.GetGuardianRejectedIdsAsync(UserName!); + Tallies.Clear(); + foreach (var item in tallies) + { + if (!rejected.Contains(item.TallyId) && item.State < TallyState.Complete) + { + Tallies.Add(item); + } + } + + var multiTallies = await _multiTallyService.GetAllAsync(); + foreach (var tally in multiTallies) + { + if (!keys.Contains(tally.KeyCeremonyId!)) + { + continue; + } + + var addMulti = false; + // check each tally in the multitally to see if any are not complete / abandoned + foreach (var (tallyId, _, _) in tally.TallyIds) + { + if (await _tallyService.IsRunningByTallyIdAsync(tallyId)) + { + addMulti = true; + break; + } + } + if (addMulti) + { + if (MultiTallies.Count(m => m.MultiTallyId == tally.MultiTallyId) == 0) + { + MultiTallies.Add(tally); + } + } + else + { + if (MultiTallies.Count(m => m.MultiTallyId == tally.MultiTallyId) > 0) + { + MultiTallies.Remove(tally); + } + } + } + } + catch(Exception) + { + // if we have an exception, do not try to update anymore + _timer.Stop(); + } + } +} diff --git a/src/electionguard-ui/ElectionGuard.UI/ViewModels/LoginViewModel.cs b/src/electionguard-ui/ElectionGuard.UI/ViewModels/LoginViewModel.cs index 06b60dd5e..c5161afcc 100644 --- a/src/electionguard-ui/ElectionGuard.UI/ViewModels/LoginViewModel.cs +++ b/src/electionguard-ui/ElectionGuard.UI/ViewModels/LoginViewModel.cs @@ -1,5 +1,5 @@ using CommunityToolkit.Mvvm.Input; - + namespace ElectionGuard.UI.ViewModels; public partial class LoginViewModel : BaseViewModel @@ -23,7 +23,7 @@ public LoginViewModel(IServiceProvider serviceProvider, ILogger [RelayCommand(CanExecute = nameof(CanLogin), AllowConcurrentExecutions = true)] public async Task Login() - { + { await AuthenticationService.Login(Name, _logger); HomeCommand.Execute(this); // reset the UI name field @@ -37,10 +37,10 @@ public void OpenSettingsUnsetData() { if (!DbContext.IsValid()) { - _ = Shell.Current.CurrentPage.Dispatcher.DispatchAsync(async () => - { - await NavigationService.GoToModal(typeof(SettingsViewModel)); - _hasSeenAutoSettingPage = true; + _ = Shell.Current.CurrentPage.Dispatcher.DispatchAsync(async () => + { + await NavigationService.GoToModal(typeof(SettingsViewModel)); + _hasSeenAutoSettingPage = true; }); } } @@ -58,7 +58,7 @@ public override async Task OnAppearing() // update the database info right away HandleDbPing(null, EventArgs.Empty); - SubscribeDbPing(); + SubscribeDbPing(); } public override async Task OnLeavingPage() @@ -68,7 +68,7 @@ public override async Task OnLeavingPage() } private void SubscribeDbPing() - { + { _timer!.Tick += HandleDbPing; if (!_timer.IsRunning) { @@ -88,14 +88,14 @@ private void UnsubscribeDbPing() private void HandleDbPing(object? sender, EventArgs e) { DbNotAvailable = !DbService.Ping(); - ErrorMessage = DbNotAvailable ? AppResources.DatabaseUnavailable : string.Empty; - if (sender != null && ErrorLog.AppPreviousCrashed()) - { - ErrorLog.DeleteCrashedFile(); - _ = Shell.Current.CurrentPage.Dispatcher.DispatchAsync(async () => - { - await Shell.Current.CurrentPage.DisplayAlert(AppResources.PreviousCrash, AppResources.ViewLogsText, AppResources.OkText); - }); + ErrorMessage = DbNotAvailable ? AppResources.DatabaseUnavailable : string.Empty; + if (sender != null && ErrorLog.AppPreviousCrashed()) + { + ErrorLog.DeleteCrashedFile(); + _ = Shell.Current.CurrentPage.Dispatcher.DispatchAsync(async () => + { + await Shell.Current.CurrentPage.DisplayAlert(AppResources.PreviousCrash, AppResources.ViewLogsText, AppResources.OkText); + }); } } } diff --git a/src/electionguard-ui/ElectionGuard.UI/ViewModels/ManifestViewModel.cs b/src/electionguard-ui/ElectionGuard.UI/ViewModels/ManifestViewModel.cs index 4721534bc..0e2de4999 100644 --- a/src/electionguard-ui/ElectionGuard.UI/ViewModels/ManifestViewModel.cs +++ b/src/electionguard-ui/ElectionGuard.UI/ViewModels/ManifestViewModel.cs @@ -1,139 +1,139 @@ -using System.Text; - -namespace ElectionGuard.UI.ViewModels; - -public record PartyDisplay(string Name, string Abbreviation, string PartyId); -public record CandidateDisplay(string CandidateName, string Party, string CandidateId, bool isWritein=false); -public record BallotStyleDisplay(string Name, string Units); -public record GeopoliticalUnitDisplay(string UnitName, string GPType, string GeopoliticalUnitId); -public record ContestDisplay(string Name, string Variation, ulong NumberElected, ulong VotesAllowed, string Selections); - - -public partial class ManifestViewModel : BaseViewModel -{ - private ManifestService _manifestService; - - public ManifestViewModel(IServiceProvider serviceProvider, ManifestService manifestService) : base("ManifestViewer", serviceProvider) - { - _manifestService = manifestService; - } - - [ObservableProperty] - private Manifest? _manifest; - - [ObservableProperty] - private string _manifestName = string.Empty; - - [ObservableProperty] - private string _Name = string.Empty; - - [ObservableProperty] - private string _units = string.Empty; - - [ObservableProperty] - private string _manifestFile = string.Empty; - - [ObservableProperty] - private ObservableCollection _parties = new(); - - [ObservableProperty] - private ObservableCollection _candidates = new(); - - [ObservableProperty] - private ObservableCollection _ballotStyles = new(); - - [ObservableProperty] - private ObservableCollection _geopoliticalUnits = new(); - - [ObservableProperty] - private ObservableCollection _contests = new(); - - - partial void OnManifestFileChanged(string value) - { - if (string.IsNullOrEmpty(value)) - { - Manifest = null; - return; - } - - this.Manifest = new Manifest(File.ReadAllText(value)); - } - - partial void OnManifestChanged(Manifest? value) - { - Parties.Clear(); - Candidates.Clear(); - GeopoliticalUnits.Clear(); - BallotStyles.Clear(); - Contests.Clear(); - - if (value == null) - { - return; - } - - ManifestName = value.Name.GetTextAt(0).Value; - - for (ulong i = 0; i < value.PartiesSize; i++) - { - var local = value.GetPartyAtIndex(i); - Parties.Add(new(local.Name.GetTextAt(0).Value, local.Abbreviation, local.ObjectId)); - } - - for (ulong i = 0; i < value.CandidatesSize; i++) - { - var local = Manifest.GetCandidateAtIndex(i); - var party = Parties.FirstOrDefault(p => p.PartyId == local.PartyId) ?? new PartyDisplay(string.Empty, string.Empty, string.Empty); - var name = local.Name.GetTextAt(0).Value; - if(name == string.Empty) - { - name = AppResources.WriteinText; - } - Candidates.Add(new(name, party.Name, local.ObjectId)); - } - - for (ulong i = 0; i < value.GeopoliticalUnitsSize; i++) - { - var local = value.GetGeopoliticalUnitAtIndex(i); - GeopoliticalUnits.Add(new(local.Name, local.ReportingUnitType.ToString(), local.ObjectId)); - } - - for (ulong i = 0; i < value.BallotStylesSize; i++) - { - var local = value.GetBallotStyleAtIndex(i); - var gpunits = new List(); - var units = new StringBuilder(); - var geopoliticalUnits = local.GeopoliticalUnitIds; - for (ulong j = 0; j < local.GeopoliticalUnitIdsSize; j++) - { - var unit = GeopoliticalUnits.FirstOrDefault(u => u.GeopoliticalUnitId == local.GetGeopoliticalUnitIdAtIndex(j)) ?? new(string.Empty, string.Empty, string.Empty); - gpunits.Add(unit.UnitName); - units.AppendLine(unit.UnitName); - } - BallotStyles.Add(new(local.ObjectId, units.ToString())); - } - - for (ulong i = 0; i < value.ContestsSize; i++) - { - var local = value.GetContestAtIndex(i); - var selections = new StringBuilder(); - for (ulong j = 0; j < local.SelectionsSize; j++) - { - var selection = local.GetSelectionAtIndex(j); - var candidate = Candidates.FirstOrDefault(c => c.CandidateId == selection.CandidateId); - if (candidate != null) - { - selections.Append($"{candidate.CandidateName}"); - if (!string.IsNullOrEmpty(candidate.Party)) - { - selections.Append($" ({candidate.Party})"); - } - selections.AppendLine(); - } - } - Contests.Add(new ContestDisplay(local.Name, local.VoteVariationType.ToString(), local.NumberElected, local.VotesAllowed, selections.ToString())); - } - } - -} +using System.Text; + +namespace ElectionGuard.UI.ViewModels; + +public record PartyDisplay(string Name, string Abbreviation, string PartyId); +public record CandidateDisplay(string CandidateName, string Party, string CandidateId, bool isWritein=false); +public record BallotStyleDisplay(string Name, string Units); +public record GeopoliticalUnitDisplay(string UnitName, string GPType, string GeopoliticalUnitId); +public record ContestDisplay(string Name, string Variation, ulong NumberElected, ulong VotesAllowed, string Selections); + + +public partial class ManifestViewModel : BaseViewModel +{ + private ManifestService _manifestService; + + public ManifestViewModel(IServiceProvider serviceProvider, ManifestService manifestService) : base("ManifestViewer", serviceProvider) + { + _manifestService = manifestService; + } + + [ObservableProperty] + private Manifest? _manifest; + + [ObservableProperty] + private string _manifestName = string.Empty; + + [ObservableProperty] + private string _Name = string.Empty; + + [ObservableProperty] + private string _units = string.Empty; + + [ObservableProperty] + private string _manifestFile = string.Empty; + + [ObservableProperty] + private ObservableCollection _parties = new(); + + [ObservableProperty] + private ObservableCollection _candidates = new(); + + [ObservableProperty] + private ObservableCollection _ballotStyles = new(); + + [ObservableProperty] + private ObservableCollection _geopoliticalUnits = new(); + + [ObservableProperty] + private ObservableCollection _contests = new(); + + + partial void OnManifestFileChanged(string value) + { + if (string.IsNullOrEmpty(value)) + { + Manifest = null; + return; + } + + this.Manifest = new Manifest(File.ReadAllText(value)); + } + + partial void OnManifestChanged(Manifest? value) + { + Parties.Clear(); + Candidates.Clear(); + GeopoliticalUnits.Clear(); + BallotStyles.Clear(); + Contests.Clear(); + + if (value == null) + { + return; + } + + ManifestName = value.Name.GetTextAt(0).Value; + + for (ulong i = 0; i < value.PartiesSize; i++) + { + var local = value.GetPartyAtIndex(i); + Parties.Add(new(local.Name.GetTextAt(0).Value, local.Abbreviation, local.ObjectId)); + } + + for (ulong i = 0; i < value.CandidatesSize; i++) + { + var local = Manifest.GetCandidateAtIndex(i); + var party = Parties.FirstOrDefault(p => p.PartyId == local.PartyId) ?? new PartyDisplay(string.Empty, string.Empty, string.Empty); + var name = local.Name.GetTextAt(0).Value; + if(name == string.Empty) + { + name = AppResources.WriteinText; + } + Candidates.Add(new(name, party.Name, local.ObjectId)); + } + + for (ulong i = 0; i < value.GeopoliticalUnitsSize; i++) + { + var local = value.GetGeopoliticalUnitAtIndex(i); + GeopoliticalUnits.Add(new(local.Name, local.ReportingUnitType.ToString(), local.ObjectId)); + } + + for (ulong i = 0; i < value.BallotStylesSize; i++) + { + var local = value.GetBallotStyleAtIndex(i); + var gpunits = new List(); + var units = new StringBuilder(); + var geopoliticalUnits = local.GeopoliticalUnitIds; + for (ulong j = 0; j < local.GeopoliticalUnitIdsSize; j++) + { + var unit = GeopoliticalUnits.FirstOrDefault(u => u.GeopoliticalUnitId == local.GetGeopoliticalUnitIdAtIndex(j)) ?? new(string.Empty, string.Empty, string.Empty); + gpunits.Add(unit.UnitName); + units.AppendLine(unit.UnitName); + } + BallotStyles.Add(new(local.ObjectId, units.ToString())); + } + + for (ulong i = 0; i < value.ContestsSize; i++) + { + var local = value.GetContestAtIndex(i); + var selections = new StringBuilder(); + for (ulong j = 0; j < local.SelectionsSize; j++) + { + var selection = local.GetSelectionAtIndex(j); + var candidate = Candidates.FirstOrDefault(c => c.CandidateId == selection.CandidateId); + if (candidate != null) + { + selections.Append($"{candidate.CandidateName}"); + if (!string.IsNullOrEmpty(candidate.Party)) + { + selections.Append($" ({candidate.Party})"); + } + selections.AppendLine(); + } + } + Contests.Add(new ContestDisplay(local.Name, local.VoteVariationType.ToString(), local.NumberElected, local.VotesAllowed, selections.ToString())); + } + } + +} diff --git a/src/electionguard-ui/ElectionGuard.UI/ViewModels/SettingsViewModel.cs b/src/electionguard-ui/ElectionGuard.UI/ViewModels/SettingsViewModel.cs index 469bd5db9..7cacdd848 100644 --- a/src/electionguard-ui/ElectionGuard.UI/ViewModels/SettingsViewModel.cs +++ b/src/electionguard-ui/ElectionGuard.UI/ViewModels/SettingsViewModel.cs @@ -1,5 +1,5 @@ -using CommunityToolkit.Mvvm.Input; - +using CommunityToolkit.Mvvm.Input; + namespace ElectionGuard.UI.ViewModels; public partial class SettingsViewModel : BaseViewModel @@ -17,13 +17,13 @@ public SettingsViewModel(IServiceProvider serviceProvider) : base(null, serviceP [ObservableProperty] private string _databaseConnectionString = DbContext.DbConnection; - partial void OnDatabaseConnectionStringChanged(string value) - { - if (!string.IsNullOrWhiteSpace(DatabaseConnectionString)) - { - DatabaseAddress = string.Empty; - DatabasePassword = string.Empty; - } + partial void OnDatabaseConnectionStringChanged(string value) + { + if (!string.IsNullOrWhiteSpace(DatabaseConnectionString)) + { + DatabaseAddress = string.Empty; + DatabasePassword = string.Empty; + } } [RelayCommand] @@ -34,19 +34,19 @@ private void Save() DbContext.DbPassword = DatabasePassword; DbContext.DbConnection = DatabaseConnectionString; - if (!string.IsNullOrEmpty(DatabaseConnectionString)) - { - DbService.Init(DatabaseConnectionString); - return; - } - - DbService.Init(DatabaseAddress, DatabasePassword); - } - + if (!string.IsNullOrEmpty(DatabaseConnectionString)) + { + DbService.Init(DatabaseConnectionString); + return; + } + + DbService.Init(DatabaseAddress, DatabasePassword); + } + [RelayCommand] private async Task Logs() - { - _ = await Launcher.Default.OpenAsync(ErrorLog.CreateLogPath()); + { + _ = await Launcher.Default.OpenAsync(ErrorLog.CreateLogPath()); } diff --git a/src/electionguard-ui/ElectionGuard.UI/ViewModels/TallyProcessViewModel.cs b/src/electionguard-ui/ElectionGuard.UI/ViewModels/TallyProcessViewModel.cs index 4398e37f2..ae02c977f 100644 --- a/src/electionguard-ui/ElectionGuard.UI/ViewModels/TallyProcessViewModel.cs +++ b/src/electionguard-ui/ElectionGuard.UI/ViewModels/TallyProcessViewModel.cs @@ -1,517 +1,517 @@ -using System.Threading.Tasks; -using CommunityToolkit.Maui.Core.Extensions; -using CommunityToolkit.Mvvm.Input; -using ElectionGuard.UI.Lib.Extensions; -using ElectionGuard.UI.Models; -using ElectionGuard.UI.Services; - -namespace ElectionGuard.UI.ViewModels; - -[QueryProperty(CurrentTallyIdParam, nameof(TallyId))] -[QueryProperty(MultiTallyIdParam, nameof(MultiTallyId))] -public partial class TallyProcessViewModel : BaseViewModel -{ - public const string CurrentTallyIdParam = nameof(TallyId); - public const string MultiTallyIdParam = nameof(MultiTallyId); - - [ObservableProperty] - private string _tallyId = string.Empty; - - [ObservableProperty] - [NotifyPropertyChangedFor(nameof(IsMultiTally))] - [NotifyPropertyChangedFor(nameof(MultiTallyNames))] - private ObservableCollection<(string TallyId, string Name)> _multiTallyIds = new(); - - public ObservableCollection MultiTallyNames => MultiTallyIds.Select(m => m.Name).ToObservableCollection(); - - [ObservableProperty] - [NotifyPropertyChangedFor(nameof(IsMultiTally))] - private string _multiTallyId = string.Empty; - - [ObservableProperty] - private MultiTallyRecord? _currentMultiTally; - - [ObservableProperty] - private bool _canUserJoinTally; - - [ObservableProperty] - private bool _canUserStartTally; - - [ObservableProperty] - private string _multiTallyProgress; - - public bool IsMultiTally - { - get => !string.IsNullOrEmpty(MultiTallyId); - } - - [ObservableProperty] - [NotifyCanExecuteChangedFor(nameof(JoinTallyCommand))] - [NotifyCanExecuteChangedFor(nameof(StartTallyCommand))] - [NotifyCanExecuteChangedFor(nameof(RejectTallyCommand))] - [NotifyCanExecuteChangedFor(nameof(AbandonTallyCommand))] - private TallyRecord? _tally = default; - - [ObservableProperty] - private Election _currentElection = new(); - - [ObservableProperty] - private List _ballotUploads = new(); - - [ObservableProperty] - [NotifyCanExecuteChangedFor(nameof(StartTallyCommand))] - private ObservableCollection _joinedGuardians = new(); - - [ObservableProperty] - private TallyCeremonyChecklist _checklist = new(); - - private List _generationTasks = new(); - - private readonly ElectionService _electionService; - private readonly TallyService _tallyService; - private readonly BallotUploadService _ballotUploadService; - private readonly TallyJoinedService _tallyJoinedService; - private readonly ITallyStateMachine _tallyRunner; - private readonly DecryptionShareService _decryptionShareService; - private readonly ChallengeResponseService _challengeResponseService; - private readonly MultiTallyService _multiTallyService; - - public TallyProcessViewModel( - IServiceProvider serviceProvider, - TallyService tallyService, - TallyJoinedService tallyJoinedService, - ElectionService electionService, - BallotUploadService ballotUploadService, - DecryptionShareService decryptionShareService, - ChallengeResponseService challengeResponseService, - MultiTallyService multiTallyService, - ITallyStateMachine tallyRunner, - ILogger logger) : - base("TallyProcess", serviceProvider) - { - _logger = logger; - _tallyService = tallyService; - _electionService = electionService; - _tallyJoinedService = tallyJoinedService; - _ballotUploadService = ballotUploadService; - _tallyRunner = tallyRunner; - _decryptionShareService = decryptionShareService; - _challengeResponseService = challengeResponseService; - _multiTallyService = multiTallyService; - - MultiTallyIds.CollectionChanged += MultiTallyIds_CollectionChanged; - LocalizationResourceManager.Current.PropertyChanged += Current_PropertyChanged; - } - - private void Current_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e) - { - if (IsMultiTally && CurrentMultiTally != null && string.IsNullOrEmpty(TallyId) && MultiTallyIds.Any()) - { - UpdateProgressString(); - } - } - - private void MultiTallyIds_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) - { - OnPropertyChanged(nameof(MultiTallyNames)); - } - - partial void OnMultiTallyIdChanged(string value) - { - if (string.IsNullOrEmpty(value)) - { - CurrentMultiTally = null; - return; - } - - _ = Shell.Current.CurrentPage.Dispatcher.DispatchAsync(async () => - { - // load the elections that are in the multitally - var multiTally = await _multiTallyService.GetByMultiTallyIdAsync(value); - if (multiTally != null) - { - CurrentMultiTally = multiTally; - - foreach (var (tallyId, electionId, name) in multiTally.TallyIds) - { - MultiTallyIds.Add((tallyId, name)); - } - - } - }); - } - - partial void OnJoinedGuardiansChanged(ObservableCollection value) - { - CanUserJoinTally = CanJoinTally(); // needs to be aware of who joined the tally. - } - - partial void OnTallyChanged(TallyRecord? oldValue, TallyRecord? newValue) - { - if (newValue is null || oldValue?.TallyId == newValue?.TallyId) - { - return; - } - - JoinedGuardians.Clear(); - - _ = Shell.Current.CurrentPage.Dispatcher.DispatchAsync(async () => - { - if (newValue?.State == TallyState.Abandoned && !IsMultiTally) - { - await Shell.Current.CurrentPage.DisplayAlert(AppResources.AbandonTallyTitle, AppResources.AbandonTallyText, AppResources.OkText); - await NavigationService.GoHome(); - - return; - } - - await UpdateElection(newValue); - await UpdateTallyData(); - - // Needs to be last. Needs to be aware of tally state change. - CanUserJoinTally = CanJoinTally(); - }); - } - - private async Task UpdateElection(TallyRecord? newValue) - { - if (newValue is null) - { - throw new ArgumentException($"{nameof(UpdateElection)}: Invalid {typeof(TallyRecord)}"); - } - - ArgumentException.ThrowIfNullOrEmpty(newValue.ElectionId, nameof(newValue.ElectionId)); - - var election = await _electionService.GetByElectionIdAsync(newValue.ElectionId); - - ElectionGuardException.ThrowIfNull(election, $"ElectionId {newValue.ElectionId} not found! Tally {newValue.Id}"); // This should never happen. - - CurrentElection = election; - - BallotUploads = await _ballotUploadService.GetByElectionIdAsync(newValue.ElectionId); - } - - partial void OnTallyIdChanged(string value) - { - _ = Shell.Current.CurrentPage.Dispatcher.DispatchAsync(async () => - { - Tally = null; - if (string.IsNullOrEmpty(value)) - { - return; - } - Tally = await _tallyService.GetByTallyIdAsync(value); - }); - } - - [RelayCommand(CanExecute = nameof(CanJoinTally))] - private async Task JoinTally() - { - try - { - var joiner = new TallyJoinedRecord() - { - TallyId = TallyId, - GuardianId = UserName!, // can assume not null, since you need to be signed into - Joined = true, - }; - - await _tallyJoinedService.JoinTallyAsync(joiner); - - if (!(_timer?.IsRunning ?? true)) - { - _timer.Start(); - } - } - catch (Exception ex) - { - ErrorMessage = ex.Message; - _logger.LogError(ex, "Cannot join the tally {TallyId}", TallyId); - } - } - - private bool CanJoinTally() - { - return Tally?.State == TallyState.PendingGuardiansJoin && - !CurrentUserJoinedAlready() && - !IsAdmin; - } - - private bool CurrentUserJoinedAlready() - { - return JoinedGuardians.Count(g => g.Name == UserName) != 0; - } - - // guardian pulls big T tally from mongo - // Tally + Tally. - - [RelayCommand(CanExecute = nameof(CanJoinTally))] - private async Task RejectTally() - { - var joiner = new TallyJoinedRecord() - { - TallyId = TallyId, - GuardianId = UserName!, // can assume not null, since you need to be signed in to get here - }; - - await _tallyJoinedService.JoinTallyAsync(joiner); - - HomeCommand.Execute(null); - } - - [RelayCommand(CanExecute = nameof(CanStartTally))] - private async Task StartTally() - { - if (Tally is null) - { - return; - } - - await _tallyService.UpdateStateAsync(Tally.TallyId, TallyState.TallyStarted); - Tally.State = TallyState.TallyStarted; - } - - [RelayCommand(CanExecute = nameof(CanAbandon))] - private async Task AbandonTally() - { - if (Tally == null) - { - // should never hit this. handles null case. - await NavigationService.GoHome(); - return; - } - - await _tallyService.UpdateStateAsync(TallyId, TallyState.Abandoned); - - await NavigationService.GoToPage(typeof(ElectionViewModel), new() - { - { ElectionViewModel.CurrentElectionParam, CurrentElection }, - }); - } - - [RelayCommand] - private async Task ViewTally() - { - await NavigationService.GoToPage(typeof(ViewTallyViewModel), new() { { nameof(TallyId), TallyId } }); - } - - private bool CanAbandon() - { - return AuthenticationService.IsAdmin && - Tally?.State == TallyState.PendingGuardiansJoin; - } - - private bool CanStartTally() - { - if (Tally == null || JoinedGuardians.Count == 0) - { - return false; - } - - // add count >= quorum - var quorumReached = JoinedGuardians.Count(g => g.Joined) >= Tally.Quorum; - - return Tally?.State == TallyState.PendingGuardiansJoin && - AuthenticationService.IsAdmin && - quorumReached; - } - - public override async Task OnAppearing() - { - await base.OnAppearing(); - _timer!.Tick += CeremonyPollingTimer_Tick; - - _timer?.Start(); - CeremonyPollingTimer_Tick(this, null); - } - - private void MakeElectionRecord(string tallyId, string resultsPath) - { - ElectionGuardException.ThrowIfNull(TallyId, "Election record cannot be generated without a TallyId."); - ElectionGuardException.ThrowIfNull(Tally, "Election record cannot be generated without a Tally."); - ElectionGuardException.ThrowIfNull(CurrentMultiTally, $"Election record cannot be generated for Tally {TallyId} without path to store it in."); - - if (!IsAdmin || Tally.State == TallyState.Abandoned) - { - return; - } - - var makeRecord = Task.Run(async () => - { - var tally = await _tallyService.GetByTallyIdAsync(tallyId); - ElectionGuardException.ThrowIfNull(tally, $"Election record cannot be generated, tally {tallyId} cannot be loaded from db."); - - await ElectionRecordGenerator.GenerateElectionRecordAsync(tally, resultsPath); - }); - _generationTasks.Add(makeRecord); - } - - private void StartNextTally() - { - TallyId = MultiTallyIds.First().TallyId; - MultiTallyIds.RemoveAt(0); - } - - void UpdateProgressString() - { - var count = 0; - if (MultiTallyIds.Count == CurrentMultiTally?.TallyIds.Count) - { - count = 0; - } - else if (MultiTallyIds.Count == 0 && string.IsNullOrEmpty(TallyId)) - { - count = CurrentMultiTally?.TallyIds.Count ?? 0; - } - else - { - // separate formula here since the ceremony will be working on 1 of them - // and it will be removed from the list and not counted yet - count = (CurrentMultiTally?.TallyIds.Count ?? 0) - MultiTallyIds.Count - 1; - } - MultiTallyProgress = $"{count} / {CurrentMultiTally?.TallyIds.Count ?? 0} {AppResources.Complete}"; - } - - private void CeremonyPollingTimer_Tick(object? sender, EventArgs e) - { - // if we are running a multi tally and we are not running a tally yet - if (IsMultiTally && CurrentMultiTally != null && string.IsNullOrEmpty(TallyId) && MultiTallyIds.Any()) - { - UpdateProgressString(); - - // set the current tally id and let it load and run that one - StartNextTally(); - return; - } - - if (Tally is null) - { - return; - } - - // if user is a guardian and we are running a multitally and have finished with a tally, move to the next one - // or if user is an admin and the tally is complete, move to the next - if ((!IsAdmin && IsMultiTally && Tally.State > TallyState.PendingGuardianRespondChallenge) || - (IsAdmin && IsMultiTally && Tally.State == TallyState.Complete) || - (IsMultiTally && Tally.State == TallyState.Abandoned)) - { - // move on to the next one if there are any left - if (MultiTallyIds.Any()) - { - // create the election record for the tally just completed - MakeElectionRecord(TallyId, CurrentMultiTally!.ResultsPath); - - UpdateProgressString(); - - // set the current tally id and let it load and run that one - StartNextTally(); - return; - } - else - { - if (IsAdmin) - { - // create the election record for the tally just completed - MakeElectionRecord(TallyId, CurrentMultiTally!.ResultsPath); - - // wait for all of the election records to be created before stopping - Task.WaitAll(_generationTasks.ToArray()); - } - - TallyId = string.Empty; - - // there are no more multi tally to run - _timer?.Stop(); - return; - } - } - - if (Tally.State == TallyState.Complete) - { - _timer?.Stop(); - return; - } - - _ = Task.Run(async () => - { - var localTally = await _tallyService.GetByTallyIdAsync(TallyId); - if (localTally != null) - { - try - { - _ = Shell.Current.CurrentPage.Dispatcher.DispatchAsync(async () => - { - Tally = localTally; - }); - await UpdateTallyData(); -#if DEBUG - ErrorMessage = Tally.State.ToString(); -#endif - if (await _tallyRunner.Run(localTally)) - { - ErrorMessage = string.Empty; -#if DEBUG - ErrorMessage = $"{Tally.State.ToString()} ran"; -#endif - } - else - { -#if DEBUG - ErrorMessage = $"{Tally.State.ToString()} waiting"; -#endif - } - } - catch (Exception ex) - { - ErrorMessage = ex.Message; - _logger.LogError(ex, "Exception in Tally Ceremony at {localTally.State}", localTally.State); - } - } - }); - } - - private async Task UpdateTallyData() - { - if (Tally == null) - { - return; - } - - // if we have fewer than max number, see if anyone else joined - if (JoinedGuardians.Count != Tally?.NumberOfGuardians) - { - var newGuardians = - from joinedGuardian in await _tallyJoinedService.GetAllByTallyIdAsync(TallyId) - let tallyItem = new GuardianTallyItem - { - Name = joinedGuardian.GuardianId, - Joined = joinedGuardian.Joined, - } - where !JoinedGuardians.Contains(tallyItem) - select tallyItem; - - JoinedGuardians.AddRange(newGuardians); - } - foreach (var guardian in JoinedGuardians) - { - guardian.HasDecryptShares = await _decryptionShareService.GetExistsByTallyAsync(TallyId, guardian.Name); - guardian.HasResponse = await _challengeResponseService.GetExistsByTallyAsync(TallyId, guardian.Name); - guardian.IsSelf = guardian.Name == UserName!; - } - - var sharesComputed = JoinedGuardians.Count(g => g.HasDecryptShares); - var challengesResponded = JoinedGuardians.Count(g => g.HasResponse); - var consentingGuardians = JoinedGuardians.Count(g => g.Joined); - - CanUserStartTally = Tally.State == TallyState.PendingGuardiansJoin - && consentingGuardians >= Tally.Quorum && IsAdmin; - - Checklist = new TallyCeremonyChecklist( - Tally!, - consentingGuardians, - sharesComputed, - challengesResponded - ); - } - -} +using System.Threading.Tasks; +using CommunityToolkit.Maui.Core.Extensions; +using CommunityToolkit.Mvvm.Input; +using ElectionGuard.ElectionSetup.Extensions; +using ElectionGuard.UI.Models; +using ElectionGuard.UI.Services; + +namespace ElectionGuard.UI.ViewModels; + +[QueryProperty(CurrentTallyIdParam, nameof(TallyId))] +[QueryProperty(MultiTallyIdParam, nameof(MultiTallyId))] +public partial class TallyProcessViewModel : BaseViewModel +{ + public const string CurrentTallyIdParam = nameof(TallyId); + public const string MultiTallyIdParam = nameof(MultiTallyId); + + [ObservableProperty] + private string _tallyId = string.Empty; + + [ObservableProperty] + [NotifyPropertyChangedFor(nameof(IsMultiTally))] + [NotifyPropertyChangedFor(nameof(MultiTallyNames))] + private ObservableCollection<(string TallyId, string Name)> _multiTallyIds = new(); + + public ObservableCollection MultiTallyNames => MultiTallyIds.Select(m => m.Name).ToObservableCollection(); + + [ObservableProperty] + [NotifyPropertyChangedFor(nameof(IsMultiTally))] + private string _multiTallyId = string.Empty; + + [ObservableProperty] + private MultiTallyRecord? _currentMultiTally; + + [ObservableProperty] + private bool _canUserJoinTally; + + [ObservableProperty] + private bool _canUserStartTally; + + [ObservableProperty] + private string _multiTallyProgress; + + public bool IsMultiTally + { + get => !string.IsNullOrEmpty(MultiTallyId); + } + + [ObservableProperty] + [NotifyCanExecuteChangedFor(nameof(JoinTallyCommand))] + [NotifyCanExecuteChangedFor(nameof(StartTallyCommand))] + [NotifyCanExecuteChangedFor(nameof(RejectTallyCommand))] + [NotifyCanExecuteChangedFor(nameof(AbandonTallyCommand))] + private TallyRecord? _tally = default; + + [ObservableProperty] + private Election _currentElection = new(); + + [ObservableProperty] + private List _ballotUploads = new(); + + [ObservableProperty] + [NotifyCanExecuteChangedFor(nameof(StartTallyCommand))] + private ObservableCollection _joinedGuardians = new(); + + [ObservableProperty] + private TallyCeremonyChecklist _checklist = new(); + + private List _generationTasks = new(); + + private readonly ElectionService _electionService; + private readonly TallyService _tallyService; + private readonly BallotUploadService _ballotUploadService; + private readonly TallyJoinedService _tallyJoinedService; + private readonly ITallyStateMachine _tallyRunner; + private readonly DecryptionShareService _decryptionShareService; + private readonly ChallengeResponseService _challengeResponseService; + private readonly MultiTallyService _multiTallyService; + + public TallyProcessViewModel( + IServiceProvider serviceProvider, + TallyService tallyService, + TallyJoinedService tallyJoinedService, + ElectionService electionService, + BallotUploadService ballotUploadService, + DecryptionShareService decryptionShareService, + ChallengeResponseService challengeResponseService, + MultiTallyService multiTallyService, + ITallyStateMachine tallyRunner, + ILogger logger) : + base("TallyProcess", serviceProvider) + { + _logger = logger; + _tallyService = tallyService; + _electionService = electionService; + _tallyJoinedService = tallyJoinedService; + _ballotUploadService = ballotUploadService; + _tallyRunner = tallyRunner; + _decryptionShareService = decryptionShareService; + _challengeResponseService = challengeResponseService; + _multiTallyService = multiTallyService; + + MultiTallyIds.CollectionChanged += MultiTallyIds_CollectionChanged; + LocalizationResourceManager.Current.PropertyChanged += Current_PropertyChanged; + } + + private void Current_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e) + { + if (IsMultiTally && CurrentMultiTally != null && string.IsNullOrEmpty(TallyId) && MultiTallyIds.Any()) + { + UpdateProgressString(); + } + } + + private void MultiTallyIds_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + OnPropertyChanged(nameof(MultiTallyNames)); + } + + partial void OnMultiTallyIdChanged(string value) + { + if (string.IsNullOrEmpty(value)) + { + CurrentMultiTally = null; + return; + } + + _ = Shell.Current.CurrentPage.Dispatcher.DispatchAsync(async () => + { + // load the elections that are in the multitally + var multiTally = await _multiTallyService.GetByMultiTallyIdAsync(value); + if (multiTally != null) + { + CurrentMultiTally = multiTally; + + foreach (var (tallyId, electionId, name) in multiTally.TallyIds) + { + MultiTallyIds.Add((tallyId, name)); + } + + } + }); + } + + partial void OnJoinedGuardiansChanged(ObservableCollection value) + { + CanUserJoinTally = CanJoinTally(); // needs to be aware of who joined the tally. + } + + partial void OnTallyChanged(TallyRecord? oldValue, TallyRecord? newValue) + { + if (newValue is null || oldValue?.TallyId == newValue?.TallyId) + { + return; + } + + JoinedGuardians.Clear(); + + _ = Shell.Current.CurrentPage.Dispatcher.DispatchAsync(async () => + { + if (newValue?.State == TallyState.Abandoned && !IsMultiTally) + { + await Shell.Current.CurrentPage.DisplayAlert(AppResources.AbandonTallyTitle, AppResources.AbandonTallyText, AppResources.OkText); + await NavigationService.GoHome(); + + return; + } + + await UpdateElection(newValue); + await UpdateTallyData(); + + // Needs to be last. Needs to be aware of tally state change. + CanUserJoinTally = CanJoinTally(); + }); + } + + private async Task UpdateElection(TallyRecord? newValue) + { + if (newValue is null) + { + throw new ArgumentException($"{nameof(UpdateElection)}: Invalid {typeof(TallyRecord)}"); + } + + ArgumentException.ThrowIfNullOrEmpty(newValue.ElectionId, nameof(newValue.ElectionId)); + + var election = await _electionService.GetByElectionIdAsync(newValue.ElectionId); + + ElectionGuardException.ThrowIfNull(election, $"ElectionId {newValue.ElectionId} not found! Tally {newValue.Id}"); // This should never happen. + + CurrentElection = election; + + BallotUploads = await _ballotUploadService.GetByElectionIdAsync(newValue.ElectionId); + } + + partial void OnTallyIdChanged(string value) + { + _ = Shell.Current.CurrentPage.Dispatcher.DispatchAsync(async () => + { + Tally = null; + if (string.IsNullOrEmpty(value)) + { + return; + } + Tally = await _tallyService.GetByTallyIdAsync(value); + }); + } + + [RelayCommand(CanExecute = nameof(CanJoinTally))] + private async Task JoinTally() + { + try + { + var joiner = new TallyJoinedRecord() + { + TallyId = TallyId, + GuardianId = UserName!, // can assume not null, since you need to be signed into + Joined = true, + }; + + await _tallyJoinedService.JoinTallyAsync(joiner); + + if (!(_timer?.IsRunning ?? true)) + { + _timer.Start(); + } + } + catch (Exception ex) + { + ErrorMessage = ex.Message; + _logger.LogError(ex, "Cannot join the tally {TallyId}", TallyId); + } + } + + private bool CanJoinTally() + { + return Tally?.State == TallyState.PendingGuardiansJoin && + !CurrentUserJoinedAlready() && + !IsAdmin; + } + + private bool CurrentUserJoinedAlready() + { + return JoinedGuardians.Count(g => g.Name == UserName) != 0; + } + + // guardian pulls big T tally from mongo + // Tally + Tally. + + [RelayCommand(CanExecute = nameof(CanJoinTally))] + private async Task RejectTally() + { + var joiner = new TallyJoinedRecord() + { + TallyId = TallyId, + GuardianId = UserName!, // can assume not null, since you need to be signed in to get here + }; + + await _tallyJoinedService.JoinTallyAsync(joiner); + + HomeCommand.Execute(null); + } + + [RelayCommand(CanExecute = nameof(CanStartTally))] + private async Task StartTally() + { + if (Tally is null) + { + return; + } + + await _tallyService.UpdateStateAsync(Tally.TallyId, TallyState.TallyStarted); + Tally.State = TallyState.TallyStarted; + } + + [RelayCommand(CanExecute = nameof(CanAbandon))] + private async Task AbandonTally() + { + if (Tally == null) + { + // should never hit this. handles null case. + await NavigationService.GoHome(); + return; + } + + await _tallyService.UpdateStateAsync(TallyId, TallyState.Abandoned); + + await NavigationService.GoToPage(typeof(ElectionViewModel), new() + { + { ElectionViewModel.CurrentElectionParam, CurrentElection }, + }); + } + + [RelayCommand] + private async Task ViewTally() + { + await NavigationService.GoToPage(typeof(ViewTallyViewModel), new() { { nameof(TallyId), TallyId } }); + } + + private bool CanAbandon() + { + return AuthenticationService.IsAdmin && + Tally?.State == TallyState.PendingGuardiansJoin; + } + + private bool CanStartTally() + { + if (Tally == null || JoinedGuardians.Count == 0) + { + return false; + } + + // add count >= quorum + var quorumReached = JoinedGuardians.Count(g => g.Joined) >= Tally.Quorum; + + return Tally?.State == TallyState.PendingGuardiansJoin && + AuthenticationService.IsAdmin && + quorumReached; + } + + public override async Task OnAppearing() + { + await base.OnAppearing(); + _timer!.Tick += CeremonyPollingTimer_Tick; + + _timer?.Start(); + CeremonyPollingTimer_Tick(this, null); + } + + private void MakeElectionRecord(string tallyId, string resultsPath) + { + ElectionGuardException.ThrowIfNull(TallyId, "Election record cannot be generated without a TallyId."); + ElectionGuardException.ThrowIfNull(Tally, "Election record cannot be generated without a Tally."); + ElectionGuardException.ThrowIfNull(CurrentMultiTally, $"Election record cannot be generated for Tally {TallyId} without path to store it in."); + + if (!IsAdmin || Tally.State == TallyState.Abandoned) + { + return; + } + + var makeRecord = Task.Run(async () => + { + var tally = await _tallyService.GetByTallyIdAsync(tallyId); + ElectionGuardException.ThrowIfNull(tally, $"Election record cannot be generated, tally {tallyId} cannot be loaded from db."); + + await ElectionRecordGenerator.GenerateElectionRecordAsync(tally, resultsPath); + }); + _generationTasks.Add(makeRecord); + } + + private void StartNextTally() + { + TallyId = MultiTallyIds.First().TallyId; + MultiTallyIds.RemoveAt(0); + } + + void UpdateProgressString() + { + var count = 0; + if (MultiTallyIds.Count == CurrentMultiTally?.TallyIds.Count) + { + count = 0; + } + else if (MultiTallyIds.Count == 0 && string.IsNullOrEmpty(TallyId)) + { + count = CurrentMultiTally?.TallyIds.Count ?? 0; + } + else + { + // separate formula here since the ceremony will be working on 1 of them + // and it will be removed from the list and not counted yet + count = (CurrentMultiTally?.TallyIds.Count ?? 0) - MultiTallyIds.Count - 1; + } + MultiTallyProgress = $"{count} / {CurrentMultiTally?.TallyIds.Count ?? 0} {AppResources.Complete}"; + } + + private void CeremonyPollingTimer_Tick(object? sender, EventArgs e) + { + // if we are running a multi tally and we are not running a tally yet + if (IsMultiTally && CurrentMultiTally != null && string.IsNullOrEmpty(TallyId) && MultiTallyIds.Any()) + { + UpdateProgressString(); + + // set the current tally id and let it load and run that one + StartNextTally(); + return; + } + + if (Tally is null) + { + return; + } + + // if user is a guardian and we are running a multitally and have finished with a tally, move to the next one + // or if user is an admin and the tally is complete, move to the next + if ((!IsAdmin && IsMultiTally && Tally.State > TallyState.PendingGuardianRespondChallenge) || + (IsAdmin && IsMultiTally && Tally.State == TallyState.Complete) || + (IsMultiTally && Tally.State == TallyState.Abandoned)) + { + // move on to the next one if there are any left + if (MultiTallyIds.Any()) + { + // create the election record for the tally just completed + MakeElectionRecord(TallyId, CurrentMultiTally!.ResultsPath); + + UpdateProgressString(); + + // set the current tally id and let it load and run that one + StartNextTally(); + return; + } + else + { + if (IsAdmin) + { + // create the election record for the tally just completed + MakeElectionRecord(TallyId, CurrentMultiTally!.ResultsPath); + + // wait for all of the election records to be created before stopping + Task.WaitAll(_generationTasks.ToArray()); + } + + TallyId = string.Empty; + + // there are no more multi tally to run + _timer?.Stop(); + return; + } + } + + if (Tally.State == TallyState.Complete) + { + _timer?.Stop(); + return; + } + + _ = Task.Run(async () => + { + var localTally = await _tallyService.GetByTallyIdAsync(TallyId); + if (localTally != null) + { + try + { + _ = Shell.Current.CurrentPage.Dispatcher.DispatchAsync(async () => + { + Tally = localTally; + }); + await UpdateTallyData(); +#if DEBUG + ErrorMessage = Tally.State.ToString(); +#endif + if (await _tallyRunner.Run(localTally)) + { + ErrorMessage = string.Empty; +#if DEBUG + ErrorMessage = $"{Tally.State.ToString()} ran"; +#endif + } + else + { +#if DEBUG + ErrorMessage = $"{Tally.State.ToString()} waiting"; +#endif + } + } + catch (Exception ex) + { + ErrorMessage = ex.Message; + _logger.LogError(ex, "Exception in Tally Ceremony at {localTally.State}", localTally.State); + } + } + }); + } + + private async Task UpdateTallyData() + { + if (Tally == null) + { + return; + } + + // if we have fewer than max number, see if anyone else joined + if (JoinedGuardians.Count != Tally?.NumberOfGuardians) + { + var newGuardians = + from joinedGuardian in await _tallyJoinedService.GetAllByTallyIdAsync(TallyId) + let tallyItem = new GuardianTallyItem + { + Name = joinedGuardian.GuardianId, + Joined = joinedGuardian.Joined, + } + where !JoinedGuardians.Contains(tallyItem) + select tallyItem; + + JoinedGuardians.AddRange(newGuardians); + } + foreach (var guardian in JoinedGuardians) + { + guardian.HasDecryptShares = await _decryptionShareService.GetExistsByTallyAsync(TallyId, guardian.Name); + guardian.HasResponse = await _challengeResponseService.GetExistsByTallyAsync(TallyId, guardian.Name); + guardian.IsSelf = guardian.Name == UserName!; + } + + var sharesComputed = JoinedGuardians.Count(g => g.HasDecryptShares); + var challengesResponded = JoinedGuardians.Count(g => g.HasResponse); + var consentingGuardians = JoinedGuardians.Count(g => g.Joined); + + CanUserStartTally = Tally.State == TallyState.PendingGuardiansJoin + && consentingGuardians >= Tally.Quorum && IsAdmin; + + Checklist = new TallyCeremonyChecklist( + Tally!, + consentingGuardians, + sharesComputed, + challengesResponded + ); + } + +} diff --git a/src/electionguard-ui/ElectionGuard.UI/ViewModels/ViewKeyCeremonyViewModel.cs b/src/electionguard-ui/ElectionGuard.UI/ViewModels/ViewKeyCeremonyViewModel.cs index 43e68c2c0..ad6924212 100644 --- a/src/electionguard-ui/ElectionGuard.UI/ViewModels/ViewKeyCeremonyViewModel.cs +++ b/src/electionguard-ui/ElectionGuard.UI/ViewModels/ViewKeyCeremonyViewModel.cs @@ -1,7 +1,6 @@ using CommunityToolkit.Mvvm.Input; -using ElectionGuard.ElectionSetup; using ElectionGuard.UI.Models; - + namespace ElectionGuard.UI.ViewModels; [QueryProperty(CurrentKeyCeremonyParam, "KeyCeremony")] @@ -49,17 +48,17 @@ public override async Task OnAppearing() _timer!.Tick += CeremonyPollingTimer_Tick; - try - { - _joinPressed = await HasJoined(); - if (!_timer.IsRunning) - { - _timer.Start(); + try + { + _joinPressed = await HasJoined(); + if (!_timer.IsRunning) + { + _timer.Start(); } } catch (Exception) - { - _timer.Stop(); + { + _timer.Stop(); } } @@ -100,31 +99,31 @@ partial void OnKeyCeremonyChanged(KeyCeremonyRecord? value) { _timer!.Start(); CeremonyPollingTimer_Tick(this, null); - } + } } } [RelayCommand(CanExecute = nameof(CanJoin))] public async Task Join() { - _joinPressed = true; - // TODO: Tell the signalR hub what user has joined - try - { - await _mediator!.RunKeyCeremony(IsAdmin); - } - catch (Exception ex) - { - ErrorMessage = ex.Message; - _logger.LogError(ex, "Exception in Key Ceremony at {KeyCeremony.State}", KeyCeremony.State); - } + _joinPressed = true; + // TODO: Tell the signalR hub what user has joined + try + { + await _mediator!.RunKeyCeremony(IsAdmin); + } + catch (Exception ex) + { + ErrorMessage = ex.Message; + _logger.LogError(ex, "Exception in Key Ceremony at {KeyCeremony.State}", KeyCeremony.State); + } } private void CeremonyPollingTimer_Tick(object? sender, EventArgs e) { - if (KeyCeremony is null) - { - return; + if (KeyCeremony is null) + { + return; } if (KeyCeremony.State == KeyCeremonyState.Complete) @@ -133,29 +132,29 @@ private void CeremonyPollingTimer_Tick(object? sender, EventArgs e) return; } - _ = Task.Run(async () => + _ = Task.Run(async () => { - try - { - await UpdateGuardiansData(); - if (IsAdmin || (!IsAdmin && _joinPressed)) - { - await _mediator!.RunKeyCeremony(IsAdmin); - ErrorMessage = string.Empty; + try + { + await UpdateGuardiansData(); + if (IsAdmin || (!IsAdmin && _joinPressed)) + { + await _mediator!.RunKeyCeremony(IsAdmin); + ErrorMessage = string.Empty; } - } - catch (Exception ex) - { - ErrorMessage = ex.Message; - _logger.LogError(ex, "Exception in Key Ceremony at {KeyCeremony.State}", KeyCeremony.State); - } + } + catch (Exception ex) + { + ErrorMessage = ex.Message; + _logger.LogError(ex, "Exception in Key Ceremony at {KeyCeremony.State}", KeyCeremony.State); + } }); } - private async Task HasJoined() - { - ElectionGuardException.ThrowIfNull(UserName); - + private async Task HasJoined() + { + ElectionGuardException.ThrowIfNull(UserName); + var publicKey = await _publicKeyService.GetByIdsAsync(KeyCeremonyId, UserName); return publicKey is not null; @@ -164,23 +163,23 @@ private async Task HasJoined() private async Task UpdateGuardiansData() { // if we have fewer than max number, see if anyone else joined - if (GuardianList.Count != KeyCeremony.NumberOfGuardians) - { + if (GuardianList.Count != KeyCeremony.NumberOfGuardians) + { var localData = await _publicKeyService.GetAllByKeyCeremonyIdAsync(KeyCeremonyId); - - foreach (var item in localData) - { - if (!GuardianList.Any(g => g.Name == item.GuardianId)) - { - GuardianList.Add(new GuardianItem() { Name = item.GuardianId }); - } - } - } - foreach (var guardian in GuardianList) - { - guardian.HasBackup = await _mediator!.HasBackup(guardian.Name); - (guardian.HasVerified, guardian.BadVerified) = await _mediator!.HasVerified(guardian.Name); - guardian.IsSelf = guardian.Name == UserName!; + + foreach (var item in localData) + { + if (!GuardianList.Any(g => g.Name == item.GuardianId)) + { + GuardianList.Add(new GuardianItem() { Name = item.GuardianId }); + } + } + } + foreach (var guardian in GuardianList) + { + guardian.HasBackup = await _mediator!.HasBackup(guardian.Name); + (guardian.HasVerified, guardian.BadVerified) = await _mediator!.HasVerified(guardian.Name); + guardian.IsSelf = guardian.Name == UserName!; } } diff --git a/src/electionguard-ui/ElectionGuard.UI/ViewModels/ViewTallyViewModel.cs b/src/electionguard-ui/ElectionGuard.UI/ViewModels/ViewTallyViewModel.cs index d0627d056..83e0e9419 100644 --- a/src/electionguard-ui/ElectionGuard.UI/ViewModels/ViewTallyViewModel.cs +++ b/src/electionguard-ui/ElectionGuard.UI/ViewModels/ViewTallyViewModel.cs @@ -1,248 +1,248 @@ -using CommunityToolkit.Maui.Storage; -using CommunityToolkit.Mvvm.Input; -using ElectionGuard.Decryption.Tally; -using ElectionGuard.UI.Lib.Models; -using ElectionGuard.UI.Models; -using Newtonsoft.Json; - -namespace ElectionGuard.UI.ViewModels; - -[QueryProperty(CurrentTallyIdParam, nameof(TallyId))] -public partial class ViewTallyViewModel : BaseViewModel -{ - public const string CurrentTallyIdParam = "TallyId"; - - [ObservableProperty] - private string _tallyId = string.Empty; - - [ObservableProperty] - private TallyRecord? _tally = default; - - [ObservableProperty] - private Election? _currentElection = default; - - [ObservableProperty] - private Manifest? _originalManifest = default; - - [ObservableProperty] - private InternalManifest? _currentManifest = default; - - [ObservableProperty] - private PlaintextTally? _plaintextTally = default; - - [ObservableProperty] - private ObservableCollection _joinedGuardians = new(); - - [ObservableProperty] - private ObservableCollection _contests = new(); - - private readonly ElectionService _electionService; - private readonly TallyService _tallyService; - private readonly ManifestService _manifestService; - private readonly BallotUploadService _ballotUploadService; - private readonly TallyJoinedService _tallyJoinedService; - private readonly DecryptionShareService _decryptionShareService; - private readonly ChallengeResponseService _challengeResponseService; - private readonly PlaintextTallyService _plaintextTallyService; - - public ViewTallyViewModel( - IServiceProvider serviceProvider, - TallyService tallyService, - TallyJoinedService tallyJoinedService, - ElectionService electionService, - BallotUploadService ballotUploadService, - DecryptionShareService decryptionShareService, - PlaintextTallyService plaintextTallyService, - ManifestService manifestService, - ChallengeResponseService challengeResponseService, - ILogger logger) : - base("ViewTally", serviceProvider) - { - _tallyService = tallyService; - _electionService = electionService; - _manifestService = manifestService; - _tallyJoinedService = tallyJoinedService; - _ballotUploadService = ballotUploadService; - _decryptionShareService = decryptionShareService; - _challengeResponseService = challengeResponseService; - _plaintextTallyService = plaintextTallyService; - _logger = logger; - } - - partial void OnTallyIdChanged(string value) - { - _ = Shell.Current.CurrentPage.Dispatcher.DispatchAsync(async () => - { - Tally = await _tallyService.GetByTallyIdAsync(value); - - var plaintextRecord = await _plaintextTallyService.GetByTallyIdAsync(value); - if (plaintextRecord is null) - { - throw new ElectionGuardException($"Plaintext tally not found! Tally {value}"); - } - this.PlaintextTally = JsonConvert.DeserializeObject(plaintextRecord); - }); - } - - partial void OnTallyChanged(TallyRecord? oldValue, TallyRecord? newValue) - { - if (newValue is not null) - { - ArgumentException.ThrowIfNullOrEmpty(newValue.ElectionId); - - _ = Shell.Current.CurrentPage.Dispatcher.DispatchAsync(async () => - { - var electionId = newValue.ElectionId ?? string.Empty; - var election = await _electionService.GetByElectionIdAsync(electionId); - ElectionGuardException.ThrowIfNull(election, $"ElectionId {electionId} not found! Tally {newValue.TallyId}"); - - CurrentElection = election; - - await UpdateTallyData(); - }); - } - } - - partial void OnCurrentElectionChanged(Election? oldValue, Election? newValue) - { - if (newValue is not null) - { - ArgumentException.ThrowIfNullOrEmpty(newValue.ElectionId); - - _ = Shell.Current.CurrentPage.Dispatcher.DispatchAsync(async () => - { - var manifest = await _manifestService.GetByElectionIdAsync(newValue.ElectionId); - ElectionGuardException.ThrowIfNull(manifest, $"Could not load manifest for election {newValue.ElectionId}"); - - OriginalManifest = JsonConvert.DeserializeObject(manifest); - CurrentManifest = new(OriginalManifest); - - GenerateContestData(); - }); - } - } - - private async Task UpdateTallyData() - { - // if we have fewer than max number, see if anyone else joined - if (JoinedGuardians.Count != Tally?.NumberOfGuardians) - { - var localData = await _tallyJoinedService.GetAllByTallyIdAsync(TallyId); - - foreach (var item in localData) - { - if (!JoinedGuardians.Any(g => g.Name == item.GuardianId)) - { - JoinedGuardians.Add(new GuardianTallyItem() { Name = item.GuardianId, Joined = item.Joined }); - } - } - } - foreach (var guardian in JoinedGuardians) - { - guardian.HasDecryptShares = await _decryptionShareService.GetExistsByTallyAsync(TallyId, guardian.Name); - guardian.HasResponse = await _challengeResponseService.GetExistsByTallyAsync(TallyId, guardian.Name); - guardian.IsSelf = guardian.Name == UserName!; - } - } - - [RelayCommand] - private async Task ExportTally() - { - var token = new CancellationToken(); - var outputResult = await FolderPicker.PickAsync(token); - if (outputResult.IsSuccessful) - { - await ElectionRecordGenerator.GenerateElectionRecordAsync(Tally!, outputResult.Folder!.Path); - } - } - - private void GenerateContestData() - { - ElectionGuardException.ThrowIfNull(CurrentManifest); - ElectionGuardException.ThrowIfNull(OriginalManifest); - ElectionGuardException.ThrowIfNull(PlaintextTally); - - List parties = new(); - List candidates = new(); - - for (ulong i = 0; i < OriginalManifest.PartiesSize; i++) - { - var local = OriginalManifest.GetPartyAtIndex(i); - parties.Add(new(local.Name.GetTextAt(0).Value, local.Abbreviation, local.ObjectId)); - } - - for (ulong i = 0; i < OriginalManifest.CandidatesSize; i++) - { - var local = OriginalManifest.GetCandidateAtIndex(i); - var party = parties.FirstOrDefault(p => p.PartyId == local.PartyId) ?? new PartyDisplay(string.Empty, string.Empty, string.Empty); ; - candidates.Add(new(local.Name.GetTextAt(0).Value, party.Name, local.ObjectId, local.IsWriteIn)); - } - - foreach (var (key, item) in PlaintextTally.Contests) - { - var contest = CurrentManifest.Contests.Single(c => c.ObjectId == item.ObjectId); - var contestItem = new ContestItem() { Name = contest.Name, TotalVotes = contest.VotesAllowed * (ulong)Tally.CastBallotCount }; - ulong writeInTotal = 0; - ulong totalVotes = 0; - - foreach (var (skey, selection) in item.Selections) - { - try - { - var fullSelection = contest.Selections.Single(c => c.ObjectId == selection.ObjectId); - var candidate = candidates.Single(c => c.CandidateId == fullSelection.CandidateId); - var percent = (float)selection.Tally / (contest.VotesAllowed * (ulong)Tally.CastBallotCount) * 100; - if (!candidate.isWritein) - { - contestItem.Selections.Add(new() { Name = candidate.CandidateName, Party = candidate.Party, Votes = selection.Tally, Percent = percent }); - } - else - { - writeInTotal += selection.Tally; - } - totalVotes += selection.Tally; - } - catch (Exception ex) - { - _logger?.LogError(ex, "Error parsing contest {item.ObjectId} selection {selection.ObjectId}", item.ObjectId, selection.ObjectId); - } - } - if (writeInTotal > 0) - { - var percent = (float)writeInTotal / (contest.VotesAllowed * (ulong)Tally.CastBallotCount) * 100; - contestItem.Selections.Add(new() { Name = "Write-ins", Party = string.Empty, Votes = writeInTotal, Percent = percent }); - } - - // TallyOverVoteUndervote(contest, Tally, contestItem, totalVotes); - - Contests.Add(contestItem); - } - } - - // TODO: Fix calculation and add to contest item. - private void TallyOverVoteUndervote(ContestDescriptionWithPlaceholders contest, ContestItem contestItem, ulong totalVotes) - { - if (Tally == null) - { - return; - } - - var overVoteTotal = 0UL; - var underVoteTotal = (contest.VotesAllowed * (ulong)Tally.CastBallotCount) - totalVotes; - var underPercent = (float)underVoteTotal / (contest.VotesAllowed * (ulong)Tally.CastBallotCount) * 100; - - contestItem.Selections.Add(new() { Name = "Undervotes", Party = string.Empty, Votes = underVoteTotal, Percent = underPercent }); - var overPercent = (float)overVoteTotal / (contest.VotesAllowed * (ulong)Tally.CastBallotCount) * 100; - - contestItem.Selections.Add(new() { Name = "Overvotes", Party = string.Empty, Votes = overVoteTotal, Percent = overPercent }); - } - - public override async Task OnLeavingPage() - { - OriginalManifest?.Dispose(); - CurrentManifest?.Dispose(); - PlaintextTally?.Dispose(); - - await base.OnLeavingPage(); - } -} +using CommunityToolkit.Maui.Storage; +using CommunityToolkit.Mvvm.Input; +using ElectionGuard.Decryption.Tally; +using ElectionGuard.UI.Lib.Models; +using ElectionGuard.UI.Models; +using Newtonsoft.Json; + +namespace ElectionGuard.UI.ViewModels; + +[QueryProperty(CurrentTallyIdParam, nameof(TallyId))] +public partial class ViewTallyViewModel : BaseViewModel +{ + public const string CurrentTallyIdParam = "TallyId"; + + [ObservableProperty] + private string _tallyId = string.Empty; + + [ObservableProperty] + private TallyRecord? _tally = default; + + [ObservableProperty] + private Election? _currentElection = default; + + [ObservableProperty] + private Manifest? _originalManifest = default; + + [ObservableProperty] + private InternalManifest? _currentManifest = default; + + [ObservableProperty] + private PlaintextTally? _plaintextTally = default; + + [ObservableProperty] + private ObservableCollection _joinedGuardians = new(); + + [ObservableProperty] + private ObservableCollection _contests = new(); + + private readonly ElectionService _electionService; + private readonly TallyService _tallyService; + private readonly ManifestService _manifestService; + private readonly BallotUploadService _ballotUploadService; + private readonly TallyJoinedService _tallyJoinedService; + private readonly DecryptionShareService _decryptionShareService; + private readonly ChallengeResponseService _challengeResponseService; + private readonly PlaintextTallyService _plaintextTallyService; + + public ViewTallyViewModel( + IServiceProvider serviceProvider, + TallyService tallyService, + TallyJoinedService tallyJoinedService, + ElectionService electionService, + BallotUploadService ballotUploadService, + DecryptionShareService decryptionShareService, + PlaintextTallyService plaintextTallyService, + ManifestService manifestService, + ChallengeResponseService challengeResponseService, + ILogger logger) : + base("ViewTally", serviceProvider) + { + _tallyService = tallyService; + _electionService = electionService; + _manifestService = manifestService; + _tallyJoinedService = tallyJoinedService; + _ballotUploadService = ballotUploadService; + _decryptionShareService = decryptionShareService; + _challengeResponseService = challengeResponseService; + _plaintextTallyService = plaintextTallyService; + _logger = logger; + } + + partial void OnTallyIdChanged(string value) + { + _ = Shell.Current.CurrentPage.Dispatcher.DispatchAsync(async () => + { + Tally = await _tallyService.GetByTallyIdAsync(value); + + var plaintextRecord = await _plaintextTallyService.GetByTallyIdAsync(value); + if (plaintextRecord is null) + { + throw new ElectionGuardException($"Plaintext tally not found! Tally {value}"); + } + this.PlaintextTally = JsonConvert.DeserializeObject(plaintextRecord); + }); + } + + partial void OnTallyChanged(TallyRecord? oldValue, TallyRecord? newValue) + { + if (newValue is not null) + { + ArgumentException.ThrowIfNullOrEmpty(newValue.ElectionId); + + _ = Shell.Current.CurrentPage.Dispatcher.DispatchAsync(async () => + { + var electionId = newValue.ElectionId ?? string.Empty; + var election = await _electionService.GetByElectionIdAsync(electionId); + ElectionGuardException.ThrowIfNull(election, $"ElectionId {electionId} not found! Tally {newValue.TallyId}"); + + CurrentElection = election; + + await UpdateTallyData(); + }); + } + } + + partial void OnCurrentElectionChanged(Election? oldValue, Election? newValue) + { + if (newValue is not null) + { + ArgumentException.ThrowIfNullOrEmpty(newValue.ElectionId); + + _ = Shell.Current.CurrentPage.Dispatcher.DispatchAsync(async () => + { + var manifest = await _manifestService.GetByElectionIdAsync(newValue.ElectionId); + ElectionGuardException.ThrowIfNull(manifest, $"Could not load manifest for election {newValue.ElectionId}"); + + OriginalManifest = JsonConvert.DeserializeObject(manifest); + CurrentManifest = new(OriginalManifest); + + GenerateContestData(); + }); + } + } + + private async Task UpdateTallyData() + { + // if we have fewer than max number, see if anyone else joined + if (JoinedGuardians.Count != Tally?.NumberOfGuardians) + { + var localData = await _tallyJoinedService.GetAllByTallyIdAsync(TallyId); + + foreach (var item in localData) + { + if (!JoinedGuardians.Any(g => g.Name == item.GuardianId)) + { + JoinedGuardians.Add(new GuardianTallyItem() { Name = item.GuardianId, Joined = item.Joined }); + } + } + } + foreach (var guardian in JoinedGuardians) + { + guardian.HasDecryptShares = await _decryptionShareService.GetExistsByTallyAsync(TallyId, guardian.Name); + guardian.HasResponse = await _challengeResponseService.GetExistsByTallyAsync(TallyId, guardian.Name); + guardian.IsSelf = guardian.Name == UserName!; + } + } + + [RelayCommand] + private async Task ExportTally() + { + var token = new CancellationToken(); + var outputResult = await FolderPicker.PickAsync(token); + if (outputResult.IsSuccessful) + { + await ElectionRecordGenerator.GenerateElectionRecordAsync(Tally!, outputResult.Folder!.Path); + } + } + + private void GenerateContestData() + { + ElectionGuardException.ThrowIfNull(CurrentManifest); + ElectionGuardException.ThrowIfNull(OriginalManifest); + ElectionGuardException.ThrowIfNull(PlaintextTally); + + List parties = new(); + List candidates = new(); + + for (ulong i = 0; i < OriginalManifest.PartiesSize; i++) + { + var local = OriginalManifest.GetPartyAtIndex(i); + parties.Add(new(local.Name.GetTextAt(0).Value, local.Abbreviation, local.ObjectId)); + } + + for (ulong i = 0; i < OriginalManifest.CandidatesSize; i++) + { + var local = OriginalManifest.GetCandidateAtIndex(i); + var party = parties.FirstOrDefault(p => p.PartyId == local.PartyId) ?? new PartyDisplay(string.Empty, string.Empty, string.Empty); ; + candidates.Add(new(local.Name.GetTextAt(0).Value, party.Name, local.ObjectId, local.IsWriteIn)); + } + + foreach (var (key, item) in PlaintextTally.Contests) + { + var contest = CurrentManifest.Contests.Single(c => c.ObjectId == item.ObjectId); + var contestItem = new ContestItem() { Name = contest.Name, TotalVotes = contest.VotesAllowed * (ulong)Tally.CastBallotCount }; + ulong writeInTotal = 0; + ulong totalVotes = 0; + + foreach (var (skey, selection) in item.Selections) + { + try + { + var fullSelection = contest.Selections.Single(c => c.ObjectId == selection.ObjectId); + var candidate = candidates.Single(c => c.CandidateId == fullSelection.CandidateId); + var percent = (float)selection.Tally / (contest.VotesAllowed * (ulong)Tally.CastBallotCount) * 100; + if (!candidate.isWritein) + { + contestItem.Selections.Add(new() { Name = candidate.CandidateName, Party = candidate.Party, Votes = selection.Tally, Percent = percent }); + } + else + { + writeInTotal += selection.Tally; + } + totalVotes += selection.Tally; + } + catch (Exception ex) + { + _logger?.LogError(ex, "Error parsing contest {item.ObjectId} selection {selection.ObjectId}", item.ObjectId, selection.ObjectId); + } + } + if (writeInTotal > 0) + { + var percent = (float)writeInTotal / (contest.VotesAllowed * (ulong)Tally.CastBallotCount) * 100; + contestItem.Selections.Add(new() { Name = "Write-ins", Party = string.Empty, Votes = writeInTotal, Percent = percent }); + } + + // TallyOverVoteUndervote(contest, Tally, contestItem, totalVotes); + + Contests.Add(contestItem); + } + } + + // TODO: Fix calculation and add to contest item. + private void TallyOverVoteUndervote(ContestDescriptionWithPlaceholders contest, ContestItem contestItem, ulong totalVotes) + { + if (Tally == null) + { + return; + } + + var overVoteTotal = 0UL; + var underVoteTotal = (contest.VotesAllowed * (ulong)Tally.CastBallotCount) - totalVotes; + var underPercent = (float)underVoteTotal / (contest.VotesAllowed * (ulong)Tally.CastBallotCount) * 100; + + contestItem.Selections.Add(new() { Name = "Undervotes", Party = string.Empty, Votes = underVoteTotal, Percent = underPercent }); + var overPercent = (float)overVoteTotal / (contest.VotesAllowed * (ulong)Tally.CastBallotCount) * 100; + + contestItem.Selections.Add(new() { Name = "Overvotes", Party = string.Empty, Votes = overVoteTotal, Percent = overPercent }); + } + + public override async Task OnLeavingPage() + { + OriginalManifest?.Dispose(); + CurrentManifest?.Dispose(); + PlaintextTally?.Dispose(); + + await base.OnLeavingPage(); + } +} diff --git a/src/electionguard-ui/ElectionGuard.UI/Views/AdminHomePage.xaml b/src/electionguard-ui/ElectionGuard.UI/Views/AdminHomePage.xaml index b4d09e12f..28abe8cd0 100644 --- a/src/electionguard-ui/ElectionGuard.UI/Views/AdminHomePage.xaml +++ b/src/electionguard-ui/ElectionGuard.UI/Views/AdminHomePage.xaml @@ -1,89 +1,89 @@ - - - -