public void PublicKeyLength()
        {
            var publicKey = @"-----BEGIN PUBLIC KEY-----
MIIBCgKCAQEAzOmgHr6eI+2uDGCYkEg+aGGxcRwRWYL7g6ynwMxunYdPMw6Kylym
xP5bEGn9s7svfvQdklJNeqU/QdnyNflne70SHB4m7hNYimF8mNbJyUPGs4nIkHW2
jtRmJUeWR3RYcB9upMsNWcZG2wej7oV5eDmVrF7haeMIrQKSU4/IypYgc5coZWf6
EXAdjRPYddpjyS1GaatSBqVp66hlQB8GchcxogTxbWN/jcQp8VwAptK2hx5r/K9C
H9DxWR0VM/m9OIbmrC5cKbksn41OtwpaMe/1KErODVbmVuYm/ol+TCO7CV2Tumoc
F5VttjXLf59tV6ikrhMmuY8fUlnFW1ujvwIDAQAB
-----END PUBLIC KEY-----";

            var keyString = MyRsa.ReadPublicKeyFromPem(publicKey);

            var key = Convert.FromBase64String(keyString);

            Console.WriteLine($"{key.Length}   {keyString.Length}");


            var rsa = RSA.Create(1024);

            var privateKey1 = rsa.ExportRSAPrivateKey();
            var publicKey1  = rsa.ExportRSAPublicKey();


            Console.WriteLine($"{privateKey1.Length}   {publicKey1.Length}");
        }
        public void Signature4()
        {
            // flutter: https://pub.dev/packages/fast_rsa

            var originalText = "070098c1499e4760a5c1d7888f0e4378_2021-04-28T14:38:13";
            var signature    = "Jb1fOu6tPxYPnf0vn7B4/lp17iaBTiLTExQ7O13TxqE8RywO6W1p8uQ1uAIfFIYcDFTGA06QKwk0lZyybMAjMIFtP59NsTyeicPVKnPfu+1ukTDt28yYRdUGj9ZMd1zHh5llaaH8tLHH8JG2WmyKAefuyk5vRanegftQfc5QcpDeKiobI3AVGhPUy7edOx1lMlWrIaKgR3mHc/psmDH2FVBZF5P3aOE6O6Pnn/4ZG0WzRoTTF9Btr+3qV5dry0NldlCQKSHldltEhQlBTWJwTBao24RDmgRuahR40WGn5d+5mersMsMVjP5nsI7Fp7HjEIJmvPd6nO7cYbBaTz5N2w==";
            var publicKey    = @"-----BEGIN PUBLIC KEY-----
MIIBCgKCAQEAzOmgHr6eI+2uDGCYkEg+aGGxcRwRWYL7g6ynwMxunYdPMw6Kylym
xP5bEGn9s7svfvQdklJNeqU/QdnyNflne70SHB4m7hNYimF8mNbJyUPGs4nIkHW2
jtRmJUeWR3RYcB9upMsNWcZG2wej7oV5eDmVrF7haeMIrQKSU4/IypYgc5coZWf6
EXAdjRPYddpjyS1GaatSBqVp66hlQB8GchcxogTxbWN/jcQp8VwAptK2hx5r/K9C
H9DxWR0VM/m9OIbmrC5cKbksn41OtwpaMe/1KErODVbmVuYm/ol+TCO7CV2Tumoc
F5VttjXLf59tV6ikrhMmuY8fUlnFW1ujvwIDAQAB
-----END PUBLIC KEY-----";

            var result = MyRsa.ValidateSignature(originalText, signature, MyRsa.ReadPublicKeyFromPem(publicKey));

            Assert.IsTrue(result);
        }
        public async Task <AuthorizationResponse> AuthorizationAsync(AuthorizationRequest request)
        {
            using var activity = MyTelemetry.StartActivity("Authorization base on session token");

            if (string.IsNullOrEmpty(request.Token) ||
                string.IsNullOrEmpty(request.BrandId) ||
                string.IsNullOrEmpty(request.BrokerId))
            {
                return(new AuthorizationResponse()
                {
                    Result = false
                });
            }

            var(result, baseToken) = TokensManager.ParseBase64Token <JetWalletToken>(request.Token, AuthConst.GetSessionEncodingKey(), DateTime.UtcNow);

            if (result != TokenParseResult.Ok)
            {
                activity.SetStatus(Status.Error);
                return(new AuthorizationResponse()
                {
                    Result = false
                });
            }

            if (!string.IsNullOrEmpty(baseToken.SessionRootId))
            {
                _logger.LogWarning("Cannot Authorization session base on token with existing RootSession: {rootIdText}", baseToken.SessionRootId);
                activity.SetStatus(Status.Error);
                return(new AuthorizationResponse()
                {
                    Result = false
                });
            }

            var token = new JetWalletToken()
            {
                Id            = baseToken.Id,
                Expires       = DateTime.UtcNow.AddMinutes(_settings.SessionLifeTimeMinutes),
                SessionRootId = Guid.NewGuid().ToString("N"),
                SessionId     = Guid.NewGuid().ToString("N"),
                BrandId       = request.BrandId,
                BrokerId      = request.BrokerId
            };

            token.Id.AddToActivityAsTag("clientId");
            token.BrokerId.AddToActivityAsTag("brokerId");
            token.BrandId.AddToActivityAsTag("brandId");

            token.SessionRootId.AddToActivityAsTag("sessionRootId");


            var clientIdentity = new JetClientIdentity(request.BrokerId, request.BrandId, baseToken.Id);
            var response       = await _clientRegistrationService.GetOrRegisterClientAsync(clientIdentity);

            if (response.Result != ClientRegistrationResponse.RegistrationResult.Ok)
            {
                _logger.LogError("Cannot register client. Client already register with another brand. BrokerId/BrandId/ClientId: {brokerId}/{brandId}/{clientId}",
                                 clientIdentity.BrokerId, clientIdentity.BrandId, clientIdentity.ClientId);

                activity.SetStatus(Status.Error);
                return(new AuthorizationResponse()
                {
                    Result = false
                });
            }

            ClientWallet wallet  = null;
            var          wallets = await _clientWalletService.GetWalletsByClient(clientIdentity);

            if (string.IsNullOrEmpty(request.WalletId))
            {
                wallet = wallets?.Wallets?.FirstOrDefault(w => w.IsDefault) ?? wallets?.Wallets?.FirstOrDefault();
            }
            else
            {
                wallet = wallets?.Wallets?.FirstOrDefault(w => w.WalletId == request.WalletId);
            }

            if (wallet == null)
            {
                request.WalletId.AddToActivityAsTag("walletId");
                _logger.LogWarning("Cannot Authorization session, wallet do not found. WalletId {walletId}. ClientId: {clientId}", request.WalletId, token.Id);
                activity.SetStatus(Status.Error);
                return(new AuthorizationResponse()
                {
                    Result = false
                });
            }

            token.WalletId = wallet.WalletId;
            token.WalletId.AddToActivityAsTag("walletId");

            var session = token.IssueTokenAsBase64String(AuthConst.GetSessionEncodingKey());

            var dueData   = DateTime.UtcNow.AddHours(_settings.RootSessionLifeTimeHours);
            var publicKey = MyRsa.ReadPublicKeyFromPem(request.PublicKeyPem);

            var entity = SpotSessionNoSql.Create(request.BrokerId, request.BrandId, baseToken.Id, dueData, publicKey, token.SessionRootId);
            await _writer.InsertOrReplaceAsync(entity);

            await _sessionAuditService.NewSessionAudit(baseToken, token, request.UserAgent, request.Ip);

            _logger.LogInformation("Session Authorization is success. RootSessionId: {rootIdText}. ClientId:{clientId}", token.SessionRootId, token.ClientId());

            return(new AuthorizationResponse()
            {
                Result = true,
                Token = session
            });
        }