connectionRequest method

Future<bool?> connectionRequest()

Check this client

Implementation

Future<bool?> connectionRequest() async {
  ///Client tarafına benzer şekilde(aynı şekilde )
  ///4 aşamalı bağlantı protokolü var
  try {
    // print("CONNECTION  STARTED");

    ///
    ///                       type
    ///                       -----
    ///                        id
    ///
    ///
    ///   Server Side                            Client Side
    ///   Server Side                            Client Side
    ///
    ///
    ///   deviceID       request_connection
    ///       |      <-----------------------     deviceID
    ///       |               requestID
    ///       |
    ///       |
    ///       |
    ///       |           nonce_sending
    ///  serverNonce  ------------------------>  serverNonce
    ///                     requestID                 |
    ///                                               |
    ///                                               |
    ///                                               |
    ///                                               |
    ///   auth_data      c_nonce_sending            auth_data
    ///  clientNonce  <--------------------------  clientNonce
    ///       |              secondID
    ///       |
    ///       |
    ///       |
    ///       |
    ///       |           token_sending                 ✅
    ///  auth_token   --------------------------->  auth token
    ///                     secondID                    ✅
    ///
    ///

    ///Received connection request
    ///{
    /// id: string,
    /// type : 'request_connection',
    /// device_id : string
    ///}
    var stage1Data =
        await waitMessage(socketBroadcast, type: 'request_connection');

    if (stage1Data.fullData == null ||
        stage1Data.type == null ||
        stage1Data.messageId == null) {
      throw Exception('Message is null');
    }
    // print('CONNECTION REQUESTED DATA : ${stage1Data.runtimeType}');

    ///unique id for each request
    var requestID = stage1Data.messageId;

    if (stage1Data.fullData!['device_id'] == null) return null;

    ///unique device id
    deviceID = await encryptionService
        .decrypt4((stage1Data.fullData!['device_id']) ?? "");

    // print("DEVICE ID REVEIVED ::: $deviceID");

    var req = WebSocketConnectRequest.received(deviceID);

    if (service.connectRequests.contains(req)) {
      service.connectRequests.remove(req);
    }

    ///log device id and request id
    var db = server.databaseApi;
    await db.logConnection({
      'id': requestID,
      'deviceID': deviceID,
      'timestamp': DateTime.now().millisecondsSinceEpoch,
    }).timeout(const Duration(milliseconds: 500), onTimeout: () {
      return {"error": "log_timeout"};
    }).catchError((e) {
      return {"error": e.toString()};
    });

    ///generate server side nonce
    nonce = Nonce.random();

    /// Sending "nonce_sending" and waiting "c_nonce_sending"
    /// ----------------------------------------
    /// !!!! These messages are different id !!!!
    /// ------------------------------------------
    /// send stage 2 data
    /// {
    ///   id : requestID
    ///   nonce : server side nonce Uint8List
    ///   type : 'nonce_sending'
    /// }
    /// wait stage 3 data
    /// {
    ///  id : secondID
    ///  c_nonce: client side nonce Uint8List
    ///  type : 'c_nonce_sending'
    ///  data : encrypted auth data
    /// }
    ///
    ///
    var stage3Data = await sendAndWaitMessage(
        this,
        SocketData.fromFullData({
          'message_id': requestID,
          'nonce': nonce!.list,
          'message_type': 'nonce_sending',
          'success': true,
          'data': {}
        }),
        waitingType: 'c_nonce_sending',
        anyID: true);
    // print('STAGE 3 : $stage3Data');
    if (stage3Data == null ||
        stage3Data.fullData == null ||
        stage3Data.type == null ||
        stage3Data.messageId == null) {
      throw Exception('Message is null');
    }
    var secondID = stage3Data.fullData!['message_id'];

    if (!stage3Data.success) return false;

    ///client nonce
    cnonce = Statics.nonceCast(stage3Data.fullData!['c_nonce']);

    ///decrypt stage3 data
    await stage3Data.decrypt(nonce, cnonce);
    // print(stage3Data.data);
    if (stage3Data.data!['auth_type'] == null) {
      return false;
    } else if (stage3Data.data!['auth_type'] == 'auth') {
      var userData = await db.confirmUser(stage3Data.data, deviceID);
      if (userData != null && userData['success']) {
        // print("USER CONFIRMED : $userData");

        ///User Confirmed
        var token = await AccessToken.generateForUser(
                authType: AuthType.loggedIn,
                deviceID: deviceID!,
                mail: userData['open']['user_mail'],
                uId: userData['open']['user_id'])
            .encryptedToken;

        isLogged = true;
        userId = userData['open']['user_id'];
        chatService.addOnline(userId, this);
        var sending = SocketData.fromFullData({
          'message_id': secondID,
          'message_type': 'token_sending',
          'success': true,
          'data': {
            'token': token,
            'timestamp': DateTime.now().millisecondsSinceEpoch,
            'timeout': 30,
            'auth_type': 'auth',
            'user_data': userData['open']
          }
        });

        // print(
        //"ACCESS::: ${await AccessToken.fromToken(token).decryptToken()}");

        // print("SENDING DATA STAGE 4 : ${sending.fullData}");

        await sending.encrypt(nonce, cnonce);

        ///Send token
        sendMessage(client, sending);
        return true;
      } else {
        // print("USER NOT CONFIRMED");

        ///User Confirmed
        var token =
            await AccessToken.generateForGuess(AuthType.guess, deviceID!)
                .encryptedToken;

        sendMessage(
            client,
            SocketData.fromFullData({
              'message_id': secondID,
              'message_type': 'token_sending',
              'success': true,
              'data': {
                'token': token,
                'timestamp': DateTime.now().millisecondsSinceEpoch,
                'timeout': 30,
                'auth_type': 'guess'
              }
            }));
        return true;
      }

      /// if auth type admin
    } else if (stage3Data.data!['auth_type'] == '_admin') {
      var isAdmin = (await db.exists(Query.allowAll(
        queryType: QueryType.exists,
        equals: {"mail": stage3Data.data!["user_mail"]},
      )))!["exists"];

      if (!isAdmin) {
        var userData = await db.confirmUser(stage3Data.data, deviceID);
        if (userData != null && userData['success']) {
          // print("USER CONFIRMED : $userData");

          ///User Confirmed
          var token = await AccessToken.generateForUser(
                  authType: AuthType.admin,
                  deviceID: deviceID!,
                  mail: userData['open']['user_mail'],
                  uId: userData['open']['user_id'])
              .encryptedToken;

          isLogged = true;
          userId = userData['open']['user_id'];
          chatService.addOnline(userId, this);
          var sending = SocketData.fromFullData({
            'message_id': secondID,
            'message_type': 'token_sending',
            'success': true,
            'data': {
              'token': token,
              'timestamp': DateTime.now().millisecondsSinceEpoch,
              'timeout': 30,
              'auth_type': 'admin',
              'user_data': userData['open']
            }
          });

          // print(
          //"ACCESS::: ${await AccessToken.fromToken(token).decryptToken()}");

          // print("SENDING DATA STAGE 4 : ${sending.fullData}");

          await sending.encrypt(nonce, cnonce);

          ///Send token
          sendMessage(client, sending);
          return true;
        } else {
          // print("USER NOT CONFIRMED");

          ///User Confirmed
          var token =
              await AccessToken.generateForGuess(AuthType.guess, deviceID!)
                  .encryptedToken;

          sendMessage(
              client,
              SocketData.fromFullData({
                'message_id': secondID,
                'message_type': 'token_sending',
                'success': true,
                'data': {
                  'token': token,
                  'timestamp': DateTime.now().millisecondsSinceEpoch,
                  'timeout': 30,
                  'auth_type': 'guess'
                }
              }));
          return true;
        }
      } else {
        throw Exception("Not Admin");
      }
    } else {
      stage3Data.data!['timestamp'] = DateTime.now().millisecondsSinceEpoch;

      var token =
          await AccessToken.generateForGuess(AuthType.guess, deviceID!)
              .encryptedToken;

      ///Send token
      sendMessage(
          client,
          await SocketData.fromFullData({
            'message_id': secondID,
            'message_type': 'token_sending',
            'success': true,
            'data': {
              'token': token,
              'timestamp': DateTime.now().millisecondsSinceEpoch,
              'timeout': 30,
              'auth_type': 'guess'
            }
          }).encrypt(nonce, cnonce));
      return true;
    }
  } on Exception {
    //TODO:ADD ERROR
    return false;
  }
}