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
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>
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
5 changes: 3 additions & 2 deletions languages/csharp/Bitwarden.Sdk/Bitwarden.Sdk.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<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>
Expand All @@ -25,7 +26,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="System.Text.Json" Version="8.0.5" />
<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
27 changes: 17 additions & 10 deletions languages/csharp/Bitwarden.Sdk/BitwardenClient.Debug.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
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 +28,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 +42,24 @@ public async Task<int> ErrorTestAsync()
},
}, CancellationToken.None);

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

private JsonElement ParseResult(JsonElement result)
private JToken ParseResult(JToken result)
{
if (result.GetProperty("success").GetBoolean())
// Expecting: { "success": true|false, "data": ..., "errorMessage": "..." }
if (result is JObject obj && obj.Value<bool?>("success") == true)
{
return result.GetProperty("data");
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
12 changes: 6 additions & 6 deletions languages/csharp/Bitwarden.Sdk/CommandRunner.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Text.Json;
using Newtonsoft.Json;

namespace Bitwarden.Sdk;

Expand All @@ -13,21 +13,21 @@ internal CommandRunner(BitwardenSafeHandle handle)

internal T? RunCommand<T>(Command command)
{
var req = JsonSerializer.Serialize(command, Converter.Settings);
var req = JsonConvert.SerializeObject(command, Converter.Settings);
var result = BitwardenLibrary.RunCommand(req, _handle);
return JsonSerializer.Deserialize<T>(result, Converter.Settings);
return JsonConvert.DeserializeObject<T>(result, Converter.Settings);
}

internal async Task<T?> RunCommandAsync<T>(Command command, CancellationToken cancellationToken)
{
var req = JsonSerializer.Serialize(command, Converter.Settings);
var req = JsonConvert.SerializeObject(command, Converter.Settings);
var result = await BitwardenLibrary.RunCommandAsync(req, _handle, cancellationToken);
return JsonSerializer.Deserialize<T>(result, Converter.Settings);
return JsonConvert.DeserializeObject<T>(result, Converter.Settings);
}

internal async Task<T?> RunCommandAsync<T>(string command, CancellationToken cancellationToken)
{
var result = await BitwardenLibrary.RunCommandAsync(command, _handle, cancellationToken);
return JsonSerializer.Deserialize<T>(result, Converter.Settings);
return JsonConvert.DeserializeObject<T>(result, Converter.Settings);
}
}
29 changes: 15 additions & 14 deletions languages/csharp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,28 @@ using var bitwardenClient = new BitwardenClient(new BitwardenSettings
IdentityUrl = identityUrl
});

bitwardenClient.LoginAccessToken(accessToken, stateFile);
await bitwardenClient.Auth.LoginAccessTokenAsync(accessToken, stateFile);
```

### Create new project

```csharp
var organizationId = Guid.Parse("<organization-id>");
var projectResponse = bitwardenClient.Projects().Create(organizationId, "TestProject");
var projectResponse = await bitwardenClient.Projects.CreateAsync(organizationId, "TestProject");
```

### List all projects

```csharp
var response = bitwardenClient.Projects.List(organizationId);
var projectList = await bitwardenClient.Projects.ListAsync(organizationId);
```

### Update project

```csharp
var projectId = projectResponse.Id;
projectResponse = bitwardenClient.Projects.Get(projectId);
projectResponse = bitwardenClient.Projects.Update(organizationId, projectId, "TestProjectUpdated");
projectResponse = await bitwardenClient.Projects.UpdateAsync(organizationId, projectId, "TestProjectUpdated");
projectResponse = await bitwardenClient.Projects.GetAsync(projectId);
```

### Add new secret
Expand All @@ -50,40 +50,41 @@ projectResponse = bitwardenClient.Projects.Update(organizationId, projectId, "Te
var key = "key";
var value = "value";
var note = "note";
var secretResponse = bitwardenClient.Secrets.Create(organizationId, key, value, note, new[] { projectId });
var secretResponse = await bitwardenClient.Secrets.CreateAsync(organizationId, key, value, note, new[] { projectId });
```

### Update secret
```csharp
var secretId = secretResponse.Id;
secretResponse = bitwardenClient.Secrets.Get(secretId);
secretResponse = bitwardenClient.Secrets.Update(organizationId, secretId, "key2", "value2", "note2", new[] { projectId });
secretResponse = await bitwardenClient.Secrets.UpdateAsync(organizationId, secretId, "key2", "value2", "note2", new[] { projectId });
secretResponse = await bitwardenClient.Secrets.GetAsync(secretId);
```

### Secret GetByIds

```csharp
var secretsResponse = bitwardenClient.Secrets.GetByIds(new[] { secretResponse.Id });
var secretsResponse = await bitwardenClient.Secrets.GetByIdsAsync(new[] { secretResponse.Id });
```

### List secrets

```csharp
var secretIdentifiersResponse = bitwardenClient.Secrets.List(organizationId);
var secretsList = await bitwardenClient.Secrets.ListAsync(organizationId);
```

### Sync secrets

```csharp
var syncResponse = bitwardenClient.Secrets.Sync(organizationId, null);
var syncResponse = await bitwardenClient.Secrets.SyncAsync(organizationId, null);
```

# Delete secret or project

```csharp
bitwardenClient.Secrets.Delete(new [] { secretId });
bitwardenClient.Projects.Delete(new [] { projectId });
await bitwardenClient.Secrets.DeleteAsync(new [] { secretId });
await bitwardenClient.Projects.DeleteAsync(new [] { projectId });
```
# All main SDK methods are asynchronous. Use `await` and ensure your calling code is in an `async Task` method.

[Access Tokens]: https://bitwarden.com/help/access-tokens/
[Bitwarden Secrets Manager]: https://bitwarden.com/products/secrets-manager/
[Bitwarden Secrets Manager]: https://bitwarden.com/products/secrets-manager/
2 changes: 1 addition & 1 deletion languages/csharp/global.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"sdk": {
"version": "8.0.100",
"version": "10.0.100-rc.2.25502.107",
"rollForward": "latestFeature"
}
}
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"devDependencies": {
"prettier": "3.6.0",
"quicktype-core": "23.2.6",
"rimraf": "6.0.1",
"rimraf": "^6.0.1",
"ts-node": "10.9.2",
"typescript": "5.5.4"
}
Expand Down
2 changes: 1 addition & 1 deletion support/scripts/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ async function main() {
lang: "csharp",
rendererOptions: {
namespace: "Bitwarden.Sdk",
framework: "SystemTextJson",
framework: "NewtonSoft",
"csharp-version": "6",
},
});
Expand Down
Loading