login user with pos qr code and set to cashier mode - issue #212
This commit is contained in:
parent
ccd160c4e0
commit
4dbab4038c
@ -55,11 +55,11 @@ public class AuthStateProvider(
|
||||
}
|
||||
}
|
||||
|
||||
public BTCPayAppClient GetClient(string? baseUri = null)
|
||||
public BTCPayAppClient GetClient(string? baseUri = null, string? token = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(baseUri) && string.IsNullOrEmpty(Account?.BaseUri))
|
||||
throw new ArgumentException("No base URI present or provided.", nameof(baseUri));
|
||||
var token = Account?.ModeToken ?? Account?.OwnerToken;
|
||||
token ??= Account?.ModeToken ?? Account?.OwnerToken;
|
||||
return new BTCPayAppClient(baseUri ?? Account!.BaseUri, token, clientFactory.CreateClient());
|
||||
}
|
||||
|
||||
@ -199,7 +199,7 @@ public class AuthStateProvider(
|
||||
await CheckAuthenticated(true);
|
||||
store = GetUserStore(store.Id)!;
|
||||
}
|
||||
catch (Exception)
|
||||
catch (Exception ex)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
@ -278,13 +278,19 @@ public class AuthStateProvider(
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<FormResult> LoginWithCode(string serverUrl, string email, string code, CancellationToken? cancellation = default)
|
||||
public async Task<FormResult> LoginWithCode(string serverUrl, string? email, string code, CancellationToken? cancellation = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
var client = GetClient(serverUrl);
|
||||
var response = await client.Login(code, cancellation.GetValueOrDefault());
|
||||
if (string.IsNullOrEmpty(response.AccessToken)) throw new Exception("Did not obtain valid API token.");
|
||||
if (string.IsNullOrEmpty(email))
|
||||
{
|
||||
var clientWithToken = GetClient(serverUrl, response.AccessToken);
|
||||
var userInfo = await clientWithToken.GetUserInfo();
|
||||
email = userInfo?.Email!;
|
||||
}
|
||||
var account = new BTCPayAccount(serverUrl, email, response.AccessToken);
|
||||
await SetAccount(account);
|
||||
return new FormResult(true);
|
||||
|
||||
@ -9,7 +9,7 @@ public interface IAccountManager
|
||||
public BTCPayAccount? Account { get; }
|
||||
public AppUserInfo? UserInfo { get; }
|
||||
public AppUserStoreInfo? CurrentStore { get; }
|
||||
public BTCPayAppClient GetClient(string? baseUri = null);
|
||||
public BTCPayAppClient GetClient(string? baseUri = null, string? token = null);
|
||||
public Task<string?> GetEncryptionKey();
|
||||
public Task SetEncryptionKey(string value);
|
||||
public Task<bool> CheckAuthenticated(bool refreshUser = false);
|
||||
@ -18,7 +18,7 @@ public interface IAccountManager
|
||||
public Task<FormResult<AcceptInviteResult>> AcceptInvite(string inviteUrl, CancellationToken? cancellation = default);
|
||||
public Task<FormResult<LoginInfoResult>> LoginInfo(string serverUrl, string email, CancellationToken? cancellation = default);
|
||||
public Task<FormResult> Login(string serverUrl, string email, string password, string? otp, CancellationToken? cancellation = default);
|
||||
public Task<FormResult> LoginWithCode(string serverUrl, string email, string code, CancellationToken? cancellation = default);
|
||||
public Task<FormResult> LoginWithCode(string serverUrl, string? email, string code, CancellationToken? cancellation = default);
|
||||
public Task<FormResult> Register(string serverUrl, string email, string password, CancellationToken? cancellation = default);
|
||||
public Task<FormResult> ResetPassword(string serverUrl, string email, string? resetCode, string? newPassword, CancellationToken? cancellation = default);
|
||||
public Task<FormResult<ApplicationUserData>> ChangePassword(string currentPassword, string newPassword, CancellationToken? cancellation = default);
|
||||
|
||||
@ -5,4 +5,5 @@ public static class Constants
|
||||
public const string LoginCodeSeparator = ";";
|
||||
public const string EncryptionKeySeparator = "*";
|
||||
public const string InviteSeparator = "/invite/";
|
||||
public const string POSQRLoginSeparator = "loginCode";
|
||||
}
|
||||
|
||||
@ -35,7 +35,7 @@
|
||||
{
|
||||
<LightningNodeStateAlert NodeState="State.Value.LightningNodeState" ConnectionState="State.Value.ConnectionState" />
|
||||
}
|
||||
@if (State.Value.LightningNodeState is LightningNodeState.NotConfigured)
|
||||
@if (State.Value.LightningNodeState is LightningNodeState.NotConfigured && AppSettings.AllowWalletGeneration)
|
||||
{
|
||||
<button class="btn btn-primary" @onclick="ConfigureLNWallet">Configure Lightning Wallet</button>
|
||||
}
|
||||
|
||||
@ -390,22 +390,22 @@
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<h2>Logout</h2>
|
||||
<div class="box">
|
||||
@switch (State.Value.ConnectionState)
|
||||
{
|
||||
case BTCPayConnectionState.ConnectedAsPrimary:
|
||||
<p>This device is currently connected as the primary device for communication with the BTCPay Server.</p>
|
||||
<p>Please note that when you sign out of the account on this device, your Lightning node will go offline, and you will not be able to receive any payments.</p>
|
||||
break;
|
||||
case BTCPayConnectionState.ConnectedAsSecondary:
|
||||
<p>This device is currently connected as an additional device for communication with the BTCPay Server.</p>
|
||||
<p>Please ensure that your primary device is still connected to the BTCPay Server, because otherwise you will not be able to receive any payments.</p>
|
||||
break;
|
||||
}
|
||||
<button class="btn btn-outline-danger w-100 mt-2" type="button" @onclick="Logout">Logout</button>
|
||||
</div>
|
||||
</AuthorizeView>
|
||||
<h2>Logout</h2>
|
||||
<div class="box">
|
||||
@switch (State.Value.ConnectionState)
|
||||
{
|
||||
case BTCPayConnectionState.ConnectedAsPrimary:
|
||||
<p>This device is currently connected as the primary device for communication with the BTCPay Server.</p>
|
||||
<p>Please note that when you sign out of the account on this device, your Lightning node will go offline, and you will not be able to receive any payments.</p>
|
||||
break;
|
||||
case BTCPayConnectionState.ConnectedAsSecondary:
|
||||
<p>This device is currently connected as an additional device for communication with the BTCPay Server.</p>
|
||||
<p>Please ensure that your primary device is still connected to the BTCPay Server, because otherwise you will not be able to receive any payments.</p>
|
||||
break;
|
||||
}
|
||||
<button class="btn btn-outline-danger w-100 mt-2" type="button" @onclick="Logout">Logout</button>
|
||||
</div>
|
||||
</section>
|
||||
}
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
@using BTCPayApp.Core.Models
|
||||
@using BTCPayApp.UI.Features
|
||||
@using Microsoft.Extensions.Logging
|
||||
@using System.Web
|
||||
@inject IJSRuntime JS
|
||||
@inject IAccountManager AccountManager
|
||||
@inject BTCPayConnectionManager ConnectionManager
|
||||
@ -93,6 +94,10 @@
|
||||
{
|
||||
return await HandleLoginCode(urlOrLoginCode);
|
||||
}
|
||||
if (urlOrLoginCode.Contains(Constants.POSQRLoginSeparator))
|
||||
{
|
||||
return await HandlePOSQRLoginCode(urlOrLoginCode);
|
||||
}
|
||||
if (urlOrLoginCode.Contains(Constants.EncryptionKeySeparator))
|
||||
{
|
||||
return await HandleEncryptionKey(urlOrLoginCode);
|
||||
@ -160,6 +165,42 @@
|
||||
return false;
|
||||
}
|
||||
|
||||
private async Task<bool> HandlePOSQRLoginCode(string url)
|
||||
{
|
||||
var uri = new Uri(url);
|
||||
var baseUrl = uri.GetLeftPart(UriPartial.Authority);
|
||||
var queryParams = HttpUtility.ParseQueryString(new Uri(url).Query);
|
||||
|
||||
if (queryParams is not null)
|
||||
{
|
||||
var loginCode = queryParams[Constants.POSQRLoginSeparator];
|
||||
if(string.IsNullOrEmpty(loginCode))
|
||||
{
|
||||
ErrorMessage = "Invalid employee login code";
|
||||
StateHasChanged();
|
||||
return false;
|
||||
}
|
||||
|
||||
ErrorMessage = null;
|
||||
Sending = true;
|
||||
StateHasChanged();
|
||||
var result = await AccountManager.LoginWithCode(baseUrl, null, loginCode);
|
||||
Sending = false;
|
||||
|
||||
if (result.Succeeded) return true;
|
||||
|
||||
ErrorMessage = result.Messages?.Contains("Failed") is false
|
||||
? string.Join(",", result.Messages)
|
||||
: "Invalid login attempt.";
|
||||
}
|
||||
else
|
||||
{
|
||||
ErrorMessage = "Invalid login code";
|
||||
}
|
||||
StateHasChanged();
|
||||
return false;
|
||||
}
|
||||
|
||||
private async Task<bool> HandleEncryptionKey(string code)
|
||||
{
|
||||
var parts = code.Split(Constants.EncryptionKeySeparator);
|
||||
@ -206,25 +247,29 @@
|
||||
switch (ConnectionManager.ConnectionState)
|
||||
{
|
||||
case BTCPayConnectionState.Connecting or BTCPayConnectionState.Syncing:
|
||||
{
|
||||
route = Routes.Index;
|
||||
break;
|
||||
}
|
||||
{
|
||||
route = Routes.Index;
|
||||
break;
|
||||
}
|
||||
case BTCPayConnectionState.WaitingForEncryptionKey:
|
||||
route = Routes.Pairing;
|
||||
break;
|
||||
default:
|
||||
{
|
||||
if (storeId == null)
|
||||
{
|
||||
route = AccountManager.UserInfo?.Stores?.Any() is true
|
||||
? Routes.SelectStore
|
||||
: Routes.CreateStore;
|
||||
}
|
||||
else if (current == Routes.Index)
|
||||
{
|
||||
route = Routes.PointOfSale;
|
||||
}
|
||||
if (storeId == null)
|
||||
{
|
||||
route = AccountManager.UserInfo?.Stores?.Any() is true
|
||||
? Routes.SelectStore
|
||||
: Routes.CreateStore;
|
||||
}
|
||||
else if (current == Routes.Index)
|
||||
{
|
||||
route = Routes.PointOfSale;
|
||||
if(AccountManager.CurrentStore?.RoleId == "Employee")
|
||||
{
|
||||
await AccountManager.SwitchMode(storeId, "Cashier");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// do not redirect if the user is already on the correct page
|
||||
|
||||
@ -139,7 +139,7 @@
|
||||
{
|
||||
Config = await OnChainWalletManager.GetConfig();
|
||||
Derivation = Config?.Derivations.FirstOrDefault(d => d.Key == WalletDerivation.NativeSegwit).Value;
|
||||
_canConfigureWallet = await OnChainWalletManager.CanConfigureWallet();
|
||||
_canConfigureWallet = AppSettings.AllowWalletGeneration && await OnChainWalletManager.CanConfigureWallet();
|
||||
}
|
||||
|
||||
private async Task SetStorePaymentMethod()
|
||||
|
||||
@ -27,3 +27,11 @@ public static class StartupExtensions
|
||||
return serviceCollection;
|
||||
}
|
||||
}
|
||||
|
||||
public static class AppSettings
|
||||
{
|
||||
public const bool AutoGenerateWallets = false;
|
||||
public const bool AllowWalletGeneration = false;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -22,6 +22,7 @@ public class StateMiddleware(
|
||||
IDispatcher _dispatcher)
|
||||
: Middleware
|
||||
{
|
||||
|
||||
public const string UiStateConfigKey = "uistate";
|
||||
private CancellationTokenSource? _ratesCts;
|
||||
private bool _previouslyConnected;
|
||||
@ -69,9 +70,11 @@ public class StateMiddleware(
|
||||
dispatcher.Dispatch(new RootState.ConnectionStateUpdatedAction(btcPayConnectionManager.ConnectionState));
|
||||
|
||||
// initial wallet generation
|
||||
if (onChainWalletManager is { State: OnChainWalletState.NotConfigured } && await onChainWalletManager.CanConfigureWallet())
|
||||
if (AppSettings.AutoGenerateWallets &&
|
||||
onChainWalletManager is { State: OnChainWalletState.NotConfigured } &&
|
||||
await onChainWalletManager.CanConfigureWallet())
|
||||
{
|
||||
await onChainWalletManager.Generate();
|
||||
await onChainWalletManager.Generate();
|
||||
}
|
||||
|
||||
// refresh after returning from the background
|
||||
@ -100,8 +103,8 @@ public class StateMiddleware(
|
||||
_dispatcher.Dispatch(new StoreState.FetchOnchainHistogram(store.Id));
|
||||
}
|
||||
break;
|
||||
case OnChainWalletState.NotConfigured when await onChainWalletManager.CanConfigureWallet():
|
||||
await onChainWalletManager.Generate();
|
||||
case OnChainWalletState.NotConfigured when await onChainWalletManager.CanConfigureWallet() && AppSettings.AutoGenerateWallets:
|
||||
await onChainWalletManager.Generate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -119,11 +122,13 @@ public class StateMiddleware(
|
||||
lightningNodeService.StateChanged += async (_, _) =>
|
||||
{
|
||||
dispatcher.Dispatch(new RootState.LightningNodeStateUpdatedAction(lightningNodeService.State));
|
||||
if (lightningNodeService is {State: LightningNodeState.NotConfigured} && await lightningNodeService.CanConfigureLightningNode())
|
||||
if (lightningNodeService is {State: LightningNodeState.NotConfigured} &&
|
||||
await lightningNodeService.CanConfigureLightningNode() &&
|
||||
AppSettings.AutoGenerateWallets)
|
||||
{
|
||||
try
|
||||
{
|
||||
await lightningNodeService.Generate();
|
||||
// await lightningNodeService.Generate();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -241,7 +246,9 @@ public class StateMiddleware(
|
||||
_ = RefreshRates(dispatcher, _ratesCts.Token);
|
||||
|
||||
// initial wallet generation
|
||||
if (onChainWalletManager is { State: OnChainWalletState.NotConfigured } && await onChainWalletManager.CanConfigureWallet())
|
||||
if (onChainWalletManager is { State: OnChainWalletState.NotConfigured } &&
|
||||
await onChainWalletManager.CanConfigureWallet() &&
|
||||
AppSettings.AutoGenerateWallets)
|
||||
{
|
||||
await onChainWalletManager.Generate();
|
||||
}
|
||||
|
||||
58
setup.ps1
Normal file
58
setup.ps1
Normal file
@ -0,0 +1,58 @@
|
||||
# Check if not in a CI environment
|
||||
if (-not (Test-Path Env:CI)) {
|
||||
# Initialize the server submodule
|
||||
Write-Host "Initializing and updating submodules..."
|
||||
git submodule init
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
git submodule update --recursive
|
||||
} else {
|
||||
Write-Error "git submodule init failed."
|
||||
exit 1
|
||||
}
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error "git submodule update --recursive failed."
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Install the workloads
|
||||
Write-Host "Restoring dotnet workloads..."
|
||||
dotnet workload restore
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error "dotnet workload restore failed."
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# Create appsettings file to include app plugin when running the server
|
||||
$appsettings = "submodules/btcpayserver/BTCPayServer/appsettings.dev.json"
|
||||
if (-not (Test-Path $appsettings -PathType Leaf)) {
|
||||
Write-Host "Creating $appsettings..."
|
||||
$content = '{ "DEBUG_PLUGINS": "../../../BTCPayServer.Plugins.App/bin/Debug/net8.0/BTCPayServer.Plugins.App.dll" }'
|
||||
Set-Content -Path $appsettings -Value $content -Encoding UTF8
|
||||
}
|
||||
|
||||
# Publish plugin to share its dependencies with the server
|
||||
$originalLocation = Get-Location
|
||||
$pluginDir = "BTCPayServer.Plugins.App"
|
||||
|
||||
if (Test-Path $pluginDir) {
|
||||
Write-Host "Changing directory to $pluginDir..."
|
||||
Set-Location $pluginDir
|
||||
|
||||
Write-Host "Publishing plugin..."
|
||||
dotnet publish -c Debug -o "bin/Debug/net8.0"
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error "dotnet publish failed."
|
||||
Set-Location $originalLocation # Ensure we return to original location on error
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host "Returning to original directory..."
|
||||
Set-Location $originalLocation
|
||||
} else {
|
||||
Write-Error "Plugin directory $pluginDir not found."
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host "Setup complete."
|
||||
@ -1 +1 @@
|
||||
Subproject commit 21d609aab09b6a24e49d509104839b3cc45d7760
|
||||
Subproject commit c6f960cef510932ce2abf9bc098f7e0ba3714428
|
||||
Loading…
Reference in New Issue
Block a user