mirror of
https://github.com/bitwarden/mobile
synced 2025-12-27 21:53:57 +00:00
Added icons for iOS. Broke out data access into repositories. Added syncing service.
This commit is contained in:
112
src/App/Repositories/ApiRepository.cs
Normal file
112
src/App/Repositories/ApiRepository.cs
Normal file
@@ -0,0 +1,112 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.App.Models.Api;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Bit.App.Repositories
|
||||
{
|
||||
public abstract class ApiRepository<TRequest, TResponse, TId> : BaseApiRepository, IApiRepository<TRequest, TResponse, TId>
|
||||
where TId : IEquatable<TId>
|
||||
where TRequest : class
|
||||
where TResponse : class
|
||||
{
|
||||
public ApiRepository()
|
||||
{ }
|
||||
|
||||
public virtual async Task<ApiResult<TResponse>> GetByIdAsync(TId id)
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage()
|
||||
{
|
||||
Method = HttpMethod.Get,
|
||||
RequestUri = new Uri(Client.BaseAddress, string.Concat(ApiRoute, "/", id)),
|
||||
};
|
||||
|
||||
var response = await Client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync<TResponse>(response);
|
||||
}
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObj = JsonConvert.DeserializeObject<TResponse>(responseContent);
|
||||
return ApiResult<TResponse>.Success(responseObj, response.StatusCode);
|
||||
}
|
||||
|
||||
public virtual async Task<ApiResult<ListResponse<TResponse>>> GetAsync()
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage()
|
||||
{
|
||||
Method = HttpMethod.Get,
|
||||
RequestUri = new Uri(Client.BaseAddress, ApiRoute),
|
||||
};
|
||||
|
||||
var response = await Client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync<ListResponse<TResponse>>(response);
|
||||
}
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObj = JsonConvert.DeserializeObject<ListResponse<TResponse>>(responseContent);
|
||||
return ApiResult<ListResponse<TResponse>>.Success(responseObj, response.StatusCode);
|
||||
}
|
||||
|
||||
public virtual async Task<ApiResult<TResponse>> PostAsync(TRequest requestObj)
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage(requestObj)
|
||||
{
|
||||
Method = HttpMethod.Post,
|
||||
RequestUri = new Uri(Client.BaseAddress, ApiRoute),
|
||||
};
|
||||
|
||||
var response = await Client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync<TResponse>(response);
|
||||
}
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObj = JsonConvert.DeserializeObject<TResponse>(responseContent);
|
||||
return ApiResult<TResponse>.Success(responseObj, response.StatusCode);
|
||||
}
|
||||
|
||||
public virtual async Task<ApiResult<TResponse>> PutAsync(TId id, TRequest requestObj)
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage(requestObj)
|
||||
{
|
||||
Method = HttpMethod.Put,
|
||||
RequestUri = new Uri(Client.BaseAddress, string.Concat(ApiRoute, "/", id)),
|
||||
};
|
||||
|
||||
var response = await Client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync<TResponse>(response);
|
||||
}
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObj = JsonConvert.DeserializeObject<TResponse>(responseContent);
|
||||
return ApiResult<TResponse>.Success(responseObj, response.StatusCode);
|
||||
}
|
||||
|
||||
public virtual async Task<ApiResult<object>> DeleteAsync(TId id)
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage()
|
||||
{
|
||||
Method = HttpMethod.Delete,
|
||||
RequestUri = new Uri(Client.BaseAddress, string.Concat(ApiRoute, "/", id)),
|
||||
};
|
||||
|
||||
var response = await Client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync<object>(response);
|
||||
}
|
||||
|
||||
return ApiResult<object>.Success(null, response.StatusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
52
src/App/Repositories/AuthApiRepository.cs
Normal file
52
src/App/Repositories/AuthApiRepository.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.App.Models.Api;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Bit.App.Repositories
|
||||
{
|
||||
public class AuthApiRepository : BaseApiRepository, IAuthApiRepository
|
||||
{
|
||||
protected override string ApiRoute => "auth";
|
||||
|
||||
public virtual async Task<ApiResult<TokenResponse>> PostTokenAsync(TokenRequest requestObj)
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage(requestObj)
|
||||
{
|
||||
Method = HttpMethod.Post,
|
||||
RequestUri = new Uri(Client.BaseAddress, string.Concat(ApiRoute, "/token")),
|
||||
};
|
||||
|
||||
var response = await Client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync<TokenResponse>(response);
|
||||
}
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObj = JsonConvert.DeserializeObject<TokenResponse>(responseContent);
|
||||
return ApiResult<TokenResponse>.Success(responseObj, response.StatusCode);
|
||||
}
|
||||
|
||||
public virtual async Task<ApiResult<TokenResponse>> PostTokenTwoFactorAsync(TokenTwoFactorRequest requestObj)
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage(requestObj)
|
||||
{
|
||||
Method = HttpMethod.Post,
|
||||
RequestUri = new Uri(Client.BaseAddress, string.Concat(ApiRoute, "/token/two-factor")),
|
||||
};
|
||||
|
||||
var response = await Client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync<TokenResponse>(response);
|
||||
}
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObj = JsonConvert.DeserializeObject<TokenResponse>(responseContent);
|
||||
return ApiResult<TokenResponse>.Success(responseObj, response.StatusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
50
src/App/Repositories/BaseApiRepository.cs
Normal file
50
src/App/Repositories/BaseApiRepository.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.App.Models.Api;
|
||||
using ModernHttpClient;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Bit.App.Repositories
|
||||
{
|
||||
public abstract class BaseApiRepository
|
||||
{
|
||||
public BaseApiRepository()
|
||||
{
|
||||
Client = new HttpClient(new NativeMessageHandler());
|
||||
Client.BaseAddress = new Uri("https://api.bitwarden.com");
|
||||
Client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
}
|
||||
|
||||
protected virtual HttpClient Client { get; private set; }
|
||||
protected abstract string ApiRoute { get; }
|
||||
|
||||
public async Task<ApiResult<T>> HandleErrorAsync<T>(HttpResponseMessage response)
|
||||
{
|
||||
try
|
||||
{
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var errorResponseModel = JsonConvert.DeserializeObject<ErrorResponse>(responseContent);
|
||||
|
||||
var errors = new List<ApiError>();
|
||||
foreach(var valError in errorResponseModel.ValidationErrors)
|
||||
{
|
||||
foreach(var errorMessage in valError.Value)
|
||||
{
|
||||
errors.Add(new ApiError { Message = errorMessage });
|
||||
}
|
||||
}
|
||||
|
||||
return ApiResult<T>.Failed(response.StatusCode, errors.ToArray());
|
||||
}
|
||||
catch(JsonReaderException)
|
||||
{ }
|
||||
|
||||
return ApiResult<T>.Failed(response.StatusCode, new ApiError { Message = "An unknown error has occured." });
|
||||
}
|
||||
}
|
||||
}
|
||||
34
src/App/Repositories/FolderApiRepository.cs
Normal file
34
src/App/Repositories/FolderApiRepository.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.App.Models.Api;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Bit.App.Repositories
|
||||
{
|
||||
public class FolderApiRepository : ApiRepository<FolderRequest, FolderResponse, string>, IFolderApiRepository
|
||||
{
|
||||
protected override string ApiRoute => "folders";
|
||||
|
||||
public virtual async Task<ApiResult<ListResponse<FolderResponse>>> GetByRevisionDateAsync(DateTime since)
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage()
|
||||
{
|
||||
Method = HttpMethod.Get,
|
||||
RequestUri = new Uri(Client.BaseAddress, string.Concat(ApiRoute, "?since=", since)),
|
||||
};
|
||||
|
||||
var response = await Client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync<ListResponse<FolderResponse>>(response);
|
||||
}
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObj = JsonConvert.DeserializeObject<ListResponse<FolderResponse>>(responseContent);
|
||||
return ApiResult<ListResponse<FolderResponse>>.Success(responseObj, response.StatusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
22
src/App/Repositories/FolderRepository.cs
Normal file
22
src/App/Repositories/FolderRepository.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.App.Models.Data;
|
||||
|
||||
namespace Bit.App.Repositories
|
||||
{
|
||||
public class FolderRepository : Repository<FolderData, string>, IFolderRepository
|
||||
{
|
||||
public FolderRepository(ISqlService sqlService)
|
||||
: base(sqlService)
|
||||
{ }
|
||||
|
||||
public Task<IEnumerable<FolderData>> GetAllByUserIdAsync(string userId)
|
||||
{
|
||||
var folders = Connection.Table<FolderData>().Where(f => f.UserId == userId).Cast<FolderData>();
|
||||
return Task.FromResult(folders);
|
||||
}
|
||||
}
|
||||
}
|
||||
54
src/App/Repositories/Repository.cs
Normal file
54
src/App/Repositories/Repository.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.App.Abstractions;
|
||||
using SQLite;
|
||||
|
||||
namespace Bit.App.Repositories
|
||||
{
|
||||
public abstract class Repository<T, TId> : IRepository<T, TId>
|
||||
where TId : IEquatable<TId>
|
||||
where T : class, IDataObject<TId>, new()
|
||||
{
|
||||
public Repository(ISqlService sqlService)
|
||||
{
|
||||
Connection = sqlService.GetConnection();
|
||||
}
|
||||
|
||||
protected SQLiteConnection Connection { get; private set; }
|
||||
|
||||
public virtual Task<T> GetByIdAsync(TId id)
|
||||
{
|
||||
return Task.FromResult(Connection.Get<T>(id));
|
||||
}
|
||||
|
||||
public virtual Task<IEnumerable<T>> GetAllAsync()
|
||||
{
|
||||
return Task.FromResult(Connection.Table<T>().Cast<T>());
|
||||
}
|
||||
|
||||
public virtual Task InsertAsync(T obj)
|
||||
{
|
||||
Connection.Insert(obj);
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public virtual Task UpdateAsync(T obj)
|
||||
{
|
||||
Connection.Update(obj);
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public virtual async Task DeleteAsync(T obj)
|
||||
{
|
||||
await DeleteAsync(obj.Id);
|
||||
}
|
||||
|
||||
public virtual Task DeleteAsync(TId id)
|
||||
{
|
||||
Connection.Delete<T>(id);
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
34
src/App/Repositories/SiteApiRepository.cs
Normal file
34
src/App/Repositories/SiteApiRepository.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.App.Models.Api;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Bit.App.Repositories
|
||||
{
|
||||
public class SiteApiRepository : ApiRepository<SiteRequest, SiteResponse, string>, ISiteApiRepository
|
||||
{
|
||||
protected override string ApiRoute => "sites";
|
||||
|
||||
public virtual async Task<ApiResult<ListResponse<SiteResponse>>> GetByRevisionDateAsync(DateTime since)
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage()
|
||||
{
|
||||
Method = HttpMethod.Get,
|
||||
RequestUri = new Uri(Client.BaseAddress, string.Concat(ApiRoute, "?since=", since)),
|
||||
};
|
||||
|
||||
var response = await Client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync<ListResponse<SiteResponse>>(response);
|
||||
}
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObj = JsonConvert.DeserializeObject<ListResponse<SiteResponse>>(responseContent);
|
||||
return ApiResult<ListResponse<SiteResponse>>.Success(responseObj, response.StatusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
22
src/App/Repositories/SiteRepository.cs
Normal file
22
src/App/Repositories/SiteRepository.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.App.Models.Data;
|
||||
|
||||
namespace Bit.App.Repositories
|
||||
{
|
||||
public class SiteRepository : Repository<SiteData, string>, ISiteRepository
|
||||
{
|
||||
public SiteRepository(ISqlService sqlService)
|
||||
: base(sqlService)
|
||||
{ }
|
||||
|
||||
public Task<IEnumerable<SiteData>> GetAllByUserIdAsync(string userId)
|
||||
{
|
||||
var sites = Connection.Table<SiteData>().Where(f => f.UserId == userId).Cast<SiteData>();
|
||||
return Task.FromResult(sites);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user