override def receive()

in finagle-postgresql/src/main/scala/com/twitter/finagle/postgresql/machine/HandshakeMachine.scala [66:129]


  override def receive(
    state: State,
    msg: BackendMessage
  ): StateMachine.TransitionResult[State, Response.ConnectionParameters] = (state, msg) match {
    case (Authenticating, AuthenticationMD5Password(salt)) =>
      def hex(input: Array[Byte]) = input.map(s => f"$s%02x").mkString
      def bytes(str: String) = str.getBytes(StandardCharsets.UTF_8)
      def md5(input: Array[Byte]*): String =
        hex(
          input
            .foldLeft(MessageDigest.getInstance("MD5")) { case (d, v) => d.update(v); d }.digest())

      credentials.password match {
        case None => Complete(ReadyForQuery(NoTx), Some(Throw(PgSqlPasswordRequired)))
        case Some(password) =>
          // concat('md5', md5(concat(md5(concat(password, username)), random-salt)))
          val hashed = md5(
            bytes(md5(bytes(password), bytes(credentials.username))),
            Buf.ByteArray.Owned.extract(salt)
          )

          Transition(Authenticating, Send(FrontendMessage.PasswordMessage(s"md5$hashed")))
      }

    case (Authenticating, AuthenticationCleartextPassword) =>
      credentials.password match {
        case None => Complete(ReadyForQuery(NoTx), Some(Throw(PgSqlPasswordRequired)))
        case Some(password) =>
          Transition(Authenticating, Send(FrontendMessage.PasswordMessage(password)))
      }

    case (
          Authenticating,
          AuthenticationOk
        ) => // This can happen at Startup when there's no password
      Transition(BackendStarting(Nil, None), NoOp)

    case (BackendStarting(params, bkd), p: BackendMessage.ParameterStatus) =>
      Transition(BackendStarting(p :: params, bkd), NoOp)
    case (BackendStarting(params, _), bkd: BackendMessage.BackendKeyData) =>
      Transition(BackendStarting(params, Some(bkd)), NoOp)

    case (BackendStarting(params, bkd), ready: BackendMessage.ReadyForQuery) =>
      Complete(ready, Some(Return(Response.ConnectionParameters(params, bkd))))

    case (state, _: BackendMessage.NoticeResponse) => Transition(state, NoOp) // TODO: don't ignore
    case (_, e: BackendMessage.ErrorResponse) =>
      // The backend closes the connection, so we use a bogus ReadyForQuery value
      Complete(ReadyForQuery(NoTx), Some(Throw(PgSqlServerError(e))))

    case (
          _,
          AuthenticationGSS | AuthenticationKerberosV5 | AuthenticationSCMCredential |
          AuthenticationSSPI | AuthenticationSASL(_)
        ) =>
      Complete(
        ReadyForQuery(NoTx),
        Some(
          Throw(PgSqlUnsupportedAuthenticationMechanism(
            msg.asInstanceOf[BackendMessage.AuthenticationMessage])))
      )

    case (state, msg) => throw PgSqlNoSuchTransition("HandshakeMachine", state, msg)
  }