/*
 * Copyright 2023 Signal Messenger, LLC
 * SPDX-License-Identifier: AGPL-3.0-only
 */

syntax = "proto3";

option java_multiple_files = true;

package org.signal.chat.device;

import "google/protobuf/empty.proto";

import "org/signal/chat/common.proto";
import "org/signal/chat/errors.proto";
import "org/signal/chat/require.proto";
import "org/signal/chat/tag.proto";

// Provides methods for working with devices attached to a Signal account.
service Devices {
  // Returns a list of devices associated with the caller's account.
  rpc GetDevices(GetDevicesRequest) returns (GetDevicesResponse) {}

  // Removes a linked device from the caller's account.
  //
  // Linked devices may only remove themselves. Primary devices may remove
  // any device other than themselves.
  rpc RemoveDevice(RemoveDeviceRequest) returns (RemoveDeviceResponse) {}

  // Sets the encrypted human-readable name for a specific devices. Primary
  // devices may change the name of any device associated with their account,
  // but linked devices may only change their own name. The response will
  // indicate if the target device was not found.
  rpc SetDeviceName(SetDeviceNameRequest) returns (SetDeviceNameResponse) {}

  // Sets the token(s) the server should use to send new message notifications
  // to the authenticated device.
  rpc SetPushToken(SetPushTokenRequest) returns (SetPushTokenResponse) {}

  // Removes any push tokens associated with the authenticated device. After
  // calling this method, the server will assume that the authenticated device
  // will periodically poll for new messages.
  rpc ClearPushToken(ClearPushTokenRequest) returns (ClearPushTokenResponse) {}

  // Declares that the authenticated device supports certain features.
  rpc SetCapabilities(SetCapabilitiesRequest) returns (SetCapabilitiesResponse) {}
}

message GetDevicesRequest {}

message GetDevicesResponse {
  message LinkedDevice {
    // The identifier for the device within an account.
    uint32 id = 1;

    // A sequence of bytes that encodes an encrypted human-readable name for
    // this device.
    bytes name = 2;

    // The approximate time, in milliseconds since the epoch, at which this
    // device last connected to the server.
    uint64 last_seen = 3;

    // The registration ID of the given device.
    uint32 registration_id = 4 [(require.range).max = 0x3fff];

    // A sequence of bytes that encodes the time,
    // in milliseconds since the epoch, at which this device was
    // attached to its parent account.
    bytes created_at_ciphertext = 5;
  }

  // A list of devices linked to the authenticated account.
  repeated LinkedDevice devices = 1;
}

message RemoveDeviceRequest {
  // The identifier for the device to remove from the authenticated account. The
  // identifier must not be for the primary device.
  uint32 id = 1;
}

message SetDeviceNameRequest {
  // A sequence of bytes that encodes an encrypted human-readable name for this
  // device.
  bytes name = 1 [(require.size) = {min: 1, max: 225}];

  // The identifier for the device for which to set a name.
  uint32 id = 2;
}

message SetDeviceNameResponse {
  oneof response {
    // The device name was successfully set
    google.protobuf.Empty success = 1;

    // No device with the provided identifier was found on the account
    errors.NotFound target_device_not_found = 2 [(tag.reason) = "not_found"];
  }
}

message RemoveDeviceResponse {}

message SetPushTokenRequest {
  message ApnsTokenRequest {
    // A "standard" APNs device token.
    string apns_token = 1 [(require.nonEmpty) = true];
  }

  message FcmTokenRequest {
    // An FCM push token.
    string fcm_token = 1 [(require.nonEmpty) = true];
  }

  oneof token_request {
    // If present, specifies the APNs device token(s) the server will use to
    // send new message notifications to the authenticated device.
    ApnsTokenRequest apns_token_request = 1;

    // If present, specifies the FCM push token the server will use to send new
    // message notifications to the authenticated device.
    FcmTokenRequest fcm_token_request = 2;
  }
}

message SetPushTokenResponse {}

message ClearPushTokenRequest {}

message ClearPushTokenResponse {}

message SetCapabilitiesRequest {
  repeated common.DeviceCapability capabilities = 1;
}

message SetCapabilitiesResponse {}
