syntax = "proto3";
package hbb;

message RegisterPeer {
  string id = 1;
  int32 serial = 2;
}

enum ConnType {
  DEFAULT_CONN = 0;
  FILE_TRANSFER = 1;
  PORT_FORWARD = 2;
  RDP = 3;
  VIEW_CAMERA = 4;
  TERMINAL = 5;
}

message RegisterPeerResponse { bool request_pk = 2; }

message PunchHoleRequest { 
  string id = 1; 
  NatType nat_type = 2;
  string licence_key = 3;
  ConnType conn_type = 4;
  string token = 5;
  string version = 6;
  int32 udp_port = 7;
  bool force_relay = 8;
  int32 upnp_port = 9;
  bytes socket_addr_v6 = 10;
}

message ControlPermissions {
  enum Permission {
    keyboard = 0;
    remote_printer = 1;
    clipboard = 2;
    file = 3;
    audio = 4;
    camera = 5;
    terminal = 6;
    tunnel = 7;
    restart = 8;
    recording = 9;
    block_input = 10;
    remote_modify = 11;
    privacy_mode = 12;
  }
  uint64 permissions = 1;
}

message ControlledContext {
  string conn_audit_ref = 1;
}

message PunchHole {
  bytes socket_addr = 1;
  string relay_server = 2;
  NatType nat_type = 3;
  int32 udp_port = 4;
  bool force_relay = 5;
  int32 upnp_port = 6;
  bytes socket_addr_v6 = 7;
  ControlPermissions control_permissions = 8;
  ControlledContext controlled_context = 9;
}

message TestNatRequest {
  int32 serial = 1;
}

// per my test, uint/int has no difference in encoding, int not good for negative, use sint for negative
message TestNatResponse {
  int32 port = 1; 
  ConfigUpdate cu = 2; // for mobile
}

enum NatType {
  UNKNOWN_NAT = 0;
  ASYMMETRIC = 1;
  SYMMETRIC = 2;
}

message PunchHoleSent {
  bytes socket_addr = 1;
  string id = 2;
  string relay_server = 3;
  NatType nat_type = 4;
  string version = 5;
  int32 upnp_port = 6;
  bytes socket_addr_v6 = 7;
}

message RegisterPk {
  string id = 1;
  bytes uuid = 2;
  bytes pk = 3;
  string old_id = 4;
  bool no_register_device = 5;
}

message RegisterPkResponse {
  enum Result {
    OK = 0;
    UUID_MISMATCH = 2;
    ID_EXISTS = 3;
    TOO_FREQUENT = 4;
    INVALID_ID_FORMAT = 5;
    NOT_SUPPORT = 6;
    SERVER_ERROR = 7;
    NOT_DEPLOYED = 8;
  }
  Result result = 1;
  int32 keep_alive = 2;
}

message PunchHoleResponse {
  bytes socket_addr = 1;
  bytes pk = 2;
  enum Failure {
    ID_NOT_EXIST = 0;
    OFFLINE = 2;
    LICENSE_MISMATCH = 3;
    LICENSE_OVERUSE = 4;
  }
  Failure failure = 3;
  string relay_server = 4;
  oneof union {
    NatType nat_type = 5;
    bool is_local = 6;
  }
  string other_failure = 7;
  int32 feedback = 8;
  bool is_udp = 9;
  int32 upnp_port = 10;
  bytes socket_addr_v6 = 11;
}

message ConfigUpdate {
  int32 serial = 1;
  repeated string rendezvous_servers = 2;
}

message RequestRelay {
  string id = 1;
  string uuid = 2;
  bytes socket_addr = 3;
  string relay_server = 4;
  bool secure = 5;
  string licence_key = 6;
  ConnType conn_type = 7;
  string token = 8;
  ControlPermissions control_permissions = 9;
  ControlledContext controlled_context = 10;
}

message RelayResponse {
  bytes socket_addr = 1;
  string uuid = 2;
  string relay_server = 3;
  oneof union {
    string id = 4;
    bytes pk = 5;
  }
  string refuse_reason = 6;
  string version = 7;
  int32 feedback = 9;
  bytes socket_addr_v6 = 10;
  int32 upnp_port = 11;
}

message SoftwareUpdate { string url = 1; }

// if in same intranet, punch hole won't work both for udp and tcp,
// even some router has below connection error if we connect itself,
//  { kind: Other, error: "could not resolve to any address" },
// so we request local address to connect.
message FetchLocalAddr {
  bytes socket_addr = 1;
  string relay_server = 2;
  bytes socket_addr_v6 = 3;
  ControlPermissions control_permissions = 4;
  ControlledContext controlled_context = 5;
}

message LocalAddr {
  bytes socket_addr = 1;
  bytes local_addr = 2;
  string relay_server = 3;
  string id = 4;
  string version = 5;
  bytes socket_addr_v6 = 6;
}

message PeerDiscovery {
  string cmd = 1;
  string mac = 2;
  string id = 3;
  string username = 4;
  string hostname = 5;
  string platform = 6;
  string misc = 7;
}

message OnlineRequest {
  string id = 1;
  repeated string peers = 2;
}

message OnlineResponse {
  bytes states = 1;
}

message KeyExchange {
  repeated bytes keys = 1; 
}

message HealthCheck {
  string token = 1;
}

message HeaderEntry {
  string name = 1;
  string value = 2;
}

message HttpProxyRequest {
  string method = 1;
  string path = 2;
  repeated HeaderEntry headers = 3;
  bytes body = 4;
}

message HttpProxyResponse {
  int32 status = 1;
  repeated HeaderEntry headers = 2;
  bytes body = 3;
  string error = 4;
}

message RendezvousMessage {
  oneof union {
    RegisterPeer register_peer = 6;
    RegisterPeerResponse register_peer_response = 7;
    PunchHoleRequest punch_hole_request = 8;
    PunchHole punch_hole = 9;
    PunchHoleSent punch_hole_sent = 10;
    PunchHoleResponse punch_hole_response = 11;
    FetchLocalAddr fetch_local_addr = 12;
    LocalAddr local_addr = 13;
    ConfigUpdate configure_update = 14;
    RegisterPk register_pk = 15;
    RegisterPkResponse register_pk_response = 16;
    SoftwareUpdate software_update = 17;
    RequestRelay request_relay = 18;
    RelayResponse relay_response = 19;
    TestNatRequest test_nat_request = 20;
    TestNatResponse test_nat_response = 21;
    PeerDiscovery peer_discovery = 22;
    OnlineRequest online_request = 23;
    OnlineResponse online_response = 24;
    KeyExchange key_exchange = 25;
    HealthCheck hc = 26;
    HttpProxyRequest http_proxy_request = 27;
    HttpProxyResponse http_proxy_response = 28;
  }
}
