Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .github/workflows/build-dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@ jobs:
name: libbitwarden_c_files-x86_64-pc-windows-msvc
path: languages/csharp/Bitwarden.Sdk/windows-x64

- name: Download i686-pc-windows-msvc files
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: libbitwarden_c_files-i686-pc-windows-msvc
path: languages/csharp/Bitwarden.Sdk/windows-x86

- name: Build .NET Project
working-directory: languages/csharp/Bitwarden.Sdk
run: |
Expand All @@ -105,6 +111,6 @@ jobs:
- name: Upload NuGet package
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: Bitwarden.Sdk.${{ needs.version.outputs.version }}.nupkg
name: Community.Bitwarden.Secrets.Sdk.Standard.${{ needs.version.outputs.version }}.nupkg
path: |
./languages/csharp/Bitwarden.Sdk/nuget-output/*.nupkg
4 changes: 4 additions & 0 deletions .github/workflows/build-rust-cross-platform.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ jobs:
target: aarch64-apple-darwin
- os: windows-2022
target: x86_64-pc-windows-msvc
- os: windows-2022
target: i686-pc-windows-msvc
- os: windows-2022
target: x86_64-pc-windows-gnu
# caution: updating the linux runner OS version for GNU
Expand Down Expand Up @@ -89,12 +91,14 @@ jobs:
run: cargo build -p bitwarden-c --target ${{ matrix.settings.target }} --release

- name: Upload Artifact
if: ${{ matrix.settings.target != 'x86_64-pc-windows-gnu' }}
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: libbitwarden_c_files-${{ matrix.settings.target }}
path: target/${{ matrix.settings.target }}/release/*bitwarden_c*

- name: Upload Artifact
if: ${{ matrix.settings.target == 'x86_64-pc-windows-gnu' }}
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: libbitwarden_c_files-${{ matrix.settings.target }}
Expand Down
15 changes: 12 additions & 3 deletions .github/workflows/publish-dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,15 @@ jobs:
VERSION: ${{ inputs.version }}
run: |
if [[ "${VERSION}" == "latest" || "${VERSION}" == "" ]]; then
TAG_NAME=$(curl "https://api.github.com/repos/bitwarden/sdk-sm/releases" | jq -c '.[] | select(.tag_name | contains("dotnet")) | .tag_name' | head -1)
VERSION=$(echo "$TAG_NAME" | grep -ohE '20[0-9]{2}\.([1-9]|1[0-2])\.[0-9]+')
TAG_NAME=$(
curl --silent --fail "https://api.github.com/repos/${GITHUB_REPOSITORY}/releases" |
jq -r 'map(select(.tag_name | startswith("dotnet-v"))) | first | .tag_name // empty'
)
if [[ -z "${TAG_NAME}" ]]; then
echo "No .NET release tags were found in ${GITHUB_REPOSITORY}" >&2
exit 1
fi
VERSION="${TAG_NAME#dotnet-v}"
echo "Latest Released Version: $VERSION"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"

Expand Down Expand Up @@ -85,7 +92,9 @@ jobs:
run: |
mkdir -p nuget-output
cd nuget-output
wget "https://github.com/bitwarden/sdk-sm/releases/download/dotnet-v${VERSION}/Bitwarden.Secrets.Sdk.${VERSION}.nupkg"
PACKAGE_NAME="Community.Bitwarden.Secrets.Sdk.Standard.${VERSION}.nupkg"
curl --fail --location --output "${PACKAGE_NAME}" \
"https://github.com/${GITHUB_REPOSITORY}/releases/download/dotnet-v${VERSION}/${PACKAGE_NAME}"

- name: Log in to Azure
uses: bitwarden/gh-actions/azure-login@main
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/release-dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ jobs:
with:
workflow: build-dotnet.yml
workflow_conclusion: success
branch: main
artifacts: Bitwarden.Sdk.${{ needs.setup.outputs.version }}.nupkg
branch: ${{ github.ref_name }}
artifacts: Community.Bitwarden.Secrets.Sdk.Standard.${{ needs.setup.outputs.version }}.nupkg
path: ./nuget-output

- name: Create release
Expand All @@ -85,4 +85,4 @@ jobs:
token: ${{ secrets.GITHUB_TOKEN }}
draft: true
artifacts: |
./nuget-output/Bitwarden.Secrets.Sdk.${{ needs.setup.outputs.version }}.nupkg
./nuget-output/Community.Bitwarden.Secrets.Sdk.Standard.${{ needs.setup.outputs.version }}.nupkg
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
Expand All @@ -22,8 +22,8 @@
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Bitwarden.Sdk\Bitwarden.Sdk.csproj" />
<ItemGroup>
<ProjectReference Include="..\Bitwarden.Sdk\Bitwarden.Sdk.csproj" />
</ItemGroup>

</Project>
22 changes: 11 additions & 11 deletions languages/csharp/Bitwarden.Sdk.Tests/InteropTests.cs
Original file line number Diff line number Diff line change
@@ -1,35 +1,35 @@
#if DEBUG
using Bitwarden.Sdk;
using System.Diagnostics;

namespace Bitwarden.Sdk.Tests;

public class InteropTests
{
[Fact]
public async void CancelingTest_ThrowsTaskCanceledException()
public async Task CancelingTest_ThrowsTaskCanceledException()
{
var client = new BitwardenClient();
using var client = new BitwardenClient();
using var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(250));

var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(250));

await Assert.ThrowsAsync<TaskCanceledException>(async () => await client.CancellationTestAsync(cts.Token));
await Assert.ThrowsAsync<TaskCanceledException>(() => client.CancellationTestAsync(cts.Token));
}

[Fact]
public async void NoCancel_TaskCompletesSuccessfully()
public async Task NoCancel_TaskCompletesSuccessfully()
{
var client = new BitwardenClient();
using var client = new BitwardenClient();

var result = await client.CancellationTestAsync(CancellationToken.None);
Assert.Equal(42, result);
}

[Fact]
public async void Error_ThrowsException()
public async Task Error_ThrowsException()
{
var client = new BitwardenClient();
using var client = new BitwardenClient();

var bitwardenException = await Assert.ThrowsAsync<BitwardenException>(async () => await client.ErrorTestAsync());
var bitwardenException = await Assert.ThrowsAsync<BitwardenException>(client.ErrorTestAsync);
Assert.Equal("Internal error: This is an error.", bitwardenException.Message);
}
}
#endif
2 changes: 1 addition & 1 deletion languages/csharp/Bitwarden.Sdk.Tests/SampleTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Bitwarden.Sdk.Tests;
namespace Bitwarden.Sdk.Tests;

public class SampleTests
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public SecretsManagerFactAttribute()

private static bool TryGetEnvironment(string variable, out string value)
{
value = Environment.GetEnvironmentVariable(variable);
value = Environment.GetEnvironmentVariable(variable) ?? string.Empty;

if (string.IsNullOrWhiteSpace(value))
{
Expand Down
38 changes: 22 additions & 16 deletions languages/csharp/Bitwarden.Sdk/Bitwarden.Sdk.csproj
Original file line number Diff line number Diff line change
@@ -1,31 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>latest</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>Bitwarden.Sdk</RootNamespace>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Title>Bitwarden Secrets Manager SDK</Title>
<Authors>Bitwarden Inc.</Authors>
<Description>.NET bindings for interacting with the Bitwarden Secrets Manager</Description>
<Copyright>Bitwarden Inc.</Copyright>
<Product>SDK</Product>
<Title>Bitwarden Secrets Manager SDK (Community Fork)</Title>
<Authors>youcefnb</Authors>
<Description>Forked .NET bindings for interacting with the Bitwarden Secrets Manager</Description>
<Copyright>Bitwarden Inc. (forked by youcefnb)</Copyright>
<Product>SDK</Product>

<RepositoryUrl>https://github.com/bitwarden/sdk-sm/tree/main/languages/csharp</RepositoryUrl>
<RepositoryType>Git</RepositoryType>
<RepositoryUrl>https://github.com/youcefnb/sdk-sm/tree/main/languages/csharp</RepositoryUrl>
<RepositoryType>Git</RepositoryType>

<PackageProjectUrl>https://bitwarden.com/products/secrets-manager/</PackageProjectUrl>
<PackageId>Bitwarden.Secrets.Sdk</PackageId>
<PackageIcon>bitwarden.png</PackageIcon>
<PackageTags>Bitwarden;Secrets Manager;Sdk;.NET</PackageTags>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageLicenseFile>LICENSE.txt</PackageLicenseFile>
<Version>1.0.0</Version>
<PackageProjectUrl>https://bitwarden.com/products/secrets-manager/</PackageProjectUrl>
<PackageId>Community.Bitwarden.Secrets.Sdk.Standard</PackageId>
<PackageIcon>bitwarden.png</PackageIcon>
<PackageTags>Bitwarden;Secrets Manager;Sdk;.NET;Standard</PackageTags>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageLicenseFile>LICENSE.txt</PackageLicenseFile>
<Version>2.0.0</Version>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="System.Text.Json" Version="10.0.2" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
<None Include="bitwarden.png" Pack="true" PackagePath="\" />
<None Include="../README.md" Pack="true" PackagePath="\" />
<None Include="../LICENSE.txt" Pack="true" PackagePath="\" />
Expand Down Expand Up @@ -73,5 +74,10 @@
<PackageCopyToOutput>true</PackageCopyToOutput>
<PackagePath>runtimes/win-x64/native</PackagePath>
</Content>
<Content Include="windows-x86/bitwarden_c*.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<PackageCopyToOutput>true</PackageCopyToOutput>
<PackagePath>runtimes/win-x86/native</PackagePath>
</Content>
</ItemGroup>
</Project>
33 changes: 22 additions & 11 deletions languages/csharp/Bitwarden.Sdk/BitwardenClient.Debug.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
using System;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
using Newtonsoft.Json.Linq;

namespace Bitwarden.Sdk;

[Obsolete("DebugCommand is intended for tests only, using any of these commands will throw errors in production code.")]
[EditorBrowsable(EditorBrowsableState.Never)]
partial class DebugCommand
{

}

#if DEBUG
public sealed partial class BitwardenClient
{
public async Task<int> CancellationTestAsync(CancellationToken token)
{
var result = await _commandRunner.RunCommandAsync<JsonElement>(
var result = await _commandRunner.RunCommandAsync<JToken>(
new Command
{
Debug = new DebugCommand
Expand All @@ -28,12 +27,12 @@ public async Task<int> CancellationTestAsync(CancellationToken token)
},
}, token);

return ParseResult(result).GetInt32();
return ParseResult(result).Value<int>();
}

public async Task<int> ErrorTestAsync()
{
var result = await _commandRunner.RunCommandAsync<JsonElement>(
var result = await _commandRunner.RunCommandAsync<JToken>(
new Command
{
Debug = new DebugCommand
Expand All @@ -42,17 +41,29 @@ public async Task<int> ErrorTestAsync()
},
}, CancellationToken.None);

return ParseResult(result).GetInt32();
return ParseResult(result).Value<int>();
}

private JsonElement ParseResult(JsonElement result)
private static JToken ParseResult(JToken? result)
{
if (result.GetProperty("success").GetBoolean())
if (result is null)
{
return result.GetProperty("data");
throw new BitwardenException("Missing response from debug command.");
}

// Expecting: { "success": true|false, "data": ..., "errorMessage": "..." }
if (result is JObject obj && obj.Value<bool?>("success") == true)
{
var data = obj["data"];
if (data is null)
{
throw new BitwardenException("Missing 'data' in successful response.");
}
return data;
}

throw new BitwardenException(result.GetProperty("errorMessage").GetString());
var message = (result as JObject)?.Value<string>("errorMessage") ?? "Unknown error.";
throw new BitwardenException(message);
}
}
#endif
4 changes: 1 addition & 3 deletions languages/csharp/Bitwarden.Sdk/BitwardenClient.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System.Text.Json;

namespace Bitwarden.Sdk;
namespace Bitwarden.Sdk;

public sealed partial class BitwardenClient : IDisposable
{
Expand Down
34 changes: 19 additions & 15 deletions languages/csharp/Bitwarden.Sdk/BitwardenLibrary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,38 @@ namespace Bitwarden.Sdk;

internal static partial class BitwardenLibrary
{
[LibraryImport("bitwarden_c", StringMarshalling = StringMarshalling.Utf8)]
private static partial BitwardenSafeHandle init(string settings);
[DllImport("bitwarden_c", CharSet = CharSet.Ansi, EntryPoint = "init")]
private static extern BitwardenSafeHandle init(string settings);

[LibraryImport("bitwarden_c", StringMarshalling = StringMarshalling.Utf8)]
private static partial void free_mem(IntPtr handle);
[DllImport("bitwarden_c", CharSet = CharSet.Ansi, EntryPoint = "free_mem")]
private static extern void free_mem(IntPtr handle);

[LibraryImport("bitwarden_c", StringMarshalling = StringMarshalling.Utf8)]
private static partial string run_command(string json, BitwardenSafeHandle handle);
[DllImport("bitwarden_c", CharSet = CharSet.Ansi, EntryPoint = "run_command")]
private static extern IntPtr run_command(string json, BitwardenSafeHandle handle);

internal delegate void OnCompleteCallback(IntPtr json);

[LibraryImport("bitwarden_c", StringMarshalling = StringMarshalling.Utf8)]
private static partial IntPtr run_command_async(string json,
[DllImport("bitwarden_c", CharSet = CharSet.Ansi, EntryPoint = "run_command_async")]
private static extern IntPtr run_command_async(string json,
BitwardenSafeHandle handle,
OnCompleteCallback onCompletedCallback,
[MarshalAs(UnmanagedType.U1)] bool isCancellable);

[LibraryImport("bitwarden_c", StringMarshalling = StringMarshalling.Utf8)]
private static partial void abort_and_free_handle(IntPtr joinHandle);
[DllImport("bitwarden_c", CharSet = CharSet.Ansi, EntryPoint = "abort_and_free_handle")]
private static extern void abort_and_free_handle(IntPtr joinHandle);

[LibraryImport("bitwarden_c", StringMarshalling = StringMarshalling.Utf8)]
private static partial void free_handle(IntPtr joinHandle);
[DllImport("bitwarden_c", CharSet = CharSet.Ansi, EntryPoint = "free_handle")]
private static extern void free_handle(IntPtr joinHandle);

internal static BitwardenSafeHandle Init(string settings) => init(settings);

internal static void FreeMemory(IntPtr handle) => free_mem(handle);

internal static string RunCommand(string json, BitwardenSafeHandle handle) => run_command(json, handle);
internal static string RunCommand(string json, BitwardenSafeHandle handle)
{
IntPtr resultPtr = run_command(json, handle);
return Marshal.PtrToStringAnsi(resultPtr);
}

internal static Task<string> RunCommandAsync(string json, BitwardenSafeHandle handle, CancellationToken cancellationToken)
{
Expand All @@ -45,7 +49,7 @@ internal static Task<string> RunCommandAsync(string json, BitwardenSafeHandle ha

abortPointer = run_command_async(json, handle, (resultPointer) =>
{
var stringResult = Marshal.PtrToStringUTF8(resultPointer);
var stringResult = Marshal.PtrToStringAnsi(resultPointer);
tcs.SetResult(stringResult);

if (abortPointer != IntPtr.Zero)
Expand All @@ -64,7 +68,7 @@ internal static Task<string> RunCommandAsync(string json, BitwardenSafeHandle ha
// This register delegate will never be called unless the token is cancelable
// therefore we know that the abortPointer is a valid pointer.
abort_and_free_handle((IntPtr)state);
tcs.SetCanceled(cancellationToken);
tcs.SetCanceled();
}, abortPointer);

return tcs.Task;
Expand Down
Loading
Loading