Gestión de cuentas

En esta sección, aprenderá a administrar la cuenta de aJami: crear una cuenta, modificar su configuración básica y eliminar una cuenta. Esta sección no cubre el significado de cada configuración individual o el uso de la cuenta para realizar acciones como agregar contactos.

¿Qué es una cuenta?

En Jami, una cuenta está representada por una cadena de certificados X.509 compuesta por tres certificados:

  1. CA: Un certificado autofirmado si se genera localmente o lo emite una empresa.

  2. Cuenta: Contiene la clave pública, su huella dactilar sirve como Jami ID.

  3. Dispositivo: Asociado a la cuenta.

Nota

Esta estructura permite a una empresa revocar una cuenta completa si es necesario, y permite al propietario de una cuenta revocar dispositivos individuales (por ejemplo, si se roba un dispositivo).

Crear una Cuenta Nueva

Nueva cuenta-daemon API

El ConfigurationManager API (cx.ring.Ring.ConfigurationManager) proporciona el método addAccount:

<method name="addAccount" tp:name-for-bindings="addAccount">
    <tp:docstring>
        Add a new account. When created, the signal <tp:member-ref>accountsChanged</tp:member-ref> is emitted. The clients must then call <tp:member-ref>getAccountList</tp:member-ref> to update their internal data structure.
        <tp:rationale>If no details are specified, the default parameters are used.</tp:rationale>
        <tp:rationale>The core tries to register the account as soon it is created.</tp:rationale>
    </tp:docstring>
    <annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="MapStringString"/>
    <arg type="a{ss}" name="details" direction="in"  tp:type="String_String_Map">
        <tp:docstring>
             The new account settings
        </tp:docstring>
    </arg>
    <arg type="s" name="createdAccountId" direction="out">
        <tp:docstring>
             A new account ID
        </tp:docstring>
    </arg>
</method>

Nueva cuenta-implementación básica

La lógica central para la creación de cuentas reside en “src/account_factory.cpp”, dentro del método “AccountFactory:: createAccount”`

std::shared_ptr<Account>
AccountFactory::createAccount(std::string_view accountType, const std::string& id)
{
    if (hasAccount(id)) {
        JAMI_ERROR("Existing account {}", id);
        return nullptr;
    }

    const auto& it = generators_.find(accountType);
    if (it == generators_.cend())
        return {};

    std::shared_ptr<Account> account = it->second(id);
    {
        std::lock_guard lock(mutex_);
        auto m = accountMaps_.find(accountType);
        if (m == accountMaps_.end())
            m = accountMaps_.emplace(std::string(accountType), AccountMap<Account>{}).first;
        m->second.emplace(id, account);
    }
    return account;
}

Después de llamar a “addAccount” (o createAccount a través de AccountFactory), se emite la señal “accountsChanged”` Los clientes deben manejar esta señal e invocar “getAccountList” para actualizar su estado local.

Formato de archivo interno

Cuando se crea una cuenta, sus datos se almacenan en un archivo gzip. Si se proporciona una contraseña, el archivo se cifra con AES: dht::crypto::aesEncrypt(archive, password) (dht::crypto::aesEncrypt is defined in OpenDHT and use nettle/{aes,gcm}).. Dentro del archivo, encontrará un archivo JSON que contiene:

  1. La clave privada “ringAccountKey” y la cadena de certificados “ringAccountCert”, codificadas en base64.

  2. La clave de CA generada ringCAKey.

  3. La lista de revocación de certificados para dispositivos ringAccountCRL.

  4. La lista de contactos.

  5. Las configuraciones de la cuenta

Eliminar una cuenta

Eliminar la cuenta de aJami es sencillo: dado que todo el material clave reside en el dispositivo local, eliminar esos archivos clave elimina efectivamente la cuenta. El único registro externo es el nombre de usuario de la cuenta en el servidor de nombres, que puede persistir según las políticas del servidor (por ejemplo, `https://ns.jami.net “ actualmente no admite la eliminación remota de nombres).

Eliminar cuenta-daemon API

El ConfigurationManager API proporciona el método removeAccount:

<method name="removeAccount" tp:name-for-bindings="removeAccount">
    <tp:docstring>
        Remove an existing account. When removed, the signal <tp:member-ref>accountsChanged</tp:member-ref> is emitted. The clients must then call <tp:member-ref>getAccountList</tp:member-ref> to update their internal data structure.
    </tp:docstring>
    <arg type="s" name="accoundID" direction="in">
        <tp:docstring>
             The account to remove, identified by its ID
        </tp:docstring>
    </arg>
</method>

Cuando se elimina la cuenta, se emitirá la señal accountsChanged. El cliente debe actualizar su estructura interna después de esta señal con otros métodos en ConfigurationManager.

Eliminar cuenta-implementación principal

La lógica de eliminación del núcleo está en “src/accout_factory.cpp (AccountFactory::removeAccount), que elimina los archivos de la cuenta y actualiza la configuración de dring.yml`.

void
AccountFactory::removeAccount(Account& account)
{
    std::string_view account_type = account.getAccountType();
    std::lock_guard lock(mutex_);
    const auto& id = account.getAccountID();
    JAMI_DEBUG("Removing account {:s}", id);
    auto m = accountMaps_.find(account_type);
    if (m != accountMaps_.end()) {
        m->second.erase(id);
        JAMI_DEBUG("Remaining {:d} {:s} account(s)", m->second.size(), account_type);
    }
}

Actualización de los detalles de una cuenta

Actualizar cuenta-daemon API

El ConfigurationManager API proporciona el método setAccountDetails:

<method name="setAccountDetails" tp:name-for-bindings="setAccountDetails">
    <tp:docstring>
        Send new account parameters, or account parameters changes, to the core. The hash table is not required to be complete, only the updated parameters may be specified.
        <tp:rationale>Account settings are written to the configuration file when the app properly quits.</tp:rationale>
        <tp:rationale>After calling this method, the core will emit the signal <tp:member-ref>accountDetailsChanged</tp:member-ref> with the updated data. The client must subscribe to this signal and use it to update its internal data structure.</tp:rationale>
    </tp:docstring>
    <arg type="s" name="accountID" direction="in">
    </arg>
    <annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="MapStringString"/>
    <arg type="a{ss}" name="details" direction="in" tp:type="String_String_Map">
    </arg>
</method>

El mapa puede contener una actualización parcial y se emitirá accountDetailsChanged al tener éxito. getAccountDetails

Administrar Dispositivos

Añadir un dispositivo

Hay dos métodos para agregar un dispositivo a una cuenta existente.

1. Restore from Backup Archive

Use “exportToFile” para extraer el archivo de la cuenta a una ruta local:

<method name="exportToFile" tp:name-for-bindings="exportToFile">
    <tp:added version="5.1.0"/>
    <tp:docstring>
        Copy the account archive to the path provided in argument.
    </tp:docstring>
    <arg type="s" name="accountID" direction="in">
    </arg>
    <arg type="s" name="destinationPath" direction="in">
    </arg>
    <arg type="s" name="password" direction="in">
    </arg>
    <arg type="b" name="success" direction="out">
        <tp:docstring>
            True if the operation was initialized successfully.
        </tp:docstring>
    </arg>
</method>

2. Export on the DHT network

Use “exportOnRing” para publicar el archivo cifrado en el DHT y obtener un PIN:

<method name="exportOnRing" tp:name-for-bindings="exportOnRing">
    <tp:docstring>
        Export account on the DHT using the given password and generated PIN (returned through exportOnRingEnded signal).
    </tp:docstring>
    <arg type="s" name="accountID" direction="in">
    </arg>
    <arg type="s" name="password" direction="in">
    </arg>
    <arg type="b" name="success" direction="out">
        <tp:docstring>
            True if the operation was initialized successfully. exportOnRingEnded will be trigered on completion.
        </tp:docstring>
    </arg>
</method>

Entonces se emite “exportOnRingEnded”` Los clientes deben escuchar la señal para recuperar el PIN.

Revocar un dispositivo

Para revocar un dispositivo, llamar a revokeDevice:

<method name="revokeDevice" tp:name-for-bindings="revokeDevice">
    <tp:docstring>
        Revoke device attached to the given Jami account, and publish the new revocation list.
    </tp:docstring>
    <arg type="s" name="accountID" direction="in">
    </arg>
    <arg type="s" name="password" direction="in">
    </arg>
    <arg type="s" name="deviceId" direction="in">
    </arg>
    <arg type="b" name="success" direction="out">
        <tp:docstring>
            True if the operation was performed successfully.
        </tp:docstring>
    </arg>
</method>
<signal name="deviceRevocationEnded" tp:name-for-bindings="deviceRevocationEnded">
    <tp:docstring>
        Notify clients when the revokeDevice operation ended.
    </tp:docstring>
    <arg type="s" name="accountID">
    </arg>
    <arg type="s" name="deviceId">
    </arg>
    <arg type="i" name="status">
        <tp:docstring>
            Status code: 0 for success
            <ul>
                <li>SUCCESS = 0         everything went fine. Device is now revoked.</li>
                <li>WRONG_PASSWORD = 1  revocation failed: wrong password.</li>
                <li>UNKNOWN_DEVICE = 2  revocation failed: unknown device.</li>
            </ul>
        </tp:docstring>
    </arg>
</signal>

Al finalizar, se emite la señal “deviceRevocationEnded” con un código de estado:

  • 0 (SUCCESS)

  • 1 (WRONG_PASSWORD)

  • 2 (UNKNOWN_DEVICE)

Los clientes deben manejar esta señal para confirmar el estado de revocación.