From 5b8586d73dc503e425e139d7b98dd08e9fab9c3a Mon Sep 17 00:00:00 2001 From: Philippe Desmarais Date: Sun, 1 Dec 2024 23:20:56 -0500 Subject: [PATCH 01/11] build(cicd): add on-PR workflow to build project artifacts --- .../workflows/create_pre-release-on-pr.yml | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 .github/workflows/create_pre-release-on-pr.yml diff --git a/.github/workflows/create_pre-release-on-pr.yml b/.github/workflows/create_pre-release-on-pr.yml new file mode 100644 index 0000000..463647e --- /dev/null +++ b/.github/workflows/create_pre-release-on-pr.yml @@ -0,0 +1,78 @@ +name: Create pre-release on PR + +on: pull_request + + +jobs: + create-prerelease: + runs-on: windows-latest + permissions: + pull-requests: write + + steps: + - uses: actions/checkout@v3 + + - uses: microsoft/setup-msbuild@v2 + + - name: publish + run: | + msbuild -t:restore,build -m -p:"Configuration=Release;Platform=Any Cpu" .\src\KPSyncForDrive.csproj ` + -p:'CompileTimeConfig_ClientId=${{vars.GCPCLIENTID}}' -p:'CompileTimeConfig_GoogleDrivePickerAppId=${{vars.GDRIVEAPPID}}' ` + -p:'CompileTimeConfig_DriveFilePickerPublicApiKey=${{vars.GDRIVEFILEPICKERAPIKEY}}' ` + -p:'CompileTimeConfig_PublicClientSecret=${{vars.PublicClientSecret }}' + + # The publish needs to be run separately, since the PLGX build task seems to not run on first build + msbuild -t:publish -m -p:"Configuration=Release;Platform=Any Cpu" .\src\KPSyncForDrive.csproj ` + -p:'CompileTimeConfig_ClientId=${{vars.GCPCLIENTID}}' -p:'CompileTimeConfig_GoogleDrivePickerAppId=${{vars.GDRIVEAPPID}}' ` + -p:'CompileTimeConfig_DriveFilePickerPublicApiKey=${{vars.GDRIVEFILEPICKERAPIKEY}}' ` + -p:'CompileTimeConfig_PublicClientSecret=${{vars.PublicClientSecret }}' + + + - name: zip results + env: + PR_NUMBER: ${{ github.event.number }} + shell: pwsh + run: | + $randString = -join ((48..57) + (97..122) | Get-Random -Count 10 | % {[char]$_}) + mkdir ./dist + move-item "./src/bin/Any Cpu/Release/net48/*.plgx" -Destination ./dist/pr-$ENV:PR_NUMBER.$randString.plgx + Compress-Archive -Path "./src/bin/Any Cpu/Release/net48/publish/*" -DestinationPath ./dist/pr-$ENV:PR_NUMBER.$randString.zip -CompressionLevel Optimal -Force + [System.IO.FileSystemInfo[]]$files = Get-ChildItem ./dist/ + Write-Host "$($files.Count) files found in dist directory:" + $files + + - name: Upload plgx Artifact + uses: actions/upload-artifact@v4 + id: plgx-upload + with: + name: plgx-artifact + retention-days: 15 + path: ./dist/*.plgx + if-no-files-found: error + + - name: Upload zipped Artifacts + uses: actions/upload-artifact@v4 + id: zip-upload + with: + name: zip-artifact + retention-days: 15 + path: ./dist/*.zip + if-no-files-found: error + + - uses: actions/github-script@v6 + env: + PR_NUMBER: ${{ github.event.number }} + PR_NOTES: | + Build artifacts (expire in 15 days): + | Name | Link | + |------|------| + | PLGX | ${{ steps.plgx-upload.outputs.artifact-url }} | + | zip | ${{ steps.zip-upload.outputs.artifact-url }} | + with: + script: | + github.rest.issues.createComment({ + issue_number: process.env.PR_NUMBER, + owner: context.repo.owner, + repo: context.repo.repo, + body: process.env.PR_NOTES + }) \ No newline at end of file From 95d45b56696bb851739fef8dc93a458ff5b4b514 Mon Sep 17 00:00:00 2001 From: Philippe Desmarais Date: Sun, 1 Dec 2024 21:02:03 -0500 Subject: [PATCH 02/11] chore: various config files for Rider-based development --- .editorconfig | 3 +++ .gitignore | 1 + 2 files changed, 4 insertions(+) diff --git a/.editorconfig b/.editorconfig index 49de0d3..6a559d6 100644 --- a/.editorconfig +++ b/.editorconfig @@ -5,6 +5,9 @@ # All files [*] indent_style = space + +[*.csproj] +indent_size = 2 # Code files [*.{cs,csx,vb,vbx}] indent_size = 4 diff --git a/.gitignore b/.gitignore index 6557d5e..048edbe 100644 --- a/.gitignore +++ b/.gitignore @@ -179,3 +179,4 @@ kp/ # Local VS settings /src/Properties/launchSettings.json +/.idea From afa858cebc7e73f0cc5c3e220d50b11b2c1bb115 Mon Sep 17 00:00:00 2001 From: Philippe Desmarais Date: Sat, 7 Dec 2024 16:08:18 -0500 Subject: [PATCH 03/11] build(deps): upgrade various vulnerable deps --- BuildMe.bat | 2 +- lib/src/GenVerInfo/GenVerInfo.csproj | 2 +- .../WindowsControls/WindowsControls.csproj | 4 ++-- src/KPSyncForDrive.csproj | 20 +++++++--------- src/app.config | 23 ------------------- 5 files changed, 12 insertions(+), 39 deletions(-) delete mode 100644 src/app.config diff --git a/BuildMe.bat b/BuildMe.bat index fb92965..2868c3d 100644 --- a/BuildMe.bat +++ b/BuildMe.bat @@ -26,7 +26,7 @@ set archname=KPSyncForDrive set kp_version_manifest_name=kpsync_final set versionPrefix=4.1.0 set versionSuffix=unstable -set netsdkver=net45 +set netsdkver=net48 set sevenzip="%ProgramFiles%\7-Zip\7z.exe" :: set dotnetPgm="%ProgramFiles%\dotnet\dotnet.exe" diff --git a/lib/src/GenVerInfo/GenVerInfo.csproj b/lib/src/GenVerInfo/GenVerInfo.csproj index c052e91..9930121 100644 --- a/lib/src/GenVerInfo/GenVerInfo.csproj +++ b/lib/src/GenVerInfo/GenVerInfo.csproj @@ -2,7 +2,7 @@ Exe - net45 + net48 1.0.0 1.0.0.0 KPSync For Google Drive diff --git a/lib/src/WindowsControls/WindowsControls.csproj b/lib/src/WindowsControls/WindowsControls.csproj index f8dd967..1283ad7 100644 --- a/lib/src/WindowsControls/WindowsControls.csproj +++ b/lib/src/WindowsControls/WindowsControls.csproj @@ -7,8 +7,8 @@ KPSyncWindows KPSyncForDrive.WindowsControls - v4.5 - net45 + v4.8 + net48 true true KPSync For Google Drive diff --git a/src/KPSyncForDrive.csproj b/src/KPSyncForDrive.csproj index f241197..f68e9a8 100644 --- a/src/KPSyncForDrive.csproj +++ b/src/KPSyncForDrive.csproj @@ -6,11 +6,11 @@ Library - net45 + net48 KeePass Plugin KPSync For Google Drive Safely synchronize KeePass database files with Google Drive. - Copyright © 2020-2021 + Copyright © 2020-2021 en Images\gdsync.ico AnyCPU @@ -33,16 +33,15 @@ - + - - + + ..\lib\bin\KeePass.exe False - @@ -71,6 +70,7 @@ True GdsDefs.Data.tt + @@ -133,9 +133,6 @@ - - - @@ -150,9 +147,8 @@ --> - + $(AssemblyName)-$(Version) diff --git a/src/app.config b/src/app.config deleted file mode 100644 index 377c87e..0000000 --- a/src/app.config +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - From a7e299250806644787e1c755f0a44cccf1ba03ec Mon Sep 17 00:00:00 2001 From: Philippe Desmarais Date: Sat, 7 Dec 2024 16:11:24 -0500 Subject: [PATCH 04/11] feat: add build-time configuration accessor This will serve to replace the GenClientId process by using commandLine args to pass values to be inlined into the plugin --- GoogleDriveSync.sln | 20 ++- .../CompileTimeConfigGenerator.csproj | 25 ++++ .../ConfigSourceGenerator.cs | 118 ++++++++++++++++++ .../CompileTimeConfigPublicMembers.csproj | 7 ++ .../GenerateConfigAccessorAttribute.cs | 15 +++ .../ICompileTimeConfigAccessor.cs | 7 ++ src/KPSyncForDrive.csproj | 15 +++ src/OptionsAccessor.cs | 17 +++ 8 files changed, 220 insertions(+), 4 deletions(-) create mode 100644 lib/src/CompileTimeConfigGenerator/CompileTimeConfigGenerator.csproj create mode 100644 lib/src/CompileTimeConfigGenerator/ConfigSourceGenerator.cs create mode 100644 lib/src/CompileTimeConfigPublicMembers/CompileTimeConfigPublicMembers.csproj create mode 100644 lib/src/CompileTimeConfigPublicMembers/GenerateConfigAccessorAttribute.cs create mode 100644 lib/src/CompileTimeConfigPublicMembers/ICompileTimeConfigAccessor.cs create mode 100644 src/OptionsAccessor.cs diff --git a/GoogleDriveSync.sln b/GoogleDriveSync.sln index 37750db..05dad14 100644 --- a/GoogleDriveSync.sln +++ b/GoogleDriveSync.sln @@ -24,16 +24,16 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsControls", "lib\src\WindowsControls\WindowsControls.csproj", "{31D48296-6B88-4532-B0C3-6DDBF183499F}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CompileTimeConfigGenerator", "lib\src\CompileTimeConfigGenerator\CompileTimeConfigGenerator.csproj", "{C9EABBC7-D089-46E8-996B-F34F3C6C8CBD}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CompileTimeConfigPublicMembers", "lib\src\CompileTimeConfigPublicMembers\CompileTimeConfigPublicMembers.csproj", "{1960BE1C-5EB4-4679-9510-976F1A085CA3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {4C1BB6F8-D2CD-49C2-9053-21705681356C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4C1BB6F8-D2CD-49C2-9053-21705681356C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4C1BB6F8-D2CD-49C2-9053-21705681356C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4C1BB6F8-D2CD-49C2-9053-21705681356C}.Release|Any CPU.Build.0 = Release|Any CPU {F7B92FBF-F5D8-45E0-B357-4CA8F05AD652}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F7B92FBF-F5D8-45E0-B357-4CA8F05AD652}.Debug|Any CPU.Build.0 = Debug|Any CPU {F7B92FBF-F5D8-45E0-B357-4CA8F05AD652}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -46,6 +46,18 @@ Global {31D48296-6B88-4532-B0C3-6DDBF183499F}.Debug|Any CPU.Build.0 = Debug|Any CPU {31D48296-6B88-4532-B0C3-6DDBF183499F}.Release|Any CPU.ActiveCfg = Release|Any CPU {31D48296-6B88-4532-B0C3-6DDBF183499F}.Release|Any CPU.Build.0 = Release|Any CPU + {C9EABBC7-D089-46E8-996B-F34F3C6C8CBD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C9EABBC7-D089-46E8-996B-F34F3C6C8CBD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C9EABBC7-D089-46E8-996B-F34F3C6C8CBD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C9EABBC7-D089-46E8-996B-F34F3C6C8CBD}.Release|Any CPU.Build.0 = Release|Any CPU + {1960BE1C-5EB4-4679-9510-976F1A085CA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1960BE1C-5EB4-4679-9510-976F1A085CA3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1960BE1C-5EB4-4679-9510-976F1A085CA3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1960BE1C-5EB4-4679-9510-976F1A085CA3}.Release|Any CPU.Build.0 = Release|Any CPU + {4C1BB6F8-D2CD-49C2-9053-21705681356C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4C1BB6F8-D2CD-49C2-9053-21705681356C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4C1BB6F8-D2CD-49C2-9053-21705681356C}.Release|Any CPU.ActiveCfg = Debug|Any CPU + {4C1BB6F8-D2CD-49C2-9053-21705681356C}.Release|Any CPU.Build.0 = Debug|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/lib/src/CompileTimeConfigGenerator/CompileTimeConfigGenerator.csproj b/lib/src/CompileTimeConfigGenerator/CompileTimeConfigGenerator.csproj new file mode 100644 index 0000000..9a66999 --- /dev/null +++ b/lib/src/CompileTimeConfigGenerator/CompileTimeConfigGenerator.csproj @@ -0,0 +1,25 @@ + + + + netstandard2.0 + 12 + enable + true + false + true + + + + + + + + + + + + + + + diff --git a/lib/src/CompileTimeConfigGenerator/ConfigSourceGenerator.cs b/lib/src/CompileTimeConfigGenerator/ConfigSourceGenerator.cs new file mode 100644 index 0000000..1d718e3 --- /dev/null +++ b/lib/src/CompileTimeConfigGenerator/ConfigSourceGenerator.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace CompileTimeConfigGenerator; + +public record MetadataOnAccessorConfigRecordsToGenerate +{ + public string RecordFullClassName { get; set; } = ""; + public List Properties { get; set; } = []; +} + +public record MetadataOnAccessorToGenerate +{ + public List Records { get; set; } = []; + public string AccessorClassName { get; set; } = ""; + public string AccessorNamespace { get; set; } = ""; +} + +[Generator] +public class ConfigSourceGenerator : IIncrementalGenerator +{ + public void Initialize(IncrementalGeneratorInitializationContext context) + { + var metadataOnAccessorsToGenerate = context.SyntaxProvider + .ForAttributeWithMetadataName( + "CompileTimeConfigPublicMembers.GenerateConfigAccessorAttribute", + predicate: static (_, _) => true, + transform: (ctx, _) => + { + if (ctx.SemanticModel.GetDeclaredSymbol(ctx.TargetNode) is not INamedTypeSymbol generatorSymbol) + return null; + + var records = ctx.Attributes + .Select(attributeData => attributeData.ConstructorArguments[0].Value) + .OfType() + .Select(recordSymbol => + { + var properties = recordSymbol.GetMembers() + .OfType() + .Where(x => x.SetMethod?.DeclaredAccessibility == Accessibility.Public && + x.Type.Name == nameof(String)); + + return new MetadataOnAccessorConfigRecordsToGenerate + { + RecordFullClassName = + recordSymbol.ToDisplayString( + new SymbolDisplayFormat(SymbolDisplayGlobalNamespaceStyle.Included)), + Properties = properties.Select(x => x.Name).ToList() + }; + }).ToList(); + + + return new MetadataOnAccessorToGenerate + { + Records = records, + AccessorNamespace = generatorSymbol.ContainingNamespace.Name, + AccessorClassName = generatorSymbol.Name, + }; + }).Collect(); + + var combine = metadataOnAccessorsToGenerate.Combine(context.AnalyzerConfigOptionsProvider); + + context.RegisterSourceOutput(combine, + static (spc, tuple) => + { + foreach (var metadata in tuple.Left) + { + if (metadata == null) continue; + + var interfacesToImplement = metadata.Records.Select(CreateInterfaceString); + var accessorMethods = metadata.Records.Select(x => GenerateRecordAccessMethod(x, tuple.Right)); + + string generatorString = + $$""" + using CompileTimeConfigPublicMembers; + + namespace {{metadata.AccessorNamespace}} { + public partial class {{metadata.AccessorClassName}}: {{string.Join(", ", interfacesToImplement)}} { + {{string.Join("\n", accessorMethods)}} + } + } + """; + + spc.AddSource( + $"CompileTimeConfigAccessors.{metadata.AccessorClassName}.g.cs", + generatorString); + } + }); + } + + private static string? GetBuildParam(string paramName, AnalyzerConfigOptionsProvider context) + { + context.GlobalOptions.TryGetValue($"build_property.CompileTimeConfig_{paramName}", out string? value); + return value; + } + + private static string CreateInterfaceString(MetadataOnAccessorConfigRecordsToGenerate record) + { + return $"ICompileTimeConfigAccessor<{record.RecordFullClassName}>"; + } + + private static string GenerateRecordAccessMethod(MetadataOnAccessorConfigRecordsToGenerate record, + AnalyzerConfigOptionsProvider configOptionsProvider) + { + return $$""" + {{record.RecordFullClassName}} {{CreateInterfaceString(record)}}.GetConfig() { + return new {{record.RecordFullClassName}} { + {{ + string.Join("\n\t\t\t\t", record.Properties.Select(y => $"""{y} = "{GetBuildParam(y, configOptionsProvider)}",""")) + }} + }; + } + """; + } +} diff --git a/lib/src/CompileTimeConfigPublicMembers/CompileTimeConfigPublicMembers.csproj b/lib/src/CompileTimeConfigPublicMembers/CompileTimeConfigPublicMembers.csproj new file mode 100644 index 0000000..ec0e84d --- /dev/null +++ b/lib/src/CompileTimeConfigPublicMembers/CompileTimeConfigPublicMembers.csproj @@ -0,0 +1,7 @@ + + + + netstandard2.0 + 5 + + \ No newline at end of file diff --git a/lib/src/CompileTimeConfigPublicMembers/GenerateConfigAccessorAttribute.cs b/lib/src/CompileTimeConfigPublicMembers/GenerateConfigAccessorAttribute.cs new file mode 100644 index 0000000..2dccf13 --- /dev/null +++ b/lib/src/CompileTimeConfigPublicMembers/GenerateConfigAccessorAttribute.cs @@ -0,0 +1,15 @@ +using System; + +namespace CompileTimeConfigPublicMembers +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] + public class GenerateConfigAccessorAttribute : Attribute + { + public Type ConfigRecordType { get; private set; } + + public GenerateConfigAccessorAttribute(Type configRecordType) + { + ConfigRecordType = configRecordType; + } + } +} diff --git a/lib/src/CompileTimeConfigPublicMembers/ICompileTimeConfigAccessor.cs b/lib/src/CompileTimeConfigPublicMembers/ICompileTimeConfigAccessor.cs new file mode 100644 index 0000000..e4b4d39 --- /dev/null +++ b/lib/src/CompileTimeConfigPublicMembers/ICompileTimeConfigAccessor.cs @@ -0,0 +1,7 @@ +namespace CompileTimeConfigPublicMembers +{ + public interface ICompileTimeConfigAccessor where T : class + { + T GetConfig(); + } +} diff --git a/src/KPSyncForDrive.csproj b/src/KPSyncForDrive.csproj index f68e9a8..2204aba 100644 --- a/src/KPSyncForDrive.csproj +++ b/src/KPSyncForDrive.csproj @@ -22,13 +22,28 @@ true KeePass Plugin Satellite Resources 2.35 + DevClientId + DevPublicApiKey + DevAppId + DevClientSecret + + + + + + + DEBUG;$(DefineConstants) + + diff --git a/src/OptionsAccessor.cs b/src/OptionsAccessor.cs new file mode 100644 index 0000000..8bffb66 --- /dev/null +++ b/src/OptionsAccessor.cs @@ -0,0 +1,17 @@ +using CompileTimeConfigPublicMembers; + +namespace KPSyncForDrive +{ + [GenerateConfigAccessor(typeof(PluginStaticConfiguration))] + public partial class OptionsAccessor + { + } + + public class PluginStaticConfiguration + { + public string ClientId { get; set; } + public string PublicClientSecret { get; set; } + public string DriveFilePickerPublicApiKey { get; set; } + public string GoogleDrivePickerAppId { get; set; } + } +} From fc4ce43e9fd644407e31316c78379a272d93f9e5 Mon Sep 17 00:00:00 2001 From: Philippe Desmarais Date: Sat, 7 Dec 2024 16:14:41 -0500 Subject: [PATCH 05/11] feat: add google drive file picker service This allows us to grant access to specific files to our application, instead of granting global access. That'll help us get around both the google blocking issue, and the kdbx file duplication issue when using limited file scope The UI elements wrapping around this will be added in a later commit --- GoogleDriveSync.sln | 6 + lib/src/FilePicker/FilePicker.cs | 164 ++++++++++++++++++++++ lib/src/FilePicker/FilePicker.csproj | 19 +++ lib/src/FilePicker/FilePickerException.cs | 10 ++ lib/src/FilePicker/FilePickerOptions.cs | 9 ++ lib/src/FilePicker/FilePickerView.html | 67 +++++++++ lib/src/FilePicker/IFilePicker.cs | 17 +++ src/KPSyncForDrive.csproj | 1 + 8 files changed, 293 insertions(+) create mode 100644 lib/src/FilePicker/FilePicker.cs create mode 100644 lib/src/FilePicker/FilePicker.csproj create mode 100644 lib/src/FilePicker/FilePickerException.cs create mode 100644 lib/src/FilePicker/FilePickerOptions.cs create mode 100644 lib/src/FilePicker/FilePickerView.html create mode 100644 lib/src/FilePicker/IFilePicker.cs diff --git a/GoogleDriveSync.sln b/GoogleDriveSync.sln index 05dad14..7fa1ffa 100644 --- a/GoogleDriveSync.sln +++ b/GoogleDriveSync.sln @@ -24,6 +24,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsControls", "lib\src\WindowsControls\WindowsControls.csproj", "{31D48296-6B88-4532-B0C3-6DDBF183499F}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FilePicker", "lib\src\FilePicker\FilePicker.csproj", "{89B54C4A-00DF-49FD-BD57-4DA01AAF9710}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CompileTimeConfigGenerator", "lib\src\CompileTimeConfigGenerator\CompileTimeConfigGenerator.csproj", "{C9EABBC7-D089-46E8-996B-F34F3C6C8CBD}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CompileTimeConfigPublicMembers", "lib\src\CompileTimeConfigPublicMembers\CompileTimeConfigPublicMembers.csproj", "{1960BE1C-5EB4-4679-9510-976F1A085CA3}" @@ -46,6 +48,10 @@ Global {31D48296-6B88-4532-B0C3-6DDBF183499F}.Debug|Any CPU.Build.0 = Debug|Any CPU {31D48296-6B88-4532-B0C3-6DDBF183499F}.Release|Any CPU.ActiveCfg = Release|Any CPU {31D48296-6B88-4532-B0C3-6DDBF183499F}.Release|Any CPU.Build.0 = Release|Any CPU + {89B54C4A-00DF-49FD-BD57-4DA01AAF9710}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {89B54C4A-00DF-49FD-BD57-4DA01AAF9710}.Debug|Any CPU.Build.0 = Debug|Any CPU + {89B54C4A-00DF-49FD-BD57-4DA01AAF9710}.Release|Any CPU.ActiveCfg = Release|Any CPU + {89B54C4A-00DF-49FD-BD57-4DA01AAF9710}.Release|Any CPU.Build.0 = Release|Any CPU {C9EABBC7-D089-46E8-996B-F34F3C6C8CBD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C9EABBC7-D089-46E8-996B-F34F3C6C8CBD}.Debug|Any CPU.Build.0 = Debug|Any CPU {C9EABBC7-D089-46E8-996B-F34F3C6C8CBD}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/lib/src/FilePicker/FilePicker.cs b/lib/src/FilePicker/FilePicker.cs new file mode 100644 index 0000000..2867f04 --- /dev/null +++ b/lib/src/FilePicker/FilePicker.cs @@ -0,0 +1,164 @@ +using System.Diagnostics; +using System.IO; +using System.Net; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using Newtonsoft.Json; +using HttpListener = System.Net.HttpListener; + +namespace FilePicker +{ + public class FilePicker : IFilePicker + { + private readonly Serilog.ILogger _logger; + + public FilePicker(Serilog.ILogger logger) + { + _logger = logger; + } + + private static bool TryBindListenerOnFreePort(out HttpListener httpListener, out int port) + { + // IANA suggested range for dynamic or private ports + const int minPort = 49215; + const int maxPort = 65535; + + for (port = minPort; port < maxPort; port++) + { + httpListener = new HttpListener(); + httpListener.Prefixes.Add("http://localhost:" + port + "/"); + try + { + httpListener.Start(); + return true; + } + catch (HttpListenerException) + { + // nothing to do here -- the listener disposes itself when Start throws + } + } + + port = 0; + httpListener = null; + return false; + } + + public async Task SelectFile(FilePickerOptions options, CancellationToken cancellationToken) + { + int port; + HttpListener listener; + if (!TryBindListenerOnFreePort(out listener, out port)) + { + throw new FilePickerException("No available ports"); + } + + using (listener) + { + var uri = "http://localhost:" + port + "/"; + _logger.Debug("Listening for '{uri}'...", uri); + var _ = await Task.Run(() => Process.Start(uri), cancellationToken); + + while (!cancellationToken.IsCancellationRequested) + { + HttpListenerContext context; + try + { + using (var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken)) + { + + var contextAsync = listener.GetContextAsync(); + // Allows us to cancel the GetContextAsync call despite its lack of cancellation token support + var completed = await Task.WhenAny(contextAsync, Task.Delay(Timeout.Infinite, cts.Token)); + if (completed != contextAsync) + { + return null; + } + + cts.Cancel(); // cancel the infinite task.Delay + context = contextAsync.Result; + } + } + catch (HttpListenerException ex) + { + _logger.Error(ex, "Failed to get context: {0}", ex.ErrorCode); + throw new FilePickerException("Http listener failed to open", ex); + } + + if (context.Request.HttpMethod == "POST") + { + return await HandlePost(context); + } + + await HandleGet(options, context); + } + } + + return null; + } + + private async Task HandleGet(FilePickerOptions viewModel, HttpListenerContext context) + { + string html; + using (var stream = Assembly.GetExecutingAssembly() + .GetManifestResourceStream("FilePicker.FilePickerView.html")) + { + if (stream == null) + { + throw new FilePickerException("File picker view could not be loaded"); + } + + using (var reader = new StreamReader(stream)) + { + html = await reader.ReadToEndAsync(); + } + } + + html = html.Replace("@AccessToken", viewModel.AccessToken) + .Replace("@AppId", viewModel.AppId) + .Replace("@GDrivePickerApiKey", viewModel.GDrivePickerApiKey); + + context.Response.KeepAlive = false; + using (StreamWriter streamWriter = new StreamWriter(context.Response.OutputStream)) + { + await streamWriter.WriteAsync(html); + } + + _logger.Debug("File picker page returned to browser."); + } + + private async Task HandlePost(HttpListenerContext context) + { + string input; + using (var sr = new StreamReader(context.Request.InputStream)) + { + input = await sr.ReadToEndAsync(); + } + + FilePick pick; + try + { + pick = JsonConvert.DeserializeObject(input); + } + catch (JsonSerializationException ex) + { + _logger.Error(ex, "Failed to deserialize file pick {response}", input); + throw new FilePickerException("Invalid post request submitted to listener", ex); + } + + if (pick == null) + { + throw new FilePickerException("Invalid post request submitted to listener") + { + Data = { { "Payload", input } } + }; + } + + _logger.Debug("Picked {0}, {1}", pick.Id, pick.Name); + context.Response.StatusCode = 200; + context.Response.Close(); + + return pick; + } + } +} diff --git a/lib/src/FilePicker/FilePicker.csproj b/lib/src/FilePicker/FilePicker.csproj new file mode 100644 index 0000000..f9e3b6d --- /dev/null +++ b/lib/src/FilePicker/FilePicker.csproj @@ -0,0 +1,19 @@ + + + + netStandard2.0 + 5 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib/src/FilePicker/FilePickerException.cs b/lib/src/FilePicker/FilePickerException.cs new file mode 100644 index 0000000..82a01b1 --- /dev/null +++ b/lib/src/FilePicker/FilePickerException.cs @@ -0,0 +1,10 @@ +using System; + +namespace FilePicker +{ + public class FilePickerException : Exception + { + public FilePickerException(string message) : base(message) { } + public FilePickerException(string message, Exception innerException) : base(message, innerException) { } + } +} diff --git a/lib/src/FilePicker/FilePickerOptions.cs b/lib/src/FilePicker/FilePickerOptions.cs new file mode 100644 index 0000000..821f1f7 --- /dev/null +++ b/lib/src/FilePicker/FilePickerOptions.cs @@ -0,0 +1,9 @@ +namespace FilePicker +{ + public class FilePickerOptions + { + public string GDrivePickerApiKey { get; set; } + public string AppId { get; set; } + public string AccessToken { get; set; } + } +} diff --git a/lib/src/FilePicker/FilePickerView.html b/lib/src/FilePicker/FilePickerView.html new file mode 100644 index 0000000..5ac8bce --- /dev/null +++ b/lib/src/FilePicker/FilePickerView.html @@ -0,0 +1,67 @@ + + + + + Google Drive File Picker + + + + + + + + + \ No newline at end of file diff --git a/lib/src/FilePicker/IFilePicker.cs b/lib/src/FilePicker/IFilePicker.cs new file mode 100644 index 0000000..26ef8c3 --- /dev/null +++ b/lib/src/FilePicker/IFilePicker.cs @@ -0,0 +1,17 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace FilePicker +{ + public interface IFilePicker + { + Task SelectFile(FilePickerOptions options, CancellationToken cancellationToken); + } + + + public class FilePick + { + public string Id { get; set; } + public string Name { get; set; } + } +} diff --git a/src/KPSyncForDrive.csproj b/src/KPSyncForDrive.csproj index 2204aba..480c835 100644 --- a/src/KPSyncForDrive.csproj +++ b/src/KPSyncForDrive.csproj @@ -44,6 +44,7 @@ Include="..\lib\src\CompileTimeConfigPublicMembers\CompileTimeConfigPublicMembers.csproj" /> + From 87234f58377bd2d5a875307ecf0165b8bb674cf0 Mon Sep 17 00:00:00 2001 From: Philippe Desmarais Date: Sat, 7 Dec 2024 16:23:40 -0500 Subject: [PATCH 06/11] feat: add FilePicker form UI element This PR adds a UI element that displays a cancellation button, and calls the file picker service. This will allows us to add a button in the plugin config that makes this form show up and redirect the user to their browser --- src/AuthWaitOrCancel.cs | 21 +++++++++ src/DatabaseContext.cs | 2 +- src/FilePickerForm.cs | 79 +++++++++++++++++++++++++++++++++ src/IDatabaseContextAccessor.cs | 54 ++++++++++++++++++++++ 4 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 src/FilePickerForm.cs create mode 100644 src/IDatabaseContextAccessor.cs diff --git a/src/AuthWaitOrCancel.cs b/src/AuthWaitOrCancel.cs index 9792687..d6f1b46 100644 --- a/src/AuthWaitOrCancel.cs +++ b/src/AuthWaitOrCancel.cs @@ -25,7 +25,10 @@ using KeePass.UI; using KeePass.Util; using System; +using System.Threading; +using System.Threading.Tasks; using System.Windows.Forms; +using KeePass; namespace KPSyncForDrive { @@ -67,6 +70,24 @@ internal AuthWaitOrCancel(IPluginHost host, DatabaseContext dbCtx, GdsDefs.ProductName), string.Format("{0} {1}", GdsDefs.ProductName, GdsDefs.Version)); } + + public async Task ShowDialogAsync(CancellationTokenSource cts) + { + FormClosing += (o, e) => + { + cts.Cancel(); + }; + + if (Program.MainForm.InvokeRequired || InvokeRequired != Program.MainForm.InvokeRequired) + { + Log.Debug("Form not created or shown on UI thread - aborting."); + return DialogResult.Abort; + } + + await Task.Yield(); + return IsDisposed ? DialogResult.Cancel : ShowDialog(); + } + private void lnkHelp_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { diff --git a/src/DatabaseContext.cs b/src/DatabaseContext.cs index c7e254f..2745810 100644 --- a/src/DatabaseContext.cs +++ b/src/DatabaseContext.cs @@ -27,7 +27,7 @@ namespace KPSyncForDrive { - class DatabaseContext + public class DatabaseContext { readonly PwDatabase m_db; readonly Guid m_uuid; diff --git a/src/FilePickerForm.cs b/src/FilePickerForm.cs new file mode 100644 index 0000000..24aeead --- /dev/null +++ b/src/FilePickerForm.cs @@ -0,0 +1,79 @@ +using System; +using System.Drawing; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; +using CompileTimeConfigPublicMembers; +using FilePicker; +using KeePass; +using KeePass.Plugins; +using Microsoft.CodeAnalysis; +using Serilog; + +namespace KPSyncForDrive +{ + public class FilePickerForm + { + private readonly IPluginHost _mHost; + private readonly IFilePicker _filePicker; + private readonly ILogger _logger; + private readonly IDatabaseContextAccessor _databaseContextAccessor; + private readonly ICompileTimeConfigAccessor _compileTimeConfigAccessor; + + public FilePickerForm(IPluginHost host, + IFilePicker filePicker, + ILogger logger, + IDatabaseContextAccessor databaseContextAccessor, + ICompileTimeConfigAccessor compileTimeConfigAccessor) + { + _filePicker = filePicker; + _logger = logger; + _databaseContextAccessor = databaseContextAccessor; + _compileTimeConfigAccessor = compileTimeConfigAccessor; + _mHost = host; + } + + public async Task> SelectFile(string accessToken, SyncConfiguration syncConfig, CancellationToken cancellationToken) + { + using (CancellationTokenSource cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken)) + { + cts.CancelAfter(TimeSpan.FromMinutes(5)); + return await ShowFilePickForm(accessToken, syncConfig, cts); + } + } + + private async Task> ShowFilePickForm(string accessToken, + SyncConfiguration syncConfig, + CancellationTokenSource cts) + { + using (AuthWaitOrCancel form = new AuthWaitOrCancel(_mHost, _databaseContextAccessor.GetDatabaseContext(), syncConfig as EntryConfiguration)) + { + form.StartPosition = FormStartPosition.CenterParent; + FilePick res; + var dialogTask = form.ShowDialogAsync(cts); + try + { + res = await _filePicker.SelectFile(new FilePickerOptions + { + AccessToken = accessToken, + AppId = _compileTimeConfigAccessor.GetConfig().GoogleDrivePickerAppId, + GDrivePickerApiKey = _compileTimeConfigAccessor.GetConfig().DriveFilePickerPublicApiKey + }, cts.Token); + _mHost.MainWindow.BeginInvoke(new MethodInvoker(_mHost.MainWindow.Activate)); + } + catch(FilePickerException ex){ + _logger.Error(ex, "An error occured during file picker form, returning without authorizing file"); + return null; + } + finally + { + form.Close(); + } + + await dialogTask; + return res; + } + } + } +} diff --git a/src/IDatabaseContextAccessor.cs b/src/IDatabaseContextAccessor.cs new file mode 100644 index 0000000..d57b6fc --- /dev/null +++ b/src/IDatabaseContextAccessor.cs @@ -0,0 +1,54 @@ +using System; +using System.Threading; +using Microsoft.CodeAnalysis; + +namespace KPSyncForDrive +{ + public interface IDatabaseContextAccessor + { + Optional DatabaseContext { get; set; } + DatabaseContext GetDatabaseContext(); + } + public class DatabaseContextAccessor : IDatabaseContextAccessor + { + private static readonly AsyncLocal _databaseContextCurrent = new AsyncLocal(); + + public Optional DatabaseContext + { + get + { + return _databaseContextCurrent.Value.Context; + } + set + { + var holder = _databaseContextCurrent.Value; + if (holder != null) + { + // Clear current HttpContext trapped in the AsyncLocals, as its done. + holder.Context = null; + } + + if (value.HasValue) + { + // Use an object indirection to hold the HttpContext in the AsyncLocal, + // so it can be cleared in all ExecutionContexts when its cleared. + _databaseContextCurrent.Value = new DatabaseContextHolder { Context = value }; + } + } + } + + public DatabaseContext GetDatabaseContext() + { + if (DatabaseContext.HasValue) + { + return DatabaseContext.Value; + } + throw new InvalidOperationException("Database context was not initialized"); + } + private sealed class DatabaseContextHolder + { + public Optional Context; + } + + } +} From 990ad9f44b10c136c1360c96813feeec48eb23d9 Mon Sep 17 00:00:00 2001 From: Philippe Desmarais Date: Sat, 7 Dec 2024 16:24:59 -0500 Subject: [PATCH 07/11] refactor: remove GenClientId process Since we've already implemented a new process to read some configuration items from build params, we no longer need the T4 generation to build the clientId into the app --- GoogleDriveSync.sln | 9 -- lib/src/GenClientId/GenClientId.csproj | 26 ---- lib/src/GenClientId/Generator.cs | 124 ------------------ lib/src/GenClientId/Program.cs | 111 ---------------- .../GenClientId/Properties/AssemblyInfo.cs | 22 ---- src/GdsDefs.Data.tt | 57 -------- src/GdsDefs.OAuthCreds.txt | 4 - src/GdsDefs.cs | 35 +---- src/KPSyncForDrive.csproj | 38 +----- 9 files changed, 6 insertions(+), 420 deletions(-) delete mode 100644 lib/src/GenClientId/GenClientId.csproj delete mode 100644 lib/src/GenClientId/Generator.cs delete mode 100644 lib/src/GenClientId/Program.cs delete mode 100644 lib/src/GenClientId/Properties/AssemblyInfo.cs delete mode 100644 src/GdsDefs.Data.tt delete mode 100644 src/GdsDefs.OAuthCreds.txt diff --git a/GoogleDriveSync.sln b/GoogleDriveSync.sln index 7fa1ffa..0291a4a 100644 --- a/GoogleDriveSync.sln +++ b/GoogleDriveSync.sln @@ -4,11 +4,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 VisualStudioVersion = 16.0.29920.165 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KPSyncForDrive", "src\KPSyncForDrive.csproj", "{4C1BB6F8-D2CD-49C2-9053-21705681356C}" - ProjectSection(ProjectDependencies) = postProject - {F7B92FBF-F5D8-45E0-B357-4CA8F05AD652} = {F7B92FBF-F5D8-45E0-B357-4CA8F05AD652} - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GenClientId", "lib\src\GenClientId\GenClientId.csproj", "{F7B92FBF-F5D8-45E0-B357-4CA8F05AD652}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GenVerInfo", "lib\src\GenVerInfo\GenVerInfo.csproj", "{552F1DC6-E4B4-4766-B0B3-7A37276AB86B}" EndProject @@ -36,10 +31,6 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {F7B92FBF-F5D8-45E0-B357-4CA8F05AD652}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F7B92FBF-F5D8-45E0-B357-4CA8F05AD652}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F7B92FBF-F5D8-45E0-B357-4CA8F05AD652}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F7B92FBF-F5D8-45E0-B357-4CA8F05AD652}.Release|Any CPU.Build.0 = Release|Any CPU {552F1DC6-E4B4-4766-B0B3-7A37276AB86B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {552F1DC6-E4B4-4766-B0B3-7A37276AB86B}.Debug|Any CPU.Build.0 = Debug|Any CPU {552F1DC6-E4B4-4766-B0B3-7A37276AB86B}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/lib/src/GenClientId/GenClientId.csproj b/lib/src/GenClientId/GenClientId.csproj deleted file mode 100644 index 736851c..0000000 --- a/lib/src/GenClientId/GenClientId.csproj +++ /dev/null @@ -1,26 +0,0 @@ - - - - Exe - net45 - 1.0.0 - 1.0.0.0 - KPSync For Google Drive - GenClientId - Build-time helper for credential obfuscation. - Copyright © 2020-2021 - en-US - AnyCPU - - - - DEBUG;$(DefineConstants) - - - - - ..\..\bin\KeePass.exe - - - - diff --git a/lib/src/GenClientId/Generator.cs b/lib/src/GenClientId/Generator.cs deleted file mode 100644 index 8f57950..0000000 --- a/lib/src/GenClientId/Generator.cs +++ /dev/null @@ -1,124 +0,0 @@ -/** - * KPSync for Google Drive - * Copyright(C) 2020 Walter Goodwin - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . -**/ - -using KeePassLib.Security; -using System; -using System.IO; -using System.Security.Cryptography; -using System.Text; - -namespace GenClientId -{ - public class Generator - { - static string GenSrc(byte[] bytes) - { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < bytes.Length; i++) - { - if (0 == i % 8) - { - sb.Append(" "); - } - sb.AppendFormat("0x{0:x2},", bytes[i]); - if (0 != (i + 1) % 8 && - (i + 1) < bytes.Length) - { - sb.Append(' '); - } - else - { - sb.Append(Environment.NewLine); - } - } - return sb.ToString(); - } - - public Generator() - { - } - - public string SourceFilePath { get; set; } - - public string LegacyIdCsharpConstant { get; set; } - public string LegacyIdPadCsharpConstant { get; set; } - public string LegacySecretCsharpConstant { get; set; } - public string LegacySecretPadCsharpConstant { get; set; } - public string ClientIdCsharpConstant { get; set; } - public string ClientIdPadCsharpConstant { get; set; } - public string ClientSecretCsharpConstant { get; set; } - public string ClientSecretPadCsharpConstant { get; set; } - - byte[] LegacyIdBytes { get; set; } - byte[] LegacyIdPadBytes { get; set; } - byte[] LegacySecretBytes { get; set; } - byte[] LegacySecretPadBytes { get; set; } - byte[] ClientIdBytes { get; set; } - byte[] ClientIdPadBytes { get; set; } - byte[] ClientSecretBytes { get; set; } - byte[] ClientSecretPadBytes { get; set; } - - public void Run() - { - using (StreamReader reader = File.OpenText(SourceFilePath)) - { - LegacyIdBytes = Encoding.UTF8.GetBytes( - reader.ReadLine().Trim()); - LegacySecretBytes = Encoding.UTF8.GetBytes( - reader.ReadLine().Trim()); - ClientIdBytes = Encoding.UTF8.GetBytes( - reader.ReadLine().Trim()); - ClientSecretBytes = Encoding.UTF8.GetBytes( - reader.ReadLine().Trim()); - LegacyIdPadBytes = new byte[LegacyIdBytes.Length]; - LegacySecretPadBytes = new byte[LegacySecretBytes.Length]; - ClientIdPadBytes = new byte[ClientIdBytes.Length]; - ClientSecretPadBytes = new byte[ClientSecretBytes.Length]; - - using (RandomNumberGenerator rng = - RandomNumberGenerator.Create()) - { - rng.GetNonZeroBytes(LegacyIdPadBytes); - rng.GetNonZeroBytes(LegacySecretPadBytes); - rng.GetNonZeroBytes(ClientIdPadBytes); - rng.GetNonZeroBytes(ClientSecretPadBytes); - } - - XorredBuffer clientIdBuf = new XorredBuffer(LegacyIdBytes, - LegacyIdPadBytes); - XorredBuffer secretBuf = new XorredBuffer(LegacySecretBytes, - LegacySecretPadBytes); - - LegacyIdCsharpConstant = GenSrc(clientIdBuf.ReadPlainText()); - LegacyIdPadCsharpConstant = GenSrc(LegacyIdPadBytes); - LegacySecretCsharpConstant = GenSrc(secretBuf.ReadPlainText()); - LegacySecretPadCsharpConstant = GenSrc(LegacySecretPadBytes); - - clientIdBuf = new XorredBuffer(ClientIdBytes, - ClientIdPadBytes); - secretBuf = new XorredBuffer(ClientSecretBytes, - ClientSecretPadBytes); - - ClientIdCsharpConstant = GenSrc(clientIdBuf.ReadPlainText()); - ClientIdPadCsharpConstant = GenSrc(ClientIdPadBytes); - ClientSecretCsharpConstant = GenSrc(secretBuf.ReadPlainText()); - ClientSecretPadCsharpConstant = GenSrc(ClientSecretPadBytes); - } - } - } -} diff --git a/lib/src/GenClientId/Program.cs b/lib/src/GenClientId/Program.cs deleted file mode 100644 index daac73f..0000000 --- a/lib/src/GenClientId/Program.cs +++ /dev/null @@ -1,111 +0,0 @@ -/** - * KPSync for Google Drive - * Copyright(C) 2020 Walter Goodwin - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . -**/ - -using System.Diagnostics; -using System.IO; -using System.Text; - -namespace GenClientId -{ - class Program - { - static void Main(string[] args) - { - // FOR TESTING PURPOSES ONLY. - - // Two arguments: - // 1. The path of a source file. - // 2. The path of a target file. - // - // The UTF8-encoded source file must contain two lines of text: - // 1. An OAuth2.0 client ID. - // 2. The cleartext secret associated with the client ID - // - - Generator gen = new Generator() - { - SourceFilePath = args[0] - }; - gen.Run(); - - StringBuilder src = new StringBuilder(@" -namespace KPSyncForDrive -{ - static partial class GdsDefs - { - static readonly byte[] s_legacyClientIdBytes = new byte[] - { -"); - src.Append(gen.LegacyIdCsharpConstant); - src.Append(@" - }; - static readonly byte[] s_legacyClientIdPad = new byte[] - { -"); - src.Append(gen.LegacyIdPadCsharpConstant); - src.Append(@" - }; - static readonly byte[] s_legacyClientSecretBytes = new byte[] - { -"); - src.Append(gen.LegacySecretCsharpConstant); - src.Append(@" - }; - static readonly byte[] s_legacyClientSecretPad = new byte[] - { -"); - src.Append(gen.LegacySecretPadCsharpConstant); - src.Append(@" - }; - static readonly byte[] s_clientIdBytes = new byte[] - { -"); - src.Append(gen.ClientIdCsharpConstant); - src.Append(@" - }; - static readonly byte[] s_clientIdPad = new byte[] - { -"); - src.Append(gen.ClientIdPadCsharpConstant); - src.Append(@" - }; - static readonly byte[] s_clientSecretBytes = new byte[] - { -"); - src.Append(gen.ClientSecretCsharpConstant); - src.Append(@" - }; - static readonly byte[] s_clientSecretPad = new byte[] - { -"); - src.Append(gen.ClientSecretPadCsharpConstant); - src.Append(@" - }; - - } -}"); - - Debug.WriteLine(src.ToString()); - - using (StreamWriter sw = File.CreateText(args[1])) - { - sw.Write(src.ToString()); - } - } - } -} diff --git a/lib/src/GenClientId/Properties/AssemblyInfo.cs b/lib/src/GenClientId/Properties/AssemblyInfo.cs deleted file mode 100644 index 5efbe80..0000000 --- a/lib/src/GenClientId/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,22 +0,0 @@ -/** - * KPSync for Google Drive - * Copyright(C) 2021-2021 Walter Goodwin - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . -**/ - -using System.Runtime.InteropServices; - -[assembly: ComVisible(false)] -[assembly: Guid("f7b92fbf-f5d8-45e0-b357-4ca8f05ad652")] diff --git a/src/GdsDefs.Data.tt b/src/GdsDefs.Data.tt deleted file mode 100644 index 42e2255..0000000 --- a/src/GdsDefs.Data.tt +++ /dev/null @@ -1,57 +0,0 @@ -<#@ template hostspecific="true" language="C#" #> -<#@ parameter type="System.String" name="ClientIdSrcFolder" #> -<#@ output extension=".cs" encoding="utf-8" #> -<#@ assembly name="System.dll" #> -<#@ assembly name="$(GenClientIdFolder)GenClientId.exe" #> -<#@ import namespace="GenClientId" #> -<# var clientIdSrc = this.Host.ResolveParameterValue("-", "-", "ClientIdSrcFolder"); #> -<# clientIdSrc += "GdsDefs.OAuthCreds.txt"; #> -<# - Generator gen = new Generator() - { - SourceFilePath = this.Host.ResolvePath(clientIdSrc) - }; - gen.Run(); -#> -// -// Design-time generated file. Do not modify or check into source control. -// <#= DateTime.Now #> -// -namespace KPSyncForDrive -{ - static partial class GdsDefs - { - static readonly byte[] s_legacyClientIdBytes = new byte[] - { -<#= gen.LegacyIdCsharpConstant #> - }; - static readonly byte[] s_legacyClientIdPad = new byte[] - { -<#= gen.LegacyIdPadCsharpConstant #> - }; - static readonly byte[] s_legacyClientSecretBytes = new byte[] - { -<#= gen.LegacySecretCsharpConstant #> - }; - static readonly byte[] s_legacyClientSecretPad = new byte[] - { -<#= gen.LegacySecretPadCsharpConstant #> - }; - static readonly byte[] s_clientIdBytes = new byte[] - { -<#= gen.ClientIdCsharpConstant #> - }; - static readonly byte[] s_clientIdPad = new byte[] - { -<#= gen.ClientIdPadCsharpConstant #> - }; - static readonly byte[] s_clientSecretBytes = new byte[] - { -<#= gen.ClientSecretCsharpConstant #> - }; - static readonly byte[] s_clientSecretPad = new byte[] - { -<#= gen.ClientSecretPadCsharpConstant #> - }; - } -} \ No newline at end of file diff --git a/src/GdsDefs.OAuthCreds.txt b/src/GdsDefs.OAuthCreds.txt deleted file mode 100644 index ba924ae..0000000 --- a/src/GdsDefs.OAuthCreds.txt +++ /dev/null @@ -1,4 +0,0 @@ -replace the text on this line with the KPGS 3.0 (legacy) built-in ClientId -replace the text on this line with the KPGS 3.0 (legacy) ClientId secret -replace the text on this line with the current built-in ClientId -replace the text on this line with the current ClientId secret \ No newline at end of file diff --git a/src/GdsDefs.cs b/src/GdsDefs.cs index cdf4205..12d5056 100644 --- a/src/GdsDefs.cs +++ b/src/GdsDefs.cs @@ -21,7 +21,6 @@ **/ using KeePassLib.Security; -using System; using System.Reflection; namespace KPSyncForDrive @@ -36,24 +35,6 @@ static partial class GdsDefs static ProtectedString s_currentClientId; static ProtectedString s_currentClientSecret; - static ProtectedString GetData(byte[] data, byte[] pad) - { - XorredBuffer buf = null; - try - { - buf = new XorredBuffer(data, pad); - return new ProtectedString(true, buf); - } - finally - { - // $$REVIEW - // XorredBuffer isn't IDisposable until sometime after KeePass - // v2.35, so fool the compiler and dispose if necessary. - object unknown = buf; - using (IDisposable disposable = unknown as IDisposable) { } - } - } - public static string ProductName { get @@ -125,9 +106,7 @@ public static ProtectedString ClientSecret { if (s_currentClientSecret == null) { - s_currentClientSecret = GetData( - s_clientSecretBytes, - s_clientSecretPad); + s_currentClientSecret = ProtectedString.Empty; } return s_currentClientSecret; } @@ -139,9 +118,7 @@ public static ProtectedString ClientId { if (s_currentClientId == null) { - s_currentClientId = GetData( - s_clientIdBytes, - s_clientIdPad); + s_currentClientId = ProtectedString.Empty; } return s_currentClientId; } @@ -153,9 +130,7 @@ public static ProtectedString LegacyClientSecret { if (s_legacyClientSecret == null) { - s_legacyClientSecret = GetData( - s_legacyClientSecretBytes, - s_legacyClientSecretPad); + s_legacyClientSecret = ProtectedString.Empty; } return s_legacyClientSecret; } @@ -167,9 +142,7 @@ public static ProtectedString LegacyClientId { if (s_legacyClientId == null) { - s_legacyClientId = GetData( - s_legacyClientIdBytes, - s_legacyClientIdPad); + s_legacyClientId = ProtectedString.Empty; } return s_legacyClientId; } diff --git a/src/KPSyncForDrive.csproj b/src/KPSyncForDrive.csproj index 480c835..4b654f2 100644 --- a/src/KPSyncForDrive.csproj +++ b/src/KPSyncForDrive.csproj @@ -16,8 +16,6 @@ AnyCPU 5 true - $(MSBuildProjectDirectory)\..\lib\src\GenClientId\bin\$(Configuration)\$(TargetFramework)\ - $(MSBuildProjectDirectory)\ true true KeePass Plugin Satellite Resources @@ -40,6 +38,8 @@ + + False - - - - - - true - - - TextTemplatingFileGenerator - GdsDefs.Data.cs - true - true - - - $(ClientIdSrcFolder) - false - true - - - $(GenClientIdFolder) - false - true - - - True - True - GdsDefs.Data.tt - @@ -148,12 +120,6 @@ - - - - - -