1
0
mirror of https://github.com/bitwarden/server.git synced 2024-11-23 12:25:16 +01:00

metadata repository for table storage

This commit is contained in:
Kyle Spearrin 2019-09-13 16:02:01 -04:00
parent e1e147b78f
commit 3037b95920
3 changed files with 249 additions and 0 deletions

View File

@ -0,0 +1,138 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Table;
namespace Bit.Core.Models.Data
{
public class DictionaryEntity : TableEntity, IDictionary<string, EntityProperty>
{
private IDictionary<string, EntityProperty> _properties = new Dictionary<string, EntityProperty>();
public ICollection<EntityProperty> Values => _properties.Values;
public EntityProperty this[string key]
{
get => _properties[key];
set => _properties[key] = value;
}
public int Count => _properties.Count;
public bool IsReadOnly => _properties.IsReadOnly;
public ICollection<string> Keys => _properties.Keys;
public override void ReadEntity(IDictionary<string, EntityProperty> properties,
OperationContext operationContext)
{
_properties = properties;
}
public override IDictionary<string, EntityProperty> WriteEntity(OperationContext operationContext)
{
return _properties;
}
public void Add(string key, EntityProperty value)
{
_properties.Add(key, value);
}
public void Add(string key, bool value)
{
_properties.Add(key, new EntityProperty(value));
}
public void Add(string key, byte[] value)
{
_properties.Add(key, new EntityProperty(value));
}
public void Add(string key, DateTime? value)
{
_properties.Add(key, new EntityProperty(value));
}
public void Add(string key, DateTimeOffset? value)
{
_properties.Add(key, new EntityProperty(value));
}
public void Add(string key, double value)
{
_properties.Add(key, new EntityProperty(value));
}
public void Add(string key, Guid value)
{
_properties.Add(key, new EntityProperty(value));
}
public void Add(string key, int value)
{
_properties.Add(key, new EntityProperty(value));
}
public void Add(string key, long value)
{
_properties.Add(key, new EntityProperty(value));
}
public void Add(string key, string value)
{
_properties.Add(key, new EntityProperty(value));
}
public void Add(KeyValuePair<string, EntityProperty> item)
{
_properties.Add(item);
}
public bool ContainsKey(string key)
{
return _properties.ContainsKey(key);
}
public bool Remove(string key)
{
return _properties.Remove(key);
}
public bool TryGetValue(string key, out EntityProperty value)
{
return _properties.TryGetValue(key, out value);
}
public void Clear()
{
_properties.Clear();
}
public bool Contains(KeyValuePair<string, EntityProperty> item)
{
return _properties.Contains(item);
}
public void CopyTo(KeyValuePair<string, EntityProperty>[] array, int arrayIndex)
{
_properties.CopyTo(array, arrayIndex);
}
public bool Remove(KeyValuePair<string, EntityProperty> item)
{
return _properties.Remove(item);
}
public IEnumerator<KeyValuePair<string, EntityProperty>> GetEnumerator()
{
return _properties.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _properties.GetEnumerator();
}
}
}

View File

@ -0,0 +1,14 @@
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Bit.Core.Repositories
{
public interface IMetaDataRespository
{
Task DeleteAsync(string id);
Task<IDictionary<string, string>> GetAsync(string id);
Task<string> GetAsync(string id, string prop);
Task UpsertAsync(string id, IDictionary<string, string> dict);
Task UpsertAsync(string id, KeyValuePair<string, string> keyValuePair);
}
}

View File

@ -0,0 +1,97 @@
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Bit.Core.Models.Data;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Table;
namespace Bit.Core.Repositories.TableStorage
{
public class MetaDataRespository : IMetaDataRespository
{
private readonly CloudTable _table;
public MetaDataRespository(GlobalSettings globalSettings)
: this(globalSettings.Events.ConnectionString)
{ }
public MetaDataRespository(string storageConnectionString)
{
var storageAccount = CloudStorageAccount.Parse(storageConnectionString);
var tableClient = storageAccount.CreateCloudTableClient();
_table = tableClient.GetTableReference("metadata");
}
public async Task<IDictionary<string, string>> GetAsync(string id)
{
var query = new TableQuery<DictionaryEntity>().Where(
TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, id));
var queryResults = await _table.ExecuteQuerySegmentedAsync(query, null);
return queryResults.Results.FirstOrDefault()?.ToDictionary(d => d.Key, d => d.Value.StringValue);
}
public async Task<string> GetAsync(string id, string prop)
{
var dict = await GetAsync(id);
if(dict != null && dict.ContainsKey(prop))
{
return dict[prop];
}
return null;
}
public async Task UpsertAsync(string id, KeyValuePair<string, string> keyValuePair)
{
var query = new TableQuery<DictionaryEntity>().Where(
TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, id));
var queryResults = await _table.ExecuteQuerySegmentedAsync(query, null);
var entity = queryResults.Results.FirstOrDefault();
if(entity == null)
{
entity = new DictionaryEntity
{
PartitionKey = id
};
}
if(entity.ContainsKey(keyValuePair.Key))
{
entity.Remove(keyValuePair.Key);
}
entity.Add(keyValuePair.Key, keyValuePair.Value);
await _table.ExecuteAsync(TableOperation.InsertOrReplace(entity));
}
public async Task UpsertAsync(string id, IDictionary<string, string> dict)
{
var entity = new DictionaryEntity
{
PartitionKey = id
};
foreach(var item in dict)
{
entity.Add(item.Key, item.Value);
}
await _table.ExecuteAsync(TableOperation.InsertOrReplace(entity));
}
public async Task DeleteAsync(string id)
{
try
{
await _table.ExecuteAsync(TableOperation.Delete(new DictionaryEntity
{
PartitionKey = id,
ETag = "*"
}));
}
catch(StorageException e)
{
if(e.RequestInformation.HttpStatusCode != (int)HttpStatusCode.NotFound)
{
throw e;
}
}
}
}
}