Restricting website usage for Google Maps API doesn’t prevent it from being used in the browser?

Say I’ve restricted my Google Maps API key to the website abc.com/*. This would mean that no other website domains could use my API key to make requests to maps.googleapis.com.

However, using the API key through the browser url bar to make requests to maps.googleapis.com still works fine. Calls made through Postman also work.

What’s the explanation for this and is there an elegant way to prevent this?

Btw, I’m using the Maps Static & Javascript API. From my understanding both are client-side Maps API and called from the browser?

Is this code code vulnerable? windows.location.href usage [closed]

Currently developing a small module and wanted to check with experts whether its code is vulnerable or not. This is part of my internship.

When a button is clicked it opens an android application from its webpage. If the webpage is visited from desktop, it will just have a redirect link. When using mobile browser, it will open the application. Implemented HTML encoding that encodes special characters such as double quotes, <>

Is this below code is secure or will it lead to XSS or redirection kind of attacks?

NOTE: Randomvalue is alphanumeric and it is passed as a part of url upon clicking the button. All values are sample.

<body> <script> function redirect() {    window.location.href="intent://randomvalue#Intent;scheme=owasp;package=com.owasp.top10.vuln;end";  } $  (document).ready(setTimeout(function () {redirect()}, 300)); <script> <a id="open" href="javascript:redirect()"> Open Application</a> 

Two levels of security on SSH for two usage

On my server, I used to use SSH for one single purpose: remote administration. I am the only administrator. Only I have the required credentials to open a remote shell on the server. I use a pair of keys, a strong password and a one-time password, only my personal IP address is allowed to reach the SSH port and the request rate is limited. I used up-to-date algorithms to encrypt my connection.

Now, I would like to use the SSH server for a second purpose: use SFTP to store my password database on my server so that I can “sync” it between my computers and my smartphone. There are a few problems however:

  • Keepass2Android, the only app I know to use my password database on my smartphone cannot work with today’s recommended algorithms. It seems like the library the app use cannot be upgraded on Android, and that there is nothing the developer (let alone myself) can do about it (see here and here). The available algorithms are:
  • Cipher: aes128-ctr,aes128-cbc,3des-ctr,3des-cbc,blowfish-cbc,aes192-ctr,aes192-cbc,aes256-ctr,aes256-cbc
  • MAC: hmac-md5,hmac-sha1,hmac-sha2-256,hmac-sha1-96,hmac-md5-96
  • Host key: ssh-rsa,ssh-dss,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521
  • If I want to be able to access my database “on the go” I cannot restrict the incoming connections to my personal IP address anymore.
  • I cannot (and do not want to) use OTP to access my database.

So here is the solution I came with:

  • Regarding my admin user:
    • He is the only one allowed to access shell through SSH.
    • I configured PAM so that only him needs OTP to log in.
    • I make sure that my client always use the recommended algorithms when I open a remote shell.
  • Regarding my SFTP user:
    • He has no shell access (ForceCommand internal-sftp).
    • He is chrooted in his home directory.
    • When connecting from the android app, the used algorithm won’t be the strongest available, but it’s all right because the only data that will be exchanged is my already well encrypted database.
  • Plus :
    • I limit the incoming connection rate on the SSH port
    • I use Fail2Ban to ban any IP which makes too many login attempts for a long time

I have three questions mainly:

  • What do you think about this setup?
  • Can you confirm that allowing weaker algorithms will only affect security by making the data exchange less “secret” when a client actually use it? In other words am I right to think that when my Android app will download/upload the database the exchange will be less secure than usual, but the rest of the time security level doesn’t change? Allowing weaker cipher, MAC or host key algorithm won’t make it easier to hack into my server?
  • Is allowing only these two users with custom settings for each (Match User) the good way to go, or should I go even further by running to sshd instances?

Thank you for your insight!

Flyerjet

How to fix MySQL high CPU usage running on VPS

I manage a WordPress site on virtual private server with 2 vCore, 80GB SSD, 4GB of memory, Ubuntu 18.04, Apache 2.4.29, and mysql community version 8.0.20.

When started the site on the server, everything worked OK, but right after running database maintenance (simple table optimization), I’m noticing high processor utilization up to 100% of the total capacity for several second, and then goes down, and the goes up again, and it’s constantly like that. After restarting the server, the high CPU usage continues.

Using the htop command, I can see that the problem is always a mysql process.

I tried going to mysql, and I used the “Show processlist” command everything looks normal, and no query is hanging. If I run the command again, some WordPress related queries will be there, but redoing the command again, the queries complete successfully.

However, running queries like saving, publishing post, querying a list of posts, deleting posts the trash takes a very long time. We’re talking 10 to 20 seconds, and the homepage now takes a long time too.

I use a cash plugin and CDN, you for people the site is OK, but something isn’t right.

I tried disabling all the plugins and theme, but the CPU continues to spike up and down.

During the testing period, I turned on the “Optimize Database after Deleting Revisions” which I used for years. Trying to delete 46 pingback links 17 minutes, and the query completed successfully.

The biggest thing to note here is that before the site was running on Ubuntu 16.04 and similar hardware specs with an older version of mysql and apache, and the processor never broke a sweat (never high CPU).

During the time I spent researching, I was thinking that high processor usage was a database problem, but now, I’m thinking that it could be a mysql configuration issue.

For instance, inside /etc/mysql folder, there are two folders and four files, including conf.d and mysql.conf.d folders and Debian.cnf, my.cnf.fallback, mysql.cnf files, and there’s a my.conf file but it’s a symlink pointing to /etc/alternatives/my.cnf which then points to /etc/mysql/mysql.cnf.

Inside the conf.d/mysql.cnf file, the content appears as followed: # The MySQL  Client configuration file. # # For explanations see # http://dev.mysql.com/doc/mysql/en/server-system-variables.html  [mysql] 

Inside the mysql.cnf, this is the content:

# The MySQL  Server configuration file. # # For explanations see # http://dev.mysql.com/doc/mysql/en/server-system-variables.html  # * IMPORTANT: Additional settings that can override those from this file! #   The files must end with '.cnf', otherwise they'll be ignored. # !includedir /etc/mysql/conf.d/ !includedir /etc/mysql/mysql.conf.d/ 

Finally, inside the mysql.conf.d the only thing I see a mysqld.cnf file with text:

# # The MySQL  Server configuration file. # # For explanations see # http://dev.mysql.com/doc/mysql/en/server-system-variables.html  [mysqld] pid-file    = /var/run/mysqld/mysqld.pid socket      = /var/run/mysqld/mysqld.sock datadir     = /var/lib/mysql log-error   = /var/log/mysql/error.log 

IMPORTANT: The below content is from the old server, not new server with the problem. I’m mentioning it below to make a point that the new server doesn’t have a configure, and I’m wondering if I can use the below config to fix the issue.

After seeing these configurations, I decided to look into one of the old backups to see the mysql configuration file, and I saw this:

In the content below, I omitted some comments to make this post a little shorter.

# Here is entries for some specific programs # The following values assume you have at least 32M ram  [mysqld_safe] socket      = /var/run/mysqld/mysqld.sock nice        = 0  [mysqld] # # * Basic Settings # user        = mysql pid-file    = /var/run/mysqld/mysqld.pid socket      = /var/run/mysqld/mysqld.sock port        = 3306 basedir     = /usr datadir     = /var/lib/mysql tmpdir      = /tmp lc-messages-dir = /usr/share/mysql skip-external-locking # # Instead of skip-networking the default is now to listen only on # localhost which is more compatible and is not less secure. bind-address        = 127.0.0.1 # # * Fine Tuning # key_buffer_size     = 16M max_allowed_packet  = 16M thread_stack        = 192K thread_cache_size       = 8 # This replaces the startup script and checks MyISAM tables if needed # the first time they are touched myisam-recover-options  = BACKUP #max_connections        = 100 #table_cache            = 64 #thread_concurrency     = 10 # # * Query Cache Configuration # query_cache_limit   = 1M query_cache_size        = 16M # # * Logging and Replication # # Both location gets rotated by the cronjob. # Be aware that this log type is a performance killer. # As of 5.1 you can enable the log at runtime! #general_log_file        = /var/log/mysql/mysql.log #general_log             = 1 # # Error log - should be very few entries. # log_error = /var/log/mysql/error.log # # Here you can see queries with especially long duration #log_slow_queries   = /var/log/mysql/mysql-slow.log #long_query_time = 2 #log-queries-not-using-indexes # # The following can be used as easy to replay backup logs or for replication. # note: if you are setting up a replication slave, see README.Debian about #       other settings you may need to change. #server-id      = 1 #log_bin            = /var/log/mysql/mysql-bin.log expire_logs_days    = 10 max_binlog_size   = 100M #binlog_do_db       = include_database_name #binlog_ignore_db   = include_database_name # # * InnoDB 

These are my questions now:

  1. The high CPU usage with mysql is because of configuration?
  2. Did I check the mysql setting correctly? (I couldn’t the /etc/my.cnf.)
  3. If the problem is configuration, can the old mysqld.cnf be use in the new server? I mean would be compatible with new server running Ubuntu 18.04 and mysql 8?
  4. Can someone provide other suggestion and/or solution to this mysql problem?

Is the usage for asymptotic notation for these algorithms correct? [duplicate]

So after reading a lot of information around asymptotic analysis of algorithms and the use of Big O / Big Ω and Θ, I’m trying to grasp how to utilise this in the best way when representing algorithms and operations on data structures.

For example there is a recommended website where I got this screenshot from describing Quicksort and I’ve noticed a few issues that stand out to me based on what I’ve learnt.

  1. Is it possible for all notations to represent “Best” “Average” and “Worst” cases? and if so how is this possible? For example for a “Worst” case, How can Big Ω represent the Upper bound. The upper bound is tied to Big O.
  2. I thought in order to find Theta Θ, Big O and Big Ω had to be the same values? In the screenshot “Best” case is n log(n) and Worst case is n^2 so how can Θ(n log(n))?
  3. Take for instance a Hash Table data structure, if you were to perform an analysis on the time complexity for insertion of an element. Would I be correct is saying you could interchangeably say Ω(1) and O(N) or conversely “Average Case is O(1)” and “Worst Case is O(N)”?

quicksort

Getting full (purpose, usage) Table names in SAP Hana

Each table in SAP Hana has a purpose, for example, BSEG is Accounting Document Segment and BKPF is Accounting Document Header.

Is there anything in Hana (along the lines of Select * From Tables) or a full list elsewhere on the Intertubes, that will get me the purpose\usage of each table in Hana?

I’m trying to put together a Workflow for Alfred that’ll allow me to look up the definitions and it would be nice if I can get it to tell me “Look Up BSEG (Accounting Document Segment)” as I’m searching inside the workflow.

I’ve already got the list of names, just really could do with that purpose\usage if possible!

Chrome: why is invalid certificate usage for resources loaded from localhost disabled?

In chrome there is a flag called: allow-insecure-localhost. As far as I can tell all it does is block localhost connection over tls if the certificate is self signed.

Why is this feature turned off by default? Does it affect regular users in any way (regular user = someone who is not developing something). Are there any serious cases of localhost connection being used malicious that could have been prevented by having this option enabled?

SDL2 Application RAM Usage

I am developing a game that uses SDL2, SDL2 Image & SDL2 TTF, while using clang compiler under Linux. When running it in release mode(compiler flags: -Wall -O3) there is a constant usage of about 52MB, I’ve checked with Valgrind for memory leaks and there are none.

My Game class:

#include "Game.h"  Game::Game(Configurations configurations) {   _graphics = std::make_unique<Graphics>(configurations.windowWidth,                                          configurations.windowHeight,                                          configurations.flags);   _gameState = std::make_unique<GameState>(configurations.windowWidth,                                            configurations.windowHeight);   _mouseInput = std::make_unique<MouseInput>(MouseInput{-1, -1, 0});   _fpsCounter = std::make_unique<FPSCounter>();   _worldWidth = configurations.worldWidth;   _worldHeight = configurations.worldHeight;   _fpsCap = configurations.fpsCap; }  auto Game::start() -> void {   _fpsCounter->fpsInit();   gameLoop(_fpsCap); }  auto Game::convertStateToGraphicsMap()     -> std::vector<std::pair<TileType, SDL_Point>> {   std::vector<std::pair<TileType, SDL_Point>> convertedVector;    for (auto o : _gameState->getGameObjects()) {     convertedVector.push_back(         std::make_pair(o.getTileType(), SDL_Point{(int)o.getPosition().x,                                                   (int)o.getPosition().y}));   }    std::remove_if(convertedVector.begin(), convertedVector.end(),                  [this](std::pair<TileType, SDL_Point> o) {                    return o.second.x - (int)_gameState->getCamera().x < 0 ||                           o.second.y - (int)_gameState->getCamera().y < 0 ||                           o.second.x - (int)_gameState->getCamera().x >                               _graphics->getWindowWidth() ||                           o.second.y - (int)_gameState->getCamera().y >                               _graphics->getWindowHeight();                  });    for (auto &o : convertedVector) {     o.second.x -= _gameState->getCamera().x;     o.second.y -= _gameState->getCamera().y;   }   return convertedVector; }  auto Game::checkForSDLQuitEvents() -> bool {   SDL_Event event;   while (SDL_PollEvent(&event)) {     switch (event.type) {     case SDL_QUIT:       std::cout << "closeRequested! quiting\n";       return true;     }   }   return false; }  auto Game::validatePlayerPosition() -> void {   Vector2d<float> &playerPosition = _gameState->getPlayer()->getPosition();   if (playerPosition.x < 0) {     playerPosition.x = 0;   }   if (playerPosition.y < 0) {     playerPosition.y = 0;   }   if (playerPosition.x > _worldWidth) {     playerPosition.x = (float)_worldWidth;   }   if (playerPosition.y > _worldHeight) {     playerPosition.y = (float)_worldHeight;   } }  auto Game::handleMouseState(float fps) -> void {   _mouseInput->mouseState =       SDL_GetMouseState(&_mouseInput->mouseX, &_mouseInput->mouseY);   if (_mouseInput->mouseState & SDL_BUTTON(SDL_BUTTON_LEFT)) {     // printf("SDL_MOUSEBUTTONDOWN\n");     auto halfWindowWidth = _graphics->getWindowWidth() / 2;     auto halfWindowHeight = _graphics->getWindowHeight() / 2;     _gameState->setCamera(         {_gameState->getPlayer()->getPosition().x - halfWindowWidth,          _gameState->getPlayer()->getPosition().y - halfWindowHeight});     _gameState->getPlayer()->onDestinationSelected(         {(float)_mouseInput->mouseX + _gameState->getCamera().x,          (float)_mouseInput->mouseY + _gameState->getCamera().y},         fps);      validatePlayerPosition();   } }  auto Game::gameLoop(float fpsCap) -> void {   float minFrameRateDelay = MILLISECOND_IN_SECOND / fpsCap;   while (true) {     // process events     if (checkForSDLQuitEvents())       return;      _graphics->clearRender();     float averageFPS = _fpsCounter->getAverageFramesPerSecond();     handleMouseState(averageFPS);     _graphics->renderGrid(convertStateToGraphicsMap());     _graphics->renderText("FPS: " + std::to_string(averageFPS),                           {255, 255, 0, 255}, 0, 0);     _graphics->presentRender();      if (fpsCap < averageFPS) {       SDL_Delay(minFrameRateDelay);     }     _fpsCounter->fpsThink();   } }  auto Game::loadMap(const char *filename) -> void {   int current, mx, my, mw, mh;   std::ifstream in(filename);   if (!in.is_open()) {     std::cout << "Failed to open map file." << std::endl;     return;   }   in >> mw;   in >> mh;   in >> mx;   in >> my;   for (int i = 0; i < mh; i++) {     for (int j = 0; j < mw; j++) {       if (in.eof()) {         std::cout << "Reached end of map file too soon." << std::endl;         return;       }       in >> current;       if (current != 0) {         GameObject tmp(DEFAULT_OBJECT_SIZE, 0, {0, 0}, HUMAN_FEMALE);         if (current == 2 || current == 4) {         }         _map.push_back(tmp);       }     }   }   in.close(); }  Game::~Game() { std::cout << "Game destructor\n"; } 

My Graphics class:

#include "Graphics.h"  Graphics::Graphics(Uint32 windowWidth, Uint32 windowHeight, Uint32 flags)     : _windowWidth(windowWidth), _windowHeight(windowHeight), _flags(flags) {   if (initializeSdl()) {     _window = std::unique_ptr<SDL_Window, std::function<void(SDL_Window *)>>(         createWindow(), SDL_DestroyWindow);     _renderer =         std::unique_ptr<SDL_Renderer, std::function<void(SDL_Renderer *)>>(             createRenderer(), SDL_DestroyRenderer);     _textures = std::unique_ptr<         std::map<TileType, SDL_Texture *>,         std::function<void(std::map<TileType, SDL_Texture *> *)>>(         loadAllTextures(), Graphics::destroyAllTextures);     _baseTile =         std::unique_ptr<RectAndTexture, std::function<void(RectAndTexture *)>>(             createBaseRect(), destroyRectAndTexture);     _globalFont = std::unique_ptr<TTF_Font, std::function<void(TTF_Font *)>>(         createRegularFont(), destroyFont);     std::cout << "Graphics created\n";   } }  auto Graphics::initializeSdl() -> bool {   // attempt to initialize graphics and timer system   if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0) {     std::cout << "error initializing SDL: \n" << SDL_GetError();     return false;   }   if (!(IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG)) {     std::cout << "could not initialize sdl2_image: \n" << IMG_GetError();     return false;   }   if (TTF_Init() == -1) {     std::cout << "SDL_ttf could not initialize! SDL_ttf Error: \n"               << TTF_GetError();     return false;   }   return true; }  auto Graphics::createWindow() -> SDL_Window * {   SDL_Window *window = SDL_CreateWindow(       "InvasiveSpecies", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,       _windowWidth, _windowHeight, _flags);   if (!window) {     std::cout << "error creating window: \n" << SDL_GetError();     SDL_Quit();     return nullptr;   }   return window; }  auto Graphics::createRenderer() -> SDL_Renderer * {   // create a renderer, which sets up the graphics hardware   Uint32 render_flags = SDL_RENDERER_ACCELERATED;    SDL_Renderer *renderer = SDL_CreateRenderer(_window.get(), -1, render_flags);   if (!renderer) {     std::cout << "error creating renderer: \n" << SDL_GetError();     quitSdl();     return nullptr;   }    return renderer; }  auto Graphics::loadTexture(const char *imagePath) -> SDL_Texture * {   SDL_Texture *texture = IMG_LoadTexture(_renderer.get(), imagePath);   if (!texture) {     std::cout << "error creating texture\n";     quitSdl();     return nullptr;   }   return texture; }  auto Graphics::createRectFromTexture(SDL_Texture *texture) -> RectAndTexture * {   auto *dest = new SDL_Rect();   SDL_QueryTexture(texture, nullptr, nullptr, &dest->w, &dest->h);   auto *rectAndTexture = new RectAndTexture{dest, texture};   return rectAndTexture; }  auto Graphics::createBaseRect() -> RectAndTexture * {   RectAndTexture *baseTile = createRectFromTexture((*_textures)[SOIL]);   return baseTile; }  auto Graphics::clearRender() -> void { SDL_RenderClear(_renderer.get()); }  auto Graphics::presentRender() -> void { SDL_RenderPresent(_renderer.get()); }  auto Graphics::renderGrid(     const std::vector<std::pair<TileType, SDL_Point>> &gameObjectsPositionsMap)     -> void {   renderGridBackground();   renderGameObjects(gameObjectsPositionsMap); }  auto Graphics::renderGameObjects(     const std::vector<std::pair<TileType, SDL_Point>> &gameObjectsPositionsMap)     -> void {   for (const auto &current : gameObjectsPositionsMap) {     _baseTile->texture = (*_textures)[current.first];     _baseTile->rect->x = current.second.x;     _baseTile->rect->y = current.second.y;     renderTexture(_baseTile.get());   } }  auto Graphics::renderGridBackground() -> void {   // printf("renderGridBackground\n");   int tileWidth = _baseTile->rect->w;   int tileHeight = _baseTile->rect->h;   _baseTile->texture = (*_textures)[SOIL];   for (int i = 0; i < _windowWidth; i += tileWidth) {     for (int j = 0; j < _windowHeight; j += tileHeight) {       _baseTile->rect->x = i;       _baseTile->rect->y = j;       renderTexture(_baseTile.get());     }   } }  auto Graphics::renderTexture(RectAndTexture *rectAndTexture) -> void {   SDL_RenderCopy(_renderer.get(), rectAndTexture->texture, nullptr,                  rectAndTexture->rect); }  auto Graphics::getImagePathStringByTileType(TileType tileType) -> const char * {   switch (tileType) {   case TileType::SOIL:     return SOIL_IMAGE_PATH;   case TileType::GRASS:     return GRASS_IMAGE_PATH;   case TileType::STONES:     return STONES_IMAGE_PATH;   case TileType::HUMAN_MALE:     return HUMAN_MALE_IMAGE_PATH;   case TileType::HUMAN_FEMALE:     return HUMAN_FEMALE_IMAGE_PATH;   default:     break;   }   return nullptr; }  auto Graphics::loadAllTextures() -> std::map<TileType, SDL_Texture *> * {   auto texturesMap = new std::map<TileType, SDL_Texture *>();   for (auto currentTileType : tileTypeVector) {     (*texturesMap)[currentTileType] =         loadTexture(getImagePathStringByTileType(currentTileType));   }   return texturesMap; }  auto Graphics::destroyAllTextures(     std::map<TileType, SDL_Texture *> *texturesMap) -> void {   for (auto const &p : *texturesMap) {     SDL_DestroyTexture(p.second);   }    texturesMap->clear();   delete texturesMap;   std::cout << "destroyAllTextures done\n"; }  auto Graphics::destroyFont(TTF_Font *font) -> void {   TTF_CloseFont(font);   std::cout << "destroyFont done\n"; }  auto Graphics::destroyRectAndTexture(RectAndTexture *rectAndTexture) -> void {   delete rectAndTexture->rect;   //    SDL_DestroyTexture(rectAndTexture->texture); //already freed at   //    destroyAllTextures()   delete rectAndTexture; }  auto Graphics::renderText(const std::string &textureText, SDL_Color textColor,                           int x, int y) -> void {   SDL_Surface *textSurface =       TTF_RenderText_Solid(_globalFont.get(), textureText.c_str(), textColor);   SDL_Texture *textTexture = nullptr;   if (textSurface == nullptr) {     std::cout << "Unable to render text surface! SDL_ttf Error: \n",         TTF_GetError();   } else {     // Create texture from surface pixels     textTexture = SDL_CreateTextureFromSurface(_renderer.get(), textSurface);     if (textTexture == nullptr) {       std::cout << "Unable to create texture from rendered text! SDL Error: \n"                 << SDL_GetError();     } else {       std::unique_ptr<RectAndTexture, std::function<void(RectAndTexture *)>>           baseTile = std::unique_ptr<RectAndTexture,                                      std::function<void(RectAndTexture *)>>(               createRectFromTexture(textTexture), destroyRectAndTexture);       baseTile->rect->x = x;       baseTile->rect->y = y;       renderTexture(baseTile.get());       baseTile.reset();       SDL_DestroyTexture(textTexture);     }      // Get rid of old surface     SDL_FreeSurface(textSurface);   } }  auto Graphics::getFontFromFile(const char *file, int ptsize) -> TTF_Font * {   TTF_Font *gFont = TTF_OpenFont(file, ptsize);    if (gFont == nullptr) {     std::cout << "Failed to load lazy font! SDL_ttf Error: \n"               << TTF_GetError();   }    return gFont; }  auto Graphics::createRegularFont() -> TTF_Font * {   return getFontFromFile(FONT_PATH, FONT_SIZE); }  auto Graphics::quitSdl() -> void {   // these must be here or else they will get called after SDL_Quit()   _globalFont.reset();   _textures.reset();   _baseTile.reset();   _renderer.reset();   _window.reset();   TTF_Quit();   IMG_Quit();   SDL_Quit(); }  Graphics::~Graphics() {   std::cout << "Graphics destructor\n";   quitSdl(); } 

The assets for the game contains .png and .tff files with a total size of about 34KiB.

The rest of the code is in My GitHub repo

Is the usage of about 50MB RAM at runtime is normal under these conditions?

Is this Way of the Kensei monk built and usage correct?

Level: 6
Race: Wood Elf
Class: Monk, Way of the Kensei
Monk Weapons: Longsword, Longbow
Str: 8
Dex: 18 (14 point buy, 2 wood elf, 2 ASI)
Con: 14
Int: 10
Wis: 16 (15 point buy, 1 wood elf)
Cha: 10

Way of the Kensei Agile parry states:

If you make an unarmed strike as part of the Attack action on your turn and are holding a kensei weapon, you can use it to defend yourself if it is a melee weapon. You gain a +2 bonus to AC until the start of your next turn, while the weapon is in your hand and you aren’t incapacitated.

RAW, I take that, at level 5, you can:

  • Make an attack with your monk weapon (I.e. Versatile long sword for 1d10+Dex)
  • Make an unarmed attack with your extra action for 1d6+dex
  • Use flurry of blows for 2 additional unarmed attacks for 1d6+dex each. Or use martial arts for just one additional unarmed attack.
  • use Agile Parry for a +2AC until next turn.

With a +4 Dex and +3 Wis that will result in:

  • +7 attack, AC 19 and 1d10+2d6+12 to 1d10+3d6+16

That is 24.5 to 31 average damage per turn, every turn, while maintaining a high AC.

Is this interpretation and build correct?

It feels like it fights better than a fighter, it’s as hard to hit as a fighter if not more has slightly lower HP but moves way more and deals considerable more damage which is what makes me doubt whether I’m interpreting the rules wrong.

Is RSA usage in combination with Java Socket secure?

I want to create a java program for server client communication. Therefore first the client creates a RSA keypair. Then the client sends the public key to the server. After that the server will create a RSA keypair and also send its public key to the client. Is it safe to say that now (after key exchange) it is safe to send all kind of data between server and client?

Or is it smart to create a SSLSocket? I honestly have no idea how the authentication with the certificats work and I also do not want to have a certificate which needs an update every now and then.