btcpayserver/BTCPayServer/Controllers/StoresController.cs

767 lines
30 KiB
C#
Raw Normal View History

2017-09-13 16:50:36 +02:00
using BTCPayServer.Authentication;
using BTCPayServer.Configuration;
using BTCPayServer.Data;
using BTCPayServer.HostedServices;
2017-09-13 16:50:36 +02:00
using BTCPayServer.Models;
using BTCPayServer.Models.StoreViewModels;
2018-05-03 18:46:52 +02:00
using BTCPayServer.Rating;
2018-04-29 19:33:42 +02:00
using BTCPayServer.Security;
2018-02-12 19:27:36 +01:00
using BTCPayServer.Services;
using BTCPayServer.Services.Rates;
using BTCPayServer.Services.Stores;
using BTCPayServer.Services.Wallets;
2017-09-13 16:50:36 +02:00
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
2018-02-12 19:27:36 +01:00
using Microsoft.Extensions.Options;
2017-09-13 16:50:36 +02:00
using NBitcoin;
2017-12-06 10:08:21 +01:00
using NBitcoin.DataEncoders;
using NBXplorer.DerivationStrategy;
2017-09-13 16:50:36 +02:00
using System;
using System.Collections.Generic;
2018-05-03 18:46:52 +02:00
using System.Globalization;
2017-09-13 16:50:36 +02:00
using System.Linq;
2018-01-19 08:00:20 +01:00
using System.Net.Http;
2018-02-12 19:27:36 +01:00
using System.Threading;
2017-09-13 16:50:36 +02:00
using System.Threading.Tasks;
namespace BTCPayServer.Controllers
{
[Route("stores")]
[Authorize(AuthenticationSchemes = Policies.CookieAuthentication)]
2018-04-29 19:33:42 +02:00
[Authorize(Policy = Policies.CanModifyStoreSettings.Key)]
[AutoValidateAntiforgeryToken]
public partial class StoresController : Controller
{
2018-05-03 18:46:52 +02:00
BTCPayRateProviderFactory _RateFactory;
2018-03-23 08:24:57 +01:00
public string CreatedStoreId { get; set; }
public StoresController(
NBXplorerDashboard dashboard,
IServiceProvider serviceProvider,
BTCPayServerOptions btcpayServerOptions,
BTCPayServerEnvironment btcpayEnv,
2018-02-12 19:27:36 +01:00
IOptions<MvcJsonOptions> mvcJsonOptions,
StoreRepository repo,
TokenRepository tokenRepo,
UserManager<ApplicationUser> userManager,
AccessTokenController tokenController,
BTCPayWalletProvider walletProvider,
BTCPayNetworkProvider networkProvider,
2018-05-03 18:46:52 +02:00
BTCPayRateProviderFactory rateFactory,
ExplorerClientProvider explorerProvider,
2018-02-12 19:27:36 +01:00
IFeeProviderFactory feeRateProvider,
2018-03-23 09:27:48 +01:00
LanguageService langService,
IHostingEnvironment env,
CoinAverageSettings coinAverage)
{
2018-05-03 18:46:52 +02:00
_RateFactory = rateFactory;
_Dashboard = dashboard;
_Repo = repo;
_TokenRepository = tokenRepo;
_UserManager = userManager;
2018-03-23 09:27:48 +01:00
_LangService = langService;
_TokenController = tokenController;
_WalletProvider = walletProvider;
_Env = env;
_NetworkProvider = networkProvider;
_ExplorerProvider = explorerProvider;
2018-02-12 19:27:36 +01:00
_MvcJsonOptions = mvcJsonOptions.Value;
_FeeRateProvider = feeRateProvider;
_ServiceProvider = serviceProvider;
_BtcpayServerOptions = btcpayServerOptions;
_BTCPayEnv = btcpayEnv;
_CoinAverage = coinAverage;
}
CoinAverageSettings _CoinAverage;
NBXplorerDashboard _Dashboard;
BTCPayServerOptions _BtcpayServerOptions;
BTCPayServerEnvironment _BTCPayEnv;
IServiceProvider _ServiceProvider;
BTCPayNetworkProvider _NetworkProvider;
private ExplorerClientProvider _ExplorerProvider;
2018-02-12 19:27:36 +01:00
private MvcJsonOptions _MvcJsonOptions;
private IFeeProviderFactory _FeeRateProvider;
BTCPayWalletProvider _WalletProvider;
AccessTokenController _TokenController;
StoreRepository _Repo;
TokenRepository _TokenRepository;
UserManager<ApplicationUser> _UserManager;
2018-03-23 09:27:48 +01:00
private LanguageService _LangService;
IHostingEnvironment _Env;
[TempData]
public string StatusMessage
{
get; set;
}
2018-02-12 19:27:36 +01:00
[HttpGet]
[Route("{storeId}/wallet/{cryptoCode}")]
public IActionResult Wallet(string cryptoCode)
2018-02-12 19:27:36 +01:00
{
WalletModel model = new WalletModel();
model.ServerUrl = GetStoreUrl(StoreData.Id);
model.CryptoCurrency = cryptoCode;
2018-02-12 19:27:36 +01:00
return View(model);
}
private string GetStoreUrl(string storeId)
{
return HttpContext.Request.GetAbsoluteRoot() + "/stores/" + storeId + "/";
2018-03-24 12:40:26 +01:00
}
2018-02-12 19:27:36 +01:00
[HttpGet]
2018-03-23 08:24:57 +01:00
[Route("{storeId}/users")]
public async Task<IActionResult> StoreUsers()
2018-03-23 08:24:57 +01:00
{
StoreUsersViewModel vm = new StoreUsersViewModel();
await FillUsers(vm);
2018-03-23 08:24:57 +01:00
return View(vm);
}
private async Task FillUsers(StoreUsersViewModel vm)
{
var users = await _Repo.GetStoreUsers(StoreData.Id);
vm.StoreId = StoreData.Id;
2018-03-23 08:24:57 +01:00
vm.Users = users.Select(u => new StoreUsersViewModel.StoreUserViewModel()
{
2018-03-23 08:24:57 +01:00
Email = u.Email,
Id = u.Id,
Role = u.Role
}).ToList();
}
public StoreData StoreData
{
get
{
return this.HttpContext.GetStoreData();
}
}
2018-03-23 08:24:57 +01:00
[HttpPost]
[Route("{storeId}/users")]
public async Task<IActionResult> StoreUsers(StoreUsersViewModel vm)
2018-02-15 05:33:29 +01:00
{
await FillUsers(vm);
2018-03-24 12:40:26 +01:00
if (!ModelState.IsValid)
2018-02-15 05:33:29 +01:00
{
2018-03-23 08:24:57 +01:00
return View(vm);
}
var user = await _UserManager.FindByEmailAsync(vm.Email);
2018-03-24 12:40:26 +01:00
if (user == null)
2018-03-23 08:24:57 +01:00
{
ModelState.AddModelError(nameof(vm.Email), "User not found");
return View(vm);
}
2018-03-24 12:40:26 +01:00
if (!StoreRoles.AllRoles.Contains(vm.Role))
2018-03-23 08:24:57 +01:00
{
ModelState.AddModelError(nameof(vm.Role), "Invalid role");
return View(vm);
}
if (!await _Repo.AddStoreUser(StoreData.Id, user.Id, vm.Role))
2018-03-23 08:24:57 +01:00
{
ModelState.AddModelError(nameof(vm.Email), "The user already has access to this store");
return View(vm);
2018-02-15 05:33:29 +01:00
}
2018-03-23 08:24:57 +01:00
StatusMessage = "User added successfully";
return RedirectToAction(nameof(StoreUsers));
2018-02-15 05:33:29 +01:00
}
[HttpGet]
2018-03-23 08:24:57 +01:00
[Route("{storeId}/users/{userId}/delete")]
public async Task<IActionResult> DeleteStoreUser(string userId)
{
2018-03-23 08:24:57 +01:00
StoreUsersViewModel vm = new StoreUsersViewModel();
var user = await _UserManager.FindByIdAsync(userId);
if (user == null)
return NotFound();
return View("Confirm", new ConfirmModel()
{
2018-03-23 08:24:57 +01:00
Title = $"Remove store user",
2018-04-29 19:33:42 +02:00
Description = $"Are you sure to remove access to remove access to {user.Email}?",
Action = "Delete"
});
}
[HttpPost]
2018-03-23 08:24:57 +01:00
[Route("{storeId}/users/{userId}/delete")]
public async Task<IActionResult> DeleteStoreUserPost(string storeId, string userId)
{
2018-03-23 08:24:57 +01:00
await _Repo.RemoveStoreUser(storeId, userId);
StatusMessage = "User removed successfully";
return RedirectToAction(nameof(StoreUsers), new { storeId = storeId, userId = userId });
}
2018-05-03 18:46:52 +02:00
[HttpGet]
[Route("{storeId}/rates")]
public IActionResult Rates()
{
var storeBlob = StoreData.GetStoreBlob();
var vm = new RatesViewModel();
vm.SetExchangeRates(GetSupportedExchanges(), storeBlob.PreferredExchange ?? CoinAverageRateProvider.CoinAverageName);
vm.RateMultiplier = (double)storeBlob.GetRateMultiplier();
vm.Script = storeBlob.GetRateRules(_NetworkProvider).ToString();
vm.DefaultScript = storeBlob.GetDefaultRateRules(_NetworkProvider).ToString();
vm.AvailableExchanges = GetSupportedExchanges();
vm.ShowScripting = storeBlob.RateScripting;
return View(vm);
}
[HttpPost]
[Route("{storeId}/rates")]
public async Task<IActionResult> Rates(RatesViewModel model, string command = null)
{
model.SetExchangeRates(GetSupportedExchanges(), model.PreferredExchange);
if (!ModelState.IsValid)
{
return View(model);
}
if (model.PreferredExchange != null)
model.PreferredExchange = model.PreferredExchange.Trim().ToLowerInvariant();
var blob = StoreData.GetStoreBlob();
model.DefaultScript = blob.GetDefaultRateRules(_NetworkProvider).ToString();
model.AvailableExchanges = GetSupportedExchanges();
blob.PreferredExchange = model.PreferredExchange;
blob.SetRateMultiplier(model.RateMultiplier);
if (!model.ShowScripting)
{
if (!GetSupportedExchanges().Select(c => c.Name).Contains(blob.PreferredExchange, StringComparer.OrdinalIgnoreCase))
{
ModelState.AddModelError(nameof(model.PreferredExchange), $"Unsupported exchange ({model.RateSource})");
return View(model);
}
}
RateRules rules = null;
if (model.ShowScripting)
{
if (!RateRules.TryParse(model.Script, out rules, out var errors))
{
errors = errors ?? new List<RateRulesErrors>();
var errorString = String.Join(", ", errors.ToArray());
ModelState.AddModelError(nameof(model.Script), $"Parsing error ({errorString})");
return View(model);
}
else
{
blob.RateScript = rules.ToString();
2018-05-04 04:48:03 +02:00
ModelState.Remove(nameof(model.Script));
model.Script = blob.RateScript;
2018-05-03 18:46:52 +02:00
}
}
rules = blob.GetRateRules(_NetworkProvider);
if (command == "Test")
{
if (string.IsNullOrWhiteSpace(model.ScriptTest))
{
ModelState.AddModelError(nameof(model.ScriptTest), "Fill out currency pair to test for (like BTC_USD,BTC_CAD)");
return View(model);
}
var splitted = model.ScriptTest.Split(',', StringSplitOptions.RemoveEmptyEntries);
var pairs = new List<CurrencyPair>();
foreach (var pair in splitted)
{
if (!CurrencyPair.TryParse(pair, out var currencyPair))
{
ModelState.AddModelError(nameof(model.ScriptTest), $"Invalid currency pair '{pair}' (it should be formatted like BTC_USD,BTC_CAD)");
return View(model);
}
pairs.Add(currencyPair);
}
var fetchs = _RateFactory.FetchRates(pairs.ToHashSet(), rules);
var testResults = new List<RatesViewModel.TestResultViewModel>();
foreach (var fetch in fetchs)
{
var testResult = await (fetch.Value);
testResults.Add(new RatesViewModel.TestResultViewModel()
{
CurrencyPair = fetch.Key.ToString(),
Error = testResult.Errors.Count != 0,
Rule = testResult.Errors.Count == 0 ? testResult.Rule + " = " + testResult.Value.Value.ToString(CultureInfo.InvariantCulture)
: testResult.EvaluatedRule
});
}
model.TestRateRules = testResults;
return View(model);
}
else // command == Save
{
if (StoreData.SetStoreBlob(blob))
{
await _Repo.UpdateStore(StoreData);
StatusMessage = "Rate settings updated";
}
return RedirectToAction(nameof(Rates), new
{
storeId = StoreData.Id
});
}
}
[HttpGet]
[Route("{storeId}/rates/confirm")]
public IActionResult ShowRateRules(bool scripting)
{
return View("Confirm", new ConfirmModel()
{
2018-05-04 09:09:43 +02:00
Action = "Continue",
2018-05-03 18:46:52 +02:00
Title = "Rate rule scripting",
Description = scripting ?
"This action will mofify your current rate sources. Are you sure to turn on rate rules scripting? (Advanced users)"
: "This action will delete your rate script. Are you sure to turn off rate rules scripting?",
ButtonClass = "btn-primary"
});
}
[HttpPost]
[Route("{storeId}/rates/confirm")]
public async Task<IActionResult> ShowRateRulesPost(bool scripting)
{
var blob = StoreData.GetStoreBlob();
blob.RateScripting = scripting;
blob.RateScript = blob.GetDefaultRateRules(_NetworkProvider).ToString();
StoreData.SetStoreBlob(blob);
await _Repo.UpdateStore(StoreData);
StatusMessage = "Rate rules scripting activated";
return RedirectToAction(nameof(Rates), new { storeId = StoreData.Id });
}
[HttpGet]
[Route("{storeId}/checkout")]
public IActionResult CheckoutExperience()
{
var storeBlob = StoreData.GetStoreBlob();
var vm = new CheckoutExperienceViewModel();
vm.SetCryptoCurrencies(_ExplorerProvider, StoreData.GetDefaultCrypto());
vm.SetLanguages(_LangService, storeBlob.DefaultLang);
vm.LightningMaxValue = storeBlob.LightningMaxValue?.ToString() ?? "";
2018-04-03 10:39:28 +02:00
vm.OnChainMinValue = storeBlob.OnChainMinValue?.ToString() ?? "";
vm.AllowCoinConversion = storeBlob.AllowCoinConversion;
vm.RequiresRefundEmail = storeBlob.RequiresRefundEmail;
vm.CustomCSS = storeBlob.CustomCSS?.AbsoluteUri;
vm.CustomLogo = storeBlob.CustomLogo?.AbsoluteUri;
2018-05-03 23:51:04 +02:00
vm.HtmlTitle = storeBlob.HtmlTitle;
return View(vm);
}
[HttpPost]
[Route("{storeId}/checkout")]
public async Task<IActionResult> CheckoutExperience(CheckoutExperienceViewModel model)
{
2018-04-03 10:39:28 +02:00
CurrencyValue lightningMaxValue = null;
if (!string.IsNullOrWhiteSpace(model.LightningMaxValue))
{
2018-04-03 10:39:28 +02:00
if (!CurrencyValue.TryParse(model.LightningMaxValue, out lightningMaxValue))
{
2018-04-03 10:39:28 +02:00
ModelState.AddModelError(nameof(model.LightningMaxValue), "Invalid lightning max value");
}
}
2018-04-03 10:39:28 +02:00
CurrencyValue onchainMinValue = null;
if (!string.IsNullOrWhiteSpace(model.OnChainMinValue))
{
if (!CurrencyValue.TryParse(model.OnChainMinValue, out onchainMinValue))
{
ModelState.AddModelError(nameof(model.OnChainMinValue), "Invalid on chain min value");
}
}
bool needUpdate = false;
var blob = StoreData.GetStoreBlob();
if (StoreData.GetDefaultCrypto() != model.DefaultCryptoCurrency)
{
needUpdate = true;
StoreData.SetDefaultCrypto(model.DefaultCryptoCurrency);
}
model.SetCryptoCurrencies(_ExplorerProvider, model.DefaultCryptoCurrency);
model.SetLanguages(_LangService, model.DefaultLang);
if (!ModelState.IsValid)
{
return View(model);
}
blob.DefaultLang = model.DefaultLang;
blob.AllowCoinConversion = model.AllowCoinConversion;
blob.RequiresRefundEmail = model.RequiresRefundEmail;
2018-04-03 10:39:28 +02:00
blob.LightningMaxValue = lightningMaxValue;
blob.OnChainMinValue = onchainMinValue;
blob.CustomLogo = string.IsNullOrWhiteSpace(model.CustomLogo) ? null : new Uri(model.CustomLogo, UriKind.Absolute);
blob.CustomCSS = string.IsNullOrWhiteSpace(model.CustomCSS) ? null : new Uri(model.CustomCSS, UriKind.Absolute);
2018-05-03 23:51:04 +02:00
blob.HtmlTitle = string.IsNullOrWhiteSpace(model.HtmlTitle) ? null : model.HtmlTitle;
if (StoreData.SetStoreBlob(blob))
{
needUpdate = true;
}
if (needUpdate)
{
await _Repo.UpdateStore(StoreData);
StatusMessage = "Store successfully updated";
}
return RedirectToAction(nameof(CheckoutExperience), new
{
storeId = StoreData.Id
});
}
[HttpGet]
[Route("{storeId}")]
2018-05-03 18:46:52 +02:00
public IActionResult UpdateStore()
{
2018-04-29 19:33:42 +02:00
var store = HttpContext.GetStoreData();
if (store == null)
return NotFound();
var storeBlob = store.GetStoreBlob();
var vm = new StoreViewModel();
vm.Id = store.Id;
vm.StoreName = store.StoreName;
vm.StoreWebsite = store.StoreWebsite;
vm.NetworkFee = !storeBlob.NetworkFeeDisabled;
vm.SpeedPolicy = store.SpeedPolicy;
AddPaymentMethods(store, vm);
vm.MonitoringExpiration = storeBlob.MonitoringExpiration;
2018-01-17 07:11:05 +01:00
vm.InvoiceExpiration = storeBlob.InvoiceExpiration;
vm.LightningDescriptionTemplate = storeBlob.LightningDescriptionTemplate;
return View(vm);
}
2018-03-24 12:40:26 +01:00
private void AddPaymentMethods(StoreData store, StoreViewModel vm)
{
2018-03-24 12:40:26 +01:00
var derivationByCryptoCode =
store
.GetSupportedPaymentMethods(_NetworkProvider)
.OfType<DerivationStrategy>()
.ToDictionary(c => c.Network.CryptoCode);
foreach (var network in _NetworkProvider.GetAll())
{
var strategy = derivationByCryptoCode.TryGet(network.CryptoCode);
vm.DerivationSchemes.Add(new StoreViewModel.DerivationScheme()
{
Crypto = network.CryptoCode,
Value = strategy?.DerivationStrategyBase?.ToString() ?? string.Empty
});
}
var lightningByCryptoCode = store
.GetSupportedPaymentMethods(_NetworkProvider)
.OfType<Payments.Lightning.LightningSupportedPaymentMethod>()
.ToDictionary(c => c.CryptoCode);
foreach (var network in _NetworkProvider.GetAll())
{
var lightning = lightningByCryptoCode.TryGet(network.CryptoCode);
vm.LightningNodes.Add(new StoreViewModel.LightningNode()
{
CryptoCode = network.CryptoCode,
Address = lightning?.GetLightningUrl()?.BaseUri.AbsoluteUri ?? string.Empty
});
}
}
[HttpPost]
[Route("{storeId}")]
public async Task<IActionResult> UpdateStore(StoreViewModel model)
{
AddPaymentMethods(StoreData, model);
bool needUpdate = false;
if (StoreData.SpeedPolicy != model.SpeedPolicy)
{
needUpdate = true;
StoreData.SpeedPolicy = model.SpeedPolicy;
}
if (StoreData.StoreName != model.StoreName)
{
needUpdate = true;
StoreData.StoreName = model.StoreName;
}
if (StoreData.StoreWebsite != model.StoreWebsite)
{
needUpdate = true;
StoreData.StoreWebsite = model.StoreWebsite;
}
var blob = StoreData.GetStoreBlob();
blob.NetworkFeeDisabled = !model.NetworkFee;
blob.MonitoringExpiration = model.MonitoringExpiration;
2018-01-17 07:59:31 +01:00
blob.InvoiceExpiration = model.InvoiceExpiration;
blob.LightningDescriptionTemplate = model.LightningDescriptionTemplate ?? string.Empty;
if (StoreData.SetStoreBlob(blob))
{
needUpdate = true;
}
if (needUpdate)
{
await _Repo.UpdateStore(StoreData);
StatusMessage = "Store successfully updated";
}
return RedirectToAction(nameof(UpdateStore), new
{
storeId = StoreData.Id
});
}
2018-05-02 20:32:42 +02:00
private CoinAverageExchange[] GetSupportedExchanges()
{
2018-05-02 20:32:42 +02:00
return _CoinAverage.AvailableExchanges
.Select(c => c.Value)
.OrderBy(s => s.Name, StringComparer.OrdinalIgnoreCase)
.ToArray();
}
2018-03-24 12:40:26 +01:00
private DerivationStrategy ParseDerivationStrategy(string derivationScheme, Script hint, BTCPayNetwork network)
{
2018-04-19 09:54:25 +02:00
var parser = new DerivationSchemeParser(network.NBitcoinNetwork);
2018-03-24 12:40:26 +01:00
parser.HintScriptPubKey = hint;
return new DerivationStrategy(parser.Parse(derivationScheme), network);
}
[HttpGet]
[Route("{storeId}/Tokens")]
public async Task<IActionResult> ListTokens()
{
var model = new TokensViewModel();
var tokens = await _TokenRepository.GetTokensByStoreIdAsync(StoreData.Id);
model.StatusMessage = StatusMessage;
model.Tokens = tokens.Select(t => new TokenViewModel()
{
Facade = t.Facade,
Label = t.Label,
SIN = t.SIN,
Id = t.Value
}).ToArray();
model.ApiKey = (await _TokenRepository.GetLegacyAPIKeys(StoreData.Id)).FirstOrDefault();
if (model.ApiKey == null)
model.EncodedApiKey = "*API Key*";
else
model.EncodedApiKey = Encoders.Base64.EncodeData(Encoders.ASCII.DecodeData(model.ApiKey));
return View(model);
}
[HttpPost]
[Route("/api-tokens")]
[Route("{storeId}/Tokens/Create")]
[AllowAnonymous]
public async Task<IActionResult> CreateToken(CreateTokenViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
model.Label = model.Label ?? String.Empty;
2018-03-23 08:24:57 +01:00
var userId = GetUserId();
if (userId == null)
return Challenge(Policies.CookieAuthentication);
var store = StoreData;
var storeId = StoreData?.Id;
if (storeId == null)
{
storeId = model.StoreId;
store = await _Repo.FindStore(storeId, userId);
if (store == null)
return Challenge(Policies.CookieAuthentication);
}
2018-04-29 19:33:42 +02:00
if (!store.HasClaim(Policies.CanModifyStoreSettings.Key))
{
return Challenge(Policies.CookieAuthentication);
}
var tokenRequest = new TokenRequest()
{
Facade = model.Facade,
Label = model.Label,
Id = model.PublicKey == null ? null : NBitpayClient.Extensions.BitIdExtensions.GetBitIDSIN(new PubKey(model.PublicKey))
};
string pairingCode = null;
if (model.PublicKey == null)
{
tokenRequest.PairingCode = await _TokenRepository.CreatePairingCodeAsync();
await _TokenRepository.UpdatePairingCode(new PairingCodeEntity()
{
Id = tokenRequest.PairingCode,
Facade = model.Facade,
Label = model.Label,
});
await _TokenRepository.PairWithStoreAsync(tokenRequest.PairingCode, storeId);
pairingCode = tokenRequest.PairingCode;
}
else
{
pairingCode = ((DataWrapper<List<PairingCodeResponse>>)await _TokenController.Tokens(tokenRequest)).Data[0].PairingCode;
}
2018-01-09 18:07:42 +01:00
GeneratedPairingCode = pairingCode;
return RedirectToAction(nameof(RequestPairing), new
{
pairingCode = pairingCode,
selectedStore = storeId
});
}
2018-01-09 18:07:42 +01:00
public string GeneratedPairingCode { get; set; }
[HttpGet]
[Route("/api-tokens")]
[Route("{storeId}/Tokens/Create")]
[AllowAnonymous]
public async Task<IActionResult> CreateToken()
{
var userId = GetUserId();
if (string.IsNullOrWhiteSpace(userId))
return Challenge(Policies.CookieAuthentication);
var storeId = StoreData?.Id;
if (StoreData != null)
{
if (!StoreData.HasClaim(Policies.CanModifyStoreSettings.Key))
{
return Challenge(Policies.CookieAuthentication);
}
}
var model = new CreateTokenViewModel();
model.Facade = "merchant";
ViewBag.HidePublicKey = storeId == null;
ViewBag.ShowStores = storeId == null;
ViewBag.ShowMenu = storeId != null;
model.StoreId = storeId;
if (storeId == null)
{
var stores = await _Repo.GetStoresByUserId(userId);
model.Stores = new SelectList(stores.Where(s => s.HasClaim(Policies.CanModifyStoreSettings.Key)), nameof(StoreData.Id), nameof(StoreData.StoreName), storeId);
}
if (model.Stores.Count() == 0)
{
StatusMessage = "Error: You need to be owner of at least one store before pairing";
return RedirectToAction(nameof(UserStoresController.ListStores), "UserStores");
}
return View(model);
}
[HttpPost]
[Route("{storeId}/Tokens/Delete")]
public async Task<IActionResult> DeleteToken(string tokenId)
{
var token = await _TokenRepository.GetToken(tokenId);
if (token == null ||
token.StoreId != StoreData.Id ||
!await _TokenRepository.DeleteToken(tokenId))
StatusMessage = "Failure to revoke this token";
else
StatusMessage = "Token revoked";
return RedirectToAction(nameof(ListTokens));
}
[HttpPost]
[Route("{storeId}/tokens/apikey")]
public async Task<IActionResult> GenerateAPIKey()
{
2018-04-29 19:33:42 +02:00
var store = HttpContext.GetStoreData();
if (store == null)
return NotFound();
await _TokenRepository.GenerateLegacyAPIKey(StoreData.Id);
StatusMessage = "API Key re-generated";
return RedirectToAction(nameof(ListTokens));
}
[HttpGet]
[Route("/api-access-request")]
[AllowAnonymous]
public async Task<IActionResult> RequestPairing(string pairingCode, string selectedStore = null)
{
var userId = GetUserId();
if (userId == null)
return Challenge(Policies.CookieAuthentication);
2018-03-23 08:24:57 +01:00
if (pairingCode == null)
return NotFound();
var pairing = await _TokenRepository.GetPairingAsync(pairingCode);
if (pairing == null)
{
StatusMessage = "Unknown pairing code";
2018-03-23 08:24:57 +01:00
return RedirectToAction(nameof(UserStoresController.ListStores), "UserStores");
}
else
{
var stores = await _Repo.GetStoresByUserId(userId);
return View(new PairingModel()
{
Id = pairing.Id,
Facade = pairing.Facade,
Label = pairing.Label,
SIN = pairing.SIN ?? "Server-Initiated Pairing",
SelectedStore = selectedStore ?? stores.FirstOrDefault()?.Id,
Stores = stores.Where(u => u.HasClaim(Policies.CanModifyStoreSettings.Key)).Select(s => new PairingModel.StoreViewModel()
{
Id = s.Id,
Name = string.IsNullOrEmpty(s.StoreName) ? s.Id : s.StoreName
}).ToArray()
});
}
}
[HttpPost]
2018-03-23 08:24:57 +01:00
[Route("/api-access-request")]
[AllowAnonymous]
public async Task<IActionResult> Pair(string pairingCode, string selectedStore)
{
if (pairingCode == null)
return NotFound();
var userId = GetUserId();
if (userId == null)
return Challenge(Policies.CookieAuthentication);
var store = await _Repo.FindStore(selectedStore, userId);
var pairing = await _TokenRepository.GetPairingAsync(pairingCode);
if (store == null || pairing == null)
return NotFound();
2018-04-29 19:33:42 +02:00
if (!store.HasClaim(Policies.CanModifyStoreSettings.Key))
2018-03-23 08:24:57 +01:00
{
return Challenge(Policies.CookieAuthentication);
2018-03-23 08:24:57 +01:00
}
var pairingResult = await _TokenRepository.PairWithStoreAsync(pairingCode, store.Id);
if (pairingResult == PairingResult.Complete || pairingResult == PairingResult.Partial)
{
2018-03-01 15:09:41 +01:00
StatusMessage = "Pairing is successful";
if (pairingResult == PairingResult.Partial)
StatusMessage = "Server initiated pairing code: " + pairingCode;
return RedirectToAction(nameof(ListTokens), new
{
storeId = store.Id
});
}
else
{
StatusMessage = $"Pairing failed ({pairingResult})";
return RedirectToAction(nameof(ListTokens), new
{
storeId = store.Id
});
}
}
private string GetUserId()
{
if (User.Identity.AuthenticationType != Policies.CookieAuthentication)
return null;
return _UserManager.GetUserId(User);
}
}
2017-09-13 16:50:36 +02:00
}