aboutsummaryrefslogtreecommitdiff
path: root/back-end
diff options
context:
space:
mode:
authorLibravatar vnugent <public@vaughnnugent.com>2024-01-28 19:56:02 -0500
committerLibravatar vnugent <public@vaughnnugent.com>2024-01-28 19:56:02 -0500
commit87645bfad3943e1110e4cb2e038124083e8ae793 (patch)
treec327a4437c98d973f45c313cf8259ad75515c4fe /back-end
parentc438ee90e3be4e5e01ae3d045d6b841a03bd46eb (diff)
progress update
Diffstat (limited to 'back-end')
-rw-r--r--back-end/libs/NVault.Crypto.Secp256k1/src/ContextExtensions.cs274
-rw-r--r--back-end/libs/NVault.Crypto.Secp256k1/src/IRandomSource.cs32
-rw-r--r--back-end/libs/NVault.Crypto.Secp256k1/src/LibSecp256k1.cs284
-rw-r--r--back-end/libs/NVault.Crypto.Secp256k1/src/NVault.Crypto.Secp256k1.csproj27
-rw-r--r--back-end/libs/NVault.Crypto.Secp256k1/src/Secp256HashFuncState.cs56
-rw-r--r--back-end/libs/NVault.Crypto.Secp256k1/src/Secp256k1Context.cs76
-rw-r--r--back-end/libs/NVault.Crypto.Secp256k1/src/Secp256k1SecretKey.cs58
-rw-r--r--back-end/libs/NVault.Crypto.Secp256k1/src/UnmanagedRandomSource.cs101
-rw-r--r--back-end/libs/NVault.VaultExtensions/src/IClientAccessScope.cs48
-rw-r--r--back-end/libs/NVault.VaultExtensions/src/IKvVaultStore.cs52
-rw-r--r--back-end/libs/NVault.VaultExtensions/src/IVaultClientScope.cs33
-rw-r--r--back-end/libs/NVault.VaultExtensions/src/IVaultKvClientScope.cs29
-rw-r--r--back-end/libs/NVault.VaultExtensions/src/KvVaultStorage.cs66
-rw-r--r--back-end/libs/NVault.VaultExtensions/src/NVault.VaultExtensions.csproj27
-rw-r--r--back-end/libs/NVault.VaultExtensions/src/VaultClientExtensions.cs156
-rw-r--r--back-end/libs/NVault.VaultExtensions/src/VaultUserScope.cs25
-rw-r--r--back-end/plugins/nvault/src/Endpoints/Endpoint.cs88
-rw-r--r--back-end/plugins/nvault/src/Model/NostrContext.cs29
-rw-r--r--back-end/plugins/nvault/src/Model/NostrEvent.cs2
-rw-r--r--back-end/plugins/nvault/src/Model/NostrEventEntry.cs47
-rw-r--r--back-end/plugins/nvault/src/Model/NostrEventHistoryStore.cs69
-rw-r--r--back-end/plugins/nvault/src/Model/NostrKeyMetaStore.cs9
-rw-r--r--back-end/plugins/nvault/src/Model/NostrRelayStore.cs11
-rw-r--r--back-end/plugins/nvault/src/NVault.csproj6
24 files changed, 235 insertions, 1370 deletions
diff --git a/back-end/libs/NVault.Crypto.Secp256k1/src/ContextExtensions.cs b/back-end/libs/NVault.Crypto.Secp256k1/src/ContextExtensions.cs
deleted file mode 100644
index bb014df..0000000
--- a/back-end/libs/NVault.Crypto.Secp256k1/src/ContextExtensions.cs
+++ /dev/null
@@ -1,274 +0,0 @@
-// Copyright (C) 2024 Vaughn Nugent
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero 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 Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-using System;
-using System.Security.Cryptography;
-using System.Runtime.InteropServices;
-
-using VNLib.Hashing;
-using VNLib.Utils;
-using VNLib.Utils.Memory;
-using VNLib.Utils.Extensions;
-
-using static NVault.Crypto.Secp256k1.LibSecp256k1;
-
-namespace NVault.Crypto.Secp256k1
-{
- /// <summary>
- /// The callback function signature required for ECDH hash functions
- /// </summary>
- /// <param name="state">The callback state</param>
- /// <returns>The return value to be passed as a result of the operation</returns>
- public delegate int Secp256k1EcdhHashFunc(in Secp256HashFuncState state);
-
- public static unsafe class ContextExtensions
- {
- /// <summary>
- /// Signs a 32byte message digest with the specified secret key on the current context and writes the signature to the specified buffer
- /// </summary>
- /// <param name="context"></param>
- /// <param name="secretKey">The 32byte secret key used to sign messages from the user</param>
- /// <param name="digest">The 32byte message digest to compute the signature of</param>
- /// <param name="signature">The buffer to write the signature output to, must be at-least 64 bytes</param>
- /// <returns>The number of bytes written to the signature buffer, or less than 1 if the operation failed</returns>
- public static ERRNO SchnorSignDigest(this in Secp256k1Context context, ReadOnlySpan<byte> secretKey, ReadOnlySpan<byte> digest, Span<byte> signature)
- {
- //Check the signature buffer size
- if (signature.Length < SignatureSize)
- {
- return ERRNO.E_FAIL;
- }
-
- //Message digest must be exactly 32 bytes long
- if (digest.Length != (int)HashAlg.SHA256)
- {
- return ERRNO.E_FAIL;
- }
-
- //Secret key size must be exactly the size of the secret key struct
- if(secretKey.Length != sizeof(Secp256k1SecretKey))
- {
- return ERRNO.E_FAIL;
- }
-
- //Stack allocated keypair
- KeyPair keyPair = new();
-
- //Init the secret key struct from key data
- Secp256k1SecretKey secKeyStruct = MemoryMarshal.Read<Secp256k1SecretKey>(secretKey);
-
- //Randomize the context and create the keypair
- if (!context.CreateKeyPair(&keyPair, &secKeyStruct))
- {
- return ERRNO.E_FAIL;
- }
-
- //Create the random nonce
- byte* random = stackalloc byte[RandomBufferSize];
-
- //Fill the buffer with random bytes
- context.Lib.GetRandomBytes(new Span<byte>(random, RandomBufferSize));
-
- try
- {
- fixed (byte* sigPtr = &MemoryMarshal.GetReference(signature),
- digestPtr = &MemoryMarshal.GetReference(digest))
- {
- //Sign the message hash and write the output to the signature buffer
- if (context.Lib._signHash(context.Context, sigPtr, digestPtr, &keyPair, random) != 1)
- {
- return ERRNO.E_FAIL;
- }
- }
- }
- finally
- {
- //Erase entropy
- MemoryUtil.InitializeBlock(random, RandomBufferSize);
-
- //Clear the keypair, contains the secret key, even if its stack allocated
- MemoryUtil.ZeroStruct(&keyPair);
- }
-
- //Signature size is always 64 bytes
- return SignatureSize;
- }
-
- /// <summary>
- /// Generates an x-only Schnor encoded public key from the specified secret key on the
- /// current context and writes it to the specified buffer.
- /// </summary>
- /// <param name="context"></param>
- /// <param name="secretKey">The 32byte secret key used to derrive the public key from</param>
- /// <param name="pubKeyBuffer">The buffer to write the x-only Schnor encoded public key</param>
- /// <returns>The number of bytes written to the output buffer, or 0 if the operation failed</returns>
- /// <exception cref="CryptographicException"></exception>
- public static ERRNO GeneratePubKeyFromSecret(this in Secp256k1Context context, ReadOnlySpan<byte> secretKey, Span<byte> pubKeyBuffer)
- {
- if (secretKey.Length != sizeof(Secp256k1SecretKey))
- {
- throw new CryptographicException($"Your secret key must be exactly {sizeof(Secp256k1SecretKey)} bytes long");
- }
-
- if (pubKeyBuffer.Length < XOnlyPublicKeySize)
- {
- throw new CryptographicException($"Your public key buffer must be at least {XOnlyPublicKeySize} bytes long");
- }
-
- //Protect for released lib
- context.Lib.SafeLibHandle.ThrowIfClosed();
-
- //Stack allocated keypair and x-only public key
- Secp256k1PublicKey xOnlyPubKey = new();
- Secp256k1SecretKey secKeyStruct = MemoryMarshal.Read<Secp256k1SecretKey>(secretKey);
- KeyPair keyPair = new();
-
- try
- {
- //Init context and keypair
- if (!context.CreateKeyPair(&keyPair, &secKeyStruct))
- {
- return ERRNO.E_FAIL;
- }
-
- //X-only public key from the keypair
- if (context.Lib._createXonly(context.Context, &xOnlyPubKey, 0, &keyPair) != 1)
- {
- return ERRNO.E_FAIL;
- }
-
- fixed (byte* pubBuffer = &MemoryMarshal.GetReference(pubKeyBuffer))
- {
- //Serialize the public key to the buffer as an X-only public key without leading status byte
- if (context.Lib._serializeXonly(context.Context, pubBuffer, &xOnlyPubKey) != 1)
- {
- return ERRNO.E_FAIL;
- }
- }
- }
- finally
- {
- //Clear the keypair, contains the secret key, even if its stack allocated
- MemoryUtil.ZeroStruct(&keyPair);
- }
-
- //PubKey length is constant
- return XOnlyPublicKeySize;
- }
-
- /// <summary>
- /// Verifies that a given secret key is valid using the current context
- /// </summary>
- /// <param name="context"></param>
- /// <param name="secretKey">The secret key to verify</param>
- /// <returns>A boolean value that indicates if the secret key is valid or not</returns>
- /// <exception cref="CryptographicException"></exception>
- public static bool VerifySecretKey(this in Secp256k1Context context, ReadOnlySpan<byte> secretKey)
- {
- if (secretKey.Length != sizeof(Secp256k1SecretKey))
- {
- throw new CryptographicException($"Your secret key must be exactly {sizeof(Secp256k1SecretKey)} bytes long");
- }
-
- context.Lib.SafeLibHandle.ThrowIfClosed();
-
- //Get sec key ref and verify
- fixed(byte* ptr = &MemoryMarshal.GetReference(secretKey))
- {
- return context.Lib._secKeyVerify.Invoke(context.Context, ptr) == 1;
- }
- }
-
-
- [StructLayout(LayoutKind.Sequential)]
- private readonly ref struct EcdhHashFuncState
- {
- public readonly IntPtr HashFunc { get; init; }
- public readonly IntPtr Opaque { get; init; }
- public readonly int OutLen { get; init; }
- }
-
- /// <summary>
- /// Verifies that a given secret key is valid using the current context
- /// </summary>
- /// <param name="context"></param>
- /// <param name="secretKey">The secret key to verify</param>
- /// <returns>A boolean value that indicates if the secret key is valid or not</returns>
- /// <exception cref="ArgumentException"></exception>
- public static bool ComputeSharedKey(this in Secp256k1Context context, Span<byte> data, ReadOnlySpan<byte> xOnlyPubKey, ReadOnlySpan<byte> secretKey, Secp256k1EcdhHashFunc callback, IntPtr opaque)
- {
- if (secretKey.Length != sizeof(Secp256k1SecretKey))
- {
- throw new ArgumentException($"Your secret key buffer must be exactly {sizeof(Secp256k1SecretKey)} bytes long");
- }
-
- //Init callback state struct
- EcdhHashFuncState state = new()
- {
- HashFunc = Marshal.GetFunctionPointerForDelegate(callback),
- Opaque = opaque,
- OutLen = data.Length
- };
-
- context.Lib.SafeLibHandle.ThrowIfClosed();
-
- //Stack allocated keypair and x-only public key
- Secp256k1PublicKey peerPubKey = new();
-
- //Parse the public key from the buffer
- fixed (byte* pubkeyPtr = &MemoryMarshal.GetReference(xOnlyPubKey))
- {
- context.Lib._xOnlyPubkeyParse(context.Context, &peerPubKey, pubkeyPtr);
- }
-
- fixed (byte* dataPtr = &MemoryMarshal.GetReference(data),
- secKeyPtr = &MemoryMarshal.GetReference(secretKey))
- {
- return context.Lib._ecdh.Invoke(
- context.Context,
- dataPtr,
- &peerPubKey,
- secKeyPtr,
- UmanagedEcdhHashFuncCallback,
- &state
- ) == 1;
- }
-
- /*
- * Umanaged wrapper function for invoking the safe user callback
- * from the unmanaged lib
- */
- static int UmanagedEcdhHashFuncCallback(byte* output, byte* x32, byte* y32, void* opaque)
- {
- //Recover the callback
- if (opaque == null)
- {
- return 0;
- }
-
- EcdhHashFuncState* state = (EcdhHashFuncState*)opaque;
-
- //Init user-state structure
- Secp256HashFuncState userState = new(output, state->OutLen, x32, 32, new(opaque));
-
- //Recover the function pointer
- Secp256k1EcdhHashFunc callback = Marshal.GetDelegateForFunctionPointer<Secp256k1EcdhHashFunc>(state->HashFunc);
-
- //Invoke the callback
- return callback(in userState);
- }
- }
- }
-} \ No newline at end of file
diff --git a/back-end/libs/NVault.Crypto.Secp256k1/src/IRandomSource.cs b/back-end/libs/NVault.Crypto.Secp256k1/src/IRandomSource.cs
deleted file mode 100644
index 4e1861d..0000000
--- a/back-end/libs/NVault.Crypto.Secp256k1/src/IRandomSource.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (C) 2024 Vaughn Nugent
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero 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 Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-using System;
-
-namespace NVault.Crypto.Secp256k1
-{
- /// <summary>
- /// Represents a generator for random data, that fills abinary buffer with random bytes
- /// on demand.
- /// </summary>
- public interface IRandomSource
- {
- /// <summary>
- /// Fills the given buffer with random bytes
- /// </summary>
- /// <param name="buffer">Binary buffer to fill with random data</param>
- void GetRandomBytes(Span<byte> buffer);
- }
-} \ No newline at end of file
diff --git a/back-end/libs/NVault.Crypto.Secp256k1/src/LibSecp256k1.cs b/back-end/libs/NVault.Crypto.Secp256k1/src/LibSecp256k1.cs
deleted file mode 100644
index 8dda269..0000000
--- a/back-end/libs/NVault.Crypto.Secp256k1/src/LibSecp256k1.cs
+++ /dev/null
@@ -1,284 +0,0 @@
-// Copyright (C) 2024 Vaughn Nugent
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero 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 Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-using System;
-using System.Runtime.InteropServices;
-
-using VNLib.Hashing;
-using VNLib.Utils;
-using VNLib.Utils.Native;
-using VNLib.Utils.Extensions;
-
-namespace NVault.Crypto.Secp256k1
-{
-
- internal unsafe delegate int EcdhHasFunc(byte* output, byte* x32, byte* y32, void* data);
-
- public unsafe class LibSecp256k1 : VnDisposeable
- {
- public const int SignatureSize = 64;
- public const int RandomBufferSize = 32;
- public const int XOnlyPublicKeySize = 32;
-
- public static readonly int SecretKeySize = sizeof(Secp256k1SecretKey);
-
- /*
- * Unsafe structures that represent the native keypair and x-only public key
- * structures. They hold character arrays
- */
- [StructLayout(LayoutKind.Sequential, Size = 96)]
- internal struct KeyPair
- {
- public fixed byte data[96];
- }
-
- /// <summary>
- /// 1:1 with the secp256k1_pubkey structure
- /// </summary>
- [StructLayout(LayoutKind.Sequential, Size = 64)]
- internal struct Secp256k1PublicKey
- {
- public fixed byte data[64];
- }
-
-
- //Native methods
- [SafeMethodName("secp256k1_context_create")]
- internal delegate IntPtr ContextCreate(int flags);
-
- [SafeMethodName("secp256k1_context_destroy")]
- internal delegate void ContextDestroy(IntPtr context);
-
- [SafeMethodName("secp256k1_context_randomize")]
- internal delegate int RandomizeContext(IntPtr context, byte* seed32);
-
- [SafeMethodName("secp256k1_keypair_create")]
- internal delegate int KeypairCreate(IntPtr context, KeyPair* keyPair, byte* secretKey);
-
- [SafeMethodName("secp256k1_keypair_xonly_pub")]
- internal delegate int KeypairXOnlyPub(IntPtr ctx, Secp256k1PublicKey* pubkey, int pk_parity, KeyPair* keypair);
-
- [SafeMethodName("secp256k1_xonly_pubkey_serialize")]
- internal delegate int XOnlyPubkeySerialize(IntPtr ctx, byte* output32, Secp256k1PublicKey* pubkey);
-
- [SafeMethodName("secp256k1_schnorrsig_sign32")]
- internal delegate int SignHash(IntPtr ctx, byte* sig64, byte* msg32, KeyPair* keypair, byte* aux_rand32);
-
- [SafeMethodName("secp256k1_ec_seckey_verify")]
- internal delegate int SecKeyVerify(IntPtr ctx, in byte* seckey);
-
- [SafeMethodName("secp256k1_ec_pubkey_serialize")]
- internal delegate int PubKeySerialize(IntPtr ctx, byte* outPubKey, ulong* outLen, Secp256k1PublicKey* pubKey, uint flags);
-
- [SafeMethodName("secp256k1_xonly_pubkey_parse")]
- internal delegate int XOnlyPubkeyParse(IntPtr ctx, Secp256k1PublicKey* pubkey, byte* input32);
-
- [SafeMethodName("secp256k1_ecdh")]
- internal delegate int Ecdh(
- IntPtr ctx,
- byte* output,
- Secp256k1PublicKey* pubkey,
- byte* scalar,
- EcdhHasFunc hashFunc,
- void* dataPtr
- );
-
-
- /// <summary>
- /// Loads the Secp256k1 library from the specified path and creates a wrapper class (loads methods from the library)
- /// </summary>
- /// <param name="dllPath">The realtive or absolute path to the shared library</param>
- /// <param name="search">The DLL probing path pattern</param>
- /// <returns>The <see cref="LibSecp256k1"/> library wrapper class</returns>
- /// <exception cref="DllNotFoundException"></exception>
- /// <exception cref="ArgumentNullException"></exception>
- /// <exception cref="MissingMemberException"></exception>
- /// <exception cref="EntryPointNotFoundException"></exception>
- public static LibSecp256k1 LoadLibrary(string dllPath, DllImportSearchPath search, IRandomSource? random)
- {
- _ = dllPath?? throw new ArgumentNullException(nameof(dllPath));
-
- //try to load the library
- SafeLibraryHandle lib = SafeLibraryHandle.LoadLibrary(dllPath, search);
-
- //try to create the wrapper class, if it fails, dispose the library
- try
- {
- //setup fallback random source if null
- random ??= new FallbackRandom();
-
- //Create the lib
- return new LibSecp256k1(lib, random);
- }
- catch
- {
- //Dispose the library if the creation failed
- lib.Dispose();
- throw;
- }
- }
-
- /// <summary>
- /// Loads the Secp256k1 library from the specified path and creates a wrapper class (loads methods from the library)
- /// </summary>
- /// <param name="handle">The handle to the shared library</param>
- /// <param name="random">An optional random source to create random entropy and secrets from</param>
- /// <returns>The <see cref="LibSecp256k1"/> library wrapper class</returns>
- /// <exception cref="ArgumentNullException"></exception>
- /// <exception cref="MissingMemberException"></exception>
- /// <exception cref="EntryPointNotFoundException"></exception>
- public static LibSecp256k1 FromHandle(SafeLibraryHandle handle, IRandomSource? random)
- {
- _ = handle ?? throw new ArgumentNullException(nameof(handle));
- //setup fallback random source if null
- random ??= new FallbackRandom();
- //Create the lib
- return new LibSecp256k1(handle, random);
- }
-
- /// <summary>
- /// The underlying library handle
- /// </summary>
- public SafeLibraryHandle SafeLibHandle { get; }
-
- internal readonly KeypairCreate _createKeyPair;
- internal readonly ContextCreate _create;
- internal readonly RandomizeContext _randomize;
- internal readonly ContextDestroy _destroy;
- internal readonly KeypairXOnlyPub _createXonly;
- internal readonly XOnlyPubkeySerialize _serializeXonly;
- internal readonly SignHash _signHash;
- internal readonly SecKeyVerify _secKeyVerify;
- internal readonly PubKeySerialize _pubKeySerialize;
- internal readonly Ecdh _ecdh;
- internal readonly XOnlyPubkeyParse _xOnlyPubkeyParse;
- private readonly IRandomSource _randomSource;
-
- /// <summary>
- /// Creates a new instance of the <see cref="LibSecp256k1"/> class from the specified library handle
- /// </summary>
- /// <param name="handle">The library handle that referrences the secp256k1 platform specific library</param>
- /// <remarks>
- /// This method attempts to capture all the native methods from the library, which may throw if the library is not valid.
- /// </remarks>
- /// <exception cref="ArgumentNullException"></exception>
- /// <exception cref="MissingMemberException"></exception>
- /// <exception cref="EntryPointNotFoundException"></exception>
- public LibSecp256k1(SafeLibraryHandle handle, IRandomSource randomSource)
- {
- //Store library handle
- SafeLibHandle = handle ?? throw new ArgumentNullException(nameof(handle));
-
- //Get all method handles and store them
- _create = handle.DangerousGetMethod<ContextCreate>();
- _createKeyPair = handle.DangerousGetMethod<KeypairCreate>();
- _randomize = handle.DangerousGetMethod<RandomizeContext>();
- _destroy = handle.DangerousGetMethod<ContextDestroy>();
- _createXonly = handle.DangerousGetMethod<KeypairXOnlyPub>();
- _serializeXonly = handle.DangerousGetMethod<XOnlyPubkeySerialize>();
- _signHash = handle.DangerousGetMethod<SignHash>();
- _secKeyVerify = handle.DangerousGetMethod<SecKeyVerify>();
- _pubKeySerialize = handle.DangerousGetMethod<PubKeySerialize>();
- _ecdh = handle.DangerousGetMethod<Ecdh>();
- _xOnlyPubkeyParse = handle.DangerousGetMethod<XOnlyPubkeyParse>();
-
- //Store random source
- _randomSource = randomSource;
- }
-
- /// <summary>
- /// Creates a new instance of the <see cref="LibSecp256k1"/> class from the specified library handle
- /// with a fallback random source
- /// </summary>
- /// <param name="handle">The library handle</param>
- /// <exception cref="ArgumentNullException"></exception>
- /// <exception cref="MissingMemberException"></exception>
- /// <exception cref="EntryPointNotFoundException"></exception>
- public LibSecp256k1(SafeLibraryHandle handle):this(handle, new FallbackRandom())
- {}
-
- /// <summary>
- /// Generates a new secret key and writes it to the specified buffer. The buffer size must be exactly <see cref="SecretKeySize"/> bytes long
- /// <para>
- /// NOTE: You should verify this validity of the key against the library with a new <see cref="Secp256k1Context"/>
- /// </para>
- /// </summary>
- /// <param name="buffer">The secret key buffer</param>
- /// <exception cref="ArgumentException"></exception>
- public void CreateSecretKey(Span<byte> buffer)
- {
- //Protect for released lib
- SafeLibHandle.ThrowIfClosed();
-
- if(buffer.Length != sizeof(Secp256k1SecretKey))
- {
- throw new ArgumentException($"Buffer must be exactly {sizeof(Secp256k1SecretKey)} bytes long", nameof(buffer));
- }
-
- //Fill the buffer with random bytes
- _randomSource.GetRandomBytes(buffer);
- }
-
- /// <summary>
- /// Fills the given buffer with random bytes from
- /// the internal random source
- /// </summary>
- /// <param name="buffer">The buffer to fill with random data</param>
- public void GetRandomBytes(Span<byte> buffer)
- {
- //Protect for released lib
- SafeLibHandle.ThrowIfClosed();
-
- _randomSource.GetRandomBytes(buffer);
- }
-
- /// <summary>
- /// Creates a new <see cref="Secp256k1Context"/> from the current managed library
- /// </summary>
- /// <param name="Lib"></param>
- /// <returns>The new <see cref="Secp256k1Context"/> object from the library</returns>
- /// <exception cref="OutOfMemoryException"></exception>
- public Secp256k1Context CreateContext()
- {
- //Protect for released lib
- SafeLibHandle.ThrowIfClosed();
-
- //Create new context
- IntPtr context = _create(1);
-
- if (context == IntPtr.Zero)
- {
- throw new OutOfMemoryException("Failed to create the new Secp256k1 context");
- }
-
- return new Secp256k1Context(this, context);
- }
-
- protected override void Free()
- {
- //Free native library
- SafeLibHandle.Dispose();
- }
-
- private record class FallbackRandom : IRandomSource
- {
- public void GetRandomBytes(Span<byte> buffer)
- {
- //Use the random generator from the crypto lib
- RandomHash.GetRandomBytes(buffer);
- }
- }
- }
-} \ No newline at end of file
diff --git a/back-end/libs/NVault.Crypto.Secp256k1/src/NVault.Crypto.Secp256k1.csproj b/back-end/libs/NVault.Crypto.Secp256k1/src/NVault.Crypto.Secp256k1.csproj
deleted file mode 100644
index 5014d89..0000000
--- a/back-end/libs/NVault.Crypto.Secp256k1/src/NVault.Crypto.Secp256k1.csproj
+++ /dev/null
@@ -1,27 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-
- <PropertyGroup>
- <TargetFramework>net8.0</TargetFramework>
- <Nullable>enable</Nullable>
- <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
- <PackageReadmeFile>README.md</PackageReadmeFile>
- <RootNamespace>NVault.Crypto.Secp256k1</RootNamespace>
- <AssemblyName>NVault.Crypto.Secp256k1</AssemblyName>
- </PropertyGroup>
-
- <PropertyGroup>
- <Authors>Vaughn Nugent</Authors>
- <Company>Vaughn Nugent</Company>
- <Product>NVault.Crypto.Secp256k1</Product>
- <Description>Provides a managed library for the Bitcoin Core secp256k1 library, along with other helper types for NVault</Description>
- <Copyright>Copyright © 2024 Vaughn Nugent</Copyright>
- <PackageProjectUrl>https://www.vaughnnugent.com/resources/software/modules/NVault</PackageProjectUrl>
- <RepositoryUrl>https://github.com/VnUgE/NVault/tree/master/</RepositoryUrl>
- </PropertyGroup>
-
- <ItemGroup>
- <PackageReference Include="VNLib.Hashing.Portable" Version="0.1.0-ci0109" />
- <PackageReference Include="VNLib.Utils" Version="0.1.0-ci0109" />
- </ItemGroup>
-
-</Project>
diff --git a/back-end/libs/NVault.Crypto.Secp256k1/src/Secp256HashFuncState.cs b/back-end/libs/NVault.Crypto.Secp256k1/src/Secp256HashFuncState.cs
deleted file mode 100644
index c82321c..0000000
--- a/back-end/libs/NVault.Crypto.Secp256k1/src/Secp256HashFuncState.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright (C) 2024 Vaughn Nugent
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero 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 Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-using System;
-using System.Runtime.InteropServices;
-
-namespace NVault.Crypto.Secp256k1
-{
- [StructLayout(LayoutKind.Sequential)]
- public unsafe readonly ref struct Secp256HashFuncState
- {
-
- /// <summary>
- /// The opaque pointer passed to the hash function
- /// </summary>
- public readonly IntPtr Opaque { get; }
-
- private readonly byte* _output;
- private readonly byte* _xCoord;
- private readonly int _outputLength;
- private readonly int _xCoordLength;
-
- internal Secp256HashFuncState(byte* output, int outputLength, byte* xCoord, int xCoordLength, IntPtr opaque)
- {
- Opaque = opaque;
- _output = output;
- _outputLength = outputLength;
- _xCoord = xCoord;
- _xCoordLength = xCoordLength;
- }
-
- /// <summary>
- /// Gets the output buffer as a span
- /// </summary>
- /// <returns>The output buffer span</returns>
- public readonly Span<byte> GetOutput() => new(_output, _outputLength);
-
- /// <summary>
- /// Gets the x coordinate argument as a span
- /// </summary>
- /// <returns>The xcoordinate buffer span</returns>
- public readonly ReadOnlySpan<byte> GetXCoordArg() => new(_xCoord, _xCoordLength);
- }
-} \ No newline at end of file
diff --git a/back-end/libs/NVault.Crypto.Secp256k1/src/Secp256k1Context.cs b/back-end/libs/NVault.Crypto.Secp256k1/src/Secp256k1Context.cs
deleted file mode 100644
index dfb3ff8..0000000
--- a/back-end/libs/NVault.Crypto.Secp256k1/src/Secp256k1Context.cs
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright (C) 2024 Vaughn Nugent
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero 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 Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-using System;
-
-using VNLib.Utils.Extensions;
-using VNLib.Utils.Memory;
-
-using static NVault.Crypto.Secp256k1.LibSecp256k1;
-
-namespace NVault.Crypto.Secp256k1
-{
- /// <summary>
- /// Represents a Secp256k1 context, it is used to randomize the instance, create key pairs,
- /// and frees the context when disposed
- /// </summary>
- /// <param name="Lib">The <see cref="LibSecp256k1"/> library instance</param>
- /// <param name="Context">A pointer to the initialized context instance</param>
- public readonly record struct Secp256k1Context(LibSecp256k1 Lib, IntPtr Context) : IDisposable
- {
- /// <summary>
- /// Randomizes the context with random data using the library's random source
- /// </summary>
- /// <returns>True if the context was successfully randomized, false otherwise</returns>
- public unsafe readonly bool Randomize()
- {
- Lib.SafeLibHandle.ThrowIfClosed();
-
- //Randomze the context
- byte* entropy = stackalloc byte[RandomBufferSize];
-
- //Get random bytes
- Lib.GetRandomBytes(new Span<byte>(entropy, RandomBufferSize));
-
- //call native randomize method
- bool result = Lib._randomize(Context, entropy) == 1;
-
- //Zero the randomness buffer before returning to avoid leaking random data
- MemoryUtil.InitializeBlock(entropy, RandomBufferSize);
-
- return result;
- }
-
- internal unsafe readonly bool CreateKeyPair(KeyPair* keyPair, Secp256k1SecretKey* secretKey)
- {
- Lib.SafeLibHandle.ThrowIfClosed();
-
- //Create the keypair from the secret key
- return Lib._createKeyPair(Context, keyPair, (byte*)secretKey) == 1;
- }
-
- /// <summary>
- /// Releases the context instance and frees the memory
- /// </summary>
- public readonly void Dispose()
- {
- if (Context != IntPtr.Zero)
- {
- //Free the context
- Lib._destroy(Context);
- }
- }
- }
-} \ No newline at end of file
diff --git a/back-end/libs/NVault.Crypto.Secp256k1/src/Secp256k1SecretKey.cs b/back-end/libs/NVault.Crypto.Secp256k1/src/Secp256k1SecretKey.cs
deleted file mode 100644
index 35734ae..0000000
--- a/back-end/libs/NVault.Crypto.Secp256k1/src/Secp256k1SecretKey.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (C) 2024 Vaughn Nugent
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero 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 Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-using System;
-using System.Runtime.InteropServices;
-
-using VNLib.Utils.Memory;
-
-namespace NVault.Crypto.Secp256k1
-{
- /// <summary>
- /// Represents a Secp256k1 secret key, the size is fixed, and should use
- /// the sizeof() operator to get the size
- /// </summary>
- [StructLayout(LayoutKind.Sequential, Size = 32)]
- public unsafe struct Secp256k1SecretKey
- {
- private fixed byte data[32];
-
- /// <summary>
- /// Implict cast to a span of raw bytes
- /// </summary>
- /// <param name="key">The secret key to cast</param>
- public static implicit operator Span<byte>(Secp256k1SecretKey key) => new(key.data, 32);
-
- /// <summary>
- /// Casts the secret key span to a <see cref="Secp256k1SecretKey"/> via a structure copy
- /// </summary>
- /// <param name="key">The key data to copy</param>
- /// <exception cref="ArgumentOutOfRangeException"></exception>
- public static explicit operator Secp256k1SecretKey(ReadOnlySpan<byte> key) => FromSpan(key);
-
- /// <summary>
- /// Creates a new <see cref="Secp256k1SecretKey"/> from a span of bytes
- /// by copying the bytes into the struct
- /// </summary>
- /// <param name="span">The secret key data to copy</param>
- /// <returns>An initilaized <see cref="Secp256k1SecretKey"/></returns>
- public static Secp256k1SecretKey FromSpan(ReadOnlySpan<byte> span)
- {
- Secp256k1SecretKey newKey = new();
- MemoryUtil.CopyStruct(span, ref newKey);
- return newKey;
- }
- }
-} \ No newline at end of file
diff --git a/back-end/libs/NVault.Crypto.Secp256k1/src/UnmanagedRandomSource.cs b/back-end/libs/NVault.Crypto.Secp256k1/src/UnmanagedRandomSource.cs
deleted file mode 100644
index 360de21..0000000
--- a/back-end/libs/NVault.Crypto.Secp256k1/src/UnmanagedRandomSource.cs
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright (C) 2024 Vaughn Nugent
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero 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 Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-using System;
-using System.Runtime.InteropServices;
-
-using VNLib.Utils;
-using VNLib.Utils.Native;
-using VNLib.Utils.Extensions;
-
-namespace NVault.Crypto.Secp256k1
-{
-
- /// <summary>
- /// A wrapper class for an unmanaged random source that conforms to the <see cref="IRandomSource"/> interface
- /// </summary>
- public class UnmanagedRandomSource : VnDisposeable, IRandomSource
- {
- public const string METHOD_NAME = "getRandomBytes";
-
- unsafe delegate void UnmanagedRandomSourceDelegate(byte* buffer, int size);
-
-
- private readonly bool OwnsHandle;
- private readonly SafeLibraryHandle _library;
- private readonly UnmanagedRandomSourceDelegate _getRandomBytes;
-
- /// <summary>
- /// Loads the unmanaged random source from the given library
- /// and attempts to get the random bytes method <see cref="METHOD_NAME"/>
- /// </summary>
- /// <param name="path"></param>
- /// <param name="search"></param>
- /// <returns>The wrapped library that conforms to the <see cref="IRandomSource"/></returns>
- public static UnmanagedRandomSource LoadLibrary(string path, DllImportSearchPath search)
- {
- //Try to load the library
- SafeLibraryHandle lib = SafeLibraryHandle.LoadLibrary(path, search);
- try
- {
- return new UnmanagedRandomSource(lib, true);
- }
- catch
- {
- //release lib
- lib.Dispose();
- throw;
- }
- }
-
- /// <summary>
- /// Creates the unmanaged random source from the given library
- /// </summary>
- /// <param name="lib">The library handle to wrap</param>
- /// <exception cref="ObjectDisposedException"></exception>
- /// <exception cref="EntryPointNotFoundException"></exception>
- public UnmanagedRandomSource(SafeLibraryHandle lib, bool ownsHandle)
- {
- lib.ThrowIfClosed();
-
- _library = lib;
-
- //get the method delegate
- _getRandomBytes = lib.DangerousGetMethod<UnmanagedRandomSourceDelegate>(METHOD_NAME);
-
- OwnsHandle = ownsHandle;
- }
-
- public unsafe void GetRandomBytes(Span<byte> buffer)
- {
- _library.ThrowIfClosed();
-
- //Fix buffer and call unmanaged method
- fixed(byte* ptr = &MemoryMarshal.GetReference(buffer))
- {
- _getRandomBytes(ptr, buffer.Length);
- }
- }
-
- ///<inheritdoc/>
- protected override void Free()
- {
- if (OwnsHandle)
- {
- _library.Dispose();
- }
- }
- }
-} \ No newline at end of file
diff --git a/back-end/libs/NVault.VaultExtensions/src/IClientAccessScope.cs b/back-end/libs/NVault.VaultExtensions/src/IClientAccessScope.cs
deleted file mode 100644
index c79f75e..0000000
--- a/back-end/libs/NVault.VaultExtensions/src/IClientAccessScope.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (C) 2024 Vaughn Nugent
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero 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 Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-using System;
-using System.Collections.Generic;
-
-namespace NVault.VaultExtensions
-{
- /// <summary>
- /// Represents a user auth token access scope
- /// configuration.
- /// </summary>
- public interface IClientAccessScope
- {
- /// <summary>
- /// The list of policies for new token generation
- /// </summary>
- IList<string> Policies { get; }
-
- /// <summary>
- /// Allows the user to renew the access token
- /// </summary>
- bool Renewable { get; }
-
- /// <summary>
- /// The token
- /// </summary>
- string TokenTtl { get; }
-
- /// <summary>
- /// The explicit number of token uses allowed by the genreated token,
- /// 0 for unlimited uses
- /// </summary>
- int NumberOfUses { get; }
- }
-} \ No newline at end of file
diff --git a/back-end/libs/NVault.VaultExtensions/src/IKvVaultStore.cs b/back-end/libs/NVault.VaultExtensions/src/IKvVaultStore.cs
deleted file mode 100644
index 037fe6c..0000000
--- a/back-end/libs/NVault.VaultExtensions/src/IKvVaultStore.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright (C) 2024 Vaughn Nugent
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero 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 Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-using System.Threading.Tasks;
-
-using VNLib.Utils.Memory;
-
-namespace NVault.VaultExtensions
-{
- /// <summary>
- /// Represents a vault key-value store that can be used to store secrets
- /// </summary>
- public interface IKvVaultStore
- {
- /// <summary>
- /// Deletes a secret from the vault
- /// </summary>
- /// <param name="user">The user scope of the secret</param>
- /// <param name="path">The path to the secret</param>
- /// <returns>A task that returns when the operation has completed</returns>
- Task DeleteSecretAsync(VaultUserScope user, string path);
-
- /// <summary>
- /// Sets a secret in the vault at the specified path and user scope
- /// </summary>
- /// <param name="user">The user scope to store the value at</param>
- /// <param name="path">The path to the secret</param>
- /// <param name="secret">The secret value to set</param>
- /// <returns>A task that resolves when the secret has been updated</returns>
- Task SetSecretAsync(VaultUserScope user, string path, PrivateString secret);
-
- /// <summary>
- /// Gets a secret from the vault at the specified path and user scope
- /// </summary>
- /// <param name="user">The user scope to get the value from</param>
- /// <param name="path">The secret path</param>
- /// <returns>A task that resolves the secret if found, null otherwise</returns>
- Task<PrivateString?> GetSecretAsync(VaultUserScope user, string path);
- }
-} \ No newline at end of file
diff --git a/back-end/libs/NVault.VaultExtensions/src/IVaultClientScope.cs b/back-end/libs/NVault.VaultExtensions/src/IVaultClientScope.cs
deleted file mode 100644
index d53bc4a..0000000
--- a/back-end/libs/NVault.VaultExtensions/src/IVaultClientScope.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (C) 2024 Vaughn Nugent
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero 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 Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-namespace NVault.VaultExtensions
-{
- /// <summary>
- /// Represents a vault client scope configuration
- /// </summary>
- public interface IVaultClientScope
- {
- /// <summary>
- /// The mount point for the vault
- /// </summary>
- string? MountPoint { get; }
-
- /// <summary>
- /// The entry path for the vault
- /// </summary>
- string? EntryPath { get; }
- }
-} \ No newline at end of file
diff --git a/back-end/libs/NVault.VaultExtensions/src/IVaultKvClientScope.cs b/back-end/libs/NVault.VaultExtensions/src/IVaultKvClientScope.cs
deleted file mode 100644
index f763473..0000000
--- a/back-end/libs/NVault.VaultExtensions/src/IVaultKvClientScope.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (C) 2024 Vaughn Nugent
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero 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 Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-namespace NVault.VaultExtensions
-{
- /// <summary>
- /// A key-value specific scoped client
- /// </summary>
- public interface IVaultKvClientScope : IVaultClientScope
- {
- /// <summary>
- /// The property to store the secret value in the
- /// storage dictionary
- /// </summary>
- string StorageProperty { get; }
- }
-} \ No newline at end of file
diff --git a/back-end/libs/NVault.VaultExtensions/src/KvVaultStorage.cs b/back-end/libs/NVault.VaultExtensions/src/KvVaultStorage.cs
deleted file mode 100644
index 8a2b9b6..0000000
--- a/back-end/libs/NVault.VaultExtensions/src/KvVaultStorage.cs
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright (C) 2024 Vaughn Nugent
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero 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 Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-using System.Threading.Tasks;
-
-using VaultSharp;
-
-using VNLib.Utils.Memory;
-
-namespace NVault.VaultExtensions
-{
- /// <summary>
- /// An abstract kv storage implementation that uses the vault client to store secrets
- /// </summary>
- public abstract class KvVaultStorage : IKvVaultStore
- {
- /// <summary>
- /// The vault client
- /// </summary>
- protected abstract IVaultClient Client { get; }
-
- /// <summary>
- /// The storage scope
- /// </summary>
- protected abstract IVaultKvClientScope Scope { get; }
-
- public virtual Task DeleteSecretAsync(VaultUserScope user, string path)
- {
- string tPath = TranslatePath(path);
- return Client.DeleteSecretAsync(Scope, user, tPath);
- }
-
- public virtual Task SetSecretAsync(VaultUserScope user, string path, PrivateString secret)
- {
- string tPath = TranslatePath(path);
- return Client.SetSecretAsync(Scope, user, tPath, secret);
- }
-
- public virtual Task<PrivateString?> GetSecretAsync(VaultUserScope user, string path)
- {
- string tPath = TranslatePath(path);
- return Client.GetSecretAsync(Scope, user, tPath);
- }
-
- /// <summary>
- /// Translates a realtive item path to a full path
- /// within the scope of the storage. This may be used to
- /// extend the scope of the operation
- /// </summary>
- /// <param name="path">The item path to scope</param>
- /// <returns>The further scoped vault path for the item</returns>
- public virtual string TranslatePath(string path) => path;
- }
-} \ No newline at end of file
diff --git a/back-end/libs/NVault.VaultExtensions/src/NVault.VaultExtensions.csproj b/back-end/libs/NVault.VaultExtensions/src/NVault.VaultExtensions.csproj
deleted file mode 100644
index e5dbe8c..0000000
--- a/back-end/libs/NVault.VaultExtensions/src/NVault.VaultExtensions.csproj
+++ /dev/null
@@ -1,27 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-
- <PropertyGroup>
- <TargetFramework>net8.0</TargetFramework>
- <Nullable>enable</Nullable>
- <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
- <PackageReadmeFile>README.md</PackageReadmeFile>
- <RootNamespace>NVault.VaultExtensions</RootNamespace>
- <AssemblyName>NVault.VaultExtensions</AssemblyName>
- </PropertyGroup>
-
- <PropertyGroup>
- <Authors>Vaughn Nugent</Authors>
- <Company>Vaughn Nugent</Company>
- <Product>NVault.VaultExtensions</Product>
- <Description>A Hashicorp Vault unified extension library for NVault</Description>
- <Copyright>Copyright © 2024 Vaughn Nugent</Copyright>
- <PackageProjectUrl>https://www.vaughnnugent.com/resources/software/modules/NVault</PackageProjectUrl>
- <RepositoryUrl>https://github.com/VnUgE/NVault/tree/master/</RepositoryUrl>
- </PropertyGroup>
-
- <ItemGroup>
- <PackageReference Include="VaultSharp" Version="1.13.0.1" />
- <PackageReference Include="VNLib.Plugins.Extensions.Loading" Version="0.1.0-ci0047" />
- </ItemGroup>
-
-</Project>
diff --git a/back-end/libs/NVault.VaultExtensions/src/VaultClientExtensions.cs b/back-end/libs/NVault.VaultExtensions/src/VaultClientExtensions.cs
deleted file mode 100644
index d90941a..0000000
--- a/back-end/libs/NVault.VaultExtensions/src/VaultClientExtensions.cs
+++ /dev/null
@@ -1,156 +0,0 @@
-// Copyright (C) 2024 Vaughn Nugent
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero 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 Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-using System.Threading;
-using System.Threading.Tasks;
-using System.Collections.Generic;
-
-using VaultSharp;
-using VaultSharp.V1.Commons;
-
-using VNLib.Utils.Memory;
-using VNLib.Plugins.Essentials.Extensions;
-
-
-namespace NVault.VaultExtensions
-{
-
- public static class VaultClientExtensions
- {
-
- private static string GetKeyPath(IVaultClientScope client, in VaultUserScope scope, string itemPath)
- {
- //Allow for null entry path
- return client.EntryPath == null ? $"{scope.UserId}/{itemPath}" : $"{client.EntryPath}/{scope.UserId}/{itemPath}";
- }
-
-
- public static Task<PrivateString?> GetSecretAsync(this IVaultClient client, IVaultKvClientScope scope, VaultUserScope user, string path)
- {
- return GetSecretAsync(client, scope, user, path, scope.StorageProperty);
- }
-
- public static async Task<PrivateString?> GetSecretAsync(this IVaultClient client, IVaultClientScope scope, VaultUserScope user, string path, string property)
- {
- //Get the path complete path for the scope
- string fullPath = GetKeyPath(scope, user, path);
-
- //Get the secret from the vault
- Secret<SecretData> result = await client.V1.Secrets.KeyValue.V2.ReadSecretAsync(fullPath, mountPoint:scope.MountPoint);
-
- //Try to get the secret value from the store
- string? value = result.Data.Data.GetValueOrDefault(property)?.ToString();
-
- //Return the secret value as a private string
- return value == null ? null : PrivateString.ToPrivateString(value, true);
- }
-
- /// <summary>
- /// Writes a secret to the vault that is scoped by the vault scope, and the user scope.
- /// </summary>
- /// <param name="client"></param>
- /// <param name="scope">The client scope configuration</param>
- /// <param name="user">The user scope to isolate the </param>
- /// <param name="path">The item path within the current scope</param>
- /// <param name="secret">The secret value to set at the desired property</param>
- /// <returns>A task that resolves when the secret has been updated</returns>
- public static async Task<CurrentSecretMetadata> SetSecretAsync(this IVaultClient client, IVaultKvClientScope scope, VaultUserScope user, string path, PrivateString secret)
- {
- Dictionary<string, string> secretDict = new()
- {
- //Dangerous cast, but we know the type
- { scope.StorageProperty, (string)secret }
- };
-
- //Await the result so we be sure the secret is not destroyed
- return await SetSecretAsync(client, scope, user, path, secretDict);
- }
-
- /// <summary>
- /// Writes a secret to the vault that is scoped by the vault scope, and the user scope.
- /// </summary>
- /// <param name="client"></param>
- /// <param name="scope">The client scope configuration</param>
- /// <param name="user">The user scope to isolate the </param>
- /// <param name="path">The item path within the current scope</param>
- /// <param name="secret">The secret value to set at the desired property</param>
- /// <returns>A task that resolves when the secret has been updated</returns>
- public static async Task<CurrentSecretMetadata> SetSecretAsync(this IVaultClient client, IVaultClientScope scope, VaultUserScope user, string path, IDictionary<string, string> secret)
- {
- //Get the path complete path for the scope
- string fullPath = GetKeyPath(scope, user, path);
-
- //Get the secret from the vault
- Secret<CurrentSecretMetadata> result = await client.V1.Secrets.KeyValue.V2.WriteSecretAsync(fullPath, secret, mountPoint:scope.MountPoint);
-
- return result.Data;
- }
-
- /// <summary>
- /// Deletes a secret from the vault that is scoped by the vault scope, and the user scope.
- /// </summary>
- /// <param name="client"></param>
- /// <param name="scope">The client scope</param>
- /// <param name="user">The vault user scope</param>
- /// <param name="path">The path to the storage</param>
- /// <returns>A task that resolves when the delete operation has completed</returns>
- public static Task DeleteSecretAsync(this IVaultClient client, IVaultClientScope scope, VaultUserScope user, string path)
- {
- string fullApth = GetKeyPath(scope, user, path);
- return client.V1.Secrets.KeyValue.V2.DeleteSecretAsync(fullApth, mountPoint:scope.MountPoint);
- }
-
- /// <summary>
- /// Deletes a secret from the vault
- /// </summary>
- /// <param name="user">The user scope of the secret</param>
- /// <param name="path">The path to the secret</param>
- /// <param name="cancellation">A token to cancel the operation</param>
- /// <returns>A task that returns when the operation has completed</returns>
- public static Task DeleteSecretAsync(this IKvVaultStore store, VaultUserScope user, string path, CancellationToken cancellation)
- {
- return store.DeleteSecretAsync(user, path).WaitAsync(cancellation);
- }
-
-
- /// <summary>
- /// Gets a secret from the vault at the specified path and user scope
- /// </summary>
- /// <param name="user">The user scope to get the value from</param>
- /// <param name="path">The secret path</param>
- /// <param name="cancellation">A token to cancel the operation</param>
- /// <returns>A task that resolves the secret if found, null otherwise</returns>
- public static Task<PrivateString?> GetSecretAsync(this IKvVaultStore store, VaultUserScope user, string path, CancellationToken cancellation)
- {
- return store.GetSecretAsync(user, path).WaitAsync(cancellation);
- }
-
-
- /// <summary>
- /// Sets a secret in the vault at the specified path and user scope
- /// </summary>
- /// <param name="user">The user scope to store the value at</param>
- /// <param name="path">The path to the secret</param>
- /// <param name="secret">The secret value to set</param>
- /// <param name="cancellation">The cancellation token</param>
- /// <returns>A task that resolves when the secret has been updated</returns>
- public static Task SetSecretAsync(this IKvVaultStore store, VaultUserScope user, string path, PrivateString secret, CancellationToken cancellation)
- {
- return store.SetSecretAsync(user, path, secret).WaitAsync(cancellation);
- }
-
-
- }
-} \ No newline at end of file
diff --git a/back-end/libs/NVault.VaultExtensions/src/VaultUserScope.cs b/back-end/libs/NVault.VaultExtensions/src/VaultUserScope.cs
deleted file mode 100644
index 0e8796c..0000000
--- a/back-end/libs/NVault.VaultExtensions/src/VaultUserScope.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (C) 2024 Vaughn Nugent
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero 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 Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-namespace NVault.VaultExtensions
-{
- /// <summary>
- /// Represents a user scope for the vault. It isolates the user's
- /// secrets from other users.
- /// </summary>
- /// <param name="UserId">The id of the user to scope the vault to</param>
- public readonly record struct VaultUserScope(string UserId)
- { }
-} \ No newline at end of file
diff --git a/back-end/plugins/nvault/src/Endpoints/Endpoint.cs b/back-end/plugins/nvault/src/Endpoints/Endpoint.cs
index b8aa0c9..5e8bf09 100644
--- a/back-end/plugins/nvault/src/Endpoints/Endpoint.cs
+++ b/back-end/plugins/nvault/src/Endpoints/Endpoint.cs
@@ -59,6 +59,7 @@ namespace NVault.Plugins.Vault.Endpoints
private readonly INostrOperations _vault;
private readonly NostrRelayStore _relays;
private readonly NostrKeyMetaStore _publicKeyStore;
+ private readonly NostrEventHistoryStore _eventHistoryStore;
private readonly bool AllowDelete;
private readonly ILogProvider? _abnoxiousLog;
@@ -69,12 +70,13 @@ namespace NVault.Plugins.Vault.Endpoints
AllowDelete = config.TryGetValue("allow_delete", out JsonElement adEl) && adEl.GetBoolean();
-
- DbContextOptions options = plugin.GetContextOptions();
+ IAsyncLazy<DbContextOptions> options = plugin.GetContextOptionsAsync();
_relays = new NostrRelayStore(options);
_publicKeyStore = new NostrKeyMetaStore(options);
- _vault = new NostrOpProvider(plugin);
+ _eventHistoryStore = new NostrEventHistoryStore(options);
+
+ _vault = new NostrOpProvider(plugin);
//Check for obnoxious logging
if (plugin.HostArgs.HasArgument("--nvault-obnoxious"))
@@ -118,6 +120,22 @@ namespace NVault.Plugins.Vault.Endpoints
return VfReturnType.VirtualSkip;
}
+ if(entity.QueryArgs.IsArgumentSet("type", "getEvents"))
+ {
+ //Get the event history
+ List<NostrEventEntry> events = _eventHistoryStore.ListRental.Rent();
+
+ //Get the first page of events for the user
+ await _eventHistoryStore.GetUserPageAsync(events, entity.Session.UserID, 0, 100);
+
+ //Return all events for the user
+ entity.CloseResponseJson(HttpStatusCode.OK, events);
+
+ _eventHistoryStore.ListRental.Return(events);
+
+ return VfReturnType.VirtualSkip;
+ }
+
return VfReturnType.NotFound;
}
@@ -174,6 +192,15 @@ namespace NVault.Plugins.Vault.Endpoints
return VirtualOk(entity, webm);
}
+ //Create new event entry and store it
+ NostrEventEntry newEvent = NostrEventEntry.FromEvent(entity.Session.UserID, nEvent);
+ result = await _eventHistoryStore.CreateUserRecordAsync(newEvent, entity.Session.UserID, entity.EventCancellation);
+
+ if (!result)
+ {
+ Log.Warn("Failed to store event in history, {evid} for user {userid}", nEvent.Id, entity.Session.UserID[..8]);
+ }
+
webm.Result = nEvent;
webm.Success = true;
@@ -443,21 +470,23 @@ namespace NVault.Plugins.Vault.Endpoints
{
ValErrWebMessage webMessage = new ();
- if(entity.QueryArgs.IsArgumentSet("type", "identity"))
+ //common id argument
+ string? id = entity.QueryArgs.GetValueOrDefault("id");
+
+ if (entity.QueryArgs.IsArgumentSet("type", "identity"))
{
if (webMessage.Assert(AllowDelete, "Deleting identies are now allowed"))
{
return VirtualClose(entity, webMessage, HttpStatusCode.Forbidden);
}
- if (!entity.QueryArgs.TryGetNonEmptyValue("key_id", out string? keyId))
+ if (webMessage.Assert(id != null, "No key id specified"))
{
- webMessage.Result = "No key id specified";
return VirtualClose(entity, webMessage, HttpStatusCode.BadRequest);
}
//Get the key metadata
- NostrKeyMeta? meta = await _publicKeyStore.GetSingleUserRecordAsync(keyId, entity.Session.UserID);
+ NostrKeyMeta? meta = await _publicKeyStore.GetSingleUserRecordAsync(id, entity.Session.UserID);
if (webMessage.Assert(meta != null, "Key metadata not found"))
{
@@ -471,13 +500,56 @@ namespace NVault.Plugins.Vault.Endpoints
await _vault.DeleteCredentialAsync(scope, meta, entity.EventCancellation);
//Remove the key metadata
- await _publicKeyStore.DeleteUserRecordAsync(keyId, entity.Session.UserID);
+ await _publicKeyStore.DeleteUserRecordAsync(id, entity.Session.UserID);
webMessage.Result = "Successfully deleted identity";
webMessage.Success = true;
return VirtualOk(entity, webMessage);
}
+ if(entity.QueryArgs.IsArgumentSet("type", "relay"))
+ {
+ if(webMessage.Assert(id != null, "No relay id specified"))
+ {
+ return VirtualClose(entity, webMessage, HttpStatusCode.BadRequest);
+ }
+
+ //Delete the relay
+ if(await _relays.DeleteUserRecordAsync(id, entity.Session.UserID))
+ {
+ webMessage.Result = "Successfully deleted relay";
+ webMessage.Success = true;
+ }
+ else
+ {
+ webMessage.Result = "Failed to delete relay";
+ }
+
+ return VirtualOk(entity, webMessage);
+ }
+
+ if(entity.QueryArgs.IsArgumentSet("type", "event"))
+ {
+ //Internal event id is required
+ if(webMessage.Assert(id != null, "No event id specified"))
+ {
+ return VirtualClose(entity, webMessage, HttpStatusCode.BadRequest);
+ }
+
+ //Delete the event
+ if(await _eventHistoryStore.DeleteUserRecordAsync(id, entity.Session.UserID))
+ {
+ webMessage.Result = "Successfully deleted event";
+ webMessage.Success = true;
+ }
+ else
+ {
+ webMessage.Result = "Failed to delete event";
+ }
+
+ return VirtualOk(entity, webMessage);
+ }
+
return VfReturnType.NotFound;
}
diff --git a/back-end/plugins/nvault/src/Model/NostrContext.cs b/back-end/plugins/nvault/src/Model/NostrContext.cs
index 15900e2..bdd1319 100644
--- a/back-end/plugins/nvault/src/Model/NostrContext.cs
+++ b/back-end/plugins/nvault/src/Model/NostrContext.cs
@@ -25,7 +25,9 @@ namespace NVault.Plugins.Vault.Model
{
public DbSet<NostrRelay> Relays { get; set; }
- public DbSet<NostrKeyMeta> PublicKeys { get; set; }
+ public DbSet<NostrKeyMeta> NostrPublicKeys { get; set; }
+
+ public DbSet<NostrEventEntry> NostrEvents { get; set; }
public NostrContext()
{ }
@@ -68,7 +70,7 @@ namespace NVault.Plugins.Vault.Model
.WithColumn(r => r.Version);
//Setup public key table
- builder.DefineTable<NostrKeyMeta>(nameof(PublicKeys))
+ builder.DefineTable<NostrKeyMeta>(nameof(NostrPublicKeys))
.WithColumn(r => r.Id)
.Next()
@@ -95,6 +97,29 @@ namespace NVault.Plugins.Vault.Model
//Finally, version, it should be set to the timestamp from annotations
.WithColumn(r => r.Version);
+
+ //Setup event table
+ builder.DefineTable<NostrEventEntry>(nameof(NostrEvents))
+ .WithColumn(r => r.Id) //PK attribute is set from model base
+ .Next()
+
+ .WithColumn(r => r.UserId)
+ .Next()
+
+ .WithColumn(r => r.EventData)
+ .AllowNull(true)
+ .Next()
+
+ .WithColumn(r => r.Created)
+ .AllowNull(false)
+ .Next()
+
+ .WithColumn(r => r.LastModified)
+ .AllowNull(false)
+ .Next()
+
+ //Finally, version, it should be set to the timestamp from annotations
+ .WithColumn(r => r.Version);
}
}
}
diff --git a/back-end/plugins/nvault/src/Model/NostrEvent.cs b/back-end/plugins/nvault/src/Model/NostrEvent.cs
index 9bbfd63..ca01e1a 100644
--- a/back-end/plugins/nvault/src/Model/NostrEvent.cs
+++ b/back-end/plugins/nvault/src/Model/NostrEvent.cs
@@ -22,6 +22,7 @@ using VNLib.Plugins.Extensions.Validation;
namespace NVault.Plugins.Vault.Model
{
+
internal sealed class NostrEvent
{
public const int MAX_CONTENT_LENGTH = 16 * 1024;
@@ -86,5 +87,6 @@ namespace NVault.Plugins.Vault.Model
return val;
}
+
}
} \ No newline at end of file
diff --git a/back-end/plugins/nvault/src/Model/NostrEventEntry.cs b/back-end/plugins/nvault/src/Model/NostrEventEntry.cs
new file mode 100644
index 0000000..9fa5aa2
--- /dev/null
+++ b/back-end/plugins/nvault/src/Model/NostrEventEntry.cs
@@ -0,0 +1,47 @@
+// Copyright (C) 2024 Vaughn Nugent
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero 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 Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+using System;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+using VNLib.Plugins.Extensions.Data;
+using VNLib.Plugins.Extensions.Data.Abstractions;
+
+
+namespace NVault.Plugins.Vault.Model
+{
+ internal sealed class NostrEventEntry : DbModelBase, IUserEntity
+ {
+ public override string Id { get; set; }
+
+ public override DateTime Created { get; set; }
+
+ public override DateTime LastModified { get; set; }
+
+ //Never share userids with the client
+ [JsonIgnore]
+ public string? UserId { get; set; }
+
+ public string? EventData { get; set; }
+
+ public static NostrEventEntry FromEvent(string userId, NostrEvent @event) => new()
+ {
+ EventData= JsonSerializer.Serialize(@event),
+ UserId = userId,
+ };
+
+ }
+} \ No newline at end of file
diff --git a/back-end/plugins/nvault/src/Model/NostrEventHistoryStore.cs b/back-end/plugins/nvault/src/Model/NostrEventHistoryStore.cs
new file mode 100644
index 0000000..68b13f7
--- /dev/null
+++ b/back-end/plugins/nvault/src/Model/NostrEventHistoryStore.cs
@@ -0,0 +1,69 @@
+// Copyright (C) 2024 Vaughn Nugent
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero 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 Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+using System;
+using System.Linq;
+
+using Microsoft.EntityFrameworkCore;
+
+using VNLib.Plugins.Extensions.Data;
+using VNLib.Plugins.Extensions.Data.Abstractions;
+using VNLib.Plugins.Extensions.Loading;
+
+namespace NVault.Plugins.Vault.Model
+{
+ internal class NostrEventHistoryStore(IAsyncLazy<DbContextOptions> Options) : DbStore<NostrEventEntry>
+ {
+ ///<inheritdoc/>
+ public override IDbQueryLookup<NostrEventEntry> QueryTable { get; } = new DbQueries();
+
+ ///<inheritdoc/>
+ public override IDbContextHandle GetNewContext() => new NostrContext(Options.Value);
+
+ ///<inheritdoc/>
+ public override string GetNewRecordId() => Guid.NewGuid().ToString("N");
+
+ public override void OnRecordUpdate(NostrEventEntry newRecord, NostrEventEntry existing)
+ {
+ existing.EventData = newRecord.EventData;
+ existing.UserId = newRecord.UserId;
+ newRecord.LastModified = DateTime.UtcNow;
+ }
+
+ sealed record class DbQueries() : IDbQueryLookup<NostrEventEntry>
+ {
+ public IQueryable<NostrEventEntry> GetCollectionQueryBuilder(IDbContextHandle context, params string[] constraints)
+ {
+ string userId = constraints[0];
+
+ return from r in context.Set<NostrEventEntry>()
+ where r.UserId == userId
+ orderby r.LastModified descending
+ select r;
+ }
+
+ public IQueryable<NostrEventEntry> GetSingleQueryBuilder(IDbContextHandle context, params string[] constraints)
+ {
+ string id = constraints[0];
+ string userId = constraints[1];
+
+ //Get entity for the given user by its id
+ return from r in context.Set<NostrEventEntry>()
+ where r.Id == id && r.UserId == userId
+ select r;
+ }
+ }
+ }
+}
diff --git a/back-end/plugins/nvault/src/Model/NostrKeyMetaStore.cs b/back-end/plugins/nvault/src/Model/NostrKeyMetaStore.cs
index bfb6a26..b57d021 100644
--- a/back-end/plugins/nvault/src/Model/NostrKeyMetaStore.cs
+++ b/back-end/plugins/nvault/src/Model/NostrKeyMetaStore.cs
@@ -20,20 +20,17 @@ using Microsoft.EntityFrameworkCore;
using VNLib.Plugins.Extensions.Data;
using VNLib.Plugins.Extensions.Data.Abstractions;
+using VNLib.Plugins.Extensions.Loading;
namespace NVault.Plugins.Vault.Model
{
- internal sealed class NostrKeyMetaStore : DbStore<NostrKeyMeta>
+ internal sealed class NostrKeyMetaStore(IAsyncLazy<DbContextOptions> Options) : DbStore<NostrKeyMeta>
{
- private readonly DbContextOptions _options;
-
- public NostrKeyMetaStore(DbContextOptions options) => _options = options;
-
///<inheritdoc/>
public override IDbQueryLookup<NostrKeyMeta> QueryTable { get; } = new DbQueries();
///<inheritdoc/>
- public override IDbContextHandle GetNewContext() => new NostrContext(_options);
+ public override IDbContextHandle GetNewContext() => new NostrContext(Options.Value);
///<inheritdoc/>
public override string GetNewRecordId() => Guid.NewGuid().ToString("N");
diff --git a/back-end/plugins/nvault/src/Model/NostrRelayStore.cs b/back-end/plugins/nvault/src/Model/NostrRelayStore.cs
index 699124b..799492a 100644
--- a/back-end/plugins/nvault/src/Model/NostrRelayStore.cs
+++ b/back-end/plugins/nvault/src/Model/NostrRelayStore.cs
@@ -20,23 +20,18 @@ using Microsoft.EntityFrameworkCore;
using VNLib.Plugins.Extensions.Data;
using VNLib.Plugins.Extensions.Data.Abstractions;
+using VNLib.Plugins.Extensions.Loading;
namespace NVault.Plugins.Vault.Model
{
- internal class NostrRelayStore : DbStore<NostrRelay>
+ internal class NostrRelayStore(IAsyncLazy<DbContextOptions> Options) : DbStore<NostrRelay>
{
- private readonly DbContextOptions _options;
-
- public NostrRelayStore(DbContextOptions options)
- {
- _options = options;
- }
///<inheritdoc/>
public override IDbQueryLookup<NostrRelay> QueryTable { get; } = new DbQueries();
///<inheritdoc/>
- public override IDbContextHandle GetNewContext() => new NostrContext(_options);
+ public override IDbContextHandle GetNewContext() => new NostrContext(Options.Value);
///<inheritdoc/>
public override string GetNewRecordId() => Guid.NewGuid().ToString("N");
diff --git a/back-end/plugins/nvault/src/NVault.csproj b/back-end/plugins/nvault/src/NVault.csproj
index d83dd2f..e876eec 100644
--- a/back-end/plugins/nvault/src/NVault.csproj
+++ b/back-end/plugins/nvault/src/NVault.csproj
@@ -27,9 +27,11 @@
</ItemGroup>
<ItemGroup>
- <ProjectReference Include="..\..\..\libs\NVault.Crypto.Secp256k1\src\NVault.Crypto.Secp256k1.csproj" />
- <ProjectReference Include="..\..\..\libs\NVault.VaultExtensions\src\NVault.VaultExtensions.csproj" />
+ <ProjectReference Include="..\..\..\..\lib\NVault.Crypto.Noscrypt\src\NVault.Crypto.Noscrypt.csproj" />
+ <ProjectReference Include="..\..\..\..\lib\NVault.Crypto.Secp256k1\src\NVault.Crypto.Secp256k1.csproj" />
+ <ProjectReference Include="..\..\..\..\lib\NVault.VaultExtensions\src\NVault.VaultExtensions.csproj" />
</ItemGroup>
+
<ItemGroup>
<None Update="NVault.example.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>