bitwarden-mobile/src/Core/Services/ApiService.cs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

857 lines
34 KiB
C#
Raw Normal View History

2019-04-10 16:49:24 +02:00
using System;
2019-04-10 21:03:09 +02:00
using System.Collections.Generic;
2019-04-10 16:49:24 +02:00
using System.Net;
using System.Net.Http;
2019-04-10 21:03:09 +02:00
using System.Text;
2019-04-10 16:49:24 +02:00
using System.Threading.Tasks;
using Bit.Core.Abstractions;
2022-02-08 17:43:40 +01:00
using Bit.Core.Enums;
2019-04-10 16:49:24 +02:00
using Bit.Core.Exceptions;
using Bit.Core.Models.Domain;
2019-04-10 21:03:09 +02:00
using Bit.Core.Models.Request;
2019-04-10 16:49:24 +02:00
using Bit.Core.Models.Response;
2019-04-10 21:03:09 +02:00
using Newtonsoft.Json;
2019-04-10 16:49:24 +02:00
using Newtonsoft.Json.Linq;
2019-04-10 21:35:23 +02:00
using Newtonsoft.Json.Serialization;
2019-04-10 16:49:24 +02:00
namespace Bit.Core.Services
{
2019-04-12 05:57:05 +02:00
public class ApiService : IApiService
2019-04-10 16:49:24 +02:00
{
2019-04-10 21:35:23 +02:00
private readonly JsonSerializerSettings _jsonSettings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
2019-06-27 02:28:23 +02:00
private readonly HttpClient _httpClient = new HttpClient();
2019-04-10 16:49:24 +02:00
private readonly ITokenService _tokenService;
private readonly IPlatformUtilsService _platformUtilsService;
Account Switching (#1807) * Account Switching (#1720) * Account switching * WIP * wip * wip * updates to send test logic * fixed Send tests * fixes for theme handling on account switching and re-adding existing account * switch fixes * fixes * fixes * cleanup * vault timeout fixes * account list status enhancements * logout fixes and token handling improvements * merge latest (#1727) * remove duplicate dependency * fix for initial login token storage paradox (#1730) * Fix avatar color update toolbar item issue on iOS for account switching (#1735) * Updated account switching menu UI (#1733) * updated account switching menu UI * additional changes * add key suffix to constant * GetFirstLetters method tweaks * Fix crash on account switching when logging out when having more than user at a time (#1740) * single account migration to multi-account on app update (#1741) * Account Switching Tap to dismiss (#1743) * Added tap to dismiss on the Account switching overlay and improved a bit the code * Fix account switching overlay background transparent on the proper place * Fixed transparent background and the shadow on the account switching overlay * Fix iOS top space on Account switching list overlay after modal (#1746) * Fix top space added to Account switching list overlay after closing modal * Fix top space added to Account switching list overlay after closing modal on lock, login and home views just in case we add modals in the future there as well * Usability: dismiss account list on certain events (#1748) * dismiss account list on certain events * use new FireAndForget method for back button logic * Create and use Account Switching overlay control (#1753) * Added Account switching overlay control and its own ViewModel and refactored accordingly * Fix account switching Accounts list binding update * Implemented dismiss account switching overlay when changing tabs and when selecting the same tab. Also updated the deprecated listener on CustomTabbedRenderer on Android (#1755) * Overriden Equals on AvatarImageSource so it doesn't get set multiple times when it's the same image thus producing blinking on tab chaged (#1756) * Usability improvements for logout on vault timeout (#1781) * accountswitching fixes (#1784) * Fix for invalid PIN lock state when switching accounts (#1792) * fix for pin lock flow * named tuple values and updated async * clear send service cache on account switch (#1796) * Global theme and account removal (#1793) * Global theme and account removal * remove redundant call to hide account list overlay * cleanup and additional tweaks * add try/catch to remove account dialog flow Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>
2022-02-23 18:40:17 +01:00
private readonly Func<Tuple<string, bool, bool>, Task> _logoutCallbackAsync;
2019-04-10 16:49:24 +02:00
public ApiService(
ITokenService tokenService,
2019-04-10 21:03:09 +02:00
IPlatformUtilsService platformUtilsService,
Account Switching (#1807) * Account Switching (#1720) * Account switching * WIP * wip * wip * updates to send test logic * fixed Send tests * fixes for theme handling on account switching and re-adding existing account * switch fixes * fixes * fixes * cleanup * vault timeout fixes * account list status enhancements * logout fixes and token handling improvements * merge latest (#1727) * remove duplicate dependency * fix for initial login token storage paradox (#1730) * Fix avatar color update toolbar item issue on iOS for account switching (#1735) * Updated account switching menu UI (#1733) * updated account switching menu UI * additional changes * add key suffix to constant * GetFirstLetters method tweaks * Fix crash on account switching when logging out when having more than user at a time (#1740) * single account migration to multi-account on app update (#1741) * Account Switching Tap to dismiss (#1743) * Added tap to dismiss on the Account switching overlay and improved a bit the code * Fix account switching overlay background transparent on the proper place * Fixed transparent background and the shadow on the account switching overlay * Fix iOS top space on Account switching list overlay after modal (#1746) * Fix top space added to Account switching list overlay after closing modal * Fix top space added to Account switching list overlay after closing modal on lock, login and home views just in case we add modals in the future there as well * Usability: dismiss account list on certain events (#1748) * dismiss account list on certain events * use new FireAndForget method for back button logic * Create and use Account Switching overlay control (#1753) * Added Account switching overlay control and its own ViewModel and refactored accordingly * Fix account switching Accounts list binding update * Implemented dismiss account switching overlay when changing tabs and when selecting the same tab. Also updated the deprecated listener on CustomTabbedRenderer on Android (#1755) * Overriden Equals on AvatarImageSource so it doesn't get set multiple times when it's the same image thus producing blinking on tab chaged (#1756) * Usability improvements for logout on vault timeout (#1781) * accountswitching fixes (#1784) * Fix for invalid PIN lock state when switching accounts (#1792) * fix for pin lock flow * named tuple values and updated async * clear send service cache on account switch (#1796) * Global theme and account removal (#1793) * Global theme and account removal * remove redundant call to hide account list overlay * cleanup and additional tweaks * add try/catch to remove account dialog flow Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>
2022-02-23 18:40:17 +01:00
Func<Tuple<string, bool, bool>, Task> logoutCallbackAsync,
2019-09-04 17:52:32 +02:00
string customUserAgent = null)
2019-04-10 16:49:24 +02:00
{
_tokenService = tokenService;
_platformUtilsService = platformUtilsService;
2019-04-10 21:03:09 +02:00
_logoutCallbackAsync = logoutCallbackAsync;
2019-09-05 03:08:08 +02:00
var device = (int)_platformUtilsService.GetDevice();
2019-09-04 17:52:32 +02:00
_httpClient.DefaultRequestHeaders.Add("Device-Type", device.ToString());
2022-02-08 17:43:40 +01:00
_httpClient.DefaultRequestHeaders.Add("Bitwarden-Client-Name", _platformUtilsService.GetClientType().GetString());
_httpClient.DefaultRequestHeaders.Add("Bitwarden-Client-Version", _platformUtilsService.GetApplicationVersion());
if (!string.IsNullOrWhiteSpace(customUserAgent))
2019-09-04 17:52:32 +02:00
{
_httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(customUserAgent);
}
2019-04-10 16:49:24 +02:00
}
public bool UrlsSet { get; private set; }
public string ApiBaseUrl { get; set; }
public string IdentityBaseUrl { get; set; }
2019-06-25 22:36:21 +02:00
public string EventsBaseUrl { get; set; }
2019-04-10 16:49:24 +02:00
public void SetUrls(EnvironmentUrls urls)
{
UrlsSet = true;
if (!string.IsNullOrWhiteSpace(urls.Base))
2019-04-10 16:49:24 +02:00
{
ApiBaseUrl = urls.Base + "/api";
IdentityBaseUrl = urls.Base + "/identity";
2019-06-25 22:36:21 +02:00
EventsBaseUrl = urls.Base + "/events";
2019-04-10 16:49:24 +02:00
return;
}
2019-06-25 22:36:21 +02:00
ApiBaseUrl = urls.Api;
IdentityBaseUrl = urls.Identity;
EventsBaseUrl = urls.Events;
// Production
if (string.IsNullOrWhiteSpace(ApiBaseUrl))
2019-04-10 16:49:24 +02:00
{
2019-06-25 22:36:21 +02:00
ApiBaseUrl = "https://api.bitwarden.com";
}
if (string.IsNullOrWhiteSpace(IdentityBaseUrl))
2019-06-25 22:36:21 +02:00
{
IdentityBaseUrl = "https://identity.bitwarden.com";
}
if (string.IsNullOrWhiteSpace(EventsBaseUrl))
2019-06-25 22:36:21 +02:00
{
EventsBaseUrl = "https://events.bitwarden.com";
2019-04-10 16:49:24 +02:00
}
}
#region Auth APIs
public async Task<IdentityResponse> PostIdentityTokenAsync(TokenRequest request)
2019-04-10 16:49:24 +02:00
{
2019-04-10 21:03:09 +02:00
var requestMessage = new HttpRequestMessage
2019-04-10 16:49:24 +02:00
{
2019-11-05 15:14:55 +01:00
Version = new Version(1, 0),
2019-04-10 16:49:24 +02:00
RequestUri = new Uri(string.Concat(IdentityBaseUrl, "/connect/token")),
2019-04-10 21:03:09 +02:00
Method = HttpMethod.Post,
2022-02-08 17:43:40 +01:00
Content = new FormUrlEncodedContent(request.ToIdentityToken(_platformUtilsService.GetClientType().GetString()))
2019-04-10 16:49:24 +02:00
};
2019-04-10 21:03:09 +02:00
requestMessage.Headers.Add("Accept", "application/json");
request.AlterIdentityTokenHeaders(requestMessage.Headers);
2019-04-10 16:49:24 +02:00
2019-04-19 15:11:17 +02:00
HttpResponseMessage response;
try
{
response = await _httpClient.SendAsync(requestMessage);
}
2019-11-15 14:55:22 +01:00
catch (Exception e)
2019-04-19 15:11:17 +02:00
{
2019-11-15 14:55:22 +01:00
throw new ApiException(HandleWebError(e));
2019-04-19 15:11:17 +02:00
}
2019-04-10 16:49:24 +02:00
JObject responseJObject = null;
if (IsJsonResponse(response))
2019-04-10 16:49:24 +02:00
{
var responseJsonString = await response.Content.ReadAsStringAsync();
responseJObject = JObject.Parse(responseJsonString);
}
var identityResponse = new IdentityResponse(response.StatusCode, responseJObject);
if (identityResponse.FailedToParse)
2019-04-10 16:49:24 +02:00
{
throw new ApiException(new ErrorResponse(responseJObject, response.StatusCode, true));
2019-04-10 16:49:24 +02:00
}
return identityResponse;
2019-04-10 16:49:24 +02:00
}
2019-04-10 21:03:09 +02:00
public async Task RefreshIdentityTokenAsync()
{
try
{
await DoRefreshTokenAsync();
}
catch
{
throw new ApiException();
}
}
#endregion
2019-04-10 21:35:23 +02:00
#region Account APIs
2019-04-16 17:07:44 +02:00
public Task<ProfileResponse> GetProfileAsync()
2019-04-10 21:35:23 +02:00
{
2019-04-16 17:07:44 +02:00
return SendAsync<object, ProfileResponse>(HttpMethod.Get, "/accounts/profile", null, true, true);
2019-04-10 21:35:23 +02:00
}
2019-04-16 17:07:44 +02:00
public Task<PreloginResponse> PostPreloginAsync(PreloginRequest request)
2019-04-10 21:35:23 +02:00
{
2019-04-16 17:07:44 +02:00
return SendAsync<PreloginRequest, PreloginResponse>(HttpMethod.Post, "/accounts/prelogin",
2019-04-10 21:35:23 +02:00
request, false, true);
}
2019-04-16 17:07:44 +02:00
public Task<long> GetAccountRevisionDateAsync()
2019-04-10 21:35:23 +02:00
{
2019-04-16 17:07:44 +02:00
return SendAsync<object, long>(HttpMethod.Get, "/accounts/revision-date", null, true, true);
2019-04-10 21:35:23 +02:00
}
2019-04-16 17:07:44 +02:00
public Task PostPasswordHintAsync(PasswordHintRequest request)
2019-04-10 21:35:23 +02:00
{
2019-04-16 17:07:44 +02:00
return SendAsync<PasswordHintRequest, object>(HttpMethod.Post, "/accounts/password-hint",
2019-04-10 21:35:23 +02:00
request, false, false);
}
public Task SetPasswordAsync(SetPasswordRequest request)
{
return SendAsync<SetPasswordRequest, object>(HttpMethod.Post, "/accounts/set-password", request, true,
false);
}
2019-04-16 17:07:44 +02:00
public Task PostRegisterAsync(RegisterRequest request)
2019-04-10 21:35:23 +02:00
{
2019-04-16 17:07:44 +02:00
return SendAsync<RegisterRequest, object>(HttpMethod.Post, "/accounts/register", request, false, false);
2019-04-10 21:35:23 +02:00
}
2019-04-16 17:07:44 +02:00
public Task PostAccountKeysAsync(KeysRequest request)
2019-04-10 21:35:23 +02:00
{
2019-04-16 17:07:44 +02:00
return SendAsync<KeysRequest, object>(HttpMethod.Post, "/accounts/keys", request, true, false);
}
public Task PostAccountVerifyPasswordAsync(PasswordVerificationRequest request)
{
return SendAsync<PasswordVerificationRequest, object>(HttpMethod.Post, "/accounts/verify-password", request,
true, false);
}
[KeyConnector] Add support for key connector OTP (#1633) * initial commit - add UsesKeyConnector to UserService - add models - begin work on authentication * finish auth workflow for key connector sso login - finish api call for get user key - start api calls for posts to key connector * Bypass lock page if already unlocked * Move logic to KeyConnectorService, log out if no pin or biometric is set * Disable password reprompt when using key connector * hide password reprompt checkbox when editing or adding cipher * add PostUserKey and PostSetKeyConnector calls * add ConvertMasterPasswordPage * add functionality to RemoveMasterPasswordPage - rename Convert to Remove * Hide Change Master Password button if using key connector * Add OTP verification for export component * Update src/App/Pages/Vault/AddEditPage.xaml.cs Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> * remove toolbar item "close" * Update src/Core/Models/Request/KeyConnectorUserKeyRequest.cs Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> * remove new line in resource string - format warning as two labels - set label in code behind for loading simultaneously * implement GetAndSetKey in KeyConnectorService - ignore EnvironmentService call * remove unnecesary orgIdentifier * move RemoveMasterPasswordPage call to LockPage * add spacing to export vault page * log out if no PIN or bio on lock page with key connector * Delete excessive whitespace * Delete excessive whitespace * Change capitalisation of OTP * add default value to models for backwards compatibility * remove this keyword * actually handle exceptions * move RemoveMasterPasswordPage to TabPage using messaging service * add minor improvements * remove 'this.' Co-authored-by: Hinton <oscar@oscarhinton.com> Co-authored-by: Thomas Rittson <trittson@bitwarden.com> Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com>
2021-11-11 02:46:48 +01:00
public Task PostAccountRequestOTP()
{
return SendAsync<object, object>(HttpMethod.Post, "/accounts/request-otp", null, true, false, false);
[KeyConnector] Add support for key connector OTP (#1633) * initial commit - add UsesKeyConnector to UserService - add models - begin work on authentication * finish auth workflow for key connector sso login - finish api call for get user key - start api calls for posts to key connector * Bypass lock page if already unlocked * Move logic to KeyConnectorService, log out if no pin or biometric is set * Disable password reprompt when using key connector * hide password reprompt checkbox when editing or adding cipher * add PostUserKey and PostSetKeyConnector calls * add ConvertMasterPasswordPage * add functionality to RemoveMasterPasswordPage - rename Convert to Remove * Hide Change Master Password button if using key connector * Add OTP verification for export component * Update src/App/Pages/Vault/AddEditPage.xaml.cs Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> * remove toolbar item "close" * Update src/Core/Models/Request/KeyConnectorUserKeyRequest.cs Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> * remove new line in resource string - format warning as two labels - set label in code behind for loading simultaneously * implement GetAndSetKey in KeyConnectorService - ignore EnvironmentService call * remove unnecesary orgIdentifier * move RemoveMasterPasswordPage call to LockPage * add spacing to export vault page * log out if no PIN or bio on lock page with key connector * Delete excessive whitespace * Delete excessive whitespace * Change capitalisation of OTP * add default value to models for backwards compatibility * remove this keyword * actually handle exceptions * move RemoveMasterPasswordPage to TabPage using messaging service * add minor improvements * remove 'this.' Co-authored-by: Hinton <oscar@oscarhinton.com> Co-authored-by: Thomas Rittson <trittson@bitwarden.com> Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com>
2021-11-11 02:46:48 +01:00
}
public Task PostAccountVerifyOTPAsync(VerifyOTPRequest request)
{
return SendAsync<VerifyOTPRequest, object>(HttpMethod.Post, "/accounts/verify-otp", request,
true, false, false);
[KeyConnector] Add support for key connector OTP (#1633) * initial commit - add UsesKeyConnector to UserService - add models - begin work on authentication * finish auth workflow for key connector sso login - finish api call for get user key - start api calls for posts to key connector * Bypass lock page if already unlocked * Move logic to KeyConnectorService, log out if no pin or biometric is set * Disable password reprompt when using key connector * hide password reprompt checkbox when editing or adding cipher * add PostUserKey and PostSetKeyConnector calls * add ConvertMasterPasswordPage * add functionality to RemoveMasterPasswordPage - rename Convert to Remove * Hide Change Master Password button if using key connector * Add OTP verification for export component * Update src/App/Pages/Vault/AddEditPage.xaml.cs Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> * remove toolbar item "close" * Update src/Core/Models/Request/KeyConnectorUserKeyRequest.cs Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> * remove new line in resource string - format warning as two labels - set label in code behind for loading simultaneously * implement GetAndSetKey in KeyConnectorService - ignore EnvironmentService call * remove unnecesary orgIdentifier * move RemoveMasterPasswordPage call to LockPage * add spacing to export vault page * log out if no PIN or bio on lock page with key connector * Delete excessive whitespace * Delete excessive whitespace * Change capitalisation of OTP * add default value to models for backwards compatibility * remove this keyword * actually handle exceptions * move RemoveMasterPasswordPage to TabPage using messaging service * add minor improvements * remove 'this.' Co-authored-by: Hinton <oscar@oscarhinton.com> Co-authored-by: Thomas Rittson <trittson@bitwarden.com> Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com>
2021-11-11 02:46:48 +01:00
}
public Task PutUpdateTempPasswordAsync(UpdateTempPasswordRequest request)
{
return SendAsync<UpdateTempPasswordRequest, object>(HttpMethod.Put, "/accounts/update-temp-password",
request, true, false);
}
[KeyConnector] Add support for key connector OTP (#1633) * initial commit - add UsesKeyConnector to UserService - add models - begin work on authentication * finish auth workflow for key connector sso login - finish api call for get user key - start api calls for posts to key connector * Bypass lock page if already unlocked * Move logic to KeyConnectorService, log out if no pin or biometric is set * Disable password reprompt when using key connector * hide password reprompt checkbox when editing or adding cipher * add PostUserKey and PostSetKeyConnector calls * add ConvertMasterPasswordPage * add functionality to RemoveMasterPasswordPage - rename Convert to Remove * Hide Change Master Password button if using key connector * Add OTP verification for export component * Update src/App/Pages/Vault/AddEditPage.xaml.cs Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> * remove toolbar item "close" * Update src/Core/Models/Request/KeyConnectorUserKeyRequest.cs Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> * remove new line in resource string - format warning as two labels - set label in code behind for loading simultaneously * implement GetAndSetKey in KeyConnectorService - ignore EnvironmentService call * remove unnecesary orgIdentifier * move RemoveMasterPasswordPage call to LockPage * add spacing to export vault page * log out if no PIN or bio on lock page with key connector * Delete excessive whitespace * Delete excessive whitespace * Change capitalisation of OTP * add default value to models for backwards compatibility * remove this keyword * actually handle exceptions * move RemoveMasterPasswordPage to TabPage using messaging service * add minor improvements * remove 'this.' Co-authored-by: Hinton <oscar@oscarhinton.com> Co-authored-by: Thomas Rittson <trittson@bitwarden.com> Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com>
2021-11-11 02:46:48 +01:00
public Task DeleteAccountAsync(DeleteAccountRequest request)
{
return SendAsync<DeleteAccountRequest, object>(HttpMethod.Delete, "/accounts", request, true, false);
}
2022-04-26 17:21:17 +02:00
[KeyConnector] Add support for key connector OTP (#1633) * initial commit - add UsesKeyConnector to UserService - add models - begin work on authentication * finish auth workflow for key connector sso login - finish api call for get user key - start api calls for posts to key connector * Bypass lock page if already unlocked * Move logic to KeyConnectorService, log out if no pin or biometric is set * Disable password reprompt when using key connector * hide password reprompt checkbox when editing or adding cipher * add PostUserKey and PostSetKeyConnector calls * add ConvertMasterPasswordPage * add functionality to RemoveMasterPasswordPage - rename Convert to Remove * Hide Change Master Password button if using key connector * Add OTP verification for export component * Update src/App/Pages/Vault/AddEditPage.xaml.cs Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> * remove toolbar item "close" * Update src/Core/Models/Request/KeyConnectorUserKeyRequest.cs Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> * remove new line in resource string - format warning as two labels - set label in code behind for loading simultaneously * implement GetAndSetKey in KeyConnectorService - ignore EnvironmentService call * remove unnecesary orgIdentifier * move RemoveMasterPasswordPage call to LockPage * add spacing to export vault page * log out if no PIN or bio on lock page with key connector * Delete excessive whitespace * Delete excessive whitespace * Change capitalisation of OTP * add default value to models for backwards compatibility * remove this keyword * actually handle exceptions * move RemoveMasterPasswordPage to TabPage using messaging service * add minor improvements * remove 'this.' Co-authored-by: Hinton <oscar@oscarhinton.com> Co-authored-by: Thomas Rittson <trittson@bitwarden.com> Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com>
2021-11-11 02:46:48 +01:00
public Task PostConvertToKeyConnector()
{
return SendAsync<object, object>(HttpMethod.Post, "/accounts/convert-to-key-connector", null, true, false);
}
public Task PostSetKeyConnectorKey(SetKeyConnectorKeyRequest request)
{
return SendAsync<SetKeyConnectorKeyRequest>(HttpMethod.Post, "/accounts/set-key-connector-key", request, true);
}
2019-04-16 17:07:44 +02:00
#endregion
#region Folder APIs
public Task<FolderResponse> GetFolderAsync(string id)
{
return SendAsync<object, FolderResponse>(HttpMethod.Get, string.Concat("/folders/", id),
null, true, true);
}
public Task<FolderResponse> PostFolderAsync(FolderRequest request)
{
return SendAsync<FolderRequest, FolderResponse>(HttpMethod.Post, "/folders", request, true, true);
}
public async Task<FolderResponse> PutFolderAsync(string id, FolderRequest request)
{
return await SendAsync<FolderRequest, FolderResponse>(HttpMethod.Put, string.Concat("/folders/", id),
request, true, true);
}
public Task DeleteFolderAsync(string id)
{
return SendAsync<object, object>(HttpMethod.Delete, string.Concat("/folders/", id), null, true, false);
}
#endregion
#region Send APIs
public Task<SendResponse> GetSendAsync(string id) =>
SendAsync<object, SendResponse>(HttpMethod.Get, $"/sends/{id}", null, true, true);
public Task<SendResponse> PostSendAsync(SendRequest request) =>
SendAsync<SendRequest, SendResponse>(HttpMethod.Post, "/sends", request, true, true);
public Task<SendFileUploadDataResponse> PostFileTypeSendAsync(SendRequest request) =>
SendAsync<SendRequest, SendFileUploadDataResponse>(HttpMethod.Post, "/sends/file/v2", request, true, true);
public Task PostSendFileAsync(string sendId, string fileId, MultipartFormDataContent data) =>
SendAsync<MultipartFormDataContent, object>(HttpMethod.Post, $"/sends/{sendId}/file/{fileId}", data, true, false);
[Obsolete("Mar 25 2021: This method has been deprecated in favor of direct uploads. This method still exists for backward compatibility with old server versions.")]
public Task<SendResponse> PostSendFileAsync(MultipartFormDataContent data) =>
SendAsync<MultipartFormDataContent, SendResponse>(HttpMethod.Post, "/sends/file", data, true, true);
public Task<SendFileUploadDataResponse> RenewFileUploadUrlAsync(string sendId, string fileId) =>
SendAsync<object, SendFileUploadDataResponse>(HttpMethod.Get, $"/sends/{sendId}/file/{fileId}", null, true, true);
public Task<SendResponse> PutSendAsync(string id, SendRequest request) =>
SendAsync<SendRequest, SendResponse>(HttpMethod.Put, $"/sends/{id}", request, true, true);
public Task<SendResponse> PutSendRemovePasswordAsync(string id) =>
SendAsync<object, SendResponse>(HttpMethod.Put, $"/sends/{id}/remove-password", null, true, true);
public Task DeleteSendAsync(string id) =>
SendAsync<object, object>(HttpMethod.Delete, $"/sends/{id}", null, true, false);
#endregion
2019-04-16 17:07:44 +02:00
#region Cipher APIs
public Task<CipherResponse> GetCipherAsync(string id)
{
return SendAsync<object, CipherResponse>(HttpMethod.Get, string.Concat("/ciphers/", id),
null, true, true);
}
public Task<CipherResponse> PostCipherAsync(CipherRequest request)
{
return SendAsync<CipherRequest, CipherResponse>(HttpMethod.Post, "/ciphers", request, true, true);
}
public Task<CipherResponse> PostCipherCreateAsync(CipherCreateRequest request)
{
return SendAsync<CipherCreateRequest, CipherResponse>(HttpMethod.Post, "/ciphers/create",
request, true, true);
}
public Task<CipherResponse> PutCipherAsync(string id, CipherRequest request)
{
return SendAsync<CipherRequest, CipherResponse>(HttpMethod.Put, string.Concat("/ciphers/", id),
request, true, true);
}
public Task<CipherResponse> PutShareCipherAsync(string id, CipherShareRequest request)
{
return SendAsync<CipherShareRequest, CipherResponse>(HttpMethod.Put,
string.Concat("/ciphers/", id, "/share"), request, true, true);
}
public Task PutCipherCollectionsAsync(string id, CipherCollectionsRequest request)
{
return SendAsync<CipherCollectionsRequest, object>(HttpMethod.Put,
string.Concat("/ciphers/", id, "/collections"), request, true, false);
}
public Task DeleteCipherAsync(string id)
{
return SendAsync<object, object>(HttpMethod.Delete, string.Concat("/ciphers/", id), null, true, false);
}
public Task PutDeleteCipherAsync(string id)
{
return SendAsync<object, object>(HttpMethod.Put, string.Concat("/ciphers/", id, "/delete"), null, true, false);
}
public Task<CipherResponse> PutRestoreCipherAsync(string id)
{
return SendAsync<object, CipherResponse>(HttpMethod.Put, string.Concat("/ciphers/", id, "/restore"), null, true, true);
}
2019-04-16 17:07:44 +02:00
#endregion
#region Attachments APIs
[Obsolete("Mar 25 2021: This method has been deprecated in favor of direct uploads. This method still exists for backward compatibility with old server versions.")]
public Task<CipherResponse> PostCipherAttachmentLegacyAsync(string id, MultipartFormDataContent data)
2019-04-16 23:21:04 +02:00
{
return SendAsync<MultipartFormDataContent, CipherResponse>(HttpMethod.Post,
string.Concat("/ciphers/", id, "/attachment"), data, true, true);
}
public Task<AttachmentUploadDataResponse> PostCipherAttachmentAsync(string id, AttachmentRequest request)
{
return SendAsync<AttachmentRequest, AttachmentUploadDataResponse>(HttpMethod.Post,
$"/ciphers/{id}/attachment/v2", request, true, true);
}
public Task<AttachmentResponse> GetAttachmentData(string cipherId, string attachmentId) =>
SendAsync<AttachmentResponse>(HttpMethod.Get, $"/ciphers/{cipherId}/attachment/{attachmentId}", true);
2019-04-16 17:07:44 +02:00
public Task DeleteCipherAttachmentAsync(string id, string attachmentId)
{
return SendAsync(HttpMethod.Delete,
string.Concat("/ciphers/", id, "/attachment/", attachmentId), true);
2019-04-16 17:07:44 +02:00
}
2019-04-16 23:21:04 +02:00
public Task PostShareCipherAttachmentAsync(string id, string attachmentId, MultipartFormDataContent data,
string organizationId)
{
return SendAsync<MultipartFormDataContent, object>(HttpMethod.Post,
string.Concat("/ciphers/", id, "/attachment/", attachmentId, "/share?organizationId=", organizationId),
data, true, false);
}
public Task<AttachmentUploadDataResponse> RenewAttachmentUploadUrlAsync(string cipherId, string attachmentId) =>
SendAsync<AttachmentUploadDataResponse>(HttpMethod.Get, $"/ciphers/{cipherId}/attachment/{attachmentId}/renew", true);
public Task PostAttachmentFileAsync(string cipherId, string attachmentId, MultipartFormDataContent data) =>
SendAsync(HttpMethod.Post,
$"/ciphers/{cipherId}/attachment/{attachmentId}", data, true);
2019-04-16 17:07:44 +02:00
#endregion
#region Sync APIs
2019-04-17 18:12:43 +02:00
public Task<SyncResponse> GetSyncAsync()
2019-04-16 17:07:44 +02:00
{
return SendAsync<object, SyncResponse>(HttpMethod.Get, "/sync", null, true, true);
2019-04-10 21:35:23 +02:00
}
2019-04-10 21:03:09 +02:00
2019-04-10 21:35:23 +02:00
#endregion
2019-04-10 21:03:09 +02:00
2019-05-27 16:28:38 +02:00
#region Two Factor APIs
public Task PostTwoFactorEmailAsync(TwoFactorEmailRequest request)
{
return SendAsync<TwoFactorEmailRequest, object>(
HttpMethod.Post, "/two-factor/send-email-login", request, false, false);
}
#endregion
2019-05-28 18:01:55 +02:00
#region Device APIs
public Task PutDeviceTokenAsync(string identifier, DeviceTokenRequest request)
{
return SendAsync<DeviceTokenRequest, object>(
2019-05-28 22:20:24 +02:00
HttpMethod.Put, $"/devices/identifier/{identifier}/token", request, true, false);
2019-05-28 18:01:55 +02:00
}
#endregion
2019-06-25 22:36:21 +02:00
#region Event APIs
2019-07-11 15:30:25 +02:00
public async Task PostEventsCollectAsync(IEnumerable<EventRequest> request)
2019-06-25 22:36:21 +02:00
{
using (var requestMessage = new HttpRequestMessage())
2019-06-25 22:36:21 +02:00
{
2019-11-05 15:14:55 +01:00
requestMessage.Version = new Version(1, 0);
2019-06-25 22:36:21 +02:00
requestMessage.Method = HttpMethod.Post;
requestMessage.RequestUri = new Uri(string.Concat(EventsBaseUrl, "/collect"));
var authHeader = await GetActiveBearerTokenAsync();
requestMessage.Headers.Add("Authorization", string.Concat("Bearer ", authHeader));
requestMessage.Content = new StringContent(JsonConvert.SerializeObject(request, _jsonSettings),
Encoding.UTF8, "application/json");
HttpResponseMessage response;
try
{
response = await _httpClient.SendAsync(requestMessage);
}
2019-11-15 14:55:22 +01:00
catch (Exception e)
2019-06-25 22:36:21 +02:00
{
2019-11-15 14:55:22 +01:00
throw new ApiException(HandleWebError(e));
2019-06-25 22:36:21 +02:00
}
if (!response.IsSuccessStatusCode)
2019-06-25 22:36:21 +02:00
{
var error = await HandleErrorAsync(response, false, false);
2019-06-25 22:36:21 +02:00
throw new ApiException(error);
}
}
}
#endregion
2019-04-17 23:10:21 +02:00
#region HIBP APIs
public Task<List<BreachAccountResponse>> GetHibpBreachAsync(string username)
{
return SendAsync<object, List<BreachAccountResponse>>(HttpMethod.Get,
string.Concat("/hibp/breach?username=", username), null, true, true);
}
#endregion
2022-04-26 17:21:17 +02:00
#region Organizations APIs
2022-04-26 17:21:17 +02:00
public Task<OrganizationKeysResponse> GetOrganizationKeysAsync(string id)
{
return SendAsync<object, OrganizationKeysResponse>(HttpMethod.Get, $"/organizations/{id}/keys", null, true, true);
}
public Task<OrganizationAutoEnrollStatusResponse> GetOrganizationAutoEnrollStatusAsync(string identifier)
{
return SendAsync<object, OrganizationAutoEnrollStatusResponse>(HttpMethod.Get,
$"/organizations/{identifier}/auto-enroll-status", null, true, true);
}
[KeyConnector] Add support for key connector OTP (#1633) * initial commit - add UsesKeyConnector to UserService - add models - begin work on authentication * finish auth workflow for key connector sso login - finish api call for get user key - start api calls for posts to key connector * Bypass lock page if already unlocked * Move logic to KeyConnectorService, log out if no pin or biometric is set * Disable password reprompt when using key connector * hide password reprompt checkbox when editing or adding cipher * add PostUserKey and PostSetKeyConnector calls * add ConvertMasterPasswordPage * add functionality to RemoveMasterPasswordPage - rename Convert to Remove * Hide Change Master Password button if using key connector * Add OTP verification for export component * Update src/App/Pages/Vault/AddEditPage.xaml.cs Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> * remove toolbar item "close" * Update src/Core/Models/Request/KeyConnectorUserKeyRequest.cs Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> * remove new line in resource string - format warning as two labels - set label in code behind for loading simultaneously * implement GetAndSetKey in KeyConnectorService - ignore EnvironmentService call * remove unnecesary orgIdentifier * move RemoveMasterPasswordPage call to LockPage * add spacing to export vault page * log out if no PIN or bio on lock page with key connector * Delete excessive whitespace * Delete excessive whitespace * Change capitalisation of OTP * add default value to models for backwards compatibility * remove this keyword * actually handle exceptions * move RemoveMasterPasswordPage to TabPage using messaging service * add minor improvements * remove 'this.' Co-authored-by: Hinton <oscar@oscarhinton.com> Co-authored-by: Thomas Rittson <trittson@bitwarden.com> Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com>
2021-11-11 02:46:48 +01:00
public Task PostLeaveOrganization(string id)
{
return SendAsync<object, object>(HttpMethod.Post, $"/organizations/{id}/leave", null, true, false);
}
#endregion
[KeyConnector] Add support for key connector OTP (#1633) * initial commit - add UsesKeyConnector to UserService - add models - begin work on authentication * finish auth workflow for key connector sso login - finish api call for get user key - start api calls for posts to key connector * Bypass lock page if already unlocked * Move logic to KeyConnectorService, log out if no pin or biometric is set * Disable password reprompt when using key connector * hide password reprompt checkbox when editing or adding cipher * add PostUserKey and PostSetKeyConnector calls * add ConvertMasterPasswordPage * add functionality to RemoveMasterPasswordPage - rename Convert to Remove * Hide Change Master Password button if using key connector * Add OTP verification for export component * Update src/App/Pages/Vault/AddEditPage.xaml.cs Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> * remove toolbar item "close" * Update src/Core/Models/Request/KeyConnectorUserKeyRequest.cs Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> * remove new line in resource string - format warning as two labels - set label in code behind for loading simultaneously * implement GetAndSetKey in KeyConnectorService - ignore EnvironmentService call * remove unnecesary orgIdentifier * move RemoveMasterPasswordPage call to LockPage * add spacing to export vault page * log out if no PIN or bio on lock page with key connector * Delete excessive whitespace * Delete excessive whitespace * Change capitalisation of OTP * add default value to models for backwards compatibility * remove this keyword * actually handle exceptions * move RemoveMasterPasswordPage to TabPage using messaging service * add minor improvements * remove 'this.' Co-authored-by: Hinton <oscar@oscarhinton.com> Co-authored-by: Thomas Rittson <trittson@bitwarden.com> Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com>
2021-11-11 02:46:48 +01:00
#region Organization User APIs
public Task PutOrganizationUserResetPasswordEnrollmentAsync(string orgId, string userId,
OrganizationUserResetPasswordEnrollmentRequest request)
{
return SendAsync<OrganizationUserResetPasswordEnrollmentRequest, object>(HttpMethod.Put,
$"/organizations/{orgId}/users/{userId}/reset-password-enrollment", request, true, false);
}
[KeyConnector] Add support for key connector OTP (#1633) * initial commit - add UsesKeyConnector to UserService - add models - begin work on authentication * finish auth workflow for key connector sso login - finish api call for get user key - start api calls for posts to key connector * Bypass lock page if already unlocked * Move logic to KeyConnectorService, log out if no pin or biometric is set * Disable password reprompt when using key connector * hide password reprompt checkbox when editing or adding cipher * add PostUserKey and PostSetKeyConnector calls * add ConvertMasterPasswordPage * add functionality to RemoveMasterPasswordPage - rename Convert to Remove * Hide Change Master Password button if using key connector * Add OTP verification for export component * Update src/App/Pages/Vault/AddEditPage.xaml.cs Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> * remove toolbar item "close" * Update src/Core/Models/Request/KeyConnectorUserKeyRequest.cs Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> * remove new line in resource string - format warning as two labels - set label in code behind for loading simultaneously * implement GetAndSetKey in KeyConnectorService - ignore EnvironmentService call * remove unnecesary orgIdentifier * move RemoveMasterPasswordPage call to LockPage * add spacing to export vault page * log out if no PIN or bio on lock page with key connector * Delete excessive whitespace * Delete excessive whitespace * Change capitalisation of OTP * add default value to models for backwards compatibility * remove this keyword * actually handle exceptions * move RemoveMasterPasswordPage to TabPage using messaging service * add minor improvements * remove 'this.' Co-authored-by: Hinton <oscar@oscarhinton.com> Co-authored-by: Thomas Rittson <trittson@bitwarden.com> Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com>
2021-11-11 02:46:48 +01:00
#endregion
#region Key Connector
public async Task<KeyConnectorUserKeyResponse> GetUserKeyFromKeyConnector(string keyConnectorUrl)
{
using (var requestMessage = new HttpRequestMessage())
{
var authHeader = await GetActiveBearerTokenAsync();
requestMessage.Version = new Version(1, 0);
requestMessage.Method = HttpMethod.Get;
requestMessage.RequestUri = new Uri(string.Concat(keyConnectorUrl, "/user-keys"));
requestMessage.Headers.Add("Authorization", string.Concat("Bearer ", authHeader));
HttpResponseMessage response;
try
{
response = await _httpClient.SendAsync(requestMessage);
}
catch (Exception e)
{
throw new ApiException(HandleWebError(e));
}
if (!response.IsSuccessStatusCode)
{
var error = await HandleErrorAsync(response, false, true);
throw new ApiException(error);
}
var responseJsonString = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<KeyConnectorUserKeyResponse>(responseJsonString);
}
}
public async Task PostUserKeyToKeyConnector(string keyConnectorUrl, KeyConnectorUserKeyRequest request)
{
using (var requestMessage = new HttpRequestMessage())
{
var authHeader = await GetActiveBearerTokenAsync();
requestMessage.Version = new Version(1, 0);
requestMessage.Method = HttpMethod.Post;
requestMessage.RequestUri = new Uri(string.Concat(keyConnectorUrl, "/user-keys"));
requestMessage.Headers.Add("Authorization", string.Concat("Bearer ", authHeader));
requestMessage.Content = new StringContent(JsonConvert.SerializeObject(request, _jsonSettings),
Encoding.UTF8, "application/json");
HttpResponseMessage response;
try
{
response = await _httpClient.SendAsync(requestMessage);
}
catch (Exception e)
{
throw new ApiException(HandleWebError(e));
}
if (!response.IsSuccessStatusCode)
{
var error = await HandleErrorAsync(response, false, true);
throw new ApiException(error);
}
}
}
2019-04-17 23:10:21 +02:00
#endregion
Passwordless feature branch PR (#2100) * [SG-471] Passwordless device login screen (#2017) * [SSG-471] Added UI for the device login request response. * [SG-471] Added text resources and arguments to Page. * [SG-471] Added properties to speed up page bindings * [SG-471] Added mock services. Added Accept/reject command binding, navigation and toast messages. * [SG-471] fixed code styling with dotnet-format * [SG-471] Fixed back button placement. PR fixes. * [SG-471] Added new Origin parameter to the page. * [SG-471] PR Fixes * [SG-471] PR fixes * [SG-471] PR Fix: added FireAndForget. * [SG-471] Moved fire and forget to run on ui thread task. * [SG-381] Passwordless - Add setting to Mobile (#2037) * [SG-381] Added settings option to approve passwordless login request. If user has notifications disabled, prompt to go to settings and enable them. * [SG-381] Update settings pop up texts. * [SG-381] Added new method to get notifications state on device settings. Added userId to property saved on device to differentiate value between users. * [SG-381] Added text for the popup on selection. * [SG-381] PR Fixes * [SG-408] Implement passwordless api methods (#2055) * [SG-408] Update notification model. * [SG-408] removed duplicated resource * [SG-408] Added implementation to Api Service of new passwordless methods. * removed qa endpoints * [SG-408] Changed auth methods implementation, added method call to viewmodel. * [SG-408] ran code format * [SG-408] PR fixes * [SG-472] Add configuration for new notification type (#2056) * [SG-472] Added methods to present local notification to the user. Configured new notification type for passwordless logins * [SG-472] Updated code to new api service changes. * [SG-472] ran dotnet format * [SG-472] PR Fixes. * [SG-472] PR Fixes * [SG-169] End-to-end testing refactor. (#2073) * [SG-169] Passwordless demo change requests (#2079) * [SG-169] End-to-end testing refactor. * [SG-169] Fixed labels. Changed color of Fingerprint phrase. Waited for app to be in foreground to launch passwordless modal to fix Android issues. * [SG-169] Anchored buttons to the bottom of the screen. * [SG-169] Changed device type from enum to string. * [SG-169] PR fixes * [SG-169] PR fixes * [SG-169] Added comment on static variable
2022-09-26 19:27:57 +02:00
#region PasswordlessLogin
public async Task<List<PasswordlessLoginResponse>> GetAuthRequestAsync()
{
var response = await SendAsync<object, PasswordlessLoginsResponse>(HttpMethod.Get, $"/auth-requests/", null, true, true);
return response.Data;
}
Passwordless feature branch PR (#2100) * [SG-471] Passwordless device login screen (#2017) * [SSG-471] Added UI for the device login request response. * [SG-471] Added text resources and arguments to Page. * [SG-471] Added properties to speed up page bindings * [SG-471] Added mock services. Added Accept/reject command binding, navigation and toast messages. * [SG-471] fixed code styling with dotnet-format * [SG-471] Fixed back button placement. PR fixes. * [SG-471] Added new Origin parameter to the page. * [SG-471] PR Fixes * [SG-471] PR fixes * [SG-471] PR Fix: added FireAndForget. * [SG-471] Moved fire and forget to run on ui thread task. * [SG-381] Passwordless - Add setting to Mobile (#2037) * [SG-381] Added settings option to approve passwordless login request. If user has notifications disabled, prompt to go to settings and enable them. * [SG-381] Update settings pop up texts. * [SG-381] Added new method to get notifications state on device settings. Added userId to property saved on device to differentiate value between users. * [SG-381] Added text for the popup on selection. * [SG-381] PR Fixes * [SG-408] Implement passwordless api methods (#2055) * [SG-408] Update notification model. * [SG-408] removed duplicated resource * [SG-408] Added implementation to Api Service of new passwordless methods. * removed qa endpoints * [SG-408] Changed auth methods implementation, added method call to viewmodel. * [SG-408] ran code format * [SG-408] PR fixes * [SG-472] Add configuration for new notification type (#2056) * [SG-472] Added methods to present local notification to the user. Configured new notification type for passwordless logins * [SG-472] Updated code to new api service changes. * [SG-472] ran dotnet format * [SG-472] PR Fixes. * [SG-472] PR Fixes * [SG-169] End-to-end testing refactor. (#2073) * [SG-169] Passwordless demo change requests (#2079) * [SG-169] End-to-end testing refactor. * [SG-169] Fixed labels. Changed color of Fingerprint phrase. Waited for app to be in foreground to launch passwordless modal to fix Android issues. * [SG-169] Anchored buttons to the bottom of the screen. * [SG-169] Changed device type from enum to string. * [SG-169] PR fixes * [SG-169] PR fixes * [SG-169] Added comment on static variable
2022-09-26 19:27:57 +02:00
public Task<PasswordlessLoginResponse> GetAuthRequestAsync(string id)
{
return SendAsync<object, PasswordlessLoginResponse>(HttpMethod.Get, $"/auth-requests/{id}", null, true, true);
}
public Task<PasswordlessLoginResponse> GetAuthResponseAsync(string id, string accessCode)
{
return SendAsync<object, PasswordlessLoginResponse>(HttpMethod.Get, $"/auth-requests/{id}/response?code={accessCode}", null, false, true);
}
public Task<PasswordlessLoginResponse> PostCreateRequestAsync(PasswordlessCreateLoginRequest passwordlessCreateLoginRequest)
{
return SendAsync<object, PasswordlessLoginResponse>(HttpMethod.Post, $"/auth-requests", passwordlessCreateLoginRequest, false, true);
}
Passwordless feature branch PR (#2100) * [SG-471] Passwordless device login screen (#2017) * [SSG-471] Added UI for the device login request response. * [SG-471] Added text resources and arguments to Page. * [SG-471] Added properties to speed up page bindings * [SG-471] Added mock services. Added Accept/reject command binding, navigation and toast messages. * [SG-471] fixed code styling with dotnet-format * [SG-471] Fixed back button placement. PR fixes. * [SG-471] Added new Origin parameter to the page. * [SG-471] PR Fixes * [SG-471] PR fixes * [SG-471] PR Fix: added FireAndForget. * [SG-471] Moved fire and forget to run on ui thread task. * [SG-381] Passwordless - Add setting to Mobile (#2037) * [SG-381] Added settings option to approve passwordless login request. If user has notifications disabled, prompt to go to settings and enable them. * [SG-381] Update settings pop up texts. * [SG-381] Added new method to get notifications state on device settings. Added userId to property saved on device to differentiate value between users. * [SG-381] Added text for the popup on selection. * [SG-381] PR Fixes * [SG-408] Implement passwordless api methods (#2055) * [SG-408] Update notification model. * [SG-408] removed duplicated resource * [SG-408] Added implementation to Api Service of new passwordless methods. * removed qa endpoints * [SG-408] Changed auth methods implementation, added method call to viewmodel. * [SG-408] ran code format * [SG-408] PR fixes * [SG-472] Add configuration for new notification type (#2056) * [SG-472] Added methods to present local notification to the user. Configured new notification type for passwordless logins * [SG-472] Updated code to new api service changes. * [SG-472] ran dotnet format * [SG-472] PR Fixes. * [SG-472] PR Fixes * [SG-169] End-to-end testing refactor. (#2073) * [SG-169] Passwordless demo change requests (#2079) * [SG-169] End-to-end testing refactor. * [SG-169] Fixed labels. Changed color of Fingerprint phrase. Waited for app to be in foreground to launch passwordless modal to fix Android issues. * [SG-169] Anchored buttons to the bottom of the screen. * [SG-169] Changed device type from enum to string. * [SG-169] PR fixes * [SG-169] PR fixes * [SG-169] Added comment on static variable
2022-09-26 19:27:57 +02:00
public Task<PasswordlessLoginResponse> PutAuthRequestAsync(string id, string encKey, string encMasterPasswordHash, string deviceIdentifier, bool requestApproved)
{
var request = new PasswordlessLoginRequest(encKey, encMasterPasswordHash, deviceIdentifier, requestApproved);
return SendAsync<object, PasswordlessLoginResponse>(HttpMethod.Put, $"/auth-requests/{id}", request, true, true);
}
[SG-166] Two Step Login - Feature Branch (#2157) * [SG-166] Update fonts to have necessary icons * [SG-166] Add new custom view to hold a button with a font icon and a label. * [SG-166] Two Step login flow - Mobile (#2153) * [SG-166] Add UI elements to Home and Login pages. Change VMs to function with new UI. Add new string resources. * [SG-166] Pass email parameter from Home to Login page. * [SG-166] Pass email to password hint page. * [SG-166] Remove remembered email from account switching. * [SG-166] Add GetKnownDevice endpoint to ApiService * [SG-166] Fix GetKnownDevice string uri * [SG-166] Add Renderer for IconLabel control. Add RemoveFontPadding bool property. * [SG-166] include IconLabelRenderer in Android csproj file * [SG-166] Add new control. Add styles for the control. * [SG-166] Add verification to start login if email is remembered * [SG-166] Pass default email to hint page * [SG-166] Login with device button only shows if it is a known device. * [SG-166] Change Remember Email to Remember me. Change Check to Switch control. * [SG-166] Add command to button for SSO Login * Revert "[SG-166] Update fonts to have necessary icons" This reverts commit 472b541cef2efa874e65035fed4952a817bdebb1. * [SG-166] Remove IconLabel Android renderer. Add RemoveFontPadding effect. * [SG-166] Update font with new device and suitcase icon * [SG-166] Fix RemoveFontPadding effect * [SG-166] Remove unused property in IconLabel * [SG-166] Fix formatting on IconLabelButton.xaml * [SG-166] Update padding effect to IconLabel * [SG-166] Add control variable to run code once on create * [SG-166] Add email validation before continue * [SG-166] Refactor icons * [SG-166] Update iOS Extension font * [SG-166] Remove HomePage login btn step * [SG-166] Make clickable area smaller * [SG-166] Fix hint filled by default * [SG-166] Fix IconButton font issue * [SG-166] Fix iOS extension * [SG-166] Move style to Base instead of platforms * [SG-166] Fix layout for IconLabelButton * [SG-166] Switched EventHandler for Command * [SG-166] Removed event handler * [SG-166] Fix LoginPage layout options * [SG-166] Fix extensions Login null email * [SG-166] Move remembered email logic to viewmodel * [SG-166] Protect method and show dialog in case of error * [SG-166] Rename of GetKnownDevice api method * [SG-166] rename text resource key name * [SG-166] Add close button to iOS extension * [SG-166] Switch event handlers for commands * [SG-166] Change commands UI thread invocation. * [SG-166] Remove Login with device button from the UI * [SG-166] Fixed appOptions and close button on iOS Extensions
2022-10-29 00:10:41 +02:00
public Task<bool> GetKnownDeviceAsync(string email, string deviceIdentifier)
{
return SendAsync<object, bool>(HttpMethod.Get, $"/devices/knowndevice/{email}/{deviceIdentifier}", null, false, true);
}
Passwordless feature branch PR (#2100) * [SG-471] Passwordless device login screen (#2017) * [SSG-471] Added UI for the device login request response. * [SG-471] Added text resources and arguments to Page. * [SG-471] Added properties to speed up page bindings * [SG-471] Added mock services. Added Accept/reject command binding, navigation and toast messages. * [SG-471] fixed code styling with dotnet-format * [SG-471] Fixed back button placement. PR fixes. * [SG-471] Added new Origin parameter to the page. * [SG-471] PR Fixes * [SG-471] PR fixes * [SG-471] PR Fix: added FireAndForget. * [SG-471] Moved fire and forget to run on ui thread task. * [SG-381] Passwordless - Add setting to Mobile (#2037) * [SG-381] Added settings option to approve passwordless login request. If user has notifications disabled, prompt to go to settings and enable them. * [SG-381] Update settings pop up texts. * [SG-381] Added new method to get notifications state on device settings. Added userId to property saved on device to differentiate value between users. * [SG-381] Added text for the popup on selection. * [SG-381] PR Fixes * [SG-408] Implement passwordless api methods (#2055) * [SG-408] Update notification model. * [SG-408] removed duplicated resource * [SG-408] Added implementation to Api Service of new passwordless methods. * removed qa endpoints * [SG-408] Changed auth methods implementation, added method call to viewmodel. * [SG-408] ran code format * [SG-408] PR fixes * [SG-472] Add configuration for new notification type (#2056) * [SG-472] Added methods to present local notification to the user. Configured new notification type for passwordless logins * [SG-472] Updated code to new api service changes. * [SG-472] ran dotnet format * [SG-472] PR Fixes. * [SG-472] PR Fixes * [SG-169] End-to-end testing refactor. (#2073) * [SG-169] Passwordless demo change requests (#2079) * [SG-169] End-to-end testing refactor. * [SG-169] Fixed labels. Changed color of Fingerprint phrase. Waited for app to be in foreground to launch passwordless modal to fix Android issues. * [SG-169] Anchored buttons to the bottom of the screen. * [SG-169] Changed device type from enum to string. * [SG-169] PR fixes * [SG-169] PR fixes * [SG-169] Added comment on static variable
2022-09-26 19:27:57 +02:00
#endregion
2019-04-10 21:03:09 +02:00
#region Helpers
public async Task<string> GetActiveBearerTokenAsync()
{
var accessToken = await _tokenService.GetTokenAsync();
if (_tokenService.TokenNeedsRefresh())
2019-04-10 21:03:09 +02:00
{
var tokenResponse = await DoRefreshTokenAsync();
accessToken = tokenResponse.AccessToken;
}
return accessToken;
}
public async Task<SsoPrevalidateResponse> PreValidateSso(string identifier)
{
var path = "/account/prevalidate?domainHint=" + WebUtility.UrlEncode(identifier);
using (var requestMessage = new HttpRequestMessage())
{
requestMessage.Version = new Version(1, 0);
requestMessage.Method = HttpMethod.Get;
requestMessage.RequestUri = new Uri(string.Concat(IdentityBaseUrl, path));
requestMessage.Headers.Add("Accept", "application/json");
2022-04-26 17:21:17 +02:00
HttpResponseMessage response;
try
{
response = await _httpClient.SendAsync(requestMessage);
}
catch (Exception e)
{
throw new ApiException(HandleWebError(e));
}
if (!response.IsSuccessStatusCode)
{
var error = await HandleErrorAsync(response, false, true);
throw new ApiException(error);
}
var responseJsonString = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<SsoPrevalidateResponse>(responseJsonString);
}
}
public Task SendAsync(HttpMethod method, string path, bool authed) =>
SendAsync<object, object>(method, path, null, authed, false);
public Task SendAsync<TRequest>(HttpMethod method, string path, TRequest body, bool authed) =>
SendAsync<TRequest, object>(method, path, body, authed, false);
public Task<TResponse> SendAsync<TResponse>(HttpMethod method, string path, bool authed) =>
SendAsync<object, TResponse>(method, path, null, authed, true);
2019-04-10 21:03:09 +02:00
public async Task<TResponse> SendAsync<TRequest, TResponse>(HttpMethod method, string path, TRequest body,
bool authed, bool hasResponse, bool logoutOnUnauthorized = true)
2019-04-10 21:03:09 +02:00
{
using (var requestMessage = new HttpRequestMessage())
2019-04-10 21:03:09 +02:00
{
2019-11-05 15:14:55 +01:00
requestMessage.Version = new Version(1, 0);
2019-04-16 23:21:04 +02:00
requestMessage.Method = method;
if (!Uri.IsWellFormedUriString(ApiBaseUrl, UriKind.Absolute))
{
throw new ApiException(new ErrorResponse
{
StatusCode = HttpStatusCode.BadGateway,
//Note: This message is hardcoded until AppResources.resx gets moved into Core.csproj
Message = "One or more URLs saved in the Settings are incorrect. Please revise it and try to log in again."
});
}
2019-04-16 23:21:04 +02:00
requestMessage.RequestUri = new Uri(string.Concat(ApiBaseUrl, path));
if (body != null)
2019-04-10 21:03:09 +02:00
{
2019-04-16 23:21:04 +02:00
var bodyType = body.GetType();
if (bodyType == typeof(string))
2019-04-16 23:21:04 +02:00
{
requestMessage.Content = new StringContent((object)bodyType as string, Encoding.UTF8,
"application/x-www-form-urlencoded; charset=utf-8");
}
else if (bodyType == typeof(MultipartFormDataContent))
2019-04-16 23:21:04 +02:00
{
requestMessage.Content = body as MultipartFormDataContent;
}
else
{
requestMessage.Content = new StringContent(JsonConvert.SerializeObject(body, _jsonSettings),
Encoding.UTF8, "application/json");
}
2019-04-10 21:03:09 +02:00
}
2019-04-16 23:21:04 +02:00
if (authed)
2019-04-10 21:03:09 +02:00
{
2019-04-16 23:21:04 +02:00
var authHeader = await GetActiveBearerTokenAsync();
requestMessage.Headers.Add("Authorization", string.Concat("Bearer ", authHeader));
2019-04-10 21:03:09 +02:00
}
if (hasResponse)
2019-04-10 21:03:09 +02:00
{
2019-04-16 23:21:04 +02:00
requestMessage.Headers.Add("Accept", "application/json");
2019-04-10 21:03:09 +02:00
}
2019-04-19 15:11:17 +02:00
HttpResponseMessage response;
try
{
response = await _httpClient.SendAsync(requestMessage);
}
2019-11-15 14:55:22 +01:00
catch (Exception e)
2019-04-19 15:11:17 +02:00
{
2019-11-15 14:55:22 +01:00
throw new ApiException(HandleWebError(e));
2019-04-19 15:11:17 +02:00
}
if (hasResponse && response.IsSuccessStatusCode)
2019-04-16 23:21:04 +02:00
{
var responseJsonString = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<TResponse>(responseJsonString);
}
else if (!response.IsSuccessStatusCode)
2019-04-16 23:21:04 +02:00
{
var error = await HandleErrorAsync(response, false, authed, logoutOnUnauthorized);
2019-04-16 23:21:04 +02:00
throw new ApiException(error);
}
return (TResponse)(object)null;
2019-04-10 21:03:09 +02:00
}
}
public async Task<IdentityTokenResponse> DoRefreshTokenAsync()
{
var refreshToken = await _tokenService.GetRefreshTokenAsync();
if (string.IsNullOrWhiteSpace(refreshToken))
2019-04-10 21:03:09 +02:00
{
throw new ApiException();
}
var decodedToken = _tokenService.DecodeToken();
var requestMessage = new HttpRequestMessage
{
2019-11-05 15:14:55 +01:00
Version = new Version(1, 0),
2019-04-10 21:03:09 +02:00
RequestUri = new Uri(string.Concat(IdentityBaseUrl, "/connect/token")),
Method = HttpMethod.Post,
Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
["grant_type"] = "refresh_token",
["client_id"] = decodedToken.GetValue("client_id")?.Value<string>(),
["refresh_token"] = refreshToken
})
};
requestMessage.Headers.Add("Accept", "application/json");
2019-04-19 15:11:17 +02:00
HttpResponseMessage response;
try
{
response = await _httpClient.SendAsync(requestMessage);
}
2019-11-15 14:55:22 +01:00
catch (Exception e)
2019-04-19 15:11:17 +02:00
{
2019-11-15 14:55:22 +01:00
throw new ApiException(HandleWebError(e));
2019-04-19 15:11:17 +02:00
}
if (response.IsSuccessStatusCode)
2019-04-10 21:03:09 +02:00
{
var responseJsonString = await response.Content.ReadAsStringAsync();
var tokenResponse = JsonConvert.DeserializeObject<IdentityTokenResponse>(responseJsonString);
await _tokenService.SetTokensAsync(tokenResponse.AccessToken, tokenResponse.RefreshToken);
return tokenResponse;
}
else
{
var error = await HandleErrorAsync(response, true, true);
2019-04-10 21:03:09 +02:00
throw new ApiException(error);
}
}
[SG-223] Mobile username generator (#2033) * SG-223 - Changed page title and password title * SG-223 - Refactored generated field * Changed position of generated field * Replaced buttons generate and copy for icons * SG-223 - Refactor type to passwordType * SG-223 - Added password or username selector * Added string for label type selection * SG-223 - Added logic for different types of username * Added strings of new types * [SG-223] - Added UI components for different username types * Added static strings for new labels * Added viewmodel properties to support username generation and their respective options * [SG-223] Added control over type picker visibility * [SG-223] Refactored username entry on add edit page and added generate icon * Added GenerateUsername command * [SG-223] - Implemented service for username generation * [SG-223] - Added support for username generation for item creation flow * Implemented cache for username options * Added exception handling for api calls * [SG-223] - Remove unused code * [SG-223] - Added a new display field for username generated and respective command * Added description label for each type of username * Changed defautl value of username from string.Empty to - * [SG-223] - Removed some StackLayouts and refactored some controls * [SG-223] - Refactored properties name * [SG-223] - Added visibility toggle icon for api keys of forwarded email username types * [SG-223] - Refactored nested StackLayouts into grids. * [SG-223] - Refactor and pr fixing * [SG-223] - Removed string keys from Resolve - Added static string to resources * [SG-223] - Refactored Copy_Clicked as AsyncCommand - Improved exception handling - Refactored TypeSelected as GeneratorTypeSelected * [SG-223] - Renamed PasswordFormatter * [SG-223] - Refactored VM properties to use UsernameGenerationOptions * Removed LoadUsernameOptions * [SG-223] - Refactored added pickers to use SelectedItem instead SelectedIndex * Deleted PickerIndexToBoolConverter as it isn't needed anymore * [SG-223] - Refactored and simplified Grid row and column definitions * [SG-223] - Refactored Command into async command * Added exception handling and feedback to the user * [SG-223] - Refactored GeneratorType picker to use Enum GeneratorType instead of string * [SG-223] - Changed some resource keys * [SG-223] - Refactor method name * [SG-223] - Refactored code and added logs for switch default cases * [SG-223] - Added flag to control visibility when in edit mode * [SG-223] - Added suffix Parenthesis to keys to prevent future conflicts * [SG-223] - Refactored multiple methods into one, GetUsernameFromAsync * Removed unused Extensions from enums * [SG-223] - Added exception message * [SG-223] - Added localizable enum values through LocalizableEnumConverter * [SG-223] - Fixed space between controls * [SG-223] - Removed unused code and refactored some variables and methods names * [SG-223] - Removed unused code and refactored constant name to be more elucidative * [SG-223] - Removed unused variable
2022-08-26 20:32:02 +02:00
public async Task<string> GetUsernameFromAsync(ForwardedEmailServiceType service, UsernameGeneratorConfig config)
{
using (var requestMessage = new HttpRequestMessage())
{
requestMessage.Version = new Version(1, 0);
requestMessage.Method = HttpMethod.Post;
requestMessage.RequestUri = new Uri(config.Url);
requestMessage.Headers.Add("Accept", "application/json");
switch (service)
{
case ForwardedEmailServiceType.AnonAddy:
requestMessage.Headers.Add("Authorization", $"Bearer {config.ApiToken}");
requestMessage.Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
["domain"] = config.Domain
});
break;
case ForwardedEmailServiceType.FirefoxRelay:
requestMessage.Headers.Add("Authorization", $"Token {config.ApiToken}");
break;
case ForwardedEmailServiceType.SimpleLogin:
requestMessage.Headers.Add("Authentication", config.ApiToken);
break;
}
HttpResponseMessage response;
try
{
response = await _httpClient.SendAsync(requestMessage);
}
catch (Exception e)
{
throw new ApiException(HandleWebError(e));
}
if (!response.IsSuccessStatusCode)
{
throw new ApiException(new ErrorResponse
{
StatusCode = response.StatusCode,
Message = $"{service} error: {(int)response.StatusCode} {response.ReasonPhrase}."
});
}
var responseJsonString = await response.Content.ReadAsStringAsync();
var result = JObject.Parse(responseJsonString);
switch (service)
{
case ForwardedEmailServiceType.AnonAddy:
return result["data"]?["email"]?.ToString();
case ForwardedEmailServiceType.FirefoxRelay:
return result["full_address"]?.ToString();
case ForwardedEmailServiceType.SimpleLogin:
return result["alias"]?.ToString();
default:
return string.Empty;
}
}
}
2019-11-15 14:55:22 +01:00
private ErrorResponse HandleWebError(Exception e)
2019-04-19 15:11:17 +02:00
{
return new ErrorResponse
{
StatusCode = HttpStatusCode.BadGateway,
2019-11-15 14:55:22 +01:00
Message = "Exception message: " + e.Message
2019-04-19 15:11:17 +02:00
};
}
private async Task<ErrorResponse> HandleErrorAsync(HttpResponseMessage response, bool tokenError,
bool authed, bool logoutOnUnauthorized = true)
2019-04-10 21:03:09 +02:00
{
if (authed
&&
(
(logoutOnUnauthorized && response.StatusCode == HttpStatusCode.Unauthorized)
||
response.StatusCode == HttpStatusCode.Forbidden
))
2019-04-10 21:03:09 +02:00
{
Account Switching (#1807) * Account Switching (#1720) * Account switching * WIP * wip * wip * updates to send test logic * fixed Send tests * fixes for theme handling on account switching and re-adding existing account * switch fixes * fixes * fixes * cleanup * vault timeout fixes * account list status enhancements * logout fixes and token handling improvements * merge latest (#1727) * remove duplicate dependency * fix for initial login token storage paradox (#1730) * Fix avatar color update toolbar item issue on iOS for account switching (#1735) * Updated account switching menu UI (#1733) * updated account switching menu UI * additional changes * add key suffix to constant * GetFirstLetters method tweaks * Fix crash on account switching when logging out when having more than user at a time (#1740) * single account migration to multi-account on app update (#1741) * Account Switching Tap to dismiss (#1743) * Added tap to dismiss on the Account switching overlay and improved a bit the code * Fix account switching overlay background transparent on the proper place * Fixed transparent background and the shadow on the account switching overlay * Fix iOS top space on Account switching list overlay after modal (#1746) * Fix top space added to Account switching list overlay after closing modal * Fix top space added to Account switching list overlay after closing modal on lock, login and home views just in case we add modals in the future there as well * Usability: dismiss account list on certain events (#1748) * dismiss account list on certain events * use new FireAndForget method for back button logic * Create and use Account Switching overlay control (#1753) * Added Account switching overlay control and its own ViewModel and refactored accordingly * Fix account switching Accounts list binding update * Implemented dismiss account switching overlay when changing tabs and when selecting the same tab. Also updated the deprecated listener on CustomTabbedRenderer on Android (#1755) * Overriden Equals on AvatarImageSource so it doesn't get set multiple times when it's the same image thus producing blinking on tab chaged (#1756) * Usability improvements for logout on vault timeout (#1781) * accountswitching fixes (#1784) * Fix for invalid PIN lock state when switching accounts (#1792) * fix for pin lock flow * named tuple values and updated async * clear send service cache on account switch (#1796) * Global theme and account removal (#1793) * Global theme and account removal * remove redundant call to hide account list overlay * cleanup and additional tweaks * add try/catch to remove account dialog flow Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>
2022-02-23 18:40:17 +01:00
await _logoutCallbackAsync(new Tuple<string, bool, bool>(null, false, true));
2019-04-10 21:03:09 +02:00
return null;
}
try
2019-04-10 21:03:09 +02:00
{
JObject responseJObject = null;
if (IsJsonResponse(response))
{
var responseJsonString = await response.Content.ReadAsStringAsync();
responseJObject = JObject.Parse(responseJsonString);
}
if (authed && tokenError
&&
response.StatusCode == HttpStatusCode.BadRequest
&&
responseJObject?["error"]?.ToString() == "invalid_grant")
{
await _logoutCallbackAsync(new Tuple<string, bool, bool>(null, false, true));
return null;
}
return new ErrorResponse(responseJObject, response.StatusCode, tokenError);
}
catch
{
return null;
2019-04-10 21:03:09 +02:00
}
}
private bool IsJsonResponse(HttpResponseMessage response)
{
2019-04-19 15:11:17 +02:00
return (response.Content?.Headers?.ContentType?.MediaType ?? string.Empty) == "application/json";
2019-04-10 21:03:09 +02:00
}
2019-04-10 16:49:24 +02:00
#endregion
}
}