/ login-server / source / cache / LoginManager.ts
LoginManager.ts
  1  import { GameServerManager } from '../service/GameServerManager'
  2  import { ServerStatus } from '../service/GameServerEnums'
  3  import { DatabaseManager } from '../database/manager'
  4  import { L2LoginClient } from '../service/L2LoginClient'
  5  import { L2GameServerClient } from '../service/GameServerClient'
  6  import { RateLimiterCache } from './RateLimiterCache'
  7  import { L2LoginDataApi } from './L2LoginDataApi'
  8  import { BanManager } from './BanManager'
  9  import { ConnectedGameServer } from '../models/RegisteredGameServer'
 10  import { L2GameServerParameters, L2LoginServerCharacters } from '../rpc/interface/LoginServerOperations'
 11  import { SessionKeyProperties } from '../service/SessionKey'
 12  import { Socket } from 'net'
 13  import { L2AccountsCount } from '../database/interface/AccountsTableApi'
 14  import { ServerLog } from '../logger/Logger'
 15  import { IPCache, IPCacheConnectionType, IPCacheListType } from './IPCache'
 16  import { IPVersion } from 'node:net'
 17  import { randomBytes } from 'node:crypto'
 18  
 19  class Manager implements L2LoginDataApi {
 20      gameClients: { [ key: string ]: L2LoginClient } = {}
 21      loginServerClients: Record<string, L2LoginClient> = {}
 22  
 23      async load(): Promise<void> {
 24          const summary : L2AccountsCount = await DatabaseManager.getAccounts().getAccountSummary()
 25          ServerLog.info( 'Total accounts available for login: %d', summary.total )
 26      }
 27  
 28      generateBlowfishKey(): Buffer {
 29          return randomBytes( 16 )
 30      }
 31  
 32      addClient( client: L2LoginClient ) {
 33          const connectionHash = client.getConnectionHash()
 34          this.gameClients[ connectionHash ] = client
 35      }
 36  
 37      addLoggedInClient( accountName: string, client: L2LoginClient ) {
 38          this.loginServerClients[ accountName ] = client
 39      }
 40  
 41      getLoggedInClient( accountName: string ) : L2LoginClient {
 42          return this.loginServerClients[ accountName ]
 43      }
 44  
 45      removeLoggedInClient( accountName: string ) : void {
 46          delete this.loginServerClients[ accountName ]
 47      }
 48  
 49      removeClient( connectionHash: string ): void {
 50          const client: L2LoginClient = this.gameClients[ connectionHash ]
 51          if ( client ) {
 52              const account: string = client.getAccountName()
 53              if ( account ) {
 54                  delete this.loginServerClients[ account ]
 55              }
 56  
 57              delete this.gameClients[ connectionHash ]
 58          }
 59      }
 60  
 61      isAllowed( connection : Socket ) : boolean {
 62          return !IPCache.isInList( connection, IPCacheConnectionType.GameClient, IPCacheListType.Block )
 63      }
 64  
 65      isAllowedAddress( ipAddress : string, version: IPVersion ) : boolean {
 66          return !IPCache.isAddressInBlockList( ipAddress, version, IPCacheConnectionType.GameClient )
 67              && BanManager.isAllowed( ipAddress )
 68              && RateLimiterCache.isAllowedIpAddress( ipAddress )
 69      }
 70  
 71  
 72      getKeyForAccount( name : string ) : SessionKeyProperties {
 73          const client = this.loginServerClients[ name ]
 74          if ( !client ) {
 75              return null
 76          }
 77  
 78          return this.loginServerClients[ name ].getSessionKey()
 79      }
 80  
 81      isLoginPossible( client : L2LoginClient, serverId : number ) : boolean {
 82          const gameServer: ConnectedGameServer = GameServerManager.getRegisteredGameServerById( serverId )
 83  
 84          if ( !gameServer ) {
 85              return false
 86          }
 87  
 88          const serverClient: L2GameServerClient = gameServer.client
 89  
 90          if ( serverClient && serverClient.getServerProperties().isServerAcceptingPlayers ) {
 91              const serverProperties : L2GameServerParameters = serverClient.getServerProperties()
 92              const isAllowed: boolean = ( ( serverClient.getPlayerCount() < serverProperties.maxPlayers ) && ( serverProperties.serverStatus !== ServerStatus.statusGmOnly ) ) ||
 93                      client.getAccessLevel() > 0
 94  
 95              if ( isAllowed && client.getLastServer() !== serverId ) {
 96                  // no need to make whole function async capable since we can defer database action to later
 97                  DatabaseManager.getAccounts().updateAccountLastServerId( client.getAccountName(), serverId )
 98              }
 99  
100              return isAllowed
101          }
102  
103          return false
104      }
105  
106      setAccountAccessLevel( accountName : string, level : number ) : Promise<void> {
107          return DatabaseManager.getAccounts().setStatus( accountName, level )
108      }
109  
110      setCharactersOnServer( accountData: L2LoginServerCharacters, serverId: number ) {
111          const client: L2LoginClient = this.loginServerClients[ accountData.accountName ]
112          if ( !client ) {
113              return
114          }
115  
116          if ( accountData.totalCharacters > 0 ) {
117              client.setCharactersOnServer( serverId, accountData.totalCharacters )
118          }
119  
120          if ( accountData.timesToDelete.length > 0 ) {
121              client.setCharactersWaitingDeleteOnServer( serverId, accountData.timesToDelete )
122          }
123      }
124  
125      getLoggedInClients() : Record<string, L2LoginClient> {
126          return this.loginServerClients
127      }
128  }
129  
130  export const LoginManager = new Manager()